@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.
Files changed (341) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/bin/add.js +7 -23
  3. package/bin/bind.js +14 -0
  4. package/bin/build.js +21 -34
  5. package/bin/cds.js +1 -1
  6. package/bin/compile/index.js +16 -41
  7. package/bin/completion/completionFs.js +11 -8
  8. package/bin/completion/index.js +603 -80
  9. package/bin/completion/scripts/cds.fish +620 -0
  10. package/bin/completion/scripts/cds.ps1 +403 -0
  11. package/bin/completion/scripts/cds.sh +327 -0
  12. package/bin/completion/scripts/cds.zsh +296 -0
  13. package/bin/completion/templates/cds-tmpl.fish +65 -0
  14. package/bin/completion/templates/cds-tmpl.ps1 +217 -0
  15. package/bin/completion/templates/cds-tmpl.sh +93 -0
  16. package/bin/completion/templates/cds-tmpl.zsh +74 -0
  17. package/bin/deploy/index.js +11 -1
  18. package/bin/deploy/options.js +25 -0
  19. package/{lib → bin}/deploy/to-hana/hana.js +8 -8
  20. package/{lib → bin}/deploy/to-hana/hdiDeployUtil.js +1 -1
  21. package/bin/deploy/{to-hana.js → to-hana/index.js} +1 -1
  22. package/{lib → bin}/deploy/to-hana/mtaUtil.js +1 -1
  23. package/bin/deploy/to-sql.js +0 -2
  24. package/bin/env.js +4 -1
  25. package/bin/export.js +44 -6
  26. package/bin/help/export.md +3 -0
  27. package/bin/help.js +1 -5
  28. package/bin/import.js +9 -0
  29. package/bin/init.js +6 -24
  30. package/bin/inspect.js +8 -0
  31. package/bin/lint.js +5 -3
  32. package/bin/login.js +26 -20
  33. package/bin/minify.js +6 -1
  34. package/bin/pull.js +19 -6
  35. package/bin/push.js +19 -6
  36. package/bin/repl.js +11 -2
  37. package/bin/run.js +12 -1
  38. package/bin/serve.js +13 -2
  39. package/bin/up.js +17 -11
  40. package/{lib → bin}/upgrade/constants.js +1 -1
  41. package/bin/{upgrade.js → upgrade/index.js} +2 -2
  42. package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
  43. package/{lib → bin}/upgrade/preflight/index.js +1 -1
  44. package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
  45. package/{lib → bin}/upgrade/steps/install.js +1 -1
  46. package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
  47. package/{lib → bin}/upgrade/steps/removals.js +1 -1
  48. package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
  49. package/{lib → bin}/upgrade/steps/verify.js +1 -1
  50. package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
  51. package/{lib → bin}/upgrade/util/pom.js +2 -2
  52. package/{lib → bin}/upgrade/util/prompt.js +1 -1
  53. package/bin/util/containerize.js +10 -4
  54. package/bin/version.js +10 -1
  55. package/{lib → bin}/watch/hot-reload.js +1 -1
  56. package/bin/{watch.js → watch/index.js} +24 -9
  57. package/{lib → bin}/watch/livereload-connect.js +1 -1
  58. package/{lib → bin}/watch/vite-watch.js +1 -1
  59. package/{lib → bin}/watch/watched.js +2 -2
  60. package/lib/build/constants.js +1 -1
  61. package/lib/build/plugins/fiori/index.js +31 -2
  62. package/lib/build/plugins/internal.js +4 -2
  63. package/lib/build/plugins/mtx-sidecar/index.js +7 -8
  64. package/lib/build/plugins/nodejs/index.js +64 -7
  65. package/lib/build/util.js +2 -4
  66. package/lib/compile/to_asyncapi.js +1 -1
  67. package/lib/env/schema.js +16 -0
  68. package/lib/env/schemas/cds-rc.js +1 -76
  69. package/lib/import/importapi.js +2 -3
  70. package/lib/import/message.js +0 -2
  71. package/lib/init/constants.js +2 -1
  72. package/lib/init/index.js +2 -2
  73. package/lib/init/merge.js +123 -280
  74. package/lib/init/plugin.js +3 -1
  75. package/lib/init/projectReader.js +22 -6
  76. package/lib/init/registries/xs-app.js +3 -5
  77. package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
  78. package/lib/init/template/ai/index.js +14 -2
  79. package/lib/init/template/ams/index.js +2 -2
  80. package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
  81. package/lib/init/template/app-frontend/index.js +4 -4
  82. package/lib/init/template/application-logging/index.js +2 -2
  83. package/lib/init/template/approuter/files/package.json +1 -1
  84. package/lib/init/template/approuter/index.js +8 -3
  85. package/lib/init/template/attachments/files/package.json.hbs +1 -1
  86. package/lib/init/template/attachments/index.js +2 -2
  87. package/lib/init/template/audit-logging/index.js +2 -2
  88. package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
  89. package/lib/init/template/cloud-logging/index.js +2 -2
  90. package/lib/init/template/completion/completionSetup.js +36 -39
  91. package/lib/init/template/connectivity/index.js +2 -2
  92. package/lib/init/template/data/as-csv.js +15 -5
  93. package/lib/init/template/data/as-json.js +117 -42
  94. package/lib/init/template/data/index.js +16 -2
  95. package/lib/init/template/destination/index.js +2 -2
  96. package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
  97. package/lib/init/template/dynatrace/index.js +2 -2
  98. package/lib/init/template/enterprise-messaging/index.js +2 -2
  99. package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
  100. package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
  101. package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
  102. package/lib/init/template/extensibility/index.js +3 -3
  103. package/lib/init/template/github-actions/index.js +2 -2
  104. package/lib/init/template/hana/index.js +3 -2
  105. package/lib/init/template/hana-serverless/files/db/package.json +14 -0
  106. package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
  107. package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
  108. package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
  109. package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
  110. package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
  111. package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
  112. package/lib/init/template/hana-serverless/index.js +184 -0
  113. package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
  114. package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
  115. package/lib/init/template/html5-repo/index.js +18 -14
  116. package/lib/init/template/http/index.js +123 -26
  117. package/lib/init/template/ias/index.js +2 -2
  118. package/lib/init/template/kafka/index.js +2 -2
  119. package/lib/init/template/kyma/index.js +7 -5
  120. package/lib/init/template/malware-scanner/index.js +2 -2
  121. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  122. package/lib/init/template/multitenancy/index.js +18 -3
  123. package/lib/init/template/notifications/index.js +2 -2
  124. package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
  125. package/lib/init/template/portal/index.js +13 -8
  126. package/lib/init/template/postgres/index.js +2 -2
  127. package/lib/init/template/redis/index.js +2 -2
  128. package/lib/init/template/sample/files/db/currencies.cds +2 -0
  129. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
  130. package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
  131. package/lib/init/template/workzone-standard/index.js +5 -5
  132. package/lib/init/template/xsuaa/index.js +20 -2
  133. package/lib/lint/eslintHelp.json +1 -1
  134. package/lib/mtx/auth_manager.js +103 -37
  135. package/lib/mtx/params.js +3 -2
  136. package/lib/mtx/settings_manager.js +45 -28
  137. package/lib/mtx/tenant_action.js +0 -1
  138. package/lib/mtx/util/credentials.js +62 -0
  139. package/node_modules/@cap-js/db-service/CHANGELOG.md +17 -0
  140. package/node_modules/@cap-js/db-service/lib/common/generic-pool.js +4 -7
  141. package/node_modules/@cap-js/db-service/lib/cqn2pql.js +1 -1
  142. package/node_modules/@cap-js/db-service/lib/cqn2sql.js +15 -11
  143. package/node_modules/@cap-js/db-service/lib/cqn4sql.js +119 -19
  144. package/node_modules/@cap-js/db-service/lib/infer/index.js +27 -16
  145. package/node_modules/@cap-js/db-service/lib/recursion-guard.js +40 -0
  146. package/node_modules/@cap-js/db-service/lib/search.js +1 -1
  147. package/node_modules/@cap-js/db-service/package.json +1 -1
  148. package/node_modules/@cap-js/sqlite/CHANGELOG.md +19 -0
  149. package/node_modules/@cap-js/sqlite/lib/SQLiteService.js +110 -14
  150. package/node_modules/@cap-js/sqlite/package.json +3 -3
  151. package/node_modules/@sap/cds/CHANGELOG.md +57 -0
  152. package/node_modules/@sap/cds/app/index.js +5 -4
  153. package/node_modules/@sap/cds/eslint.config.mjs +1 -0
  154. package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
  155. package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
  156. package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
  157. package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
  158. package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
  159. package/node_modules/@sap/cds/lib/plugins.js +9 -5
  160. package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
  161. package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
  162. package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
  163. package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
  164. package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
  165. package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
  166. package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
  167. package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
  168. package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
  169. package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
  170. package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
  171. package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
  172. package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
  173. package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
  174. package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
  175. package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
  176. package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
  177. package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
  178. package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
  179. package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
  180. package/node_modules/@sap/cds/libx/http/location.js +3 -3
  181. package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
  182. package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
  183. package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
  184. package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
  185. package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
  186. package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
  187. package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
  188. package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
  189. package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
  190. package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
  191. package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
  192. package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
  193. package/node_modules/@sap/cds/package.json +1 -1
  194. package/node_modules/@sap/cds-compiler/CHANGELOG.md +75 -8
  195. package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
  196. package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
  197. package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
  198. package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
  199. package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
  200. package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
  201. package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
  202. package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
  203. package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
  204. package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
  205. package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
  206. package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
  207. package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
  208. package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
  209. package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
  210. package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +48 -18
  211. package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
  212. package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
  213. package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
  214. package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
  215. package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
  216. package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
  217. package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
  218. package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
  219. package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
  220. package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
  221. package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
  222. package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +4 -0
  223. package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
  224. package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
  225. package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
  226. package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
  227. package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
  228. package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
  229. package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
  230. package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
  231. package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +15 -0
  232. package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +10 -2
  233. package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
  234. package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
  235. package/node_modules/@sap/cds-compiler/lib/transform/db/flattening.js +4 -3
  236. package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
  237. package/node_modules/@sap/cds-compiler/lib/transform/effective/flattening.js +17 -1
  238. package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +20 -0
  239. package/node_modules/@sap/cds-compiler/lib/transform/fioriTreeViews.js +12 -1
  240. package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +7 -2
  241. package/node_modules/@sap/cds-compiler/lib/transform/odata/adaptAnnotationRefs.js +11 -5
  242. package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +48 -10
  243. package/node_modules/@sap/cds-compiler/package.json +1 -1
  244. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +49 -0
  245. package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +26 -5
  246. package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +37 -16
  247. package/node_modules/@sap/cds-mtxs/lib/utils.js +23 -7
  248. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  249. package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +63 -8
  250. package/node_modules/@sap/cds-mtxs/srv/cf/saas-provisioning-service.js +1 -1
  251. package/node_modules/@sap/cds-mtxs/srv/cf/sms-provisioning-service.js +23 -3
  252. package/node_modules/@sap/cds-mtxs/srv/extensibility/compat/update.js +15 -0
  253. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +2 -2
  254. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/config.js +2 -0
  255. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +2 -0
  256. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/protected-namespace.js +45 -0
  257. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +30 -16
  258. package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +49 -10
  259. package/node_modules/@sap/cds-mtxs/srv/model-provider.js +28 -4
  260. package/node_modules/@sap/cds-mtxs/srv/plugins/common.js +19 -12
  261. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +1 -1
  262. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr.js +6 -3
  263. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/serverless.js +271 -0
  264. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +7 -10
  265. package/node_modules/@sap/cds-mtxs/srv/worker/job-worker-pool.js +212 -0
  266. package/node_modules/@sap/cds-mtxs/srv/worker/job-worker.js +61 -0
  267. package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
  268. package/node_modules/@sap/xsenv/package.json +10 -7
  269. package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  270. package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  271. package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  272. package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  273. package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  274. package/node_modules/hdb/cfg/VERSION +1 -1
  275. package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
  276. package/node_modules/hdb/lib/protocol/Connection.js +1 -0
  277. package/node_modules/hdb/package.json +3 -2
  278. package/node_modules/negotiator/lib/accept.js +54 -0
  279. package/node_modules/negotiator/lib/charset.js +10 -34
  280. package/node_modules/negotiator/lib/encoding.js +9 -30
  281. package/node_modules/negotiator/lib/language.js +15 -36
  282. package/node_modules/negotiator/lib/mediaType.js +16 -134
  283. package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
  284. package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
  285. package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
  286. package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
  287. package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
  288. package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
  289. package/node_modules/negotiator/package.json +16 -10
  290. package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
  291. package/node_modules/qs/CHANGELOG.md +15 -0
  292. package/node_modules/qs/README.md +19 -1
  293. package/node_modules/qs/dist/qs.js +21 -21
  294. package/node_modules/qs/eslint.config.mjs +1 -1
  295. package/node_modules/qs/lib/parse.js +3 -4
  296. package/node_modules/qs/lib/stringify.js +23 -8
  297. package/node_modules/qs/lib/utils.js +10 -3
  298. package/node_modules/qs/package.json +4 -4
  299. package/node_modules/qs/test/parse.js +192 -3
  300. package/node_modules/qs/test/stringify.js +317 -0
  301. package/node_modules/qs/test/utils.js +12 -0
  302. package/node_modules/type-is/node_modules/content-type/README.md +2 -0
  303. package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  304. package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  305. package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  306. package/node_modules/type-is/node_modules/content-type/package.json +1 -1
  307. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  308. package/node_modules/ws/package.json +1 -1
  309. package/package.json +2 -2
  310. package/bin/completion/scripts/cds-bash.sh +0 -20
  311. package/bin/completion/scripts/cds-fish.fish +0 -13
  312. package/bin/completion/scripts/cds-ps.ps1 +0 -19
  313. package/bin/completion/scripts/cds-zsh.sh +0 -13
  314. package/lib/deploy/index.js +0 -25
  315. package/lib/import/asyncapi/importAsyncAPI.js +0 -33
  316. package/lib/import/asyncapi/index.js +0 -18
  317. package/lib/import/asyncapi/parserContext.js +0 -454
  318. package/lib/import/asyncapi/utils.js +0 -49
  319. package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
  320. package/node_modules/negotiator/HISTORY.md +0 -114
  321. /package/{lib → bin}/upgrade/context.js +0 -0
  322. /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
  323. /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
  324. /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
  325. /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
  326. /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
  327. /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
  328. /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
  329. /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
  330. /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
  331. /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
  332. /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
  333. /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
  334. /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
  335. /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
  336. /package/{lib → bin}/watch/livereload-server.js +0 -0
  337. /package/{lib → bin}/watch/node-watch.js +0 -0
  338. /package/{lib → bin}/watch/open.js +0 -0
  339. /package/{lib → bin}/watch/watcher.js +0 -0
  340. /package/node_modules/@sap/cds-mtxs/srv/worker/{pool.js → model-worker-pool.js} +0 -0
  341. /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
