Compare commits

..

1 Commits

Author SHA1 Message Date
Vladislav Leonkev
6906e68142 add multitenancy 2025-04-25 17:33:53 +02:00
42 changed files with 587 additions and 592 deletions

View File

@@ -1,6 +1,11 @@
{ {
"welcomeFile": "app/bookshop/index.html", "welcomeFile": "app/bookshop/index.html",
"routes": [ "routes": [
{
"source": "^/-/cds/.*",
"destination": "mtx-api",
"authenticationType": "none"
},
{ {
"source": "^/app/(.*)$", "source": "^/app/(.*)$",
"target": "$1", "target": "$1",

View File

@@ -18,6 +18,3 @@ updates:
- dependency-name: "chai-as-promised" - dependency-name: "chai-as-promised"
# chai-as-promised 8 doesn't work atm w/ cds.test, TODO fix that in cds.test # chai-as-promised 8 doesn't work atm w/ cds.test, TODO fix that in cds.test
versions: ["8.x"] versions: ["8.x"]
- dependency-name: "express"
# express 5 not supported atm
versions: ["5.x"]

View File

@@ -15,7 +15,7 @@ jobs:
strategy: strategy:
matrix: matrix:
node-version: [22.x, 20.x] node-version: [22.x, 20.x, 18.x]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View File

@@ -1,64 +0,0 @@
ID;parent_ID;name;page;book_ID
f846b0b9-01d4-4f6d-82a4-d79204f62514;;Foreword;3;207
f846b0b9-01d4-4f6d-82a4-d79204f62515;;Chapter 1;4;207
f846b0b9-01d4-4f6d-82a4-d79204f62516;f846b0b9-01d4-4f6d-82a4-d79204f62515;Section 1.1;5;207
f846b0b9-01d4-4f6d-82a4-d79204f62517;f846b0b9-01d4-4f6d-82a4-d79204f62515;Section 1.2;28;207
f846b0b9-01d4-4f6d-82a4-d79204f62518;f846b0b9-01d4-4f6d-82a4-d79204f62517;Subsection 1.2.1;30;207
f846b0b9-01d4-4f6d-82a4-d79204f62519;f846b0b9-01d4-4f6d-82a4-d79204f62517;Subsection 1.2.2;33;207
f846b0b9-01d4-4f6d-82a4-d79204f62520;f846b0b9-01d4-4f6d-82a4-d79204f62515;Section 1.3;36;207
f846b0b9-01d4-4f6d-82a4-d79204f62521;;Chapter 2;54;207
f846b0b9-01d4-4f6d-82a4-d79204f62522;f846b0b9-01d4-4f6d-82a4-d79204f62521;Section 2.1;56;207
f846b0b9-01d4-4f6d-82a4-d79204f62523;f846b0b9-01d4-4f6d-82a4-d79204f62521;Section 2.2;58;207
f846b0b9-01d4-4f6d-82a4-d79204f62524;;Conclusion;63;207
f846b0b9-01d4-4f6d-82a4-d79204f62525;;Endnotes;65;207
f846b0b9-01d4-4f6d-82a4-d79204f62526;;Copyright notice;2;251
f846b0b9-01d4-4f6d-82a4-d79204f62527;;Chapter 1;3;251
f846b0b9-01d4-4f6d-82a4-d79204f62528;f846b0b9-01d4-4f6d-82a4-d79204f62527;Section 1.1;5;251
f846b0b9-01d4-4f6d-82a4-d79204f62529;f846b0b9-01d4-4f6d-82a4-d79204f62527;Section 1.2;13;251
f846b0b9-01d4-4f6d-82a4-d79204f62530;;Chapter 2;20;251
f846b0b9-01d4-4f6d-82a4-d79204f62531;f846b0b9-01d4-4f6d-82a4-d79204f62530;Section 2.1;21;251
f846b0b9-01d4-4f6d-82a4-d79204f62532;f846b0b9-01d4-4f6d-82a4-d79204f62530;Section 2.2;25;251
f846b0b9-01d4-4f6d-82a4-d79204f62533;f846b0b9-01d4-4f6d-82a4-d79204f62530;Section 2.3;27;251
f846b0b9-01d4-4f6d-82a4-d79204f62534;;Chapter 3;30;251
f846b0b9-01d4-4f6d-82a4-d79204f62535;;Endnotes;41;251
f846b0b9-01d4-4f6d-82a4-d79204f62551;;Acknowledgements;1;271
f846b0b9-01d4-4f6d-82a4-d79204f62552;;The Flight;2;271
f846b0b9-01d4-4f6d-82a4-d79204f62553;;Hexwood Farm;8;271
f846b0b9-01d4-4f6d-82a4-d79204f62554;f846b0b9-01d4-4f6d-82a4-d79204f62553;Castle Saburac;13;271
f846b0b9-01d4-4f6d-82a4-d79204f62555;f846b0b9-01d4-4f6d-82a4-d79204f62553;The Curse of Rapkyn;27;271
f846b0b9-01d4-4f6d-82a4-d79204f62556;f846b0b9-01d4-4f6d-82a4-d79204f62553;The Mannikin;35;271
f846b0b9-01d4-4f6d-82a4-d79204f62557;;The Eye of Time;44;271
f846b0b9-01d4-4f6d-82a4-d79204f62558;;The Enchanting;59;271
f846b0b9-01d4-4f6d-82a4-d79204f62559;f846b0b9-01d4-4f6d-82a4-d79204f62558;The Telling Bone;73;271
f846b0b9-01d4-4f6d-82a4-d79204f62560;f846b0b9-01d4-4f6d-82a4-d79204f62558;The Power of Adamcos;86;271
f846b0b9-01d4-4f6d-82a4-d79204f62561;f846b0b9-01d4-4f6d-82a4-d79204f62558;The House of the Sorcerer;98;271
f846b0b9-01d4-4f6d-82a4-d79204f62562;;The Changeling;105;271
f846b0b9-01d4-4f6d-82a4-d79204f62563;f846b0b9-01d4-4f6d-82a4-d79204f62562;The Flying Broomsticks;118;271
f846b0b9-01d4-4f6d-82a4-d79204f62564;f846b0b9-01d4-4f6d-82a4-d79204f62563;The Fish Out of Water;126;271
f846b0b9-01d4-4f6d-82a4-d79204f62565;;The Final Magic;138;271
f846b0b9-01d4-4f6d-82a4-d79204f62566;;Copyright;159;271
f846b0b9-01d4-4f6d-82a4-d79204f62567;;Editor's Note;1;201
f846b0b9-01d4-4f6d-82a4-d79204f62568;;Chapter I;2;201
f846b0b9-01d4-4f6d-82a4-d79204f62569;;Chapter II;31;201
f846b0b9-01d4-4f6d-82a4-d79204f62570;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.I;47;201
f846b0b9-01d4-4f6d-82a4-d79204f62571;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.II;62;201
f846b0b9-01d4-4f6d-82a4-d79204f62572;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.III;75;201
f846b0b9-01d4-4f6d-82a4-d79204f62573;f846b0b9-01d4-4f6d-82a4-d79204f62569;Section II.IV;87;201
f846b0b9-01d4-4f6d-82a4-d79204f62574;;Chapter III;105;201
f846b0b9-01d4-4f6d-82a4-d79204f62575;f846b0b9-01d4-4f6d-82a4-d79204f62574;Section III.I;128;201
f846b0b9-01d4-4f6d-82a4-d79204f62576;f846b0b9-01d4-4f6d-82a4-d79204f62575;Subsection III.I.I;156;201
f846b0b9-01d4-4f6d-82a4-d79204f62577;f846b0b9-01d4-4f6d-82a4-d79204f62575;Subsection III.I.II;173;201
f846b0b9-01d4-4f6d-82a4-d79204f62578;f846b0b9-01d4-4f6d-82a4-d79204f62574;Section III.II;185;201
f846b0b9-01d4-4f6d-82a4-d79204f62579;;Chapter IV;203;201
f846b0b9-01d4-4f6d-82a4-d79204f62580;;Acknowledgments;250;201
f846b0b9-01d4-4f6d-82a4-d79204f62582;;Foreword;1;252
f846b0b9-01d4-4f6d-82a4-d79204f62583;;Chapter 1;3;252
f846b0b9-01d4-4f6d-82a4-d79204f62584;f846b0b9-01d4-4f6d-82a4-d79204f62583;Section 1.1;5;252
f846b0b9-01d4-4f6d-82a4-d79204f62585;f846b0b9-01d4-4f6d-82a4-d79204f62583;Section 1.2;8;252
f846b0b9-01d4-4f6d-82a4-d79204f62586;;Chapter 2;10;252
f846b0b9-01d4-4f6d-82a4-d79204f62587;f846b0b9-01d4-4f6d-82a4-d79204f62586;Section 2.1;12;252
f846b0b9-01d4-4f6d-82a4-d79204f62588;f846b0b9-01d4-4f6d-82a4-d79204f62587;Subsection 2.1.1;14;252
f846b0b9-01d4-4f6d-82a4-d79204f62589;f846b0b9-01d4-4f6d-82a4-d79204f62587;Subsection 2.1.2;16;252
f846b0b9-01d4-4f6d-82a4-d79204f62590;f846b0b9-01d4-4f6d-82a4-d79204f62586;Section 2.2;18;252
f846b0b9-01d4-4f6d-82a4-d79204f62591;f846b0b9-01d4-4f6d-82a4-d79204f62590;Subsection 2.2.1;21;252
f846b0b9-01d4-4f6d-82a4-d79204f62592;;Endnotes;25;252
1 ID parent_ID name page book_ID
2 f846b0b9-01d4-4f6d-82a4-d79204f62514 Foreword 3 207
3 f846b0b9-01d4-4f6d-82a4-d79204f62515 Chapter 1 4 207
4 f846b0b9-01d4-4f6d-82a4-d79204f62516 f846b0b9-01d4-4f6d-82a4-d79204f62515 Section 1.1 5 207
5 f846b0b9-01d4-4f6d-82a4-d79204f62517 f846b0b9-01d4-4f6d-82a4-d79204f62515 Section 1.2 28 207
6 f846b0b9-01d4-4f6d-82a4-d79204f62518 f846b0b9-01d4-4f6d-82a4-d79204f62517 Subsection 1.2.1 30 207
7 f846b0b9-01d4-4f6d-82a4-d79204f62519 f846b0b9-01d4-4f6d-82a4-d79204f62517 Subsection 1.2.2 33 207
8 f846b0b9-01d4-4f6d-82a4-d79204f62520 f846b0b9-01d4-4f6d-82a4-d79204f62515 Section 1.3 36 207
9 f846b0b9-01d4-4f6d-82a4-d79204f62521 Chapter 2 54 207
10 f846b0b9-01d4-4f6d-82a4-d79204f62522 f846b0b9-01d4-4f6d-82a4-d79204f62521 Section 2.1 56 207
11 f846b0b9-01d4-4f6d-82a4-d79204f62523 f846b0b9-01d4-4f6d-82a4-d79204f62521 Section 2.2 58 207
12 f846b0b9-01d4-4f6d-82a4-d79204f62524 Conclusion 63 207
13 f846b0b9-01d4-4f6d-82a4-d79204f62525 Endnotes 65 207
14 f846b0b9-01d4-4f6d-82a4-d79204f62526 Copyright notice 2 251
15 f846b0b9-01d4-4f6d-82a4-d79204f62527 Chapter 1 3 251
16 f846b0b9-01d4-4f6d-82a4-d79204f62528 f846b0b9-01d4-4f6d-82a4-d79204f62527 Section 1.1 5 251
17 f846b0b9-01d4-4f6d-82a4-d79204f62529 f846b0b9-01d4-4f6d-82a4-d79204f62527 Section 1.2 13 251
18 f846b0b9-01d4-4f6d-82a4-d79204f62530 Chapter 2 20 251
19 f846b0b9-01d4-4f6d-82a4-d79204f62531 f846b0b9-01d4-4f6d-82a4-d79204f62530 Section 2.1 21 251
20 f846b0b9-01d4-4f6d-82a4-d79204f62532 f846b0b9-01d4-4f6d-82a4-d79204f62530 Section 2.2 25 251
21 f846b0b9-01d4-4f6d-82a4-d79204f62533 f846b0b9-01d4-4f6d-82a4-d79204f62530 Section 2.3 27 251
22 f846b0b9-01d4-4f6d-82a4-d79204f62534 Chapter 3 30 251
23 f846b0b9-01d4-4f6d-82a4-d79204f62535 Endnotes 41 251
24 f846b0b9-01d4-4f6d-82a4-d79204f62551 Acknowledgements 1 271
25 f846b0b9-01d4-4f6d-82a4-d79204f62552 The Flight 2 271
26 f846b0b9-01d4-4f6d-82a4-d79204f62553 Hexwood Farm 8 271
27 f846b0b9-01d4-4f6d-82a4-d79204f62554 f846b0b9-01d4-4f6d-82a4-d79204f62553 Castle Saburac 13 271
28 f846b0b9-01d4-4f6d-82a4-d79204f62555 f846b0b9-01d4-4f6d-82a4-d79204f62553 The Curse of Rapkyn 27 271
29 f846b0b9-01d4-4f6d-82a4-d79204f62556 f846b0b9-01d4-4f6d-82a4-d79204f62553 The Mannikin 35 271
30 f846b0b9-01d4-4f6d-82a4-d79204f62557 The Eye of Time 44 271
31 f846b0b9-01d4-4f6d-82a4-d79204f62558 The Enchanting 59 271
32 f846b0b9-01d4-4f6d-82a4-d79204f62559 f846b0b9-01d4-4f6d-82a4-d79204f62558 The Telling Bone 73 271
33 f846b0b9-01d4-4f6d-82a4-d79204f62560 f846b0b9-01d4-4f6d-82a4-d79204f62558 The Power of Adamcos 86 271
34 f846b0b9-01d4-4f6d-82a4-d79204f62561 f846b0b9-01d4-4f6d-82a4-d79204f62558 The House of the Sorcerer 98 271
35 f846b0b9-01d4-4f6d-82a4-d79204f62562 The Changeling 105 271
36 f846b0b9-01d4-4f6d-82a4-d79204f62563 f846b0b9-01d4-4f6d-82a4-d79204f62562 The Flying Broomsticks 118 271
37 f846b0b9-01d4-4f6d-82a4-d79204f62564 f846b0b9-01d4-4f6d-82a4-d79204f62563 The Fish Out of Water 126 271
38 f846b0b9-01d4-4f6d-82a4-d79204f62565 The Final Magic 138 271
39 f846b0b9-01d4-4f6d-82a4-d79204f62566 Copyright 159 271
40 f846b0b9-01d4-4f6d-82a4-d79204f62567 Editor's Note 1 201
41 f846b0b9-01d4-4f6d-82a4-d79204f62568 Chapter I 2 201
42 f846b0b9-01d4-4f6d-82a4-d79204f62569 Chapter II 31 201
43 f846b0b9-01d4-4f6d-82a4-d79204f62570 f846b0b9-01d4-4f6d-82a4-d79204f62569 Section II.I 47 201
44 f846b0b9-01d4-4f6d-82a4-d79204f62571 f846b0b9-01d4-4f6d-82a4-d79204f62569 Section II.II 62 201
45 f846b0b9-01d4-4f6d-82a4-d79204f62572 f846b0b9-01d4-4f6d-82a4-d79204f62569 Section II.III 75 201
46 f846b0b9-01d4-4f6d-82a4-d79204f62573 f846b0b9-01d4-4f6d-82a4-d79204f62569 Section II.IV 87 201
47 f846b0b9-01d4-4f6d-82a4-d79204f62574 Chapter III 105 201
48 f846b0b9-01d4-4f6d-82a4-d79204f62575 f846b0b9-01d4-4f6d-82a4-d79204f62574 Section III.I 128 201
49 f846b0b9-01d4-4f6d-82a4-d79204f62576 f846b0b9-01d4-4f6d-82a4-d79204f62575 Subsection III.I.I 156 201
50 f846b0b9-01d4-4f6d-82a4-d79204f62577 f846b0b9-01d4-4f6d-82a4-d79204f62575 Subsection III.I.II 173 201
51 f846b0b9-01d4-4f6d-82a4-d79204f62578 f846b0b9-01d4-4f6d-82a4-d79204f62574 Section III.II 185 201
52 f846b0b9-01d4-4f6d-82a4-d79204f62579 Chapter IV 203 201
53 f846b0b9-01d4-4f6d-82a4-d79204f62580 Acknowledgments 250 201
54 f846b0b9-01d4-4f6d-82a4-d79204f62582 Foreword 1 252
55 f846b0b9-01d4-4f6d-82a4-d79204f62583 Chapter 1 3 252
56 f846b0b9-01d4-4f6d-82a4-d79204f62584 f846b0b9-01d4-4f6d-82a4-d79204f62583 Section 1.1 5 252
57 f846b0b9-01d4-4f6d-82a4-d79204f62585 f846b0b9-01d4-4f6d-82a4-d79204f62583 Section 1.2 8 252
58 f846b0b9-01d4-4f6d-82a4-d79204f62586 Chapter 2 10 252
59 f846b0b9-01d4-4f6d-82a4-d79204f62587 f846b0b9-01d4-4f6d-82a4-d79204f62586 Section 2.1 12 252
60 f846b0b9-01d4-4f6d-82a4-d79204f62588 f846b0b9-01d4-4f6d-82a4-d79204f62587 Subsection 2.1.1 14 252
61 f846b0b9-01d4-4f6d-82a4-d79204f62589 f846b0b9-01d4-4f6d-82a4-d79204f62587 Subsection 2.1.2 16 252
62 f846b0b9-01d4-4f6d-82a4-d79204f62590 f846b0b9-01d4-4f6d-82a4-d79204f62586 Section 2.2 18 252
63 f846b0b9-01d4-4f6d-82a4-d79204f62591 f846b0b9-01d4-4f6d-82a4-d79204f62590 Subsection 2.2.1 21 252
64 f846b0b9-01d4-4f6d-82a4-d79204f62592 Endnotes 25 252

View File

@@ -11,7 +11,6 @@ entity Books : managed {
price : Price; price : Price;
currency : Currency; currency : Currency;
image : LargeBinary @Core.MediaType: 'image/png'; image : LargeBinary @Core.MediaType: 'image/png';
contents : Composition of many Contents on contents.book = $self;
} }
entity Authors : managed { entity Authors : managed {
@@ -31,16 +30,6 @@ entity Genres : sap.common.CodeList {
children : Composition of many Genres on children.parent = $self; children : Composition of many Genres on children.parent = $self;
} }
/** Hierarchically organized entity for Contents */
entity Contents {
key ID : UUID;
name : String;
page : Integer;
parent : Association to Contents;
children : Composition of many Contents on children.parent = $self;
book : Association to Books;
}
type Price : Decimal(9,2); type Price : Decimal(9,2);

View File

@@ -9,7 +9,7 @@
"index.cds" "index.cds"
], ],
"devDependencies": { "devDependencies": {
"@cap-js/sqlite": ">=1" "@cap-js/sqlite": "*"
}, },
"dependencies": { "dependencies": {
"@sap/cds": ">=7", "@sap/cds": ">=7",

View File

@@ -3,5 +3,4 @@ service AdminService @(path:'/admin') {
entity Authors as projection on my.Authors; entity Authors as projection on my.Authors;
entity Books as projection on my.Books; entity Books as projection on my.Books;
entity Genres as projection on my.Genres; entity Genres as projection on my.Genres;
entity Contents as projection on my.Contents;
} }

View File

@@ -3,14 +3,14 @@ service CatalogService @(path:'/browse') {
/** For displaying lists of Books */ /** For displaying lists of Books */
@readonly entity ListOfBooks as projection on Books @readonly entity ListOfBooks as projection on Books
excluding { descr, contents }; excluding { descr };
/** For display in details pages */ /** For display in details pages */
@readonly entity Books as projection on my.Books { *, @readonly entity Books as projection on my.Books { *,
author.name as author author.name as author
} excluding { createdBy, modifiedBy, contents }; } excluding { createdBy, modifiedBy };
@requires: 'authenticated-user' @requires: 'authenticated-user'
action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer }; action submitOrder ( book: Books:ID, quantity: Integer ) returns { stock: Integer };
event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String }; event OrderedBook : { book: Books:ID; quantity: Integer; buyer: String };
} }

View File

@@ -14,24 +14,25 @@ GET http://localhost:4004/odata/v4/test/Genres?
POST http://localhost:4004/odata/v4/test/Genres? POST http://localhost:4004/odata/v4/test/Genres?
Content-Type: application/json Content-Type: application/json
{ "ID":"100aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Some Sample Genres...", "children":[ { "ID":100, "name":"Some Sample Genres...", "children":[
{ "ID":"101aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Cat", "children":[ { "ID":101, "name":"Cat", "children":[
{ "ID":"102aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Kitty", "children":[ { "ID":102, "name":"Kitty", "children":[
{ "ID":"103aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Aristocat" }, { "ID":103, "name":"Kitty Cat", "children":[
{ "ID":"104aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Kitty Bat" } ]}, { "ID":104, "name":"Aristocat" } ]},
{ "ID":"105aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Catwoman", "children":[ { "ID":105, "name":"Kitty Bat" } ]},
{ "ID":"106aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Catalina" } ]} ]}, { "ID":106, "name":"Catwoman", "children":[
{ "ID":"107aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "name":"Catweazle" } { "ID":107, "name":"Catalina" } ]} ]},
{ "ID":108, "name":"Catweazle" }
]} ]}
### ###
GET http://localhost:4004/odata/v4/test/Genres(100aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa)? GET http://localhost:4004/odata/v4/test/Genres(100)?
&$expand=children # &$expand=children
&$expand=children($expand=children($expand=children($expand=children))) # &$expand=children($expand=children($expand=children($expand=children)))
### ###
DELETE http://localhost:4004/odata/v4/test/Genres(103aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) DELETE http://localhost:4004/odata/v4/test/Genres(103)
### ###
DELETE http://localhost:4004/odata/v4/test/Genres(100aaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa) DELETE http://localhost:4004/odata/v4/test/Genres(100)
### ###

View File

@@ -40,7 +40,8 @@ Authorization: Basic alice:
{ {
"ID": 112, "ID": 112,
"name": "Shakespeeeeere" "name": "Shakespeeeeere",
"age": 22
} }
@@ -55,7 +56,7 @@ Authorization: Basic alice:
"title": "Poems : Pocket Poets", "title": "Poems : Pocket Poets",
"descr": "The Everyman's Library Pocket Poets hardcover series is popular for its compact size and reasonable price which does not compromise content. Poems: Bronte contains poems that demonstrate a sensibility elemental in its force with an imaginative discipline and flexibility of the highest order. Also included are an Editor's Note and an index of first lines.", "descr": "The Everyman's Library Pocket Poets hardcover series is popular for its compact size and reasonable price which does not compromise content. Poems: Bronte contains poems that demonstrate a sensibility elemental in its force with an imaginative discipline and flexibility of the highest order. Also included are an Editor's Note and an index of first lines.",
"author": { "ID": 101 }, "author": { "ID": 101 },
"genre": { "ID": "12aaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" }, "genre": { "ID": 12 },
"stock": 5, "stock": 5,
"price": "12.05", "price": "12.05",
"currency": { "code": "USD" } "currency": { "code": "USD" }

6
bookstore/app/routes.js Normal file
View File

@@ -0,0 +1,6 @@
// Add routes to UIs from imported packages
module.exports = (app) => {
app.serve ('/bookshop') .from ('@capire/bookshop','app/vue')
app.serve ('/reviews') .from ('@capire/reviews','app/vue')
app.serve ('/orders') .from('@capire/orders','app/orders')
}

View File

@@ -11,7 +11,8 @@
"@sap-cloud-sdk/resilience": "^4", "@sap-cloud-sdk/resilience": "^4",
"@sap/cds": ">=5", "@sap/cds": ">=5",
"express": "^4.17.1", "express": "^4.17.1",
"@cap-js/hana": ">=1" "@cap-js/hana": "^1",
"@sap/cds-mtxs": "^2"
}, },
"cds": { "cds": {
"requires": { "requires": {
@@ -24,7 +25,10 @@
"model": "@capire/orders" "model": "@capire/orders"
}, },
"messaging": true, "messaging": true,
"db": true "db": true,
"multitenancy": true,
"auth": "xsuaa"
}, },
"log": { "service": true } "log": { "service": true }
}, },

View File

@@ -1,16 +1,10 @@
const cds = require ('@sap/cds') const cds = require ('@sap/cds')
// Add routes to UIs from imported packages // Add routes to UIs from imported packages
if (!cds.env.production) cds.once ('bootstrap', (app) => { if (!cds.env.production) cds.once ('bootstrap', require('../app/routes'))
app.serve ('/bookshop') .from ('@capire/bookshop','app/vue')
app.serve ('/reviews') .from ('@capire/reviews','app/vue')
app.serve ('/orders') .from('@capire/orders','app/orders')
})
// Mashing up bookshop services with required services... // Mashing up bookshop services with required services...
cds.once ('served', async ()=>{ cds.once ('served', async ()=>{ // called by server.js
const CatalogService = await cds.connect.to ('CatalogService') const CatalogService = await cds.connect.to ('CatalogService')
const ReviewsService = await cds.connect.to ('ReviewsService') const ReviewsService = await cds.connect.to ('ReviewsService')

View File

@@ -1,13 +0,0 @@
using { sap } from '@sap/cds/common';
extend sap.common.Currencies with {
// Currencies.code = ISO 4217 alphabetic three-letter code
// with the first two letters being equal to ISO 3166 alphabetic country codes
// See also:
// [1] https://www.iso.org/iso-4217-currency-codes.html
// [2] https://www.currency-iso.org/en/home/tables/table-a1.html
// [3] https://www.ibm.com/support/knowledgecenter/en/SSZLC2_7.0.0/com.ibm.commerce.payments.developer.doc/refs/rpylerl2mst97.htm
numcode : Integer;
exponent : Integer; //> e.g. 2 --> 1 Dollar = 10^2 Cent
minor : String; //> e.g. 'Cent'
}

View File

@@ -1,2 +1,45 @@
using from './currencies'; using { sap } from '@sap/cds/common';
using from './regions';
extend sap.common.Currencies with {
// Currencies.code = ISO 4217 alphabetic three-letter code
// with the first two letters being equal to ISO 3166 alphabetic country codes
// See also:
// [1] https://www.iso.org/iso-4217-currency-codes.html
// [2] https://www.currency-iso.org/en/home/tables/table-a1.html
// [3] https://www.ibm.com/support/knowledgecenter/en/SSZLC2_7.0.0/com.ibm.commerce.payments.developer.doc/refs/rpylerl2mst97.htm
numcode : Integer;
exponent : Integer; //> e.g. 2 --> 1 Dollar = 10^2 Cent
minor : String; //> e.g. 'Cent'
}
/**
* The Code Lists below are designed as optional extensions to
* the base schema. Switch them on by adding an Association to
* one of the code list entities in your models or by:
* annotate sap.common.Countries with @cds.persistence.skip:false;
*/
context sap.common.countries {
extend sap.common.Countries {
regions : Composition of many Regions on regions._parent = $self.code;
}
entity Regions : sap.common.CodeList {
key code : String(5); // ISO 3166-2 alpha5 codes, e.g. DE-BW
children : Composition of many Regions on children._parent = $self.code;
cities : Composition of many Cities on cities.region = $self;
_parent : String(11);
}
entity Cities : sap.common.CodeList {
key code : String(11);
region : Association to Regions;
districts : Composition of many Districts on districts.city = $self;
}
entity Districts : sap.common.CodeList {
key code : String(11);
city : Association to Cities;
}
}

View File

@@ -1,22 +0,0 @@
using { sap.common } from '@sap/cds/common';
namespace sap.common.countries;
extend common.Countries {
regions : Composition of many Regions on regions._parent = $self.code;
}
entity Regions : common.CodeList {
key code : String(5); // ISO 3166-2 alpha5 codes, e.g. DE-BW
children : Composition of many Regions on children._parent = $self.code;
cities : Composition of many Cities on cities.region = $self;
_parent : String(11);
}
entity Cities : common.CodeList {
key code : String(11);
region : Association to Regions;
districts : Composition of many Districts on districts.city = $self;
}
entity Districts : common.CodeList {
key code : String(11);
city : Association to Cities;
}

1
db Symbolic link
View File

@@ -0,0 +1 @@
shared-db/db

View File

@@ -1,9 +1,6 @@
using { AdminService } from '@capire/bookstore'; using { AdminService } from '@capire/bookstore';
using from '../common'; // to help UI linter get the complete annotations using from '../common'; // to help UI linter get the complete annotations
annotate sap.capire.bookshop.Genres with @fiori.draft.enabled;
annotate AdminService.Genres with @odata.draft.enabled;
annotate AdminService.Genres with @odata.draft.bypass;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@@ -14,11 +11,10 @@ annotate AdminService.Genres with @odata.draft.bypass;
annotate AdminService.Books with @( annotate AdminService.Books with @(
UI: { UI: {
Facets: [ Facets: [
{$Type: 'UI.ReferenceFacet', Label: '{i18n>General}', Target: '@UI.FieldGroup#General'}, {$Type: 'UI.ReferenceFacet', Label: '{i18n>General}', Target: '@UI.FieldGroup#General'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Translations}', Target: 'texts/@UI.LineItem'}, {$Type: 'UI.ReferenceFacet', Label: '{i18n>Translations}', Target: 'texts/@UI.LineItem'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'}, {$Type: 'UI.ReferenceFacet', Label: '{i18n>Details}', Target: '@UI.FieldGroup#Details'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Admin}', Target: '@UI.FieldGroup#Admin'}, {$Type: 'UI.ReferenceFacet', Label: '{i18n>Admin}', Target: '@UI.FieldGroup#Admin'},
{$Type: 'UI.ReferenceFacet', Label: '{i18n>Contents}', Target: 'contents/@UI.PresentationVariant'}
], ],
FieldGroup#General: { FieldGroup#General: {
Data: [ Data: [
@@ -66,16 +62,29 @@ annotate AdminService.Books with {
ValueListProperty: 'ID', ValueListProperty: 'ID',
} }
], ],
PresentationVariantQualifier: 'VH',
} }
}); });
} }
annotate AdminService.Genres with @UI: {
PresentationVariant #VH: {
$Type : 'UI.PresentationVariantType',
Visualizations : ['@UI.LineItem'],
RecursiveHierarchyQualifier: 'GenreHierarchy'
},
LineItem : [{
$Type: 'UI.DataField',
Value: name,
Label :'{i18n>Name}'
}],
};
// Hide ID because of the ValueHelp // Hide ID because of the ValueHelp
annotate AdminService.Genres with { annotate AdminService.Genres with {
ID @UI.Hidden; ID @UI.Hidden;
}; };
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// //
// Draft for Localized Data // Draft for Localized Data
@@ -116,4 +125,3 @@ extend service AdminService {
// Workaround for Fiori popup for asking user to enter a new UUID on Create // Workaround for Fiori popup for asking user to enter a new UUID on Create
annotate AdminService.Books with { ID @Core.Computed; } annotate AdminService.Books with { ID @Core.Computed; }
using from './tree-view';

View File

@@ -1,42 +0,0 @@
using { AdminService } from '@capire/bookstore';
////////////////////////////////////////////////////////////////////////////
//
// Contents Tree Table Annotations
//
// Tell Fiori about the structure of the hierarchy
annotate AdminService.Contents with @Aggregation.RecursiveHierarchy #ContentsHierarchy : {
ParentNavigationProperty : parent, // navigates to a node's parent
NodeProperty : ID, // identifies a node, usually the key
};
// Fiori expects the following to be defined explicitly, even though they're always the same
extend AdminService.Contents with @(
// The columns expected by Fiori to be present in hierarchy entities
Hierarchy.RecursiveHierarchy #ContentsHierarchy : {
LimitedDescendantCount : LimitedDescendantCount,
DistanceFromRoot : DistanceFromRoot,
DrillState : DrillState,
LimitedRank : LimitedRank
},
// Disallow filtering on these properties from Fiori UIs
Capabilities.FilterRestrictions.NonFilterableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'LimitedRank'
],
// Disallow sorting on these properties from Fiori UIs
Capabilities.SortRestrictions.NonSortableProperties : [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'LimitedRank'
],
) columns { // Ensure we can query these fields from database
null as LimitedDescendantCount : Int16,
null as DistanceFromRoot : Int16,
null as DrillState : String,
null as LimitedRank : Int16,
};

