", ... ],
- "attr": { ... }
- }
- }
- }
- }
-}
-```
-:::
-
-In contrast to [mocked authentication](#mocked), no default users are automatically added to the configuration.
-
### JWT-based Authentication { #jwt }
diff --git a/node.js/best-practices.md b/node.js/best-practices.md
index 218708d51e..536f2e7db0 100644
--- a/node.js/best-practices.md
+++ b/node.js/best-practices.md
@@ -201,7 +201,7 @@ If a CSRF token is cached, it can potentially be reused in multiple requests, de
#### Using App Router
-The _App Router_ is configured to require a _CSRF_ token by default for all protected routes and all HTTP requests methods except _HEAD_ and _GET_. Thus, by adding the _App Router_ as described in the [Deployment Guide: Using App Router as Gateway](../guides/deployment/to-cf#add-app-router), endpoints are CSRF protected.
+The _App Router_ is configured to require a _CSRF_ token by default for all protected routes and all HTTP requests methods except _HEAD_ and _GET_. Thus, by using an _App Router_ as described in the [_Deployment_ guide](../guides/deployment/to-cf#add-ui), endpoints are CSRF protected.
[Learn more about CSRF protection with the **App Router**](https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/c19f165084d742e096c5d1625cecd2d4.html?q=csrf#loioc19f165084d742e096c5d1625cecd2d4__section_xj4_pcg_2z){.learn-more}
@@ -278,7 +278,7 @@ cds.on('bootstrap', app => app.use ((req, res, next) => {
#### Configuring CORS in App Router
-The _App Router_ has full support for CORS. Thus, by adding the _App Router_ as described in the [Deployment Guide: Using App Router as Gateway](../guides/deployment/to-cf#add-app-router), CORS can be configured in the _App Router_ configuration.
+The _App Router_ has full support for CORS. Thus, by adding the _App Router_ as described in the [_Deployment_ guide](../guides/deployment/to-cf#add-ui), CORS can be configured in the _App Router_ configuration.
[Learn more about CORS handling with the **App Router**](https://help.sap.com/docs/BTP/65de2977205c403bbc107264b8eccf4b/ba527058dc4d423a9e0a69ecc67f4593.html?q=allowedOrigin#loioba527058dc4d423a9e0a69ecc67f4593__section_nt3_t4k_sz){.learn-more}
diff --git a/node.js/cds-connect.md b/node.js/cds-connect.md
index 99d39053ff..1b0a817cb8 100644
--- a/node.js/cds-connect.md
+++ b/node.js/cds-connect.md
@@ -46,7 +46,8 @@ async function cds.connect.to (
Argument `name` is used to look up connect options from [configured services](#cds-env-requires), which are defined in the `cds.requires` section of your _package.json_ or _.cdsrc.json_ or _.yaml_ files.
-Argument `options` also allows to pass additional options such as `credentials` programmatically, and thus create services without configurations and [service bindings](#service-bindings), for example, you could connect to a local SQLite database in your tests like this:
+Argument `options` also allows to pass additional options programmatically. The available and supported properties of options depend on the selected `kind`.
+Each `kind` defines its own set of expected configuration properties (for example, `credentials`, `model`, `service`). This allows creating services without configurations and [service bindings](#service-bindings). For example, you could connect to a local SQLite database in your tests like this:
```js
const db2 = await cds.connect.to ({
diff --git a/node.js/cds-reflect.md b/node.js/cds-reflect.md
index b364f571ff..5ed61f23fa 100644
--- a/node.js/cds-reflect.md
+++ b/node.js/cds-reflect.md
@@ -108,15 +108,22 @@ Example:
```js
let m = cds.linked`
namespace my.bookshop;
- entity Books {...}
- entity Authors {...}
+ entity Books {}
+ entity Authors {}
+ service CatalogService {
+ entity Books as projection on my.bookshop.Books;
+ entity Authors as projection on my.bookshop.Authors;
+ }
`
+
// Function nature
let { Books, Authors } = m.entities ('my.bookshop')
-
-// Object nature (uses the model's top-level namespace)
-let { Books, Authors } = m.entities
+// Object nature
+let {
+ 'my.bookshop.Books': Books,
+ 'my.bookshop.Authors': Authors
+} = m.entities
// Array nature
for (let each of m.entities) console.log (each.name)
diff --git a/node.js/core-services.md b/node.js/core-services.md
index cac08dc897..0dd8836796 100644
--- a/node.js/core-services.md
+++ b/node.js/core-services.md
@@ -396,19 +396,23 @@ var srv.options : { //> from cds.requires config
-### . entities {.property alt="The following documentation on operations also applies to entities. "}
+### . entities {.property alt="The following documentation on actions also applies to entities. "}
-### . events {.property alt="The following documentation on operations also applies to events. "}
+### . events {.property alt="The following documentation on actions also applies to events. "}
-### . operations {.property}
+### . operations {.property .deprecated alt="The following documentation on actions also applies to operations. "}
+
+Use [`.actions`](#actions) instead.
+
+### . actions {.property}
```tsx
-var srv.entities/events/operations : Iterable <{
+var srv.entities/events/actions : Iterable <{
name : CSN definition
}>
```
-These properties provide convenient access to the CSN definitions of the *entities*, *events* and operations — that is *actions* and *functions* — exposed by this service.
+These properties provide convenient access to the CSN definitions of the *entities*, *events* and *actions* (incl. *functions*) exposed by this service.
They are *iterable* objects, which means you can use them in all of these ways:
@@ -423,7 +427,6 @@ for (let d of this.entities) //... d is a CSN definition
-
### srv. init() {.method}
```tsx
diff --git a/node.js/events.md b/node.js/events.md
index 650f4998dc..4add035ad7 100644
--- a/node.js/events.md
+++ b/node.js/events.md
@@ -431,7 +431,7 @@ this.on('CREATE', Books, req => {
```
::: details **Best Practice:**{.good} Use the `@mandatory` annotation instead.
-The sample above is just for illustration. Instead, use the [`@mandatory`](../guides/providing-services.md#mandatory)
+The sample above is just for illustration. Instead, use the [`@mandatory`](../guides/services/constraints#mandatory)
annotation in your CDS model to define mandatory inputs like that:
```cds
diff --git a/node.js/fiori.md b/node.js/fiori.md
index 4dbb46664e..77a81782f0 100644
--- a/node.js/fiori.md
+++ b/node.js/fiori.md
@@ -10,15 +10,19 @@ See [Cookbook > Serving UIs > Draft Support](../advanced/fiori#draft-support) fo
[[toc]]
+
+
+
+
## Draft Entities {#draft-support}
Draft-enabled entities have corresponding CSN entities for drafts:
@@ -135,6 +139,7 @@ srv.on('someAction', [ MyEntity, MyEntity.drafts ], /*...*/)
```
+
## Draft Locks
To prevent inconsistency, the entities with draft are locked for modifications by other users. The lock is released when the draft is saved, canceled or a timeout is hit. The default timeout is 15 minutes. You can configure this timeout by the following application configuration property:
@@ -153,6 +158,7 @@ If the `draft_lock_timeout` has been reached, every user can delete other users'
:::
+
## Draft Timeouts
Inactive drafts are deleted automatically after the default timeout of 30 days. You can configure or deactivate this timeout by the following configuration:
@@ -178,43 +184,42 @@ It can occur that inactive drafts are still in the database after the configured
:::
-## Bypassing Drafts
-Creating or modifying active instances directly is possible without creating drafts. This comes in handy when technical services without a UI interact with each other.
-To enable this feature, set this feature flag in your configuration:
+## Bypassing Drafts {.deprecated}
+
+Use [Direct CRUD](#direct-crud) instead.
+
+Until the next major release (`cds10`), you can still activate the draft bypass without also allowing direct CRUD via cds.fiori.bypass_draft:true.
-```json
-{
- "cds": {
- "fiori": {
- "bypass_draft": true
- }
- }
-}
-```
-You can then create active instances directly:
+
+## Direct CRUD
+
+With cds.fiori.direct_crud:true, creating or modifying active instances directly is possible without creating drafts.
+This comes in handy when technical services without a UI interact with each other.
+
+That is, you can then create and modify active instances directly:
```http
POST /Books
{
- "ID": 123,
- "IsActiveEntity": true
+ "ID": 123
}
```
-You can modify them directly:
-
```http
-PATCH /Books(ID=123,IsActiveEntity=true)
+PUT /Books(ID=123)
{
"title": "How to be more active"
}
```
-This feature is required to enable [SAP Fiori Elements Mass Edit](https://sapui5.hana.ondemand.com/sdk/#/topic/965ef5b2895641bc9b6cd44f1bd0eb4d.html), allowing users to change multiple objects with the
+For this, the default draft creation behavior by SAP Fiori Elements is redirected to a collection-bound action via annotation `@Common.DraftRoot.NewAction`.
+The thereby freed `POST` request to draft roots without specifying `IsActiveEntity` leads to the creation of an active instance (as it would without draft enablement).
+
+The feature is required to enable [SAP Fiori Elements Mass Edit](https://sapui5.hana.ondemand.com/sdk/#/topic/965ef5b2895641bc9b6cd44f1bd0eb4d.html), allowing users to change multiple objects with the
same editable properties without creating drafts for each row.
:::warning Additional entry point
@@ -223,6 +228,7 @@ payloads rather than the complete business object.
:::
+
## Programmatic APIs
You can programmatically invoke draft actions with the following APIs:
diff --git a/package-lock.json b/package-lock.json
index 346c4660bc..ecc8bf27d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1562,9 +1562,9 @@
}
},
"node_modules/@eslint/js": {
- "version": "9.39.1",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz",
- "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==",
+ "version": "9.39.2",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
+ "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2343,15 +2343,15 @@
]
},
"node_modules/@sap/cds": {
- "version": "9.5.1",
- "resolved": "https://registry.npmjs.org/@sap/cds/-/cds-9.5.1.tgz",
- "integrity": "sha512-rMvDSRytjqYQolB0pg8tiBlpS9kKGcleRhpZmBGUmSncbbwnotKYTKoDyMCWkflS8P9/Jq9YfY1qhK+fduHCVA==",
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@sap/cds/-/cds-9.6.1.tgz",
+ "integrity": "sha512-Bx6asOBhYXBE+jB6FtmyHmAjoPi11MYb/v/AYpnp0jqL/+kAXXWo6YOxJHqpx1k5Um5FS1r6gM/5tVAo/ta7bw==",
"dev": true,
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"@sap/cds-compiler": "^6.3",
"@sap/cds-fiori": "^2",
- "js-yaml": "^4.1.0"
+ "js-yaml": "^4.1.1"
},
"bin": {
"cds-deploy": "bin/deploy.js",
@@ -2825,16 +2825,16 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/parser": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
- "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.50.0.tgz",
+ "integrity": "sha512-6/cmF2piao+f6wSxUsJLZjck7OQsYyRtcOZS02k7XINSNlz93v6emM8WutDQSXnroG2xwYlEVHJI+cPA7CPM3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "8.48.1",
- "@typescript-eslint/types": "8.48.1",
- "@typescript-eslint/typescript-estree": "8.48.1",
- "@typescript-eslint/visitor-keys": "8.48.1",
+ "@typescript-eslint/scope-manager": "8.50.0",
+ "@typescript-eslint/types": "8.50.0",
+ "@typescript-eslint/typescript-estree": "8.50.0",
+ "@typescript-eslint/visitor-keys": "8.50.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2850,14 +2850,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",
- "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.50.0.tgz",
+ "integrity": "sha512-Cg/nQcL1BcoTijEWyx4mkVC56r8dj44bFDvBdygifuS20f3OZCHmFbjF34DPSi07kwlFvqfv/xOLnJ5DquxSGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/tsconfig-utils": "^8.48.1",
- "@typescript-eslint/types": "^8.48.1",
+ "@typescript-eslint/tsconfig-utils": "^8.50.0",
+ "@typescript-eslint/types": "^8.50.0",
"debug": "^4.3.4"
},
"engines": {
@@ -2872,14 +2872,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",
- "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.50.0.tgz",
+ "integrity": "sha512-xCwfuCZjhIqy7+HKxBLrDVT5q/iq7XBVBXLn57RTIIpelLtEIZHXAF/Upa3+gaCpeV1NNS5Z9A+ID6jn50VD4A==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.48.1",
- "@typescript-eslint/visitor-keys": "8.48.1"
+ "@typescript-eslint/types": "8.50.0",
+ "@typescript-eslint/visitor-keys": "8.50.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2890,9 +2890,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",
- "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.50.0.tgz",
+ "integrity": "sha512-vxd3G/ybKTSlm31MOA96gqvrRGv9RJ7LGtZCn2Vrc5htA0zCDvcMqUkifcjrWNNKXHUU3WCkYOzzVSFBd0wa2w==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2907,9 +2907,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
- "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.50.0.tgz",
+ "integrity": "sha512-iX1mgmGrXdANhhITbpp2QQM2fGehBse9LbTf0sidWK6yg/NE+uhV5dfU1g6EYPlcReYmkE9QLPq/2irKAmtS9w==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2921,16 +2921,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",
- "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.50.0.tgz",
+ "integrity": "sha512-W7SVAGBR/IX7zm1t70Yujpbk+zdPq/u4soeFSknWFdXIFuWsBGBOUu/Tn/I6KHSKvSh91OiMuaSnYp3mtPt5IQ==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/project-service": "8.48.1",
- "@typescript-eslint/tsconfig-utils": "8.48.1",
- "@typescript-eslint/types": "8.48.1",
- "@typescript-eslint/visitor-keys": "8.48.1",
+ "@typescript-eslint/project-service": "8.50.0",
+ "@typescript-eslint/tsconfig-utils": "8.50.0",
+ "@typescript-eslint/types": "8.50.0",
+ "@typescript-eslint/visitor-keys": "8.50.0",
"debug": "^4.3.4",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
@@ -2949,13 +2949,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "8.48.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",
- "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.50.0.tgz",
+ "integrity": "sha512-Xzmnb58+Db78gT/CCj/PVCvK+zxbnsw6F+O1oheYszJbBSdEjVhQi3C/Xttzxgi/GLmpvOggRs1RFpiJ8+c34Q==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "8.48.1",
+ "@typescript-eslint/types": "8.50.0",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -3415,6 +3415,22 @@
"url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
+ "node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -4330,9 +4346,9 @@
}
},
"node_modules/eslint": {
- "version": "9.39.1",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz",
- "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
+ "version": "9.39.2",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
+ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -4342,7 +4358,7 @@
"@eslint/config-helpers": "^0.4.2",
"@eslint/core": "^0.17.0",
"@eslint/eslintrc": "^3.3.1",
- "@eslint/js": "9.39.1",
+ "@eslint/js": "9.39.2",
"@eslint/plugin-kit": "^0.4.1",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
@@ -4451,22 +4467,6 @@
"url": "https://opencollective.com/eslint"
}
},
- "node_modules/eslint/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
"node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
@@ -4932,6 +4932,19 @@
"node": ">=20"
}
},
+ "node_modules/get-east-asian-width": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz",
+ "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
@@ -5056,9 +5069,9 @@
}
},
"node_modules/gray-matter/node_modules/js-yaml": {
- "version": "3.14.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
- "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "version": "3.14.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+ "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5627,9 +5640,9 @@
}
},
"node_modules/markdownlint": {
- "version": "0.39.0",
- "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.39.0.tgz",
- "integrity": "sha512-Xt/oY7bAiHwukL1iru2np5LIkhwD19Y7frlsiDILK62v3jucXCD6JXlZlwMG12HZOR+roHIVuJZrfCkOhp6k3g==",
+ "version": "0.40.0",
+ "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.40.0.tgz",
+ "integrity": "sha512-UKybllYNheWac61Ia7T6fzuQNDZimFIpCg2w6hHjgV1Qu0w1TV0LlSgryUGzM0bkKQCBhy2FDhEELB73Kb0kAg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5640,7 +5653,8 @@
"micromark-extension-gfm-footnote": "2.1.0",
"micromark-extension-gfm-table": "2.1.1",
"micromark-extension-math": "3.1.0",
- "micromark-util-types": "2.0.2"
+ "micromark-util-types": "2.0.2",
+ "string-width": "8.1.0"
},
"engines": {
"node": ">=20"
@@ -5650,9 +5664,9 @@
}
},
"node_modules/markdownlint-cli": {
- "version": "0.46.0",
- "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.46.0.tgz",
- "integrity": "sha512-4gxTNzPjpLnY7ftrEZD4flPY0QBkQLiqezb6KURFSkV+vPHFOsYw8OMtY6fu82Yt8ghtSrWegpYdq1ix25VFLQ==",
+ "version": "0.47.0",
+ "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.47.0.tgz",
+ "integrity": "sha512-HOcxeKFAdDoldvoYDofd85vI8LgNWy8vmYpCwnlLV46PJcodmGzD7COSSBlhHwsfT4o9KrAStGodImVBus31Bg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -5663,7 +5677,7 @@
"jsonc-parser": "~3.3.1",
"jsonpointer": "~5.0.1",
"markdown-it": "~14.1.0",
- "markdownlint": "~0.39.0",
+ "markdownlint": "~0.40.0",
"minimatch": "~10.1.1",
"run-con": "~1.3.2",
"smol-toml": "~1.5.2",
@@ -7268,9 +7282,9 @@
"peer": true
},
"node_modules/sass": {
- "version": "1.94.2",
- "resolved": "https://registry.npmjs.org/sass/-/sass-1.94.2.tgz",
- "integrity": "sha512-N+7WK20/wOr7CzA2snJcUSSNTCzeCGUTFY3OgeQP3mZ1aj9NMQ0mSTXwlrnd89j33zzQJGqIN52GIOmYrfq46A==",
+ "version": "1.97.0",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.0.tgz",
+ "integrity": "sha512-KR0igP1z4avUJetEuIeOdDlwaUDvkH8wSx7FdSjyYBS3dpyX3TzHfAMO0G1Q4/3cdjcmi3r7idh+KCmKqS+KeQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -7612,6 +7626,23 @@
"node": ">= 0.8"
}
},
+ "node_modules/string-width": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz",
+ "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-east-asian-width": "^1.3.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/stringify-entities": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
@@ -7627,6 +7658,22 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/strip-ansi": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
diff --git a/plugins/index.md b/plugins/index.md
index 7754fb3a6d..912373ae17 100644
--- a/plugins/index.md
+++ b/plugins/index.md
@@ -168,7 +168,12 @@ Available for:
## Attachments
-The Attachments plugin provides out-of-the-box support for attachment handling. On Node.js, attachments are stored on AWS S/3 through [SAP BTP's Object Store service](https://discovery-center.cloud.sap/serviceCatalog/object-store). For Java: When using the package [`cds-feature-attachments-oss`](https://central.sonatype.com/artifact/com.sap.cds/cds-feature-attachments-oss), depending on your cloud environment, attachments are stored on AWS S/3, Microsoft Azure, or the Google object store through [SAP BTP's Object Store service](https://discovery-center.cloud.sap/serviceCatalog/object-store). When using the package [`cds-feature-attachments`](https://central.sonatype.com/artifact/com.sap.cds/cds-feature-attachments), attachments are stored on the SAP HANA database.
+The Attachments plugin enables efficient management of file attachments within your applications. By default, attachments are stored in the SAP HANA database.
+
+For Java, use the package [`cds-feature-attachments`](https://central.sonatype.com/artifact/com.sap.cds/cds-feature-attachments). For Node.js, this is supported by the standard plugin.
+
+To integrate with cloud storage solutions such as `AWS S3`, `Azure Blob Storage`, or `Google Cloud Storage` through [SAP BTP's Object Store service](https://discovery-center.cloud.sap/serviceCatalog/object-store), use the [`cds-feature-attachments-oss`](https://central.sonatype.com/artifact/com.sap.cds/cds-feature-attachments-oss) package for Java or the [`@cap-js/attachments`](https://www.npmjs.com/package/@cap-js/attachments) package for Node.js.
+
To use the Attachments plugin, simply add a composition of the predefined aspect `Attachments` like so:
```cds
@@ -184,7 +189,7 @@ That's all we need to automatically add an interactive list of attachments to yo
Features:
-- Pre-defined type `Attachment` to use in entity definitions
+- Pre-defined type `Attachments` to use in entity definitions
- Automatic handling of all upload and download operations
- Automatic malware scanning for uploaded files
- (Automatic) Fiori Annotations for Upload Controls
diff --git a/tools/assets/cds-export.png b/tools/assets/cds-export.png
new file mode 100644
index 0000000000..a6d2848880
Binary files /dev/null and b/tools/assets/cds-export.png differ
diff --git a/tools/assets/help/cds-version-md.out.md b/tools/assets/help/cds-version-md.out.md
index 6341e11d9b..7653e5bdec 100644
--- a/tools/assets/help/cds-version-md.out.md
+++ b/tools/assets/help/cds-version-md.out.md
@@ -4,14 +4,14 @@
| your-project | https://github.com/<your/repo> |
| ---------------------- | --------------------------------------- |
-| @sap/cds | 9.5.1 |
-| @sap/cds-compiler | 6.5.0 |
+| @sap/cds | 9.6.0 |
+| @sap/cds-compiler | 6.6.0 |
| @sap/cds-dk (global) | 9.5.0 |
| @sap/cds-fiori | 2.1.1 |
| @sap/cds-mtxs | 3.5.0 |
| @cap-js/asyncapi | 1.0.3 |
-| @cap-js/db-service | 2.7.0 |
+| @cap-js/db-service | 2.8.0 |
| @cap-js/openapi | 1.2.3 |
-| @cap-js/sqlite | 2.1.0 |
+| @cap-js/sqlite | 2.1.1 |
| Node.js | v22.21.1 |
diff --git a/tools/assets/help/cds-version.out.md b/tools/assets/help/cds-version.out.md
index 9d04283d0c..872d6ece56 100644
--- a/tools/assets/help/cds-version.out.md
+++ b/tools/assets/help/cds-version.out.md
@@ -2,14 +2,14 @@
> cds version
-@sap/cds: 9.5.1
-@sap/cds-compiler: 6.5.0
+@sap/cds: 9.6.0
+@sap/cds-compiler: 6.6.0
@sap/cds-dk (global): 9.5.0
@sap/cds-fiori: 2.1.1
@sap/cds-mtxs: 3.5.0
@cap-js/asyncapi: 1.0.3
-@cap-js/db-service: 2.7.0
+@cap-js/db-service: 2.8.0
@cap-js/openapi: 1.2.3
-@cap-js/sqlite: 2.1.0
+@cap-js/sqlite: 2.1.1
Node.js: v22.21.1
diff --git a/tools/cds-cli.md b/tools/cds-cli.md
index d4e986bd99..68370ccdc8 100644
--- a/tools/cds-cli.md
+++ b/tools/cds-cli.md
@@ -259,7 +259,7 @@ The result could look like this for a typical _Books_ entity from the _Bookshop_
- `author.ID` refers to a key from the _...Authors.json_ file that is created at the same time. If the _Authors_ entity is excluded, though, no such foreign key would be created, which cuts the association off.
- Data for _compositions_, like the `texts` composition to `Books.texts`, is always created.
- A random unique number for each record, _29894036_ here, is added to each string property, to help you correlate properties more easily.
-- Data for elements annotated with a regular expression using [`assert.format`](../guides/providing-services#assert-format) can be generated using the NPM package [randexp](https://www.npmjs.com/package/randexp), which you need to installed manually.
+- Data for elements annotated with a regular expression using [`assert.format`](../guides/services/constraints#assert-format) can be generated using the NPM package [randexp](https://www.npmjs.com/package/randexp), which you need to installed manually.
- Other constraints like [type formats](../cds/types), [enums](../cds/cdl#enums), and [validation constraints](../guides/providing-services#input-validation) are respected as well, in a best effort way.
:::
@@ -468,6 +468,70 @@ To customize the diagram layout, use these settings in the _Cds > Preview_ categ
- [Diagram: Namespaces](vscode://settings/cds.preview.diagram.namespaces)
- [Diagram: Queries](vscode://settings/cds.preview.diagram.queries)
+
+## cds export
+
+With `cds export` you create an API client package to be used
+for data exchange via CAP-level Service integration ("Calesi").
+
+Define data provider services in your CDS model that serve as an interface to your data, placing each data provider service in a separate file.
+
+For the [xflights](https://github.com/capire/xflights) sample app,
+an API that provides information about flights, airports, and airlines
+could look like this:
+
+::: code-group
+
+```cds [srv/data-service.cds]
+using { sap.capire.flights as my } from '../db/schema';
+
+@data.product @hcql @rest @odata
+service sap.capire.flights.data {
+ @readonly entity Flights as projection on my.Flights;
+ @readonly entity Airlines as projection on my.Airlines;
+ @readonly entity Airports as projection on my.Airports;
+}
+```
+
+:::
+
+Then create an API client package for this service:
+
+```sh
+cds export srv/data-service.cds
+```
+
+The command generates the API client package into a new folder _apis/data-service_.
+
+ {style="filter: drop-shadow(0 2px 5px rgba(0,0,0,.40));"}
+
+The `service.csn` contains only the interface defined in the service, removing the query part of the entities and all the underlying model.
+In addition, there are i18n bundles with the localized metadata relevant
+for the interface, and a _data_ folder with test data
+that exactly matches the structure of the entities in the API.
+
+`cds export` also adds a _package.json_. The package name combines the application name (from the main _package.json_) with the file name of the data service. In our example, this results in `@capire/xflights-data-service`.
+You can change this name as appropriate.
+
+You can then publish the generated package, for example, via `npm publish`.
+
+To consume the API in another CAP application:
+1. Import the API package with `npm add`
+2. Define consumption views on the imported entities
+3. Use them in your model as if they were local entities
+4. Add custom code to access the data in the provider app via any of the offered protocols
+
+Have a look at the [xtravels](https://github.com/capire/xtravels) sample app for an
+example of using an API client package.
+
+:::warning Do not use EDMX to exchange API information
+Prefer exporting and importing API packages via `cds export` and `npm add`.
+**Do not use** EDMX (or OpenAPI) as intermediate format for exchanging API information
+between CAP applications, as you might loose information.
+:::
+
+
+
## cds watch
Use `cds watch` to watch for changed files, restarting your Node.js server.
@@ -660,7 +724,7 @@ Make sure the port matches to what the debug tunnel uses (see the message in the
> [!NOTE] SapMachine is required
> SapMachine is required as Java runtime environment for this feature to work.
-> There is nothing to do if you set up your MTA deployment descriptors with [`cds mta`](../guides/deployment/to-cf#add-mta-yaml) or CAP project wizards.
+> There is nothing to do if you set up your MTA deployment descriptors with [`cds add mta`](../guides/deployment/to-cf#add-mta-yaml) or CAP project wizards.
> See the [documentation of SapMachine](https://help.sap.com/docs/btp/sap-business-technology-platform/sapmachine) for how to configure this manually.
#### Local Applications