@sap/cds-dk 10.0.7 → 10.1.1
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 +106 -0
- package/bin/add.js +7 -23
- package/bin/bind.js +14 -0
- package/bin/build.js +21 -34
- package/bin/cds.js +1 -1
- package/bin/compile/index.js +16 -41
- package/bin/completion/completionFs.js +11 -8
- package/bin/completion/index.js +603 -80
- package/bin/completion/scripts/cds.fish +620 -0
- package/bin/completion/scripts/cds.ps1 +403 -0
- package/bin/completion/scripts/cds.sh +327 -0
- package/bin/completion/scripts/cds.zsh +296 -0
- package/bin/completion/templates/cds-tmpl.fish +65 -0
- package/bin/completion/templates/cds-tmpl.ps1 +217 -0
- package/bin/completion/templates/cds-tmpl.sh +93 -0
- package/bin/completion/templates/cds-tmpl.zsh +74 -0
- package/bin/deploy/index.js +11 -1
- package/bin/deploy/options.js +25 -0
- package/{lib → bin}/deploy/to-hana/hana.js +8 -8
- package/{lib → bin}/deploy/to-hana/hdiDeployUtil.js +1 -1
- package/bin/deploy/{to-hana.js → to-hana/index.js} +1 -1
- package/{lib → bin}/deploy/to-hana/mtaUtil.js +1 -1
- package/bin/deploy/to-sql.js +0 -2
- package/bin/env.js +4 -1
- package/bin/export.js +44 -6
- package/bin/help/export.md +3 -0
- package/bin/help.js +1 -5
- package/bin/import.js +9 -0
- package/bin/init.js +6 -24
- package/bin/inspect.js +8 -0
- package/bin/lint.js +5 -3
- package/bin/login.js +26 -20
- package/bin/minify.js +6 -1
- package/bin/pull.js +19 -6
- package/bin/push.js +19 -6
- package/bin/repl.js +11 -2
- package/bin/run.js +12 -1
- package/bin/serve.js +13 -2
- package/bin/up.js +17 -11
- package/{lib → bin}/upgrade/constants.js +1 -1
- package/bin/{upgrade.js → upgrade/index.js} +2 -2
- package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
- package/{lib → bin}/upgrade/preflight/index.js +1 -1
- package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
- package/{lib → bin}/upgrade/steps/install.js +1 -1
- package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
- package/{lib → bin}/upgrade/steps/removals.js +1 -1
- package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
- package/{lib → bin}/upgrade/steps/verify.js +1 -1
- package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
- package/{lib → bin}/upgrade/util/pom.js +2 -2
- package/{lib → bin}/upgrade/util/prompt.js +1 -1
- package/bin/util/containerize.js +10 -4
- package/bin/version.js +10 -1
- package/{lib → bin}/watch/hot-reload.js +1 -1
- package/bin/{watch.js → watch/index.js} +24 -9
- package/{lib → bin}/watch/livereload-connect.js +1 -1
- package/{lib → bin}/watch/vite-watch.js +1 -1
- package/{lib → bin}/watch/watched.js +2 -2
- package/lib/build/constants.js +1 -1
- package/lib/build/plugins/fiori/index.js +31 -2
- package/lib/build/plugins/internal.js +4 -2
- package/lib/build/plugins/mtx-sidecar/index.js +7 -8
- package/lib/build/plugins/nodejs/index.js +64 -7
- package/lib/build/util.js +2 -4
- package/lib/compile/to_asyncapi.js +1 -1
- package/lib/env/schema.js +16 -0
- package/lib/env/schemas/cds-rc.js +1 -76
- package/lib/import/importapi.js +2 -3
- package/lib/import/message.js +0 -2
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +2 -2
- package/lib/init/merge.js +123 -280
- package/lib/init/plugin.js +3 -1
- package/lib/init/projectReader.js +22 -6
- package/lib/init/registries/xs-app.js +3 -5
- package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
- package/lib/init/template/ai/index.js +14 -2
- package/lib/init/template/ams/index.js +2 -2
- package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
- package/lib/init/template/app-frontend/index.js +4 -4
- package/lib/init/template/application-logging/index.js +2 -2
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/approuter/index.js +8 -3
- package/lib/init/template/attachments/files/package.json.hbs +1 -1
- package/lib/init/template/attachments/index.js +2 -2
- package/lib/init/template/audit-logging/index.js +2 -2
- package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
- package/lib/init/template/cloud-logging/index.js +2 -2
- package/lib/init/template/completion/completionSetup.js +36 -39
- package/lib/init/template/connectivity/index.js +2 -2
- package/lib/init/template/data/as-csv.js +15 -5
- package/lib/init/template/data/as-json.js +117 -42
- package/lib/init/template/data/index.js +16 -2
- package/lib/init/template/destination/index.js +2 -2
- package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
- package/lib/init/template/dynatrace/index.js +2 -2
- package/lib/init/template/enterprise-messaging/index.js +2 -2
- package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
- package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
- package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
- package/lib/init/template/extensibility/index.js +3 -3
- package/lib/init/template/github-actions/index.js +2 -2
- package/lib/init/template/hana/index.js +3 -2
- package/lib/init/template/hana-serverless/files/db/package.json +14 -0
- package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
- package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
- package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
- package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
- package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
- package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
- package/lib/init/template/hana-serverless/index.js +184 -0
- package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
- package/lib/init/template/html5-repo/index.js +18 -14
- package/lib/init/template/http/index.js +123 -26
- package/lib/init/template/ias/index.js +2 -2
- package/lib/init/template/kafka/index.js +2 -2
- package/lib/init/template/kyma/index.js +7 -5
- package/lib/init/template/malware-scanner/index.js +2 -2
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/multitenancy/index.js +18 -3
- package/lib/init/template/notifications/index.js +2 -2
- package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
- package/lib/init/template/portal/index.js +13 -8
- package/lib/init/template/postgres/index.js +2 -2
- package/lib/init/template/redis/index.js +2 -2
- package/lib/init/template/sample/files/db/currencies.cds +2 -0
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
- package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
- package/lib/init/template/workzone-standard/index.js +5 -5
- package/lib/init/template/xsuaa/index.js +20 -2
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/mtx/auth_manager.js +103 -37
- package/lib/mtx/params.js +3 -2
- package/lib/mtx/settings_manager.js +45 -28
- package/lib/mtx/tenant_action.js +0 -1
- package/lib/mtx/util/credentials.js +62 -0
- package/node_modules/@cap-js/db-service/CHANGELOG.md +17 -0
- package/node_modules/@cap-js/db-service/lib/common/generic-pool.js +4 -7
- package/node_modules/@cap-js/db-service/lib/cqn2pql.js +1 -1
- package/node_modules/@cap-js/db-service/lib/cqn2sql.js +15 -11
- package/node_modules/@cap-js/db-service/lib/cqn4sql.js +119 -19
- package/node_modules/@cap-js/db-service/lib/infer/index.js +27 -16
- package/node_modules/@cap-js/db-service/lib/recursion-guard.js +40 -0
- package/node_modules/@cap-js/db-service/lib/search.js +1 -1
- package/node_modules/@cap-js/db-service/package.json +1 -1
- package/node_modules/@cap-js/sqlite/CHANGELOG.md +19 -0
- package/node_modules/@cap-js/sqlite/lib/SQLiteService.js +110 -14
- package/node_modules/@cap-js/sqlite/package.json +3 -3
- package/node_modules/@sap/cds/CHANGELOG.md +57 -0
- package/node_modules/@sap/cds/app/index.js +5 -4
- package/node_modules/@sap/cds/eslint.config.mjs +1 -0
- package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
- package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
- package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
- package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
- package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
- package/node_modules/@sap/cds/lib/plugins.js +9 -5
- package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
- package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
- package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
- package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
- package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
- package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
- package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
- package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
- package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
- package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
- package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
- package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
- package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
- package/node_modules/@sap/cds/libx/http/location.js +3 -3
- package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
- package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
- package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
- package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
- package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
- package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
- package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
- package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
- package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
- package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
- package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
- package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
- package/node_modules/@sap/cds/package.json +1 -1
- package/node_modules/@sap/cds-compiler/CHANGELOG.md +75 -8
- package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
- package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
- package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
- package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
- package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
- package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
- package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
- package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
- package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
- package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
- package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
- package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
- package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
- package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
- package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +48 -18
- package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
- package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
- package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
- package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
- package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
- package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
- package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
- package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
- package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
- package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
- package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
- package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +4 -0
- package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
- package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
- package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
- package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
- package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
- package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
- package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
- package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
- package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +15 -0
- package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +10 -2
- package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
- package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
- package/node_modules/@sap/cds-compiler/lib/transform/db/flattening.js +4 -3
- package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
- package/node_modules/@sap/cds-compiler/lib/transform/effective/flattening.js +17 -1
- package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +20 -0
- package/node_modules/@sap/cds-compiler/lib/transform/fioriTreeViews.js +12 -1
- package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +7 -2
- package/node_modules/@sap/cds-compiler/lib/transform/odata/adaptAnnotationRefs.js +11 -5
- package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +48 -10
- package/node_modules/@sap/cds-compiler/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/CHANGELOG.md +49 -0
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +26 -5
- package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +37 -16
- package/node_modules/@sap/cds-mtxs/lib/utils.js +23 -7
- package/node_modules/@sap/cds-mtxs/package.json +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +63 -8
- package/node_modules/@sap/cds-mtxs/srv/cf/saas-provisioning-service.js +1 -1
- package/node_modules/@sap/cds-mtxs/srv/cf/sms-provisioning-service.js +23 -3
- package/node_modules/@sap/cds-mtxs/srv/extensibility/compat/update.js +15 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +2 -2
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/config.js +2 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +2 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/protected-namespace.js +45 -0
- package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +30 -16
- package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +49 -10
- package/node_modules/@sap/cds-mtxs/srv/model-provider.js +28 -4
- package/node_modules/@sap/cds-mtxs/srv/plugins/common.js +19 -12
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +1 -1
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr.js +6 -3
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana/serverless.js +271 -0
- package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +7 -10
- package/node_modules/@sap/cds-mtxs/srv/worker/job-worker-pool.js +212 -0
- package/node_modules/@sap/cds-mtxs/srv/worker/job-worker.js +61 -0
- package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
- package/node_modules/@sap/xsenv/package.json +10 -7
- package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
- package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
- package/node_modules/hdb/cfg/VERSION +1 -1
- package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
- package/node_modules/hdb/lib/protocol/Connection.js +1 -0
- package/node_modules/hdb/package.json +3 -2
- package/node_modules/negotiator/lib/accept.js +54 -0
- package/node_modules/negotiator/lib/charset.js +10 -34
- package/node_modules/negotiator/lib/encoding.js +9 -30
- package/node_modules/negotiator/lib/language.js +15 -36
- package/node_modules/negotiator/lib/mediaType.js +16 -134
- package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
- package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
- package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
- package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
- package/node_modules/negotiator/package.json +16 -10
- package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
- package/node_modules/qs/CHANGELOG.md +15 -0
- package/node_modules/qs/README.md +19 -1
- package/node_modules/qs/dist/qs.js +21 -21
- package/node_modules/qs/eslint.config.mjs +1 -1
- package/node_modules/qs/lib/parse.js +3 -4
- package/node_modules/qs/lib/stringify.js +23 -8
- package/node_modules/qs/lib/utils.js +10 -3
- package/node_modules/qs/package.json +4 -4
- package/node_modules/qs/test/parse.js +192 -3
- package/node_modules/qs/test/stringify.js +317 -0
- package/node_modules/qs/test/utils.js +12 -0
- package/node_modules/type-is/node_modules/content-type/README.md +2 -0
- package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
- package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
- package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
- package/node_modules/type-is/node_modules/content-type/package.json +1 -1
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/package.json +2 -2
- package/bin/completion/scripts/cds-bash.sh +0 -20
- package/bin/completion/scripts/cds-fish.fish +0 -13
- package/bin/completion/scripts/cds-ps.ps1 +0 -19
- package/bin/completion/scripts/cds-zsh.sh +0 -13
- package/lib/deploy/index.js +0 -25
- package/lib/import/asyncapi/importAsyncAPI.js +0 -33
- package/lib/import/asyncapi/index.js +0 -18
- package/lib/import/asyncapi/parserContext.js +0 -454
- package/lib/import/asyncapi/utils.js +0 -49
- package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
- package/node_modules/negotiator/HISTORY.md +0 -114
- /package/{lib → bin}/upgrade/context.js +0 -0
- /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
- /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
- /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
- /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
- /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
- /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
- /package/{lib → bin}/watch/livereload-server.js +0 -0
- /package/{lib → bin}/watch/node-watch.js +0 -0
- /package/{lib → bin}/watch/open.js +0 -0
- /package/{lib → bin}/watch/watcher.js +0 -0
- /package/node_modules/@sap/cds-mtxs/srv/worker/{pool.js → model-worker-pool.js} +0 -0
- /package/node_modules/@sap/cds-mtxs/srv/worker/{load.js → model-worker.js} +0 -0
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
const cds = require('@sap/cds')
|
|
2
|
+
const { path } = cds.utils
|
|
2
3
|
module.exports = (srv) => {
|
|
3
4
|
// mainly normalizing the input
|
|
4
5
|
srv.before(['UPDATE', 'UPSERT'], 'Extensions', req => { // must be synchronous to be handled first
|
|
5
6
|
const { csn: extension, i18n: bundles, csvs: csvData } = req.data
|
|
6
7
|
|
|
8
|
+
// reject file names with path components (path traversal, see DbAdapter.put)
|
|
9
|
+
for (const files of [bundles, csvData]) {
|
|
10
|
+
if (Array.isArray(files)) files.forEach(_assertPlainFileName)
|
|
11
|
+
}
|
|
12
|
+
|
|
7
13
|
// Validation of extension
|
|
8
14
|
if (!extension) throw new cds.error({ message: 'Property "extension" is missing', code: 400 })
|
|
9
15
|
if (Array.isArray(extension)) {
|
|
@@ -41,6 +47,15 @@ module.exports = (srv) => {
|
|
|
41
47
|
req.data.csn = extCsn
|
|
42
48
|
})
|
|
43
49
|
|
|
50
|
+
// rejects a FILE name that is not a plain file name (prevents path traversal)
|
|
51
|
+
const _assertPlainFileName = function (file) {
|
|
52
|
+
const name = file?.name
|
|
53
|
+
if (typeof name !== 'string' || !name.length) return
|
|
54
|
+
if (path.isAbsolute(name) || name.includes('/') || name.includes('\\') || path.basename(name) !== name) {
|
|
55
|
+
throw new cds.error({ message: `Invalid file name: "${name}"`, code: 400 })
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
44
59
|
const _isCSN = str => str.substring(0, 1) === '{'
|
|
45
60
|
|
|
46
61
|
const _mergeCSN = function (extension, merged) {
|
|
@@ -143,8 +143,8 @@ module.exports = class AnnotationsChecker {
|
|
|
143
143
|
// get element permissions from allowlist
|
|
144
144
|
const kind = this._getExtendedKind(fullCsn, extCsn, entityOrService)
|
|
145
145
|
const permissions = allowList.getPermission(kind, entityOrService)
|
|
146
|
-
//
|
|
147
|
-
if (permissions && permissions.annotations && permissions.annotations.includes(annotationName))
|
|
146
|
+
// skip only this annotation; keep checking the remaining ones on the same element
|
|
147
|
+
if (permissions && permissions.annotations && permissions.annotations.includes(annotationName)) continue
|
|
148
148
|
|
|
149
149
|
const fn = checkedExtensionAnnotations.get(annotationName) ?? _createGenericAnnotationWarning
|
|
150
150
|
const warning = fn(annotationName, annotation);
|
|
@@ -2,6 +2,8 @@ const EXTENSION_ALLOWLIST = 'extension-allowlist'
|
|
|
2
2
|
|
|
3
3
|
const PROTECTED_NAMESPACES = ['cds.xt']
|
|
4
4
|
|
|
5
|
+
module.exports.PROTECTED_NAMESPACES = PROTECTED_NAMESPACES
|
|
6
|
+
|
|
5
7
|
const BUILT_IN_NAMESPACES = ['cds.core', 'cds.outbox'] //> cds.outbox for legacy apps
|
|
6
8
|
|
|
7
9
|
module.exports.isBuiltIn = (name) => {
|
|
@@ -4,6 +4,7 @@ const { deduplicateMessages } = require('@sap/cds-compiler')
|
|
|
4
4
|
const NamespaceChecker = require('./namespace')
|
|
5
5
|
const AnnotationsChecker = require('./annotations')
|
|
6
6
|
const AllowlistChecker = require('./allowlist')
|
|
7
|
+
const ProtectedNamespaceChecker = require('./protected-namespace')
|
|
7
8
|
|
|
8
9
|
const customLinters = []
|
|
9
10
|
|
|
@@ -39,6 +40,7 @@ module.exports.lint = (extCsn, fullCsn, env = cds.env, cloneExt = false) => {
|
|
|
39
40
|
const reflectedFullCsn = cds.reflect(fullCsn)
|
|
40
41
|
const compileBaseDir = cds.root
|
|
41
42
|
const messages = [
|
|
43
|
+
...new ProtectedNamespaceChecker().check(reflectedCsn, reflectedFullCsn, compileBaseDir, linter_options),
|
|
42
44
|
...new NamespaceChecker().check(reflectedCsn, reflectedFullCsn, compileBaseDir, linter_options),
|
|
43
45
|
...new AnnotationsChecker().check(reflectedCsn, reflectedFullCsn, compileBaseDir, linter_options, extCsn),
|
|
44
46
|
...new AllowlistChecker().check(reflectedCsn, reflectedFullCsn, compileBaseDir, linter_options)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const LinterMessage = require('./message')
|
|
2
|
+
const { PROTECTED_NAMESPACES } = require('./config')
|
|
3
|
+
|
|
4
|
+
function _protectedNamespaceOf(name) {
|
|
5
|
+
if (!name) return null
|
|
6
|
+
return PROTECTED_NAMESPACES.find(ns => name === ns || name.startsWith(`${ns}.`)) ?? null
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function locationString(element) {
|
|
10
|
+
const loc = element?.$location
|
|
11
|
+
if (!loc) return ''
|
|
12
|
+
const line = loc.line ? `${loc.line}:` : ''
|
|
13
|
+
return loc.col ? `${loc.file}:${line}${loc.col}:` : `${loc.file}:${line}`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Rejects defining, extending or annotating artifacts in a protected namespace (e.g. 'cds.xt').
|
|
17
|
+
// Runs unconditionally, independent of linter configuration.
|
|
18
|
+
module.exports = class ProtectedNamespaceChecker {
|
|
19
|
+
|
|
20
|
+
// eslint-disable-next-line no-unused-vars
|
|
21
|
+
check(reflectedCsn, fullCsn, compileDir, mtxConfig) {
|
|
22
|
+
const messages = []
|
|
23
|
+
|
|
24
|
+
for (const name of Object.keys(reflectedCsn.definitions ?? {})) {
|
|
25
|
+
if (_protectedNamespaceOf(name)) {
|
|
26
|
+
messages.push(this._createWarning(name, reflectedCsn.definitions[name]))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const extension of reflectedCsn.extensions ?? []) {
|
|
31
|
+
const target = extension.extend ?? extension.annotate
|
|
32
|
+
if (_protectedNamespaceOf(target)) {
|
|
33
|
+
messages.push(this._createWarning(target, extension))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return messages
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
_createWarning(name, element) {
|
|
41
|
+
const namespace = _protectedNamespaceOf(name)
|
|
42
|
+
const message = `Extending, annotating or defining '${name}' in the protected namespace '${namespace}' is not supported in extensions`
|
|
43
|
+
return new LinterMessage(locationString(element) + message, element)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -2,7 +2,7 @@ const express = require('express')
|
|
|
2
2
|
const cds = require('@sap/cds/lib')
|
|
3
3
|
const { SELECT, DELETE } = cds.ql
|
|
4
4
|
const { fs, path, tar, rimraf, read, readdir, mkdirp, write } = cds.utils
|
|
5
|
-
const { token: authToken } = require('../lib/utils')
|
|
5
|
+
const { token: authToken, authUrl } = require('../lib/utils')
|
|
6
6
|
const main = require('./config')
|
|
7
7
|
const linter = require('./extensibility/linter')
|
|
8
8
|
|
|
@@ -58,7 +58,12 @@ class DbAdapter {
|
|
|
58
58
|
try {
|
|
59
59
|
const root = await mkdirp(path.join(temp, 'data'))
|
|
60
60
|
for (const csv in ext.csvs) {
|
|
61
|
-
|
|
61
|
+
// defense-in-depth: 'csv' is user-supplied and must not escape 'root'
|
|
62
|
+
const target = path.join(root, csv)
|
|
63
|
+
if (path.relative(root, target).match(/^\.\.($|[/\\])/) || path.isAbsolute(path.relative(root, target))) {
|
|
64
|
+
throw Error(`Invalid file name: "${csv}"`)
|
|
65
|
+
}
|
|
66
|
+
await write(target, ext.csvs[csv])
|
|
62
67
|
}
|
|
63
68
|
ext.archive = await tar.cz(temp)
|
|
64
69
|
} finally {
|
|
@@ -74,7 +79,7 @@ class DbAdapter {
|
|
|
74
79
|
const csn = JSON.stringify(ext.csn)
|
|
75
80
|
const i18n = ext.i18n ? JSON.stringify(ext.i18n) : null
|
|
76
81
|
const tag = ext.ID
|
|
77
|
-
await cds.tx({ tenant
|
|
82
|
+
await cds.tx({ tenant }, async tx => {
|
|
78
83
|
// remove current inactive extension with tag
|
|
79
84
|
if (tag) await tx.run(DELETE.from('cds.xt.Extensions').where({ tag, activated: { '!=': this.activated(ACTIVE) } }))
|
|
80
85
|
// will break with missing appid
|
|
@@ -399,17 +404,21 @@ module.exports = class ExtensibilityService extends cds.ApplicationService {
|
|
|
399
404
|
})
|
|
400
405
|
|
|
401
406
|
cds.on('served', () => {
|
|
402
|
-
cds.app?.post('/-/cds/login/
|
|
407
|
+
cds.app?.post('/-/cds/login/grant', express.urlencoded({ extended: false }), async (req, res) => {
|
|
403
408
|
try {
|
|
404
|
-
if (req.method === 'HEAD') return res.status(204).send()
|
|
405
|
-
|
|
406
409
|
const cred = cds.env.requires.auth.credentials || {}
|
|
407
410
|
if (!cred.clientid) throw cds.error('missing authentication service binding', { status: 500 })
|
|
408
411
|
|
|
409
|
-
const query = req.
|
|
412
|
+
const query = req.body || {}
|
|
413
|
+
|
|
414
|
+
// Endpoint accepts only passcode and refresh_token grant requests.
|
|
415
|
+
const refresh_token = typeof query.refresh_token === 'string' ? query.refresh_token : undefined
|
|
416
|
+
const passcode = typeof query.passcode === 'string' ? query.passcode : undefined
|
|
417
|
+
if (!refresh_token && !passcode)
|
|
418
|
+
throw cds.error('missing passcode or refresh_token', { status: 400 })
|
|
410
419
|
|
|
411
|
-
const form =
|
|
412
|
-
|
|
420
|
+
const form = refresh_token ? { grant_type: 'refresh_token', refresh_token } :
|
|
421
|
+
{ grant_type: 'password', passcode }
|
|
413
422
|
form.scope = `${cred.xsappname}.cds.ExtensionDeveloper`
|
|
414
423
|
const raw = await authToken(cred, { form, subdomain: query.subdomain })
|
|
415
424
|
const data = JSON.parse(raw)
|
|
@@ -424,7 +433,11 @@ module.exports = class ExtensibilityService extends cds.ApplicationService {
|
|
|
424
433
|
}
|
|
425
434
|
})
|
|
426
435
|
|
|
427
|
-
cds.app?.get('/-/cds/login/
|
|
436
|
+
cds.app?.get('/-/cds/login/grant-metadata', authMeta)
|
|
437
|
+
|
|
438
|
+
const redirectTo = to => (req, res) => res.redirect(308, to + req.url.slice(req.path.length))
|
|
439
|
+
cds.app?.post('/-/cds/login/token', redirectTo('/-/cds/login/grant'))
|
|
440
|
+
cds.app?.get('/-/cds/login/authorization-metadata', redirectTo('/-/cds/login/grant-metadata'))
|
|
428
441
|
})
|
|
429
442
|
|
|
430
443
|
const _tenant = function (req) {
|
|
@@ -447,7 +460,7 @@ module.exports = class ExtensibilityService extends cds.ApplicationService {
|
|
|
447
460
|
let extEntry
|
|
448
461
|
try {
|
|
449
462
|
// TODO: handle '*'?
|
|
450
|
-
await cds.tx(async () => {
|
|
463
|
+
await cds.tx({ tenant },async () => {
|
|
451
464
|
// use native table names to avoid issues with missing appid
|
|
452
465
|
extEntry = await SELECT(['ID','csn', 'tag','activated']).one.from('cds.xt.Extensions').where({ tag, activated: { '!=': 'database' } }).forUpdate() // select only entries with activated != 'database'
|
|
453
466
|
if (!extEntry) {
|
|
@@ -493,15 +506,16 @@ module.exports = class ExtensibilityService extends cds.ApplicationService {
|
|
|
493
506
|
}
|
|
494
507
|
|
|
495
508
|
function _passcodeUrl(c, sub) {
|
|
496
|
-
|
|
497
|
-
if (sub) u.hostname = u.hostname.replace(/^[^.]+/, sub)
|
|
498
|
-
u.pathname = '/passcode'
|
|
499
|
-
return u.toString()
|
|
509
|
+
return authUrl(c.url, sub, '/passcode').toString()
|
|
500
510
|
}
|
|
501
511
|
|
|
502
512
|
function authMeta(req, res) {
|
|
503
513
|
const cred = cds.env.requires?.auth?.credentials || {}
|
|
504
|
-
|
|
514
|
+
try {
|
|
515
|
+
res.send({ passcode_url: _passcodeUrl(cred, req.query?.subdomain) })
|
|
516
|
+
} catch (err) {
|
|
517
|
+
res.status(err.status || err.statusCode || 500).json({ error: err.message })
|
|
518
|
+
}
|
|
505
519
|
}
|
|
506
520
|
|
|
507
521
|
const _getCompilerError = messages => {
|
|
@@ -6,9 +6,13 @@ const LOG = cds.log('mtx'), DEBUG = cds.debug('mtx')
|
|
|
6
6
|
const Jobs = 'cds.xt.Jobs', Tasks = 'cds.xt.Tasks'
|
|
7
7
|
|
|
8
8
|
const { t0_ } = require('../lib/utils')
|
|
9
|
+
const getDeploymentPool = require('./worker/job-worker-pool')
|
|
9
10
|
|
|
10
11
|
const RUNNING = 'RUNNING', FINISHED = 'FINISHED', FAILED = 'FAILED', QUEUED = 'QUEUED', TIMEOUT = 'TIMEOUT'
|
|
11
12
|
|
|
13
|
+
// Pseudo-db-id for skipped tenants (e.g. already upgraded); their tasks are recorded FINISHED, not run.
|
|
14
|
+
const SKIPPED_DB = 'skipped'
|
|
15
|
+
|
|
12
16
|
// A queue, implemented as a circular buffer for O(1) insert + delete
|
|
13
17
|
class Queue {
|
|
14
18
|
constructor(capacity) {
|
|
@@ -71,13 +75,13 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
71
75
|
|
|
72
76
|
_config() {
|
|
73
77
|
const {
|
|
74
|
-
queueSize = 100, clusterSize = 3, workerSize = 4, poolSize = 1
|
|
78
|
+
queueSize = 100, clusterSize = 3, workerSize = 4, poolSize = 1, nativeWorkers = false
|
|
75
79
|
} = {
|
|
76
80
|
...(cds.env.requires.multitenancy?.jobs ?? {}),
|
|
77
81
|
...(cds.env.requires['cds.xt.SaasProvisioningService']?.jobs ?? {}),
|
|
78
82
|
...(cds.env.requires['cds.xt.SmsProvisioningService']?.jobs ?? {})
|
|
79
83
|
}
|
|
80
|
-
return { queueSize, clusterSize, workerSize, poolSize }
|
|
84
|
+
return { queueSize, clusterSize, workerSize, poolSize, nativeWorkers }
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
async enqueue(service, op, clusters, args, onJobDone) {
|
|
@@ -99,32 +103,52 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
99
103
|
const job_ID = uuid()
|
|
100
104
|
const job = { ID: job_ID, service, op, args, status: QUEUED }
|
|
101
105
|
const clustered = Object.entries(clusters).map(([database, cluster]) => {
|
|
102
|
-
|
|
103
|
-
|
|
106
|
+
// Skipped-cluster tasks are recorded FINISHED right away; others are QUEUED for processing.
|
|
107
|
+
const status = database === SKIPPED_DB ? FINISHED : QUEUED
|
|
108
|
+
if (database !== '0') return Array.from(cluster).map(tenant => ({ job_ID, ID: uuid(), tenant, service, op, args, database, status }))
|
|
109
|
+
else return Array.from(cluster).map(tenant => ({ job_ID, ID: uuid(), tenant, service, op, args, status }))
|
|
104
110
|
})
|
|
105
111
|
const tasks = clustered.flat()
|
|
112
|
+
// Clusters still needing processing (excluding the skipped pseudo-cluster and empty ones).
|
|
113
|
+
const openClusters = clustered.filter(cluster => cluster.length && cluster[0].database !== SKIPPED_DB)
|
|
114
|
+
const openTasks = openClusters.flat()
|
|
106
115
|
await t0_(async () => {
|
|
107
116
|
await INSERT.into(Jobs, job)
|
|
108
|
-
if (
|
|
117
|
+
if (openTasks.length) {
|
|
109
118
|
await INSERT.into(Tasks, tasks)
|
|
110
119
|
job.tasks = tasks
|
|
111
120
|
await this.emit('jobUpdate', { job })
|
|
112
121
|
} else {
|
|
122
|
+
// Nothing to process (empty or only skipped) -> finish directly.
|
|
123
|
+
if (tasks.length) await INSERT.into(Tasks, tasks)
|
|
113
124
|
await UPDATE(Jobs, { ID: job_ID }).with({ status: FINISHED })
|
|
114
|
-
await this.emit('jobUpdate', { job: { ...job, status: FINISHED } })
|
|
125
|
+
await this.emit('jobUpdate', { job: { ...job, tasks, status: FINISHED } })
|
|
115
126
|
}
|
|
116
127
|
})
|
|
117
128
|
|
|
118
|
-
if (
|
|
119
|
-
if (
|
|
129
|
+
if (openTasks.length) {
|
|
130
|
+
if (_canUseWorkers(this._conf)) {
|
|
131
|
+
const pool = getDeploymentPool(this._conf.workerSize)
|
|
132
|
+
const fn = async task => {
|
|
133
|
+
const result = await pool.exec(service, op, task.tenant, args)
|
|
134
|
+
// Worker ran in an isolated thread; invalidate this process's stale
|
|
135
|
+
// pool for the tenant (worker's disconnect didn't affect us).
|
|
136
|
+
if (_invalidatesTenantPool(op)) cds.db?.disconnect(task.tenant)
|
|
137
|
+
return result
|
|
138
|
+
}
|
|
139
|
+
this.jobQueue.enqueue({ job_ID, clusters: openClusters, fn, onJobDone })
|
|
140
|
+
} else if (cds.services[service]) {
|
|
120
141
|
const fn = task => cds.services[service].tx({ tenant: task.tenant }, tx => tx[op](task.tenant, ...Object.values(args)))
|
|
121
|
-
this.jobQueue.enqueue({ job_ID, clusters:
|
|
142
|
+
this.jobQueue.enqueue({ job_ID, clusters: openClusters, fn, onJobDone })
|
|
122
143
|
} else {
|
|
123
|
-
this.jobQueue.enqueue({ job_ID, clusters:
|
|
144
|
+
this.jobQueue.enqueue({ job_ID, clusters: openClusters, fn: () => {
|
|
124
145
|
LOG.warn('service', service, 'is not available, skipping job')
|
|
125
146
|
}, onJobDone })
|
|
126
147
|
}
|
|
127
148
|
this.pickJob()
|
|
149
|
+
} else if (tasks.length) {
|
|
150
|
+
// Only skipped tasks (already FINISHED) -> notify callback since the job won't run.
|
|
151
|
+
await onJobDone?.()
|
|
128
152
|
}
|
|
129
153
|
|
|
130
154
|
const url = process.env.VCAP_APPLICATION ? 'https://' + JSON.parse(process.env.VCAP_APPLICATION).uris?.[0] : cds.server.url
|
|
@@ -260,6 +284,8 @@ module.exports = class JobsService extends cds.ApplicationService {
|
|
|
260
284
|
}
|
|
261
285
|
}
|
|
262
286
|
|
|
287
|
+
module.exports.SKIPPED_DB = SKIPPED_DB
|
|
288
|
+
|
|
263
289
|
function _errorMessage(e) {
|
|
264
290
|
let message = e.message ?? 'Unknown error'
|
|
265
291
|
if (e.error) message += ' ' + e.error
|
|
@@ -267,6 +293,19 @@ function _errorMessage(e) {
|
|
|
267
293
|
return message.length > 5000 ? message.substring(0, 4997) + '...' : message // TODO use different datatype for errors -> next release
|
|
268
294
|
}
|
|
269
295
|
|
|
296
|
+
function _canUseWorkers(conf) {
|
|
297
|
+
// Workers must be explicitly enabled via configuration since they run in
|
|
298
|
+
// isolated threads with their own CDS bootstrap (no shared handlers/state)
|
|
299
|
+
if (!conf?.nativeWorkers) return false
|
|
300
|
+
return true
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Operations that change or drop a tenant's database, requiring the serving
|
|
304
|
+
// process to disconnect its stale pooled connection for the tenant.
|
|
305
|
+
function _invalidatesTenantPool(op) {
|
|
306
|
+
return op === 'unsubscribe' || op === 'subscribe'
|
|
307
|
+
}
|
|
308
|
+
|
|
270
309
|
/*********************************************
|
|
271
310
|
* Clean-up
|
|
272
311
|
*********************************************/
|
|
@@ -3,7 +3,7 @@ const fs = require('fs').promises
|
|
|
3
3
|
const path = require('path')
|
|
4
4
|
const cds = require('@sap/cds/lib'), { tar, rimraf, exists, read, merge } = cds.utils
|
|
5
5
|
const { readData, readDataCsv } = require('../lib/utils')
|
|
6
|
-
const { worker4 } = require('./worker/pool')
|
|
6
|
+
const { worker4 } = require('./worker/model-worker-pool')
|
|
7
7
|
const conf = cds.requires['cds.xt.ModelProviderService'] || cds.requires.kinds['cds.xt.ModelProviderService']
|
|
8
8
|
const TEMP_DIR = require('fs').realpathSync(require('os').tmpdir())
|
|
9
9
|
const main = require('./config')
|
|
@@ -74,6 +74,15 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
|
|
|
74
74
|
if (invalid) return req.reject(400, `Unsupported input toggle param ${production ? '' : invalid}`)
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
+
// `service` and `flavor` are interpolated into a file system path in `_getPrebuiltBundle`.
|
|
78
|
+
// Validate them here to prevent path traversal (e.g. reading arbitrary *.xml files).
|
|
79
|
+
this.before('getEdmx', req => {
|
|
80
|
+
const { service, flavor } = req.data
|
|
81
|
+
const _valid = v => v == null || /^(?!.*\.\.)[\w-.]+$/.test(v)
|
|
82
|
+
if (!_valid(service)) return req.reject(400, `Unsupported input service param ${service}`)
|
|
83
|
+
if (!_valid(flavor)) return req.reject(400, `Unsupported input flavor param ${flavor}`)
|
|
84
|
+
})
|
|
85
|
+
|
|
77
86
|
this.on('getCsn', req => _getCsn(req))
|
|
78
87
|
|
|
79
88
|
this.on('getExtCsn', req => {
|
|
@@ -202,14 +211,20 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
|
|
|
202
211
|
|
|
203
212
|
const skipMinify = (!!extensions || reqSkipMinify) && _delayMinify()
|
|
204
213
|
let csn = await lru4(baseCache, JSON.stringify({ models, flavor, javaornode, skipMinify }), () =>
|
|
205
|
-
worker4(path.join(__dirname, 'worker/
|
|
214
|
+
worker4(path.join(__dirname, 'worker/model-worker.js'), { models, flavor, javaornode, skipMinify })
|
|
206
215
|
)
|
|
207
216
|
|
|
208
217
|
if (extensions) {
|
|
209
218
|
const key = crypto.createHash('sha256').update(JSON.stringify({ extensions, models, javaornode })).digest('hex')
|
|
210
219
|
csn = lru4(extensionCache, key, () => {
|
|
211
|
-
|
|
212
|
-
|
|
220
|
+
try {
|
|
221
|
+
const result = cds.extend(csn).with(extensions)
|
|
222
|
+
return _delayMinify ? cds.minify(result) : result
|
|
223
|
+
} catch (e) {
|
|
224
|
+
if (!activated || e.code !== 'ERR_CDS_COMPILATION_FAILURE') throw e
|
|
225
|
+
const message = _getCompilerError(e.messages)
|
|
226
|
+
throw cds.error(`Extensions of tenant '${tenant}' are incompatible with the base model: ${message}`, { code: 'ERR_CDS_COMPILATION_FAILURE', status: 422, tenant, messages: e.messages })
|
|
227
|
+
}
|
|
213
228
|
})
|
|
214
229
|
}
|
|
215
230
|
|
|
@@ -410,3 +425,12 @@ module.exports = class ModelProviderService extends cds.ApplicationService {
|
|
|
410
425
|
}
|
|
411
426
|
|
|
412
427
|
module.exports.prototype._add_stub_methods = true
|
|
428
|
+
|
|
429
|
+
const _getCompilerError = messages => {
|
|
430
|
+
const defaultMsg = 'Error while compiling extension'
|
|
431
|
+
if (!messages) return defaultMsg
|
|
432
|
+
for (const msg of messages) {
|
|
433
|
+
if (msg.severity === 'Error') return msg.message
|
|
434
|
+
}
|
|
435
|
+
return defaultMsg
|
|
436
|
+
}
|
|
@@ -43,13 +43,17 @@ cds.on('serving:cds.xt.DeploymentService', ds => {
|
|
|
43
43
|
if (existingExt) cds.error(`Extensions exist, but extensibility is disabled. Upgrade aborted to avoid data loss`, { status: 500 })
|
|
44
44
|
})
|
|
45
45
|
|
|
46
|
+
const _getVersion = () => JSON.stringify({ version: require(cds.root + '/package.json').version })
|
|
47
|
+
|
|
46
48
|
ds.after('subscribe', async (_, req) => {
|
|
47
49
|
const { tenant, metadata, schema } = req.data
|
|
48
50
|
if (tenant === t0) return
|
|
49
51
|
|
|
52
|
+
const version = _getVersion()
|
|
53
|
+
|
|
50
54
|
try {
|
|
51
55
|
// can't use UPSERT here so @cds.on.insert still works for createdAt
|
|
52
|
-
await t0_(INSERT.into(Tenants, { ID: tenant, metadata: JSON.stringify(metadata), ...(schema ? { schema } : {}) }))
|
|
56
|
+
await t0_(INSERT.into(Tenants, { ID: tenant, metadata: JSON.stringify(metadata), ...(schema ? { schema } : {}), version }))
|
|
53
57
|
} catch (e) {
|
|
54
58
|
if (e.message === 'ENTITY_ALREADY_EXISTS' || e.code === 301 || e.message.match(/unique constraint/i)) {
|
|
55
59
|
await t0_(async () => {
|
|
@@ -68,17 +72,15 @@ cds.on('serving:cds.xt.DeploymentService', ds => {
|
|
|
68
72
|
LOG.info('subscribed tenant', tenant)
|
|
69
73
|
})
|
|
70
74
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
ds.after(['upgrade', 'extend'], async (_, req) => {
|
|
76
|
+
const { tenant } = req.data
|
|
77
|
+
if (tenant === t0) return
|
|
74
78
|
|
|
75
|
-
|
|
76
|
-
// version: require(cds.root + '/package.json').version
|
|
77
|
-
// })
|
|
79
|
+
const version = _getVersion()
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
await t0_(UPSERT.into(Tenants, { ID: tenant, version }))
|
|
82
|
+
LOG.info('upgraded tenant', tenant)
|
|
83
|
+
})
|
|
82
84
|
|
|
83
85
|
ds.after('unsubscribe', async (_, req) => {
|
|
84
86
|
const { tenant } = req.data
|
|
@@ -87,9 +89,14 @@ cds.on('serving:cds.xt.DeploymentService', ds => {
|
|
|
87
89
|
})
|
|
88
90
|
|
|
89
91
|
ds.prepend(() => {
|
|
90
|
-
ds.on('getTenants', async
|
|
92
|
+
ds.on('getTenants', async req => {
|
|
93
|
+
const { options } = req.data ?? {}
|
|
94
|
+
const skipAfter = options?.skipAfter
|
|
95
|
+
const query = skipAfter
|
|
96
|
+
? SELECT.from(Tenants, tenant => { tenant.ID }).where('modifiedAt <', skipAfter)
|
|
97
|
+
: SELECT.from(Tenants, tenant => { tenant.ID })
|
|
91
98
|
return (await cds.tx({ tenant: t0 }, tx =>
|
|
92
|
-
tx.run(
|
|
99
|
+
tx.run(query)
|
|
93
100
|
)).map(({ ID }) => ID)
|
|
94
101
|
})
|
|
95
102
|
})
|
|
@@ -48,7 +48,7 @@ class AbstractContainerManagerClient {
|
|
|
48
48
|
if (this.cachedToken && this.cachedToken.expiry >= Date.now() + 30_000) {
|
|
49
49
|
return `Bearer ${this.cachedToken.access_token}`
|
|
50
50
|
}
|
|
51
|
-
const raw = await token(this)
|
|
51
|
+
const raw = await token(this, { form: { grant_type: 'client_credentials' } })
|
|
52
52
|
const { access_token, expires_in } = JSON.parse(raw)
|
|
53
53
|
this.cachedToken = { access_token, expiry: Date.now() + expires_in * 1000 }
|
|
54
54
|
return `Bearer ${access_token}`
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const cds = require('@sap/cds')
|
|
2
|
-
const {
|
|
2
|
+
const { db } = cds.env.requires
|
|
3
|
+
const { sm_url, baseurl, url, identity } = db.credentials || {}
|
|
3
4
|
const LOG = cds.log('mtx')
|
|
4
5
|
|
|
5
6
|
if (sm_url) {
|
|
@@ -9,7 +10,9 @@ if (sm_url) {
|
|
|
9
10
|
LOG.warn('SaaS Provisioning Service is configured with ignoreNonExistingContainers. This can cause problems when using HANA TMS v2 as container manager.')
|
|
10
11
|
}
|
|
11
12
|
module.exports = require('./tms')
|
|
13
|
+
} else if (db.serverless || db.kind === 'hana-serverless' || (url && identity)) {
|
|
14
|
+
module.exports = require('./serverless')
|
|
12
15
|
} else {
|
|
13
|
-
LOG.warn('Neither Service Manager
|
|
16
|
+
LOG.warn('Neither Service Manager, HANA TMS, nor serverless credentials found. No HANA HDI Containers will be accessible.')
|
|
14
17
|
module.exports = { defaultInstance: ()=> {} }
|
|
15
|
-
}
|
|
18
|
+
}
|