View File

@@ -79,11 +79,6 @@
"pattern": "Books({key}/author({key2}):?query:", "pattern": "Books({key}/author({key2}):?query:",
"name": "AuthorsDetails", "name": "AuthorsDetails",
"target": "AuthorsDetails" "target": "AuthorsDetails"
},
{
"pattern": "Books({key})/contents({key2}):?query:",
"name": "ContentsDetails",
"target": "ContentsDetails"
} }
], ],
"targets": { "targets": {
@@ -117,34 +112,11 @@
"detail" : { "detail" : {
"route" : "AuthorsDetails" "route" : "AuthorsDetails"
} }
},
"contents": {
"detail": {
"route": "ContentsDetails"
}
}
},
"controlConfiguration": {
"contents/@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": {
"hierarchyQualifier": "ContentsHierarchy",
"type": "TreeTable"
}
} }
} }
} }
} }
}, },
"ContentsDetails": {
"type": "Component",
"id": "ContentsDetails",
"name": "sap.fe.templates.ObjectPage",
"options": {
"settings": {
"contextPath": "/Books/contents"
}
}
},
"AuthorsDetails": { "AuthorsDetails": {
"type": "Component", "type": "Component",
"id": "AuthorsDetailsList", "id": "AuthorsDetailsList",

View File

@@ -18,6 +18,14 @@
"title": "Browse Books", "title": "Browse Books",
"targetURL": "#Books-display" "targetURL": "#Books-display"
} }
},
{
"id": "BrowseGenres",
"tileType": "sap.ushell.ui.tile.StaticTile",
"properties": {
"title": "Browse Genres",
"targetURL": "#Genres-display"
}
} }
] ]
}, },
@@ -35,14 +43,6 @@
"title": "Manage Books", "title": "Manage Books",
"targetURL": "#Books-manage" "targetURL": "#Books-manage"
} }
},
{
"id": "ManageGenres",
"tileType": "sap.ushell.ui.tile.StaticTile",
"properties": {
"title": "Manage Genres",
"targetURL": "#Genres-manage"
}
}, },
{ {
"id": "ManageAuthors", "id": "ManageAuthors",
@@ -114,10 +114,10 @@
"url": "/admin-authors/webapp" "url": "/admin-authors/webapp"
} }
}, },
"ManageGenres": { "BrowseGenres": {
"semanticObject": "Genres", "semanticObject": "Genres",
"action": "manage", "action": "display",
"title": "Manage Genres", "title": "Browse Genres",
"signature": { "signature": {
"parameters": { "parameters": {
"Genre.ID": { "Genre.ID": {

View File

@@ -4,6 +4,7 @@
using { sap.capire.bookshop as my } from '@capire/bookstore'; using { sap.capire.bookshop as my } from '@capire/bookstore';
using { sap.common } from '@capire/common'; using { sap.common } from '@capire/common';
using { sap.common.Currencies } from '@sap/cds/common';
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
@@ -37,7 +38,7 @@ annotate my.Books with @(
author @ValueList.entity : 'Authors'; author @ValueList.entity : 'Authors';
}; };
annotate common.Currencies with { annotate Currencies with {
symbol @Common.Label : '{i18n>Currency}'; symbol @Common.Label : '{i18n>Currency}';
} }
@@ -68,53 +69,102 @@ annotate my.Books with {
image @title: '{i18n>Image}'; image @title: '{i18n>Image}';
} }
annotate my.Contents with @( ////////////////////////////////////////////////////////////////////////////
//
// Computed Fields for Tree Tables
//
// DISCLAIMER: The below are an alpha version implementation and will change in final release !!!
//
aspect Hierarchy {
LimitedDescendantCount : Integer64 = null;
DistanceFromRoot : Integer64 = null;
DrillState : String = null;
Matched : Boolean = null;
MatchedDescendantCount : Integer64 = null;
LimitedRank : Integer64 = null;
}
annotate Hierarchy with @Capabilities.FilterRestrictions.NonFilterableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'Matched',
'MatchedDescendantCount',
'LimitedRank'
];
annotate Hierarchy with @Capabilities.SortRestrictions.NonSortableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'Matched',
'MatchedDescendantCount',
'LimitedRank'
];
extend my.Genres with Hierarchy;
////////////////////////////////////////////////////////////////////////////
//
// Genres Tree Table Annotations
//
// DISCLAIMER: The below are an alpha version implementation and will change in final release !!!
//
annotate my.Genres with @Aggregation.RecursiveHierarchy #GenreHierarchy: {
$Type : 'Aggregation.RecursiveHierarchyType',
NodeProperty : ID, // identifies a node
ParentNavigationProperty: parent // navigates to a node's parent
};
annotate my.Genres with @Hierarchy.RecursiveHierarchy #GenreHierarchy: {
$Type : 'Hierarchy.RecursiveHierarchyType',
LimitedDescendantCount: LimitedDescendantCount,
DistanceFromRoot : DistanceFromRoot,
DrillState : DrillState,
Matched : Matched,
MatchedDescendantCount: MatchedDescendantCount,
LimitedRank : LimitedRank
};
annotate my.Genres with @(
readonly,
cds.search: {name} cds.search: {name}
); );
////////////////////////////////////////////////////////////////////////////
//
// Genres List
//
annotate my.Genres with @(
Common.SemanticKey : [name],
UI : {
SelectionFields : [name],
LineItem : [
{ Value : name, Label : '{i18n>Name}' },
],
}
);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //
// Contents List // Genre Details
// //
annotate my.Contents with @UI: { annotate my.Genres with @(UI : {
PresentationVariant : { Identification : [{ Value: name}],
$Type : 'UI.PresentationVariantType', HeaderInfo : {
RequestAtLeast: [name], TypeName : '{i18n>Genre}',
Visualizations: ['@UI.LineItem'], TypeNamePlural : '{i18n>Genres}',
}, Title : { Value: name },
LineItem : [{ Description : { Value: ID }
$Type: 'UI.DataField', }
Value: name, });
Label : '{i18n>Name}'
}, ////////////////////////////////////////////////////////////////////////////
{ //
$Type: 'UI.DataField', // Genres Elements
Value: page, //
Label : '{i18n>Page}' annotate my.Genres with {
}], name @title: '{i18n>Genre}';
HeaderInfo : { }
$Type : 'UI.HeaderInfoType',
TypeName : '{i18n>ContentsLevel}',
TypeNamePlural: '{i18n>ContentsLevels}',
Title : {
$Type: 'UI.DataField',
Value: name,
}
},
FieldGroup : {
$Type: 'UI.FieldGroupType',
Data : [{
$Type: 'UI.DataField',
Value: page,
Label : '{i18n>PageNumber}'
}],
},
Facets : [{
$Type : 'UI.ReferenceFacet',
Target: '@UI.FieldGroup',
Label : '{i18n>Informations}',
}],
};
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// //

View File

@@ -1,32 +1,3 @@
using { sap.capire.bookshop.Genres } from '@capire/bookstore'; /*
All annotations needed for UI5 Tree Table View are located in '../common'
annotate Genres with @cds.search: {name}; */
annotate Genres with {
name @title: '{i18n>Genre}';
}
// Lists
annotate Genres with @(
Common.SemanticKey : [name],
UI.SelectionFields : [name],
UI.LineItem : [
{ Value: name, Label: '{i18n>Name}' },
],
);
// Details
annotate Genres with @(UI : {
Identification : [{ Value: name }],
HeaderInfo : {
TypeName : '{i18n>Genre}',
TypeNamePlural : '{i18n>Genres}',
Title : { Value: name },
Description : { Value: ID }
}
});
// Tree Views
// annotate AdminService.Genres with @hierarchy; // upcomming simplification
using from './tree-view';
using from './value-help';

View File

@@ -1,42 +0,0 @@
using { AdminService } from '@capire/bookstore';
////////////////////////////////////////////////////////////////////////////
//
// Genres Tree View
//
// Tell Fiori about the structure of the hierarchy
annotate AdminService.Genres with @Aggregation.RecursiveHierarchy #GenresHierarchy : {
ParentNavigationProperty : parent, // navigates to a node's parent
NodeProperty : ID, // identifies a node, usually the key
};
// Fiori expects the following to be defined explicitly, even though they're always the same
extend AdminService.Genres with @(
// The columns expected by Fiori to be present in hierarchy entities
Hierarchy.RecursiveHierarchy #GenresHierarchy : {
LimitedDescendantCount : LimitedDescendantCount,
DistanceFromRoot : DistanceFromRoot,
DrillState : DrillState,
LimitedRank : LimitedRank
},
// Disallow filtering on these properties from Fiori UIs
Capabilities.FilterRestrictions.NonFilterableProperties: [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'LimitedRank'
],
// Disallow sorting on these properties from Fiori UIs
Capabilities.SortRestrictions.NonSortableProperties : [
'LimitedDescendantCount',
'DistanceFromRoot',
'DrillState',
'LimitedRank'
],
) columns { // Ensure we can query these fields from database
null as LimitedDescendantCount : Int16,
null as DistanceFromRoot : Int16,
null as DrillState : String,
null as LimitedRank : Int16,
};

