@sap/cds 9.0.4 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/bin/deploy.js +29 -0
- package/bin/serve.js +1 -5
- package/lib/compile/etc/csv.js +11 -6
- package/lib/compile/for/lean_drafts.js +29 -7
- package/lib/compile/load.js +8 -5
- package/lib/compile/to/hdbtabledata.js +1 -1
- package/lib/dbs/cds-deploy.js +5 -34
- package/lib/env/cds-env.js +2 -1
- package/lib/env/cds-requires.js +4 -1
- package/lib/env/defaults.js +0 -11
- package/lib/env/schemas/cds-rc.js +218 -6
- package/lib/index.js +38 -38
- package/lib/log/cds-error.js +12 -11
- package/lib/log/format/json.js +1 -1
- package/lib/ql/SELECT.js +31 -0
- package/lib/ql/resolve.js +1 -1
- package/lib/req/context.js +1 -1
- package/lib/req/request.js +1 -1
- package/lib/req/validate.js +17 -19
- package/lib/srv/cds.Service.js +18 -28
- package/lib/srv/middlewares/auth/ias-auth.js +29 -2
- package/lib/srv/middlewares/auth/jwt-auth.js +11 -1
- package/lib/srv/middlewares/auth/xssec.js +1 -1
- package/lib/srv/srv-models.js +1 -1
- package/lib/srv/srv-tx.js +2 -2
- package/lib/utils/cds-utils.js +35 -2
- package/lib/utils/csv-reader.js +1 -1
- package/lib/utils/inflect.js +2 -2
- package/lib/utils/tar.js +60 -23
- package/lib/utils/version.js +18 -0
- package/libx/_runtime/cds.js +1 -1
- package/libx/_runtime/common/aspects/any.js +1 -23
- package/libx/_runtime/common/generic/crud.js +1 -3
- package/libx/_runtime/common/generic/input.js +113 -52
- package/libx/_runtime/common/generic/sorting.js +1 -1
- package/libx/_runtime/common/generic/temporal.js +0 -6
- package/libx/_runtime/common/utils/draft.js +1 -1
- package/libx/_runtime/common/utils/entityFromCqn.js +1 -1
- package/libx/_runtime/common/utils/propagateForeignKeys.js +1 -1
- package/libx/_runtime/common/utils/resolveView.js +2 -2
- package/libx/_runtime/common/utils/structured.js +2 -2
- package/libx/_runtime/common/utils/templateProcessor.js +0 -5
- package/libx/_runtime/common/utils/vcap.js +1 -1
- package/libx/_runtime/fiori/lean-draft.js +529 -143
- package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -2
- package/libx/_runtime/messaging/service.js +1 -1
- package/libx/_runtime/remote/utils/client.js +2 -1
- package/libx/common/assert/utils.js +2 -12
- package/libx/common/utils/streaming.js +4 -9
- package/libx/http/location.js +1 -0
- package/libx/odata/ODataAdapter.js +47 -43
- package/libx/odata/index.js +1 -1
- package/libx/odata/middleware/batch.js +6 -2
- package/libx/odata/middleware/create.js +1 -1
- package/libx/odata/middleware/error.js +27 -17
- package/libx/odata/middleware/operation.js +15 -21
- package/libx/odata/middleware/stream.js +1 -1
- package/libx/odata/parse/afterburner.js +22 -8
- package/libx/odata/parse/cqn2odata.js +16 -10
- package/libx/odata/parse/grammar.peggy +185 -134
- package/libx/odata/parse/parser.js +1 -1
- package/libx/odata/utils/index.js +1 -36
- package/libx/odata/utils/metadata.js +34 -1
- package/libx/odata/utils/odataBind.js +2 -1
- package/libx/odata/utils/result.js +22 -20
- package/libx/queue/index.js +7 -4
- package/libx/rest/RestAdapter.js +1 -2
- package/libx/rest/middleware/create.js +5 -2
- package/package.json +2 -2
- package/server.js +1 -1
- package/bin/deploy/to-hana.js +0 -1
- package/lib/utils/check-version.js +0 -9
- package/lib/utils/unit.js +0 -19
- package/libx/_runtime/cds-services/util/assert.js +0 -181
- package/libx/_runtime/types/api.js +0 -129
- package/libx/common/assert/validation.js +0 -109
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,64 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## Version 9.2.0 - 2025-07-29
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `srv.schedule` allows to specify the time in a more readable way, e.g. `srv.schedule(...).after('1min')`
|
|
12
|
+
- Support for `jwt`/`xsuaa`-auth on XSA
|
|
13
|
+
- Enable `@sap/xssec`'s caching mechanisms (requires `@sap/xssec^4.8`)
|
|
14
|
+
+ The signature cache can be configured via `cds.requires.auth.config`, which is passed to `@sap/xssec`'s authentication services
|
|
15
|
+
+ The token decode cache can be configured programmatically via `require('@sap/xssec').Token.enableDecodeCache(config?)` and deactivated via `require('@sap/xssec').Token.decodeCache = false`
|
|
16
|
+
- `cds.requires` correctly resolve service credentials on Kyma when its merged env configuration is only `true` and the service is found via its property name.
|
|
17
|
+
- `ias`-auth: Support for fallback XSUAA-based authentication meant to ease migration to IAS
|
|
18
|
+
+ The fallback is automatically enabled if XSUAA credentials are available. To enable the credentials look-up, simply add `cds.requires.xsuaa = true` to your env.
|
|
19
|
+
+ In case you need a custom config for the fallback (passed through to `@sap/xssec` as is!), configure it via `cds.requires.xsuaa = { config: { ... } }`
|
|
20
|
+
- Better error message if `cds.xt.Extensions` table is missing in extensibility scenarios.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Upgrade to Peggy 5 version
|
|
25
|
+
- Enabled conversion of `not exists where not` to OData `all`, integrating the inverse of the policy applied by the OData parser.
|
|
26
|
+
- Numeric values in `.csv` files are now returned as numbers instead of strings, e.g. `1` instead of `'1'`;
|
|
27
|
+
when pre-padded with zeros, e.g., `0123`, they are returned as strings, e.g. `'0123'` instead of `123`.
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- Runtime error in transaction handling in messaging services when used with outbox
|
|
32
|
+
- Always use `cds.context` middleware for `enterprise-messaging` endpoints
|
|
33
|
+
- Crash during Location header generation caused by custom response not matching the entity definition.
|
|
34
|
+
- Support for logging of correct error locations with `cds watch` and `cds run`.
|
|
35
|
+
- Double-unescaping of values in double quotes during OData URL parsing
|
|
36
|
+
- Throw explicit error if the result of a media data query is not an instance of `Readable`, rather than responding with `No Content`
|
|
37
|
+
- When loading `.csv` files quoted strings containing the separator (comma or semicolon) where erroneously
|
|
38
|
+
parsed as two separate values instead of one.
|
|
39
|
+
|
|
40
|
+
## Version 9.1.0 - 2025-06-30
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- CDS config schema validations for `cds.requires.auth.tenants`, `cds.cdsc`, `cds.query`, `cds.log`, `cds.server`
|
|
45
|
+
- Queue option `targetPrefix` to prefix `target` value of `cds.outbox.Messages` entries for microservice isolation
|
|
46
|
+
- Basic support for CRUD for hierarchy entities
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- Reduced the amount of SELECT nesting the OData adapter does for `$apply` queries.
|
|
51
|
+
- Better error messages for unresolved parent associations in hierarchy requests
|
|
52
|
+
- Enabled updated behavior of `draftActivate` to move updates to fields of draft enabled entities with type `cds.LargeBinary` from draft to active table on the database level, with feature flag `cds.env.fiori.move_media_data_in_db`.
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- Copies of `cds.context` with `locale`
|
|
57
|
+
- Support for relative paths in `@odata.bind`
|
|
58
|
+
- `cds build` on Windows OS - fixed cli tar usage for resources.tgz
|
|
59
|
+
- Actions and functions with scalar return types use same `@odata.context` calculation as other return types, fixing e.g. `cds.odata.contextAbsoluteUrl` not being respected
|
|
60
|
+
- Improve content-type and content-length handling in OData adapter
|
|
61
|
+
- Parsing incorrect function parameters
|
|
62
|
+
- `cds deploy --dry` no longer tries to load a DB adapter, so that it works w/o one installed.
|
|
63
|
+
- Fix `@mandatory` for actions and functions
|
|
64
|
+
|
|
7
65
|
## Version 9.0.4 - 2025-06-18
|
|
8
66
|
|
|
9
67
|
### Fixed
|
|
@@ -38,6 +96,7 @@
|
|
|
38
96
|
### Changed
|
|
39
97
|
|
|
40
98
|
- Lean draft handler is registered in a service only if a draft-enabled service entity exists
|
|
99
|
+
- Add back in server version on CAP server launch info log record
|
|
41
100
|
|
|
42
101
|
### Fixed
|
|
43
102
|
|
|
@@ -135,6 +194,15 @@
|
|
|
135
194
|
- Deprecated stripping of unnecessary topic prefix `topic:` in messaging
|
|
136
195
|
- Deprecated messaging `Outbox` class. Please use config or `cds.outboxed(srv)` to outbox your service.
|
|
137
196
|
|
|
197
|
+
## Version 8.9.5 - 2025-07-25
|
|
198
|
+
|
|
199
|
+
### Fixed
|
|
200
|
+
|
|
201
|
+
- `req.diff` in case of draft entities using associations to joins/unions
|
|
202
|
+
- Locale detection does not enforce `<http-req>.query` to be present. Some protocol adapters do not set it.
|
|
203
|
+
- View metadata for requests with $apply
|
|
204
|
+
- Handling of bad timestamps in URL ($filter and temporals)
|
|
205
|
+
|
|
138
206
|
## Version 8.9.4 - 2025-05-16
|
|
139
207
|
|
|
140
208
|
### Fixed
|
package/bin/deploy.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console */
|
|
3
|
+
|
|
4
|
+
const cds = require('../lib');
|
|
5
|
+
const argv = process.argv.slice(2);
|
|
6
|
+
const o = {};
|
|
7
|
+
cds.cli = { command: 'deploy', argv, options: o }
|
|
8
|
+
|
|
9
|
+
Promise.resolve(cds.plugins).then(async () => {
|
|
10
|
+
let db = cds.requires.db || {}
|
|
11
|
+
for (let i = 0; i < argv.length; ++i) {
|
|
12
|
+
let k = argv[i], v = argv[++i]
|
|
13
|
+
if (!k.startsWith('--')) return error `Invalid argument: ${k}. Expected format --key value`
|
|
14
|
+
if (v?.startsWith('--')) { --i; v = true } // allow --key without value
|
|
15
|
+
o[k = k.slice(2)] = v ?? true // allow last --key without value
|
|
16
|
+
if (k === 'to') db = { kind: v, dialect: v }
|
|
17
|
+
else (db.credentials ??= {})[k] = v
|
|
18
|
+
}
|
|
19
|
+
console.debug('Deploying with options:', db, o)
|
|
20
|
+
cds.db = await cds.connect.to(db)
|
|
21
|
+
return await cds.deploy('*',o).to(db)
|
|
22
|
+
})
|
|
23
|
+
.catch (e => { console.error(e); process.exitCode = 1 })
|
|
24
|
+
.finally (() => cds.db?.disconnect?.())
|
|
25
|
+
|
|
26
|
+
const error = (...args) => {
|
|
27
|
+
console.error (String.raw(...args))
|
|
28
|
+
process.exitCode = 1
|
|
29
|
+
}
|
package/bin/serve.js
CHANGED
|
@@ -275,10 +275,6 @@ async function _local_server_js() {
|
|
|
275
275
|
function _prepare_logging () { // NOSONAR
|
|
276
276
|
|
|
277
277
|
const LOG = cds.log('cds.serve|server',{label:'cds'}); if (!LOG._info) return; else log = LOG.info
|
|
278
|
-
const _timer = process.env.NODE_ENV === 'production'
|
|
279
|
-
? `[cds] - server launched at ${new Date().toLocaleString()}, version: ${cds.version}, in`
|
|
280
|
-
: '[cds] - server launched in'
|
|
281
|
-
console.time (_timer)
|
|
282
278
|
|
|
283
279
|
// print information when model is loaded
|
|
284
280
|
cds.on ('loaded', ({$sources:srcs})=>{
|
|
@@ -313,7 +309,7 @@ function _prepare_logging () { // NOSONAR
|
|
|
313
309
|
cds.once ('listening', ({url})=>{
|
|
314
310
|
console.log()
|
|
315
311
|
LOG.info ('server listening on',{url})
|
|
316
|
-
|
|
312
|
+
LOG.info ('server', 'v'+cds.version, 'launched in', performance.now().toFixed(0),'ms')
|
|
317
313
|
if (process.stdin.isTTY) LOG.info (`[ terminate with ^C ]\n`)
|
|
318
314
|
})
|
|
319
315
|
}
|
package/lib/compile/etc/csv.js
CHANGED
|
@@ -34,6 +34,10 @@ function parse (csv) {
|
|
|
34
34
|
if (headers.includes(currCol)) values.push (_value4(val, quoted)) // skip value if column was skipped
|
|
35
35
|
val = undefined, quoted = false //> start new val
|
|
36
36
|
}
|
|
37
|
+
else if (c === ' ' && val === undefined) {
|
|
38
|
+
// ignore leading spaces
|
|
39
|
+
continue
|
|
40
|
+
}
|
|
37
41
|
else if (c === '"' && val === undefined) { // start quoted string
|
|
38
42
|
val = ''
|
|
39
43
|
inString = true
|
|
@@ -43,7 +47,7 @@ function parse (csv) {
|
|
|
43
47
|
else inString = false, quoted = true // stop string
|
|
44
48
|
}
|
|
45
49
|
else { // normal char
|
|
46
|
-
|
|
50
|
+
val ??= ''
|
|
47
51
|
val += c
|
|
48
52
|
}
|
|
49
53
|
}
|
|
@@ -59,12 +63,13 @@ function parse (csv) {
|
|
|
59
63
|
return rows
|
|
60
64
|
}
|
|
61
65
|
|
|
62
|
-
|
|
66
|
+
const globals = { null:null, true:true, false:false }
|
|
67
|
+
function _value4 (val, quoted) {
|
|
63
68
|
if (quoted) return val
|
|
64
|
-
if (val)
|
|
65
|
-
if (val
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
if (val) val = val.trim(); else return undefined
|
|
70
|
+
if (val in globals) return globals[val] //> null, true, false
|
|
71
|
+
let n = Number(val)
|
|
72
|
+
return n.toString() == val ? n : val
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
function _ignoreLine(line) {
|
|
@@ -41,16 +41,14 @@ const { Draft } = cds.linked(`
|
|
|
41
41
|
}
|
|
42
42
|
`).definitions
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const draft = Object.create (active, {
|
|
44
|
+
function DraftEntity4(active, name = active.name + '.drafts') {
|
|
45
|
+
const draft = Object.create(active, {
|
|
48
46
|
name: { value: name }, // REVISIT: lots of things break if we do that!
|
|
49
47
|
elements: { value: { ...active.elements, ...Draft.elements }, enumerable: true },
|
|
50
48
|
actives: { value: active },
|
|
51
49
|
query: { value: undefined }, // to not inherit that from active
|
|
52
50
|
// drafts: { value: undefined }, // to not inherit that from active -> doesn't work yet as the coding in lean-draft.js uses .drafts to identify both active and draft entities
|
|
53
|
-
isDraft: { value: true }
|
|
51
|
+
isDraft: { value: true }
|
|
54
52
|
})
|
|
55
53
|
|
|
56
54
|
// for quoted names, we need to overwrite the cds.persistence.name of the derived, draft entity
|
|
@@ -60,7 +58,6 @@ function DraftEntity4 (active, name = active.name+'.drafts') {
|
|
|
60
58
|
return draft
|
|
61
59
|
}
|
|
62
60
|
|
|
63
|
-
|
|
64
61
|
module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
65
62
|
function _redirect(assoc, target) {
|
|
66
63
|
assoc.target = target.name
|
|
@@ -153,7 +150,8 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
|
153
150
|
key === '@mandatory' ||
|
|
154
151
|
key === '@Common.FieldControl' && newEl[key]?.['#'] === 'Mandatory' ||
|
|
155
152
|
// key === '@Core.Immutable': Not allowed via UI anyway -> okay to cleanse them in PATCH
|
|
156
|
-
|
|
153
|
+
// REVISIT: Remove feature flag dependency: If active, validation errors will be degraded to messages and stored in draft admin data
|
|
154
|
+
(!active._service?.entities.DraftAdministrativeData.elements.DraftMessages && key.startsWith('@assert')) ||
|
|
157
155
|
key.startsWith('@PersonalData')
|
|
158
156
|
)
|
|
159
157
|
newEl[key] = undefined
|
|
@@ -162,6 +160,23 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
|
162
160
|
draft.elements[each] = newEl
|
|
163
161
|
}
|
|
164
162
|
|
|
163
|
+
// For list-report hierarchies, there must not be deep deletes w.r.t. recursive compositions
|
|
164
|
+
// Therefore, they are degraded to associations.
|
|
165
|
+
// Note: For object-page hiearchies, deep delete on draft recursive compositions is still needed.
|
|
166
|
+
if (draft.elements.LimitedDescendantCount && draft['@Common.DraftRoot.ActivationAction']) {
|
|
167
|
+
for (const c in draft.compositions) {
|
|
168
|
+
const comp = draft.compositions[c]
|
|
169
|
+
if (comp.target === draft.name) {
|
|
170
|
+
// modify comp to assoc
|
|
171
|
+
comp.type = 'cds.Association'
|
|
172
|
+
comp.isComposition = false
|
|
173
|
+
comp.is = function(kind) { return kind === 'Association' }
|
|
174
|
+
delete draft.compositions[c]
|
|
175
|
+
draft.associations[c] = comp
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
165
180
|
return draft
|
|
166
181
|
}
|
|
167
182
|
|
|
@@ -173,6 +188,13 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
|
|
|
173
188
|
def.elements.HasActiveEntity.virtual = true
|
|
174
189
|
if (def.elements.DraftAdministrativeData_DraftUUID) def.elements.DraftAdministrativeData_DraftUUID.virtual = true
|
|
175
190
|
def.elements.DraftAdministrativeData.virtual = true
|
|
191
|
+
if (def.elements.LimitedDescendantCount) {
|
|
192
|
+
// for hierarchies: make sure recursive compositions are not part of the draft tree
|
|
193
|
+
for (const c in def.compositions) {
|
|
194
|
+
const comp = def.compositions[c]
|
|
195
|
+
if (comp.target === def.name) comp['@odata.draft.ignore'] = true
|
|
196
|
+
}
|
|
197
|
+
}
|
|
176
198
|
// will insert drafts entities, so that others can use `.drafts` even without incoming draft requests
|
|
177
199
|
addDraftEntity(def, csn)
|
|
178
200
|
}
|
package/lib/compile/load.js
CHANGED
|
@@ -9,13 +9,16 @@ if (TRACE) {
|
|
|
9
9
|
module.exports = exports = function load (files, options) {
|
|
10
10
|
let any = cds.resolve(files,options)
|
|
11
11
|
|
|
12
|
+
// REVISIT: we need to find a better way to handle this -> doing that in cds.load is by far too central
|
|
12
13
|
// REVISIT: bandaid for grow as you go scenario with task queues enabled by default
|
|
13
14
|
let locations
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
if (cds.watched) {
|
|
16
|
+
const _is_outbox = p => cds.utils.path.posix.normalize(p).match(/\/cds\/srv\/outbox(\.cds)?$/)
|
|
17
|
+
const _outbox_only = any?.length === 1 && _is_outbox(any[0]) && (!Array.isArray(files) || !files.some(_is_outbox))
|
|
18
|
+
if (_outbox_only) {
|
|
19
|
+
any = undefined
|
|
20
|
+
locations = cds.resolve(files, false).filter(f => !_is_outbox(f))
|
|
21
|
+
}
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
if (!any) return Promise.reject (new cds.error ({
|
package/lib/dbs/cds-deploy.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
const cds = require('../index'), { local, path } = cds.utils
|
|
3
2
|
const DEBUG = cds.debug('deploy')
|
|
4
3
|
const TRACE = cds.debug('trace')
|
|
@@ -20,6 +19,9 @@ const deploy = module.exports = function cds_deploy (model, options, csvs) {
|
|
|
20
19
|
if (o.mocked) deploy.include_external_entities_in(model)
|
|
21
20
|
else deploy.exclude_external_entities_in(model)
|
|
22
21
|
|
|
22
|
+
// dry deployment (output schema only)
|
|
23
|
+
if (o.dry) return await deploy.schema ({model, options:{}}, model, o)
|
|
24
|
+
|
|
23
25
|
// prepare db
|
|
24
26
|
if (!db.run) db = await cds.connect.to(db)
|
|
25
27
|
if (!cds.db) cds.db = cds.services.db = db
|
|
@@ -34,10 +36,9 @@ const deploy = module.exports = function cds_deploy (model, options, csvs) {
|
|
|
34
36
|
|
|
35
37
|
// deploy schema and initial data...
|
|
36
38
|
try {
|
|
37
|
-
|
|
38
|
-
await _run (async tx => {
|
|
39
|
+
await db.run (async tx => {
|
|
39
40
|
let any = await deploy.schema (tx, model, o)
|
|
40
|
-
if (
|
|
41
|
+
if (any || csvs) await deploy.data (tx, model, o, csvs, file => LOG?.(GREY, ' > init from', local(file), RESET))
|
|
41
42
|
})
|
|
42
43
|
LOG?.('/> successfully deployed to', descr, '\n')
|
|
43
44
|
} catch (e) {
|
|
@@ -385,33 +386,3 @@ const _entity4 = (file, csn) => {
|
|
|
385
386
|
}
|
|
386
387
|
return entity.name ? entity : { name, __proto__:entity }
|
|
387
388
|
}
|
|
388
|
-
|
|
389
|
-
/** CLI used as via cds-deploy as deployer for PostgreSQL */
|
|
390
|
-
if (!module.parent) (async function CLI () {
|
|
391
|
-
cds.cli = { command: 'deploy', argv: process.argv.slice(2), options: {} }
|
|
392
|
-
await cds.plugins // IMPORTANT: that has to go before any call to cds.env, like through cds.deploy or cds.requires below
|
|
393
|
-
let db = cds.requires.db
|
|
394
|
-
try {
|
|
395
|
-
let o={}, recent
|
|
396
|
-
for (let each of process.argv.slice(2)) {
|
|
397
|
-
if (each.startsWith('--')) o[(recent = each.slice(2))] = true
|
|
398
|
-
else o[recent] = each
|
|
399
|
-
}
|
|
400
|
-
if (o.to) {
|
|
401
|
-
db = { kind: o.to, dialect: o.to }
|
|
402
|
-
if (o.url) (db.credentials ??= {}).url = o.url
|
|
403
|
-
if (o.host) (db.credentials ??= {}).host = o.host
|
|
404
|
-
if (o.port) (db.credentials ??= {}).port = o.port
|
|
405
|
-
if (o.username) (db.credentials ??= {}).username = o.username
|
|
406
|
-
if (o.password) (db.credentials ??= {}).password = o.password
|
|
407
|
-
}
|
|
408
|
-
cds.cli.options = o
|
|
409
|
-
db = await cds.connect.to(db);
|
|
410
|
-
db = await cds.deploy('*',o).to(db)
|
|
411
|
-
} finally {
|
|
412
|
-
await db?.disconnect?.()
|
|
413
|
-
}
|
|
414
|
-
})().catch((e) => {
|
|
415
|
-
console.error(e)
|
|
416
|
-
process.exitCode = 1
|
|
417
|
-
})
|
package/lib/env/cds-env.js
CHANGED
|
@@ -408,7 +408,8 @@ class Config {
|
|
|
408
408
|
const { credentials } = this._find_credentials_for_required_service(service, conf, vcaps) || {}
|
|
409
409
|
if (credentials) {
|
|
410
410
|
// Merge `credentials`. Needed because some app-defined things like `credentials.destination` must survive.
|
|
411
|
-
any =
|
|
411
|
+
if (conf === true) any = this.requires[service] = { credentials }
|
|
412
|
+
else any = conf.credentials = { ...conf.credentials, ...credentials }
|
|
412
413
|
}
|
|
413
414
|
}
|
|
414
415
|
return !!any
|
package/lib/env/cds-requires.js
CHANGED
|
@@ -85,6 +85,9 @@ for (let each of Object.values(_authentication_strategies)) {
|
|
|
85
85
|
}})
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
// enable credentials lookup for xsuaa fallback
|
|
89
|
+
_authentication_strategies.xsuaa = { vcap: { label: 'xsuaa' } }
|
|
90
|
+
|
|
88
91
|
const _services = {
|
|
89
92
|
|
|
90
93
|
"app-service": {
|
|
@@ -157,7 +160,7 @@ const _queue = {
|
|
|
157
160
|
storeLastError: true,
|
|
158
161
|
timeout: '1h',
|
|
159
162
|
legacyLocking: true,
|
|
160
|
-
ignoredContext: ['user', 'http', 'model', 'timestamp']
|
|
163
|
+
ignoredContext: ['user', 'http', 'model', 'timestamp', '_locale', '_features']
|
|
161
164
|
},
|
|
162
165
|
// legacy
|
|
163
166
|
"in-memory-outbox": "in-memory-queue",
|
package/lib/env/defaults.js
CHANGED
|
@@ -2,17 +2,6 @@ const production = process.env.NODE_ENV === 'production'
|
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* For our own tests to replace hard-coded checks for CDS_ENV === 'better-sqlite'
|
|
7
|
-
* which don't work anymore with cds8 where that is the default.
|
|
8
|
-
*/
|
|
9
|
-
get _better_sqlite() {
|
|
10
|
-
if (process.env.CDS_ENV === 'better-sqlite') return true
|
|
11
|
-
let conf = this.requires.db || this.requires.kinds.sql
|
|
12
|
-
if (conf?.impl === '@cap-js/sqlite') return true
|
|
13
|
-
else return false
|
|
14
|
-
},
|
|
15
|
-
|
|
16
5
|
production,
|
|
17
6
|
|
|
18
7
|
requires: require('./cds-requires'),
|
|
@@ -81,23 +81,23 @@ module.exports = {
|
|
|
81
81
|
folders: {
|
|
82
82
|
type: 'object',
|
|
83
83
|
default: {},
|
|
84
|
-
description: '
|
|
84
|
+
description: 'Overrides for default folders. Only override if you don\'t want to use the defaults \'app/\', \'db/\', \'srv/\'.',
|
|
85
85
|
additionalProperties: true,
|
|
86
86
|
properties: {
|
|
87
87
|
app: {
|
|
88
88
|
type: 'string',
|
|
89
89
|
format: 'uri-reference',
|
|
90
|
-
description: '
|
|
90
|
+
description: 'Applications, e.g. UI5 or Fiori apps'
|
|
91
91
|
},
|
|
92
92
|
db: {
|
|
93
93
|
type: 'string',
|
|
94
94
|
format: 'uri-reference',
|
|
95
|
-
description: '
|
|
95
|
+
description: 'Database models and migrations'
|
|
96
96
|
},
|
|
97
97
|
srv: {
|
|
98
98
|
type: 'string',
|
|
99
99
|
format: 'uri-reference',
|
|
100
|
-
description: '
|
|
100
|
+
description: 'Services'
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
103
|
patternProperties: {
|
|
@@ -168,7 +168,7 @@ module.exports = {
|
|
|
168
168
|
properties: {
|
|
169
169
|
kind: {
|
|
170
170
|
type: 'string',
|
|
171
|
-
description: '
|
|
171
|
+
description: 'Authentication kind.',
|
|
172
172
|
anyOf: [
|
|
173
173
|
{
|
|
174
174
|
$ref: '#/$defs/authType'
|
|
@@ -181,6 +181,27 @@ module.exports = {
|
|
|
181
181
|
users: {
|
|
182
182
|
$ref: '#/$defs/mockUsers'
|
|
183
183
|
},
|
|
184
|
+
tenants: {
|
|
185
|
+
type: 'object',
|
|
186
|
+
description: 'List of tenants with their respective features.',
|
|
187
|
+
additionalProperties: true,
|
|
188
|
+
patternProperties: {
|
|
189
|
+
'.+': {
|
|
190
|
+
type: 'object',
|
|
191
|
+
additionalProperties: true,
|
|
192
|
+
properties: {
|
|
193
|
+
features: {
|
|
194
|
+
type: 'array',
|
|
195
|
+
description: 'List of feature toggles for this tenant.',
|
|
196
|
+
uniqueItems: true,
|
|
197
|
+
items: {
|
|
198
|
+
type: 'string'
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
},
|
|
184
205
|
credentials: {
|
|
185
206
|
type: 'object',
|
|
186
207
|
description: 'You can explicitly configure credentials, but this is overruled by VCAP_SERVICES if a matching entry is found therein.',
|
|
@@ -198,6 +219,10 @@ module.exports = {
|
|
|
198
219
|
},
|
|
199
220
|
db: {
|
|
200
221
|
oneOf: [
|
|
222
|
+
{
|
|
223
|
+
type: 'boolean',
|
|
224
|
+
description: 'Shortcut to enable primary database.'
|
|
225
|
+
},
|
|
201
226
|
{
|
|
202
227
|
type: 'string',
|
|
203
228
|
description: 'Settings for the primary database (shortcut).',
|
|
@@ -645,6 +670,193 @@ module.exports = {
|
|
|
645
670
|
]
|
|
646
671
|
}
|
|
647
672
|
}
|
|
673
|
+
},
|
|
674
|
+
cdsc: {
|
|
675
|
+
type: 'object',
|
|
676
|
+
default: {},
|
|
677
|
+
description: 'CDS compiler configuration options.',
|
|
678
|
+
additionalProperties: true,
|
|
679
|
+
properties: {
|
|
680
|
+
moduleLookupDirectories: {
|
|
681
|
+
type: 'array',
|
|
682
|
+
description: 'List of directories to search for modules.',
|
|
683
|
+
uniqueItems: true,
|
|
684
|
+
items: {
|
|
685
|
+
type: 'string',
|
|
686
|
+
format: 'uri-reference'
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
},
|
|
691
|
+
query: {
|
|
692
|
+
type: 'object',
|
|
693
|
+
default: {},
|
|
694
|
+
description: 'Query configuration options.',
|
|
695
|
+
additionalProperties: true,
|
|
696
|
+
properties: {
|
|
697
|
+
limit: {
|
|
698
|
+
type: 'object',
|
|
699
|
+
description: 'Default limit for queries.',
|
|
700
|
+
additionalProperties: true,
|
|
701
|
+
properties: {
|
|
702
|
+
default: {
|
|
703
|
+
type: 'integer',
|
|
704
|
+
description: 'Default number of results returned by a query.',
|
|
705
|
+
minimum: 1
|
|
706
|
+
},
|
|
707
|
+
max: {
|
|
708
|
+
type: 'integer',
|
|
709
|
+
description: 'Maximum number of results returned by a query.',
|
|
710
|
+
minimum: 1
|
|
711
|
+
},
|
|
712
|
+
reliablePaging: {
|
|
713
|
+
type: 'boolean',
|
|
714
|
+
description: 'Enable reliable paging for queries.'
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
},
|
|
720
|
+
log: {
|
|
721
|
+
type: 'object',
|
|
722
|
+
default: {},
|
|
723
|
+
description: 'Logging configuration options.',
|
|
724
|
+
additionalProperties: true,
|
|
725
|
+
properties: {
|
|
726
|
+
format: {
|
|
727
|
+
type: 'string',
|
|
728
|
+
description: 'Log format, either \'plain\' or \'json\'.',
|
|
729
|
+
enum: [
|
|
730
|
+
'plain',
|
|
731
|
+
'json'
|
|
732
|
+
]
|
|
733
|
+
},
|
|
734
|
+
levels: {
|
|
735
|
+
type: 'object',
|
|
736
|
+
description: 'Log levels for different components.',
|
|
737
|
+
additionalProperties: {
|
|
738
|
+
type: 'string'
|
|
739
|
+
},
|
|
740
|
+
properties: {
|
|
741
|
+
cds: {
|
|
742
|
+
type: 'string',
|
|
743
|
+
description: 'Server and common output.'
|
|
744
|
+
},
|
|
745
|
+
cli: {
|
|
746
|
+
type: 'string',
|
|
747
|
+
description: 'CLI output.'
|
|
748
|
+
},
|
|
749
|
+
build: {
|
|
750
|
+
type: 'string',
|
|
751
|
+
description: 'CDS build output.'
|
|
752
|
+
},
|
|
753
|
+
app: {
|
|
754
|
+
type: 'string',
|
|
755
|
+
description: 'Application Service.'
|
|
756
|
+
},
|
|
757
|
+
db: {
|
|
758
|
+
type: 'string',
|
|
759
|
+
description: 'Databases.'
|
|
760
|
+
},
|
|
761
|
+
sql: {
|
|
762
|
+
type: 'string',
|
|
763
|
+
description: 'SQL output.'
|
|
764
|
+
},
|
|
765
|
+
messaging: {
|
|
766
|
+
type: 'string',
|
|
767
|
+
description: 'Messaging Service.'
|
|
768
|
+
},
|
|
769
|
+
remote: {
|
|
770
|
+
type: 'string',
|
|
771
|
+
description: 'Remote Service.'
|
|
772
|
+
},
|
|
773
|
+
'audit-log': {
|
|
774
|
+
type: 'string',
|
|
775
|
+
description: 'AuditLog Service.'
|
|
776
|
+
},
|
|
777
|
+
odata: {
|
|
778
|
+
type: 'string',
|
|
779
|
+
description: 'OData Protocol Adapter.'
|
|
780
|
+
},
|
|
781
|
+
rest: {
|
|
782
|
+
type: 'string',
|
|
783
|
+
description: 'REST Protocol Adapter.'
|
|
784
|
+
},
|
|
785
|
+
graphql: {
|
|
786
|
+
type: 'string',
|
|
787
|
+
description: 'GraphQL Protocol Adapter.'
|
|
788
|
+
},
|
|
789
|
+
auth: {
|
|
790
|
+
type: 'string',
|
|
791
|
+
description: 'Authentication.'
|
|
792
|
+
},
|
|
793
|
+
deploy: {
|
|
794
|
+
type: 'string',
|
|
795
|
+
description: 'Database Deployment.'
|
|
796
|
+
},
|
|
797
|
+
mtx: {
|
|
798
|
+
type: 'string',
|
|
799
|
+
description: 'Multitenancy and Extensibility.'
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
},
|
|
803
|
+
mask_headers: {
|
|
804
|
+
type: 'array',
|
|
805
|
+
description: 'List of header patterns to mask in logs.',
|
|
806
|
+
uniqueItems: true,
|
|
807
|
+
items: {
|
|
808
|
+
type: 'string'
|
|
809
|
+
},
|
|
810
|
+
default: [
|
|
811
|
+
'/authorization/i',
|
|
812
|
+
'/cookie/i',
|
|
813
|
+
'/cert/i',
|
|
814
|
+
'/ssl/i'
|
|
815
|
+
]
|
|
816
|
+
},
|
|
817
|
+
als_custom_fields: {
|
|
818
|
+
type: 'object',
|
|
819
|
+
description:
|
|
820
|
+
`Custom fields for Application Logging Service (ALS) in Kibana's error rendering.
|
|
821
|
+
Key is the index in the log message array.`,
|
|
822
|
+
additionalProperties: {
|
|
823
|
+
type: 'integer'
|
|
824
|
+
}
|
|
825
|
+
},
|
|
826
|
+
cls_custom_fields: {
|
|
827
|
+
type: 'array',
|
|
828
|
+
description:
|
|
829
|
+
`Custom fields for CLS in Kibana's error rendering.
|
|
830
|
+
Each entry is a field name.`,
|
|
831
|
+
uniqueItems: true,
|
|
832
|
+
items: {
|
|
833
|
+
type: 'string'
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
},
|
|
838
|
+
server: {
|
|
839
|
+
type: 'object',
|
|
840
|
+
default: {},
|
|
841
|
+
description: 'Server configuration options.',
|
|
842
|
+
additionalProperties: true,
|
|
843
|
+
properties: {
|
|
844
|
+
port: {
|
|
845
|
+
type: 'integer',
|
|
846
|
+
description: 'Port number for the server to listen on.',
|
|
847
|
+
minimum: 1,
|
|
848
|
+
maximum: 65535
|
|
849
|
+
},
|
|
850
|
+
cors: {
|
|
851
|
+
type: 'boolean',
|
|
852
|
+
description: 'Enable CORS support.',
|
|
853
|
+
default: true
|
|
854
|
+
},
|
|
855
|
+
index: {
|
|
856
|
+
type: 'boolean',
|
|
857
|
+
description: 'Serve the default index page.'
|
|
858
|
+
}
|
|
859
|
+
}
|
|
648
860
|
}
|
|
649
861
|
}
|
|
650
862
|
},
|
|
@@ -909,4 +1121,4 @@ module.exports = {
|
|
|
909
1121
|
}
|
|
910
1122
|
}
|
|
911
1123
|
}
|
|
912
|
-
}
|
|
1124
|
+
}
|