- // check if annotation is allowed
147
- if (permissions && permissions.annotations && permissions.annotations.includes(annotationName)) return null
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
- await write(path.join(root, csv), ext.csvs[csv])
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, user: new cds.User.Privileged() }, async tx => {
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/token', express.urlencoded({ extended: false }), async (req, res) => {
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.method === 'POST' ? (req.body || {}) : (req.query || {})
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 = query.refresh_token ? { grant_type: 'refresh_token', refresh_token: query.refresh_token } :
412
- query.passcode ? { grant_type: 'password', passcode: query.passcode } : {}
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/authorization-metadata', authMeta)
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
- const u = new URL(c.url)
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
- res.send({ passcode_url: _passcodeUrl(cred, req.query?.subdomain) })
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
- if (database !== '0') return Array.from(cluster).map(tenant => ({ job_ID, ID: uuid(), tenant, service, op, args, database, status: QUEUED }))
103
- else return Array.from(cluster).map(tenant => ({ job_ID, ID: uuid(), tenant, service, op, args, status: QUEUED }))
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 (tasks.length) {
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 (tasks.length) {
119
- if (cds.services[service]) {
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: clustered, fn, onJobDone })
142
+ this.jobQueue.enqueue({ job_ID, clusters: openClusters, fn, onJobDone })
122
143
  } else {
123
- this.jobQueue.enqueue({ job_ID, clusters: clustered, fn: () => {
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/load.js'), { models, flavor, javaornode, skipMinify })
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
- const result = cds.extend(csn).with(extensions)
212
- return _delayMinify ? cds.minify(result) : result
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
- // ds.after(['upgrade', 'extend'], async (_, req) => {
72
- // const { tenant } = req.data
73
- // if (tenant === t0) return
75
+ ds.after(['upgrade', 'extend'], async (_, req) => {
76
+ const { tenant } = req.data
77
+ if (tenant === t0) return
74
78
 
75
- // const version = JSON.stringify({
76
- // version: require(cds.root + '/package.json').version
77
- // })
79
+ const version = _getVersion()
78
80
 
79
- // await t0_(UPSERT.into(Tenants, { ID: tenant, version }))
80
- // LOG.info('upgraded tenant', tenant)
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(SELECT.from(Tenants, tenant => { tenant.ID }))
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 { sm_url, baseurl } = cds.env.requires.db.credentials
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 nor HANA TMS credentials found. No HANA HDI Containers will be accessible.')
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
+ }