View File

@@ -1,6 +0,0 @@
// Value help with Tree View
using from '../admin-books/fiori-service';
annotate AdminService.Books:genre with @Common.ValueList.PresentationVariantQualifier: 'VH';
annotate AdminService.Genres with @UI.PresentationVariant #VH: {
RecursiveHierarchyQualifier : 'GenresHierarchy',
};

View File

@@ -1,4 +1,4 @@
#XTIT #XTIT
appTitle=Manage Genres appTitle=Browse Genres
#XTXT #XTXT
appDescription=Genres as Tree View appDescription=Genres as Tree View

View File

@@ -19,13 +19,13 @@
}, },
"crossNavigation": { "crossNavigation": {
"inbounds": { "inbounds": {
"Genres-manage": { "Genres-display": {
"signature": { "signature": {
"parameters": {}, "parameters": {},
"additionalParameters": "allowed" "additionalParameters": "allowed"
}, },
"semanticObject": "Genres", "semanticObject": "Genres",
"action": "manage" "action": "display"
} }
} }
} }
@@ -51,7 +51,7 @@
"earlyRequests": true, "earlyRequests": true,
"groupProperties": { "groupProperties": {
"default": { "default": {
"submit": "Auto" "submit": "Auto"
} }
} }
} }
@@ -82,17 +82,17 @@
"Genres": { "Genres": {
"detail": { "detail": {
"route": "GenresDetails" "route": "GenresDetails"
} }
} }
}, },
"controlConfiguration": { "controlConfiguration": {
"@com.sap.vocabularies.UI.v1.LineItem": { "@com.sap.vocabularies.UI.v1.LineItem": {
"tableSettings": { "tableSettings": {
"hierarchyQualifier": "GenresHierarchy", "hierarchyQualifier": "GenreHierarchy",
"type": "TreeTable" "type": "TreeTable"
} }
} }
} }
} }
} }
}, },
@@ -121,4 +121,4 @@
"registrationIds": [], "registrationIds": [],
"archeType": "transactional" "archeType": "transactional"
} }
} }

View File

@@ -5,7 +5,6 @@
using from './admin-authors/fiori-service'; using from './admin-authors/fiori-service';
using from './admin-books/fiori-service'; using from './admin-books/fiori-service';
using from './browse/fiori-service'; using from './browse/fiori-service';
using from './genres/fiori-service';
using from './common'; using from './common';
using from '@capire/bookstore/srv/mashup'; using from '@capire/bookstore/srv/mashup';

View File

@@ -7,7 +7,7 @@
"express": "^4.17.1" "express": "^4.17.1"
}, },
"devDependencies": { "devDependencies": {
"@cap-js/sqlite": ">=1" "@cap-js/sqlite": "^1"
}, },
"scripts": { "scripts": {
"start": "cds-serve", "start": "cds-serve",

View File

@@ -1,50 +1,32 @@
const cds = require('@sap/cds/lib') const cds = require('@sap/cds/lib')
if (cds.requires.db?.kind === 'sqlite') {
// PoC for simplified Fiori Tree Views cds.on ('serving:AdminService', srv => srv.prepend(() => {
cds.on('compile.for.runtime', csn => { const {Genres} = srv.entities
for (let each of cds.linked(csn).definitions) { // Register a simplistic handler for hierarchical queries
if (each.is_entity && each._service && each['@hierarchy']) _hierarchy (each) srv.on('READ', Genres, (req,next) => {
} const q = req.query
}) // Expand query on a single row
if (q.SELECT.recurse?.where?.[0].ref[0] === 'Distance') {
q.SELECT.where[0] = 'parent_ID'
const _hierarchy = entity => { // Initial query
} else if (!q.SELECT.search && !is_count(q)) {
// Add annotations explaining the hierarchy structure to Fiori q.SELECT.where ??= [ 'parent_ID is null' ]
const Qualifier = entity.name.slice (entity._service.name.length+1) + 'Hierarchy' }
const parent = _parent4(entity) // Use scalar subselect for DrillState
entity[`@Aggregation.RecursiveHierarchy#${Qualifier}.ParentNavigationProperty`] ??= {'=': parent.name } q.SELECT.from.as = 'g'
entity[`@Aggregation.RecursiveHierarchy#${Qualifier}.NodeProperty`] ??= {'=': parent.keys[0].ref[0] } q.SELECT.columns = q.SELECT.columns.map (c => {
if (c.ref == 'DrillState') return { xpr:[`
// Add expected hierarchy elements to the entity CASE WHEN ( SELECT count(1) from ${Genres} where parent_ID = g.ID ) > 0
const columns = entity.projection.columns ??= ['*'] THEN 'collapsed' ELSE 'leaf' END`
const elements = entity.elements ], as: 'DrillState' }
for (let e of Hierarchy.elements) { else return c
entity[`@Hierarchy.RecursiveHierarchy#${Qualifier}.${e.name}`] = {'=': e.name } })
if (e.name in elements) continue // Suppress error message: Feature "recurse" queries not supported.
const { name, value, ...rest } = e delete q.SELECT.__proto__.recurse
elements[e.name] = Object.defineProperty ({ __proto__:e, ...rest }, 'parent', { value: entity }) delete q.SELECT.recurse
columns.push ({ ...value, as: name, cast: { type: e.type } }) return next()
} })
}))
// Disable filter and sort for hierarchy elements
entity['@Capabilities.FilterRestrictions.NonFilterableProperties'] =
entity['@Capabilities.SortRestrictions.NonSortableProperties'] =
Object.keys (Hierarchy.elements)
} }
const is_count = q => q.SELECT.columns?.length === 1 && q.SELECT.columns[0].func === 'count'
const _parent4 = entity => {
const parent = entity['@hierarchy.parent'] || entity['@hierarchy.via']
if (parent) return entity.elements [parent['=']||parent]
else for (let e of entity.elements) // use first recursive uplink association
if (e.is2one && e._target === entity) return e
}
const { Hierarchy } = cds.linked `aspect Hierarchy {
LimitedDescendantCount : Int16 = null;
DistanceFromRoot : Int16 = null;
DrillState : String = null;
LimitedRank : Int16 = null;
}`.definitions

View File

@@ -9,7 +9,7 @@ build-parameters:
- builder: custom - builder: custom
commands: commands:
- npm ci - npm ci
- npx cds build shared-db --for hana --production - npx cds build --production
- npx cds build orders --for nodejs --production --ws-pack - npx cds build orders --for nodejs --production --ws-pack
- npx cds build reviews --for nodejs --production - npx cds build reviews --for nodejs --production
- npx cds build bookstore --for nodejs --production --ws-pack - npx cds build bookstore --for nodejs --production --ws-pack
@@ -78,14 +78,6 @@ modules:
- name: samples-auth - name: samples-auth
- name: samples-destination - name: samples-destination
- name: samples-db-deployer
type: hdb
path: shared-db/gen/db
parameters:
buildpack: nodejs_buildpack
requires:
- name: samples-db
- name: samples - name: samples
type: approuter.nodejs type: approuter.nodejs
path: .deploy/app-router path: .deploy/app-router
@@ -93,6 +85,8 @@ modules:
keep-existing-routes: true keep-existing-routes: true
disk-quota: 256M disk-quota: 256M
memory: 256M memory: 256M
properties:
TENANT_HOST_PATTERN: "^(.*)-${default-uri}"
requires: requires:
- name: orders-api - name: orders-api
group: destinations group: destinations
@@ -112,7 +106,17 @@ modules:
name: bookstore-api # must be used in xs-app.json as well name: bookstore-api # must be used in xs-app.json as well
url: ~{srv-url} url: ~{srv-url}
forwardAuthToken: true forwardAuthToken: true
- name: mtx-api
group: destinations
properties:
name: mtx-api # must be used in xs-app.json as well
url: ~{mtx-url}
- name: samples-auth - name: samples-auth
provides:
- name: app-api
properties:
app-protocol: ${protocol}
app-uri: ${default-uri}
- name: destination-content - name: destination-content
type: com.sap.application.content type: com.sap.application.content
@@ -145,6 +149,27 @@ modules:
TokenServiceInstanceName: samples-auth TokenServiceInstanceName: samples-auth
TokenServiceKeyName: xsuaa-service-key TokenServiceKeyName: xsuaa-service-key
- name: samples-mtx
type: nodejs
path: gen/mtx/sidecar
build-parameters:
builder: npm
parameters:
instances: 1
memory: 256M
disk-quota: 512M
provides:
- name: mtx-api
properties:
mtx-url: ${default-url}
requires:
- name: samples-db
- name: samples-registry
- name: samples-auth
- name: app-api
properties:
SUBSCRIPTION_URL: ~{app-protocol}://\${tenant_subdomain}-~{app-uri}
resources: resources:
- name: samples-messaging - name: samples-messaging
type: org.cloudfoundry.managed-service type: org.cloudfoundry.managed-service
@@ -156,23 +181,51 @@ resources:
emname: bookstore-${org}-${space} emname: bookstore-${org}-${space}
namespace: cap/samples/${space} namespace: cap/samples/${space}
- name: samples-db - name: samples-db
type: com.sap.xs.hdi-container type: org.cloudfoundry.managed-service
parameters: parameters:
service: hana service: service-manager
service-plan: hdi-shared service-plan: container
- name: samples-auth - name: samples-auth
type: org.cloudfoundry.managed-service type: org.cloudfoundry.managed-service
processed-after: processed-after:
- samples-messaging - samples-messaging
requires:
- name: app-api
parameters: parameters:
service: xsuaa service: xsuaa
service-plan: application service-plan: application
path: ./xs-security.json path: ./xs-security.json
config: config:
xsappname: samples-${org}-${space} xsappname: samples-${org}-${space}
tenant-mode: dedicated tenant-mode: shared
oauth2-configuration:
redirect-uris:
- https://*-~{app-api/app-uri}/**
- name: samples-destination - name: samples-destination
type: org.cloudfoundry.managed-service type: org.cloudfoundry.managed-service
parameters: parameters:
service: destination service: destination
service-plan: lite service-plan: lite
- name: samples-registry
type: org.cloudfoundry.managed-service
requires:
- name: mtx-api
parameters:
service: saas-registry
service-plan: application
config:
xsappname: samples-${org}-${space}
appName: samples-${org}-${space}
displayName: samples-shared-db
description: CAP Samples with shared-db and multitenancy
category: 'Samples shared-db'
appUrls:
getDependencies: ~{mtx-api/mtx-url}/-/cds/saas-provisioning/dependencies
onSubscription: ~{mtx-api/mtx-url}/-/cds/saas-provisioning/tenant/{tenantId}
onSubscriptionAsync: true
onUnSubscriptionAsync: true
onUpdateDependenciesAsync: true
callbackTimeoutMillis: 300000 # Increase if your deployments are taking longer than that

19
mtx/sidecar/package.json Normal file
View File

@@ -0,0 +1,19 @@
{
"name": "samples-mtx",
"dependencies": {
"@cap-js/hana": "^1",
"@sap/cds": "^8",
"@sap/cds-mtxs": "^2",
"@sap/xssec": "^4",
"express": "^4"
},
"devDependencies": {
"@cap-js/sqlite": "^1"
},
"scripts": {
"start": "cds-serve"
},
"cds": {
"profile": "mtx-sidecar"
}
}

View File

@@ -23,8 +23,8 @@
}; };
</script> </script>
<script id="sap-ushell-bootstrap" src="https://ui5.sap.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script> <script id="sap-ushell-bootstrap" src="https://sapui5.hana.ondemand.com/test-resources/sap/ushell/bootstrap/sandbox.js"></script>
<script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js" <script id="sap-ui-bootstrap" src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout" data-sap-ui-libs="sap.m, sap.ushell, sap.collaboration, sap.ui.layout"
data-sap-ui-compatVersion="edge" data-sap-ui-compatVersion="edge"
data-sap-ui-theme="sap_horizon" data-sap-ui-theme="sap_horizon"

View File

@@ -2,15 +2,18 @@
"name": "@capire/orders", "name": "@capire/orders",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@cap-js/hana": ">=1", "@cap-js/hana": "^1",
"@capire/common": "*", "@capire/common": "*",
"@sap/cds": ">=5", "@sap/cds": ">=5",
"@sap/xssec": "^4" "@sap/xssec": "^4",
"@sap/cds-mtxs": "^2"
}, },
"cds": { "cds": {
"requires": { "requires": {
"messaging": true, "messaging": true,
"db": true "db": true,
"multitenancy": true,
"auth": "xsuaa"
} }
}, },
"scripts": { "scripts": {

339
package-lock.json generated
View File

@@ -9,15 +9,8 @@
"version": "3.0.0", "version": "3.0.0",
"license": "SEE LICENSE IN LICENSE", "license": "SEE LICENSE IN LICENSE",
"workspaces": [ "workspaces": [
"bookshop", "./*",
"bookstore", "./etc/*"
"common",
"fiori",
"orders",
"reviews",
"shared-db",
"etc/data-viewer",
"etc/loggers"
], ],
"devDependencies": { "devDependencies": {
"@cap-js/cds-test": "^0" "@cap-js/cds-test": "^0"
@@ -31,14 +24,14 @@
"express": "^4.17.1" "express": "^4.17.1"
}, },
"devDependencies": { "devDependencies": {
"@cap-js/sqlite": ">=1" "@cap-js/sqlite": "*"
} }
}, },
"bookstore": { "bookstore": {
"name": "@capire/bookstore", "name": "@capire/bookstore",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@cap-js/hana": ">=1", "@cap-js/hana": "^1",
"@capire/bookshop": "*", "@capire/bookshop": "*",
"@capire/common": "*", "@capire/common": "*",
"@capire/data-viewer": "*", "@capire/data-viewer": "*",
@@ -81,14 +74,15 @@
"express": "^4.17.1" "express": "^4.17.1"
}, },
"devDependencies": { "devDependencies": {
"@cap-js/sqlite": ">=1" "@cap-js/sqlite": "^1"
} }
}, },
"node_modules/@cap-js/cds-test": { "node_modules/@cap-js/cds-test": {
"version": "0.4.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/@cap-js/cds-test/-/cds-test-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@cap-js/cds-test/-/cds-test-0.3.0.tgz",
"integrity": "sha512-l8Ad/rV5qXIjU9qyA3twcKDYUnT1Ru1402BHhjnMjeYD9GeCmoj/0KrRGFbQIW63zAbs3QFya9X4GMGd0qYesA==", "integrity": "sha512-qt6Y7cYjhYlbVOeqMJ1wiuxmkbfYbgXvU7uqyasikJn2s5Vf/A6cawROJfSKxPTsmbnLi5nyrCSFCliUYG0rww==",
"dev": true, "dev": true,
"license": "SEE LICENSE IN LICENSE",
"dependencies": { "dependencies": {
"axios": "^1", "axios": "^1",
"chai": "^4.4.1", "chai": "^4.4.1",
@@ -107,27 +101,29 @@
} }
}, },
"node_modules/@cap-js/db-service": { "node_modules/@cap-js/db-service": {
"version": "2.2.0", "version": "1.19.1",
"resolved": "https://registry.npmjs.org/@cap-js/db-service/-/db-service-2.2.0.tgz", "resolved": "https://registry.npmjs.org/@cap-js/db-service/-/db-service-1.19.1.tgz",
"integrity": "sha512-C5n8Qy8MwOGWjpXS44CskaEZt8YKrEEs4AtJyBSfJ6+aKMu/ynqpXh0Up4Ql0XX2Frq2PwNU8Ohai/04wxd46g==", "integrity": "sha512-3IpyDq0sw0bI2SYzC+A6IwriU1sNFNRBmHj20yi4TfKaw1FMZJmdVhK8EjG0r3odEJrPcOy+gTWu4u0P85ISAg==",
"license": "SEE LICENSE",
"dependencies": { "dependencies": {
"generic-pool": "^3.9.0" "generic-pool": "^3.9.0"
}, },
"peerDependencies": { "peerDependencies": {
"@sap/cds": ">=9" "@sap/cds": ">=7.9"
} }
}, },
"node_modules/@cap-js/hana": { "node_modules/@cap-js/hana": {
"version": "2.1.1", "version": "1.8.1",
"resolved": "https://registry.npmjs.org/@cap-js/hana/-/hana-2.1.1.tgz", "resolved": "https://registry.npmjs.org/@cap-js/hana/-/hana-1.8.1.tgz",
"integrity": "sha512-4N/ByOd1N++7IEVwoSKyIqEXEzuAJE1qhpWhr3JM4LPoeCpvlv+Eki/YLIvCB06O7/PO8d2569Emjml/TwaJhQ==", "integrity": "sha512-Fz0yU+ZuwJO0ZECwHk94QNkqOO0PDC1IcMlPyytdniQbmU6OfZyiT6yJuCgNj5NJSqZar4tQTYOk4It2EwZyng==",
"license": "SEE LICENSE",
"dependencies": { "dependencies": {
"@cap-js/db-service": "^2.1.1", "@cap-js/db-service": "^1.19.0",
"hdb": "^0.19.5" "hdb": "^0.19.5"
}, },
"peerDependencies": { "peerDependencies": {
"@sap/cds": ">=9", "@sap/cds": ">=8.2",
"@sap/hana-client": "^2" "@sap/hana-client": "2"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@sap/hana-client": { "@sap/hana-client": {
@@ -136,16 +132,17 @@
} }
}, },
"node_modules/@cap-js/sqlite": { "node_modules/@cap-js/sqlite": {
"version": "2.0.2", "version": "1.10.0",
"resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-2.0.2.tgz", "resolved": "https://registry.npmjs.org/@cap-js/sqlite/-/sqlite-1.10.0.tgz",
"integrity": "sha512-oNg2f56sfELshyp0eSmYYwG1lt4Zmc135sLIzS8iykHdRVxxJpTrPj0jx0Y4Hc6sfC9u25LRXVu/ZKqjm9Yu+Q==", "integrity": "sha512-4LfBbQy/Omt7GgImwD5iIKnUsmuMIozL/XLMQjMCWryfe/RXMJBhpBW2qvZIg+tYL7ifgMrXXcbDUyKGzG+q/g==",
"dev": true, "dev": true,
"license": "SEE LICENSE",
"dependencies": { "dependencies": {
"@cap-js/db-service": "^2", "@cap-js/db-service": "^1.19.0",
"better-sqlite3": "^12.0.0" "better-sqlite3": "^11.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"@sap/cds": ">=9" "@sap/cds": ">=7.6"
} }
}, },
"node_modules/@capire/bookshop": { "node_modules/@capire/bookshop": {
@@ -205,9 +202,9 @@
} }
}, },
"node_modules/@eslint/js": { "node_modules/@eslint/js": {
"version": "9.30.1", "version": "9.24.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz",
"integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==",
"license": "MIT", "license": "MIT",
"peer": true, "peer": true,
"engines": { "engines": {
@@ -268,20 +265,22 @@
} }
}, },
"node_modules/@sap/cds": { "node_modules/@sap/cds": {
"version": "9.1.0", "version": "8.9.1",
"resolved": "https://registry.npmjs.org/@sap/cds/-/cds-9.1.0.tgz", "resolved": "https://registry.npmjs.org/@sap/cds/-/cds-8.9.1.tgz",
"integrity": "sha512-i5bAVbFzi1uN11O4U6SdPKzYDDxc+YDSWMiqt1ryxT0WYrrehJPg5pJQjy4AH1EgRIqa3eqK2RfmHS6SgkBOyg==", "integrity": "sha512-+KoY7Bw1Gc3vwK4X3CFCV+IAQO4QT0HRsaW/qgETeOGqjzbuf6KvUqlkDuPE5msdXwfz/EFDB9Vx9jTyTw581Q==",
"license": "SEE LICENSE IN LICENSE",
"dependencies": { "dependencies": {
"@sap/cds-compiler": "^6", "@sap/cds-compiler": ">=5.1",
"@sap/cds-fiori": "^2", "@sap/cds-fiori": "^1",
"js-yaml": "^4.1.0" "@sap/cds-foss": "^5.0.0"
}, },
"bin": { "bin": {
"cds-deploy": "lib/dbs/cds-deploy.js", "cds-deploy": "lib/dbs/cds-deploy.js",
"cds-serve": "bin/serve.js" "cds-serve": "bin/serve.js",
"cds-test": "bin/test.js"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=18"
}, },
"peerDependencies": { "peerDependencies": {
"@eslint/js": "^9", "@eslint/js": "^9",
@@ -298,31 +297,51 @@
} }
}, },
"node_modules/@sap/cds-compiler": { "node_modules/@sap/cds-compiler": {
"version": "6.1.0", "version": "5.9.2",
"resolved": "https://registry.npmjs.org/@sap/cds-compiler/-/cds-compiler-6.1.0.tgz", "resolved": "https://registry.npmjs.org/@sap/cds-compiler/-/cds-compiler-5.9.2.tgz",
"integrity": "sha512-s71fsxDZKqHn2xvoqoNst54K/BkBzCpiU+8xc0t3nMDXmsLzSC3VfygZGwGAZD8fkxUnXh8oL2XLHWKWcvcdNg==", "integrity": "sha512-YpRUD3L0Ylg7KNoDqdCmsH1n6vt22Uvyvtc7Maj0wPl7haqeDOax2ouOAtqgJaYJfu83pcyx04sWLK6oH+Lh0w==",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"antlr4": "4.9.3"
},
"bin": { "bin": {
"cdsc": "bin/cdsc.js", "cdsc": "bin/cdsc.js",
"cdshi": "bin/cdshi.js", "cdshi": "bin/cdshi.js",
"cdsse": "bin/cdsse.js" "cdsse": "bin/cdsse.js"
}, },
"engines": { "engines": {
"node": ">=20" "node": ">=18"
} }
}, },
"node_modules/@sap/cds-fiori": { "node_modules/@sap/cds-fiori": {
"version": "2.0.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/@sap/cds-fiori/-/cds-fiori-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@sap/cds-fiori/-/cds-fiori-1.4.1.tgz",
"integrity": "sha512-KZVLWXndydgqdlao8OL1gtgd/XMgBdiKBmmgwGpBL1y4S21FOXglnWh6d3bnSZL/qwR3z50D+0PoGghjhayF0Q==", "integrity": "sha512-laoK+xfJRcJy+zWzUdgqOOy5V6lpUi9I3CN8yeGmMIktQ1ZsXc52814WvoWt4TWchY1/+rNYuWDl9Q8ttj4Y4w==",
"license": "SEE LICENSE IN LICENSE",
"peerDependencies": { "peerDependencies": {
"@sap/cds": ">=8", "@sap/cds": ">=7.6",
"express": ">=4" "express": ">=4"
} }
}, },
"node_modules/@sap/cds-foss": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@sap/cds-foss/-/cds-foss-5.0.1.tgz",
"integrity": "sha512-q6h7LkEx6w9LswCIQzJJ2mnoyeGS8jrmBXN4I4+aECRL60mkLskoqGetot+2tX2xXGxCYJuo5v1dtSafwBqTRQ==",
"license": "See LICENSE in LICENSE",
"dependencies": {
"big.js": "^6.1.1",
"generic-pool": "^3.8.2",
"xmlbuilder": "^15.1.1",
"yaml": "^2.2.2"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@sap/xsenv": { "node_modules/@sap/xsenv": {
"version": "5.6.1", "version": "5.5.0",
"resolved": "https://registry.npmjs.org/@sap/xsenv/-/xsenv-5.6.1.tgz", "resolved": "https://registry.npmjs.org/@sap/xsenv/-/xsenv-5.5.0.tgz",
"integrity": "sha512-4pDpsYLNJsLUBWtTSG+TJ8ul5iY0dWDyJgTy2H/WZGZww9CSPLP/39x+syDDTjkggsmZAlo9t7y9TiXMmtAunw==", "integrity": "sha512-+FIpnXjDrgtJaN6AxjDRIc5ONd4Yt5UarCqqzRiZjvJaknnkT+b6/ho/va/rg8UdiCAVxn8c4vMVhgjXGc/gmQ==",
"license": "SEE LICENSE IN LICENSE file", "license": "SEE LICENSE IN LICENSE file",
"dependencies": { "dependencies": {
"debug": "4.4.0", "debug": "4.4.0",
@@ -357,21 +376,30 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/@sap/xssec": { "node_modules/@sap/xssec": {
"version": "4.8.0", "version": "4.6.0",
"resolved": "https://registry.npmjs.org/@sap/xssec/-/xssec-4.8.0.tgz", "resolved": "https://registry.npmjs.org/@sap/xssec/-/xssec-4.6.0.tgz",
"integrity": "sha512-9R9nfx6LK53B938CeUY4aIrH5kcxxkdpiQARtzH5uLFYDzUW08n5LPRkoCxR41zrIDXdWQFmQ/Xd7n4Vv+CDlQ==", "integrity": "sha512-0VYDqFymsQnpztTBUmdJaUVgHK/wIOC1KR6BmcmRJLQ3HMqGpGju1zkeY/D7SCwuQ8djYp0GEDhJ60F4aN1H/g==",
"license": "SAP DEVELOPER LICENSE AGREEMENT",
"dependencies": { "dependencies": {
"debug": "^4.3.4", "debug": "^4.3.4",
"jwt-decode": "^4" "jwt-decode": "^4"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
},
"peerDependencies": {
"@types/express": ">=4"
},
"peerDependenciesMeta": {
"@types/express": {
"optional": true
}
} }
}, },
"node_modules/@sap/xssec/node_modules/debug": { "node_modules/@sap/xssec/node_modules/debug": {
"version": "4.4.1", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"ms": "^2.1.3" "ms": "^2.1.3"
@@ -425,10 +453,14 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/argparse": { "node_modules/antlr4": {
"version": "2.0.1", "version": "4.9.3",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/antlr4/-/antlr4-4.9.3.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" "integrity": "sha512-qNy2odgsa0skmNMCuxzXhM4M8J1YDaPv3TI+vCdnOAanu0N982wBrSqziDKRDctEZLZy9VffqIZXc0UGjjSP/g==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=14"
}
}, },
"node_modules/array-flatten": { "node_modules/array-flatten": {
"version": "1.1.1", "version": "1.1.1",
@@ -477,9 +509,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/axios": { "node_modules/axios": {
"version": "1.10.0", "version": "1.8.4",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
"integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"follow-redirects": "^1.15.6", "follow-redirects": "^1.15.6",
@@ -505,20 +537,32 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
] ],
"license": "MIT"
}, },
"node_modules/better-sqlite3": { "node_modules/better-sqlite3": {
"version": "12.2.0", "version": "11.9.1",
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.2.0.tgz", "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-11.9.1.tgz",
"integrity": "sha512-eGbYq2CT+tos1fBwLQ/tkBt9J5M3JEHjku4hbvQUePCckkvVf14xWj+1m7dGoK81M/fOjFT7yM9UMeKT/+vFLQ==", "integrity": "sha512-Ba0KR+Fzxh2jDRhdg6TSH0SJGzb8C0aBY4hR8w8madIdIzzC6Y1+kx5qR6eS1Z+Gy20h6ZU28aeyg0z1VIrShQ==",
"dev": true, "dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT",
"dependencies": { "dependencies": {
"bindings": "^1.5.0", "bindings": "^1.5.0",
"prebuild-install": "^7.1.1" "prebuild-install": "^7.1.1"
}, }
},
"node_modules/big.js": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz",
"integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==",
"license": "MIT",
"engines": { "engines": {
"node": "20.x || 22.x || 23.x || 24.x" "node": "*"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/bigjs"
} }
}, },
"node_modules/bindings": { "node_modules/bindings": {
@@ -526,6 +570,7 @@
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"file-uri-to-path": "1.0.0" "file-uri-to-path": "1.0.0"
} }
@@ -535,6 +580,7 @@
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"buffer": "^5.5.0", "buffer": "^5.5.0",
"inherits": "^2.0.4", "inherits": "^2.0.4",
@@ -584,6 +630,7 @@
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"base64-js": "^1.3.1", "base64-js": "^1.3.1",
"ieee754": "^1.1.13" "ieee754": "^1.1.13"
@@ -708,7 +755,8 @@
"version": "1.1.4", "version": "1.1.4",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
"dev": true "dev": true,
"license": "ISC"
}, },
"node_modules/clone": { "node_modules/clone": {
"version": "2.1.2", "version": "2.1.2",
@@ -850,6 +898,7 @@
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"mimic-response": "^3.1.0" "mimic-response": "^3.1.0"
}, },
@@ -878,6 +927,7 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=4.0.0" "node": ">=4.0.0"
} }
@@ -911,10 +961,11 @@
} }
}, },
"node_modules/detect-libc": { "node_modules/detect-libc": {
"version": "2.0.4", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
@@ -964,10 +1015,11 @@
} }
}, },
"node_modules/end-of-stream": { "node_modules/end-of-stream": {
"version": "1.4.5", "version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"once": "^1.4.0" "once": "^1.4.0"
} }
@@ -1037,6 +1089,7 @@
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
"dev": true, "dev": true,
"license": "(MIT OR WTFPL)",
"engines": { "engines": {
"node": ">=6" "node": ">=6"
} }
@@ -1106,7 +1159,8 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "1.3.1", "version": "1.3.1",
@@ -1153,9 +1207,9 @@
} }
}, },
"node_modules/form-data": { "node_modules/form-data": {
"version": "4.0.3", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
"integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"asynckit": "^0.4.0", "asynckit": "^0.4.0",
@@ -1189,7 +1243,8 @@
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
@@ -1260,7 +1315,8 @@
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/gopd": { "node_modules/gopd": {
"version": "1.2.0", "version": "1.2.0",
@@ -1380,7 +1436,8 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
] ],
"license": "BSD-3-Clause"
}, },
"node_modules/inherits": { "node_modules/inherits": {
"version": "2.0.4", "version": "2.0.4",
@@ -1392,7 +1449,8 @@
"version": "1.3.8", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
"dev": true "dev": true,
"license": "ISC"
}, },
"node_modules/ipaddr.js": { "node_modules/ipaddr.js": {
"version": "1.9.1", "version": "1.9.1",
@@ -1421,17 +1479,6 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jsonwebtoken": { "node_modules/jsonwebtoken": {
"version": "9.0.2", "version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
@@ -1461,12 +1508,12 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/jwa": { "node_modules/jwa": {
"version": "1.4.2", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"buffer-equal-constant-time": "^1.0.1", "buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11", "ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
@@ -1645,6 +1692,7 @@
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=10" "node": ">=10"
}, },
@@ -1657,6 +1705,7 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true, "dev": true,
"license": "MIT",
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
@@ -1665,7 +1714,8 @@
"version": "0.5.3", "version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/ms": { "node_modules/ms": {
"version": "2.0.0", "version": "2.0.0",
@@ -1677,7 +1727,8 @@
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
"dev": true "dev": true,
"license": "MIT"
}, },
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "0.6.3", "version": "0.6.3",
@@ -1689,10 +1740,11 @@
} }
}, },
"node_modules/node-abi": { "node_modules/node-abi": {
"version": "3.75.0", "version": "3.74.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz",
"integrity": "sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==", "integrity": "sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"semver": "^7.3.5" "semver": "^7.3.5"
}, },
@@ -1741,6 +1793,7 @@
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true, "dev": true,
"license": "ISC",
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
} }
@@ -1755,12 +1808,12 @@
} }
}, },
"node_modules/opossum": { "node_modules/opossum": {
"version": "8.5.0", "version": "8.4.0",
"resolved": "https://registry.npmjs.org/opossum/-/opossum-8.5.0.tgz", "resolved": "https://registry.npmjs.org/opossum/-/opossum-8.4.0.tgz",
"integrity": "sha512-LZNvs+p9/ZbG4oN6unnjh4hTxkB0dyHKI2p7azVt8w+//GKDpfHss6WR7KebbpzGEssYwtSd8Mvwxqcmxg10NA==", "integrity": "sha512-YYamqKu48bZCSTJKSWLLO4SSk8tKN2Gg2z1sJZVzHJYVObMO/xQpIzAh6re9HCMHRdB1dJvBjJH18DW7xYOicg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"engines": { "engines": {
"node": "^24 || ^22 || ^21 || ^20 || ^18 || ^16" "node": "^22 || ^21 || ^20 || ^18 || ^16"
} }
}, },
"node_modules/parseurl": { "node_modules/parseurl": {
@@ -1793,6 +1846,7 @@
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"detect-libc": "^2.0.0", "detect-libc": "^2.0.0",
"expand-template": "^2.0.3", "expand-template": "^2.0.3",
@@ -1834,10 +1888,11 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/pump": { "node_modules/pump": {
"version": "3.0.3", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"end-of-stream": "^1.1.0", "end-of-stream": "^1.1.0",
"once": "^1.3.1" "once": "^1.3.1"
@@ -1887,6 +1942,7 @@
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"dev": true, "dev": true,
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
"dependencies": { "dependencies": {
"deep-extend": "^0.6.0", "deep-extend": "^0.6.0",
"ini": "~1.3.0", "ini": "~1.3.0",
@@ -1956,9 +2012,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/semver": { "node_modules/semver": {
"version": "7.7.2", "version": "7.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
"license": "ISC", "license": "ISC",
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
@@ -2117,7 +2173,8 @@
"type": "consulting", "type": "consulting",
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
] ],
"license": "MIT"
}, },
"node_modules/simple-get": { "node_modules/simple-get": {
"version": "4.0.1", "version": "4.0.1",
@@ -2138,6 +2195,7 @@
"url": "https://feross.org/support" "url": "https://feross.org/support"
} }
], ],
"license": "MIT",
"dependencies": { "dependencies": {
"decompress-response": "^6.0.0", "decompress-response": "^6.0.0",
"once": "^1.3.1", "once": "^1.3.1",
@@ -2185,6 +2243,7 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"dev": true, "dev": true,
"license": "MIT",
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
} }
@@ -2202,10 +2261,11 @@
} }
}, },
"node_modules/tar-fs": { "node_modules/tar-fs": {
"version": "2.1.3", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
"integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==", "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"chownr": "^1.1.1", "chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2", "mkdirp-classic": "^0.5.2",
@@ -2218,6 +2278,7 @@
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
"dev": true, "dev": true,
"license": "MIT",
"dependencies": { "dependencies": {
"bl": "^4.0.3", "bl": "^4.0.3",
"end-of-stream": "^1.4.1", "end-of-stream": "^1.4.1",
@@ -2258,6 +2319,7 @@
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
}, },
@@ -2381,13 +2443,35 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true "dev": true,
"license": "ISC"
},
"node_modules/xmlbuilder": {
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
"integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
"license": "MIT",
"engines": {
"node": ">=8.0"
}
},
"node_modules/yaml": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz",
"integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"
},
"engines": {
"node": ">= 14"
}
}, },
"orders": { "orders": {
"name": "@capire/orders", "name": "@capire/orders",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@cap-js/hana": ">=1", "@cap-js/hana": "^1",
"@capire/common": "*", "@capire/common": "*",
"@sap/cds": ">=5", "@sap/cds": ">=5",
"@sap/xssec": "^4" "@sap/xssec": "^4"
@@ -2397,7 +2481,7 @@
"name": "@capire/reviews", "name": "@capire/reviews",
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@cap-js/hana": ">=1", "@cap-js/hana": "^1",
"@sap/cds": ">=5", "@sap/cds": ">=5",
"@sap/xssec": "^4.2.7", "@sap/xssec": "^4.2.7",
"express": "^4.17.1" "express": "^4.17.1"
@@ -2405,12 +2489,7 @@
}, },
"shared-db": { "shared-db": {
"name": "@capire/shared-db", "name": "@capire/shared-db",
"version": "3.0.0", "version": "3.0.0"
"dependencies": {
"@capire/bookstore": "*",
"@capire/orders": "*",
"@capire/reviews": "*"
}
} }
} }
} }

View File

@@ -5,15 +5,8 @@
"repository": "https://github.com/sap-samples/cloud-cap-samples.git", "repository": "https://github.com/sap-samples/cloud-cap-samples.git",
"author": "daniel.hutzel@sap.com", "author": "daniel.hutzel@sap.com",
"workspaces": [ "workspaces": [
"bookshop", "./*",
"bookstore", "./etc/*"
"common",
"fiori",
"orders",
"reviews",
"shared-db",
"etc/data-viewer",
"etc/loggers"
], ],
"devDependencies": { "devDependencies": {
"@cap-js/cds-test": "^0" "@cap-js/cds-test": "^0"
@@ -40,5 +33,15 @@
"timeout": 6666 "timeout": 6666
}, },
"license": "SEE LICENSE IN LICENSE", "license": "SEE LICENSE IN LICENSE",
"private": true "private": true,
} "dependencies": {
"@sap/cds-mtxs": "^2"
},
"cds": {
"profile": "with-mtx-sidecar",
"requires": {
"multitenancy": true,
"auth": "xsuaa"
}
}
}

View File

@@ -7,15 +7,18 @@
"index.cds" "index.cds"
], ],
"dependencies": { "dependencies": {
"@cap-js/hana": ">=1", "@cap-js/hana": "^1",
"@sap/cds": ">=5", "@sap/cds": ">=5",
"@sap/xssec": "^4.2.7", "@sap/xssec": "^4.2.7",
"express": "^4.17.1" "express": "^4.17.1",
"@sap/cds-mtxs": "^2"
}, },
"cds": { "cds": {
"requires": { "requires": {
"messaging": true, "messaging": true,
"db": true "db": true,
"multitenancy": true,
"auth": "xsuaa"
} }
}, },
"scripts": { "scripts": {

View File

@@ -3,7 +3,7 @@ module.exports = cds.service.impl (function(){
// Get the CSN definition for Reviews from the db schema for sub-sequent queries // Get the CSN definition for Reviews from the db schema for sub-sequent queries
// ( Note: we explicitly specify the namespace to support embedded reuse ) // ( Note: we explicitly specify the namespace to support embedded reuse )
const { Reviews, Likes } = this.entities const { Reviews, Likes } = this.entities ('sap.capire.reviews')
this.before (['CREATE','UPDATE'], 'Reviews', req => { this.before (['CREATE','UPDATE'], 'Reviews', req => {
if (!req.data.rating) req.data.rating = Math.round(Math.random()*4)+1 if (!req.data.rating) req.data.rating = Math.round(Math.random()*4)+1

View File

@@ -2,11 +2,6 @@
"name": "@capire/shared-db", "name": "@capire/shared-db",
"version": "3.0.0", "version": "3.0.0",
"description": "CAP Sample CDS model deployment for shared-db scenario", "description": "CAP Sample CDS model deployment for shared-db scenario",
"dependencies": {
"@capire/bookstore": "*",
"@capire/orders": "*",
"@capire/reviews": "*"
},
"cds": { "cds": {
"sql": { "sql": {
"native_hana_associations": false "native_hana_associations": false

View File

@@ -1,5 +1,5 @@
{ {
"devDependencies": { "devDependencies": {
"@cap-js/sqlite": "*" "@cap-js/sqlite": "^1"
} }
} }

View File

@@ -7,6 +7,6 @@ extend service CatalogService with {
*, //> non-localized defaults, e.g. title *, //> non-localized defaults, e.g. title
key ID, key ID,
texts.title as localized_title, texts.title as localized_title,
texts.locale, texts.locale
} excluding { contents }; };
} }

View File

@@ -14,6 +14,13 @@
{ {
"name": "$XSAPPNAME.emmanagement", "name": "$XSAPPNAME.emmanagement",
"description": "Enterprise-Messaging Management Access" "description": "Enterprise-Messaging Management Access"
},
{
"name": "$XSAPPNAME.mtcallback",
"description": "Subscription via SaaS Registry",
"grant-as-authority-to-apps": [
"$XSAPPNAME(application,sap-provisioning,tenant-onboarding)"
]
} }
], ],
"attributes": [], "attributes": [],