@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
@@ -0,0 +1,271 @@
1
+ const cds = require('@sap/cds')
2
+ const AbstractContainerManagerClient = require('./ctnr-mgr-base')
3
+ const { token, fetchResiliently } = require('../../../lib/utils')
4
+ const { uuid } = cds.utils
5
+ const LOG = cds.log('mtx'), DEBUG = cds.debug('mtx|serverless')
6
+
7
+ const API = '/serverless/v1/containers'
8
+
9
+ class ServerlessClient extends AbstractContainerManagerClient {
10
+ constructor(credentials) {
11
+ super({ clientid: credentials.identity?.clientid, url: credentials.identity?.url })
12
+ this.gateway = credentials.url
13
+ this.identity = credentials.identity
14
+ this.certificate = this.identity?.certificate
15
+ this.key = this.identity?.key
16
+ this.certurl = this.identity?.certurl
17
+ this.url = this.identity?.url
18
+ this.clientid = this.identity?.clientid
19
+ this.credentialCache = {}
20
+ this.tokenCache = new Map()
21
+ this.delete = this.remove
22
+ }
23
+
24
+ static defaultInstance() {
25
+ ServerlessClient._defaultInstance ??= ServerlessClient.newInstance(ServerlessClient._resolveCredentials())
26
+ return ServerlessClient._defaultInstance
27
+ }
28
+
29
+ static _resolveCredentials() {
30
+ const credentials = { ...cds.env.requires.db.credentials }
31
+ let vcap
32
+ const _vcap = () => (vcap ??= (() => { try { return JSON.parse(process.env.VCAP_SERVICES || '{}') } catch { return {} } })())
33
+ if (!credentials.url) {
34
+ const serverless = (_vcap()['hana-cloud'] || []).find(s => s.plan === 'serverless') || (_vcap()['hana-cloud'] || [])[0]
35
+ const gw = credentials.credentials?.url || serverless?.credentials?.url || serverless?.credentials?.credentials?.url
36
+ if (gw) credentials.url = gw
37
+ }
38
+ const iasBinding = (_vcap().identity || [])[0]?.credentials
39
+ if (iasBinding) credentials.identity = iasBinding
40
+ else if (!credentials.identity) credentials.identity = credentials.credentials?.identity
41
+ if (!credentials.identity?.certificate) {
42
+ const identityBinding = ServerlessClient._resolveIdentityBinding()
43
+ if (identityBinding?.certificate) credentials.identity = identityBinding
44
+ }
45
+ return credentials
46
+ }
47
+
48
+ static _resolveIdentityBinding() {
49
+ const isIdentity = conf => conf?.kind === 'ias' || conf?.vcap?.label === 'identity'
50
+ for (const conf of Object.values(cds.env.requires || {})) {
51
+ if (isIdentity(conf) && conf.credentials?.certificate) return conf.credentials
52
+ }
53
+ return undefined
54
+ }
55
+
56
+ static newInstance(credentials) {
57
+ if (!credentials?.url) cds.error('Serverless gateway URL is not configured in credentials')
58
+ if (!credentials.identity?.certificate) cds.error('No identity (IAS) credentials found for the serverless Tenant API')
59
+ return new ServerlessClient(credentials)
60
+ }
61
+
62
+ _tokenFor = async () => {
63
+ const cached = this.tokenCache.get('provider')
64
+ if (cached && cached.expiry >= Date.now() + 30_000) return `Bearer ${cached.access_token}`
65
+ const raw = await token(this.identity, { form: { grant_type: 'client_credentials' }, path: '/oauth2/token' })
66
+ const { access_token, expires_in } = JSON.parse(raw)
67
+ this.tokenCache.set('provider', { access_token, expiry: Date.now() + expires_in * 1000 })
68
+ return `Bearer ${access_token}`
69
+ }
70
+
71
+ _api = async (tenant, path, conf = {}) => {
72
+ conf.headers ??= {}
73
+ conf.headers.Authorization ??= await this._tokenFor(tenant)
74
+ conf.headers['Accept'] ??= 'application/json'
75
+ conf.headers['Content-Type'] ??= 'application/json'
76
+ conf.headers['X-CorrelationID'] ??= cds.context?.id
77
+ const { retries, maxRetryAfter } = cds.requires?.multitenancy?.serviceManager ?? cds.requires?.multitenancy?.containerManager ?? {}
78
+ return fetchResiliently(this.gateway + path, conf, { retriesLeft: retries ?? 10, maxRetryAfter: maxRetryAfter ?? 5000 })
79
+ }
80
+
81
+ _pollLocation = async (tenant, location, extract) => {
82
+ let attempts = 0
83
+ const maxAttempts = 60, interval = 3000
84
+ for (;;) {
85
+ const { data } = await this._api(tenant, location.startsWith('http') ? location.slice(this.gateway.length) : location, { method: 'GET' })
86
+ const state = extract(data)
87
+ if (state === true) return data
88
+ if (state === 'FAILED') cds.error(`Serverless operation failed for ${location}: ${JSON.stringify(data)}`)
89
+ if (++attempts > maxAttempts) cds.error(`Polling ${location} timed out after ${(interval * maxAttempts) / 1000} seconds`)
90
+ await new Promise(r => setTimeout(r, interval))
91
+ }
92
+ }
93
+
94
+ _matchingContainers = (list, tenant) => {
95
+ const base = this._baseName(tenant)
96
+ return (list || []).filter(c => (c.labels || []).includes(`tenant_id=${tenant}`) || c.name === base || (c.name || '').startsWith(`${base}_`))
97
+ }
98
+
99
+ _findContainer = async (tenant) => {
100
+ const { data } = await this._api(tenant, API, { method: 'GET' })
101
+ const usable = c => !/(FAILED|DELETED|NOT_EXIST)$/.test(c.status?.state || '')
102
+ return this._matchingContainers(data.data, tenant).find(usable)
103
+ }
104
+
105
+ _removeStaleContainers = async (tenant) => {
106
+ const { data } = await this._api(tenant, API, { method: 'GET' })
107
+ const stale = this._matchingContainers(data.data, tenant).filter(c => /FAILED$/.test(c.status?.state || ''))
108
+ for (const c of stale) {
109
+ LOG.info('removing stale serverless container for', { tenant }, 'container', c.name, 'in state', c.status?.state)
110
+ const del = await this._api(tenant, `${API}/${c.id}`, { method: 'DELETE' }).catch(() => ({}))
111
+ const location = del.headers?.['location']
112
+ if (location) await this._pollLocation(tenant, location, d => /(SUCCEEDED|DELETED|NOT_EXIST)$/.test(d.status?.state || '') ? true : false).catch(() => {})
113
+ }
114
+ }
115
+
116
+ _findCredentials = async (tenant, containerId) => {
117
+ const { data } = await this._api(tenant, `${API}/${containerId}/credentials`, { method: 'GET' })
118
+ const list = data.data || []
119
+ return list.find(x => (x.state || '').endsWith('SUCCEEDED')) || list[0]
120
+ }
121
+
122
+ _credentialsDetail = async (tenant, containerId, credentialId) => {
123
+ const { data } = await this._api(tenant, `${API}/${containerId}/credentials/${credentialId}`, { method: 'GET' })
124
+ return this._toHdiCredentials(data)
125
+ }
126
+
127
+ _toHdiCredentials = (c) => ({
128
+ host: c.host,
129
+ port: String(c.port),
130
+ driver: c.driver || 'com.sap.db.jdbc.Driver',
131
+ schema: c.schema,
132
+ hdi_user: c.hdiUser,
133
+ hdi_password: c.hdiPassword,
134
+ user: c.user,
135
+ password: c.password,
136
+ certificate: c.certificate,
137
+ encrypt: true,
138
+ sslTrustAll: false,
139
+ validate_certificate: true,
140
+ })
141
+
142
+ get = async (tenant, options = {}) => {
143
+ const { disableCache } = options
144
+ if (!tenant) throw new Error('Tenant name is required')
145
+ if (!disableCache && this.credentialCache[tenant]) return this.credentialCache[tenant]
146
+ const container = await this._findContainer(tenant)
147
+ if (!container) cds.error(`Tenant '${tenant}' does not exist`, { status: 404 })
148
+ const credential = await this._findCredentials(tenant, container.id)
149
+ if (!credential) cds.error(`Tenant '${tenant}' has no usable credentials`, { status: 404 })
150
+ const credentials = await this._credentialsDetail(tenant, container.id, credential.id)
151
+ LOG.info('resolved serverless container for', { tenant }, 'container', container.name, 'schema', credentials.schema)
152
+ return this.credentialCache[tenant] = { name: container.name, tenant_id: tenant, credentials, container, tags: ['hana'] }
153
+ }
154
+
155
+ _waitContainerReady = async (tenant, containerId) => {
156
+ await this._pollLocation(tenant, `${API}/${containerId}`, d =>
157
+ d.status?.ready === true || d.status?.state?.endsWith('SUCCEEDED') ? true : (d.status?.state?.endsWith('FAILED') ? 'FAILED' : false)
158
+ )
159
+ }
160
+
161
+ _awaitBrokerContainer = async (tenant, attempts = 20, interval = 3000) => {
162
+ for (let i = 0; i < attempts; i++) {
163
+ const container = await this._findContainer(tenant)
164
+ if (container) return container
165
+ await new Promise(r => setTimeout(r, interval))
166
+ }
167
+ return undefined
168
+ }
169
+
170
+ create = async (tenant, parameters) => {
171
+ LOG.info('creating serverless HDI container for', { tenant })
172
+ let container = await this._findContainer(tenant)
173
+ const t0 = cds.env.requires.multitenancy?.t0 ?? 't0'
174
+ if (!container && tenant !== t0 && cds.env.requires.multitenancy?.serverless?.autoSubscription) {
175
+ LOG.info('awaiting broker-provisioned serverless container for', { tenant })
176
+ container = await this._awaitBrokerContainer(tenant)
177
+ }
178
+ if (!container) {
179
+ await this._removeStaleContainers(tenant)
180
+ const create = await this._api(tenant, API, {
181
+ method: 'POST',
182
+ data: { name: this._newContainerName(tenant), type: 'hdi', labels: [`tenant_id=${tenant}`, ...(parameters?.customLabels ?? [])] },
183
+ })
184
+ const location = create.headers['location']
185
+ await this._pollLocation(tenant, location, d => d.status?.state?.endsWith('SUCCEEDED') ? true : (d.status?.state?.endsWith('FAILED') ? 'FAILED' : false))
186
+ container = await this._findContainer(tenant)
187
+ if (!container) cds.error(`Serverless container for tenant '${tenant}' not found after creation`)
188
+ }
189
+ await this._waitContainerReady(tenant, container.id)
190
+ let credential = await this._findCredentials(tenant, container.id)
191
+ if (!credential) {
192
+ const create = await this._api(tenant, `${API}/${container.id}/credentials`, { method: 'POST', data: {} })
193
+ const location = create.headers['location']
194
+ await this._pollLocation(tenant, location, d => d.state?.endsWith('SUCCEEDED') ? true : (d.state?.endsWith('FAILED') ? 'FAILED' : false))
195
+ credential = await this._findCredentials(tenant, container.id)
196
+ }
197
+ const credentials = await this._credentialsDetail(tenant, container.id, credential.id)
198
+ LOG.info('created serverless container for', { tenant }, 'container', container.name, 'schema', credentials.schema)
199
+ return this.credentialCache[tenant] = { name: container.name, tenant_id: tenant, credentials, container, tags: ['hana'] }
200
+ }
201
+
202
+ getAll = async (tenants = '*', options = {}) => {
203
+ const seed = tenants === '*' ? null : tenants
204
+ const listTenant = seed?.[0]
205
+ let containers = []
206
+ if (listTenant) {
207
+ const { data } = await this._api(listTenant, API, { method: 'GET' })
208
+ containers = (data.data || []).filter(c => (c.labels || []).some(l => l.startsWith('tenant_id=')))
209
+ }
210
+ const results = []
211
+ for (const c of containers) {
212
+ const tenant_id = (c.labels.find(l => l.startsWith('tenant_id=')) || '').split('=')[1]
213
+ if (!tenant_id) continue
214
+ const entry = { labels: { tenant_id: [tenant_id] }, container: c }
215
+ if (options.skipCredentials) { results.push(entry); continue }
216
+ try {
217
+ const { credentials } = await this.get(tenant_id, options)
218
+ results.push({ ...entry, credentials })
219
+ } catch (e) {
220
+ if (e.status === 404) DEBUG?.('skipping tenant', tenant_id, 'without usable credentials')
221
+ else throw e
222
+ }
223
+ }
224
+ return results
225
+ }
226
+
227
+ remove = async (tenant) => {
228
+ const container = await this._findContainer(tenant)
229
+ if (!container) { delete this.credentialCache[tenant]; return {} }
230
+ const { data } = await this._api(tenant, `${API}/${container.id}/credentials`, { method: 'GET' })
231
+ for (const cred of data.data || []) {
232
+ const del = await this._api(tenant, `${API}/${container.id}/credentials/${cred.id}`, { method: 'DELETE' })
233
+ const location = del.headers['location']
234
+ if (location) await this._pollLocation(tenant, location, d => d.state?.endsWith('SUCCEEDED') || d.state?.endsWith('DELETED') ? true : false).catch(() => {})
235
+ }
236
+ const del = await this._api(tenant, `${API}/${container.id}`, { method: 'DELETE' })
237
+ const location = del.headers['location']
238
+ if (location) await this._pollLocation(tenant, location, d => d.status?.state?.endsWith('SUCCEEDED') || d.status?.state?.endsWith('DELETED') ? true : false).catch(() => {})
239
+ delete this.credentialCache[tenant]
240
+ return { container: container.id }
241
+ }
242
+
243
+ _createParams = (tenant, params = {}, metadata) => {
244
+ const hdiParams = this._hdiParams(tenant, params, metadata) ?? {}
245
+ const result = {}
246
+ const { custom_label } = hdiParams?.create ?? {}
247
+ if (custom_label) {
248
+ const [k] = custom_label.split('=')
249
+ if (k === 'tenant_id') cds.error('"tenant_id" is not allowed as a custom label key')
250
+ result.customLabels = [custom_label]
251
+ }
252
+ return Object.keys(result).length > 0 ? result : null
253
+ }
254
+
255
+ _encryptionParams = () => {
256
+ return {}
257
+ }
258
+
259
+ _baseName = (tenant) => {
260
+ let sanitized = String(tenant).replace(/[^A-Za-z0-9_]/g, '_').toUpperCase()
261
+ if (!/^[A-Za-z0-9]/.test(sanitized)) sanitized = `T${sanitized}`
262
+ return sanitized.slice(0, 24)
263
+ }
264
+
265
+ _newContainerName = (tenant) => {
266
+ const suffix = uuid().replace(/-/g, '').toUpperCase()
267
+ return `${this._baseName(tenant)}_${suffix}`.slice(0, 62)
268
+ }
269
+ }
270
+
271
+ module.exports = ServerlessClient
@@ -15,8 +15,9 @@ const resources = new Map()
15
15
 
16
16
  const { deepMerge } = require('../../lib/utils')
17
17
 
18
- if (db?.kind === 'hana') {
19
- if (!db.credentials?.sm_url && !db.credentials?.baseurl) cds.error('No Service Manager credentials found. Make sure the application is bound to a BTP Service Manager instance.')
18
+ if (db?.kind === 'hana' || db?.kind === 'hana-serverless') {
19
+ const serverless = db.serverless || db.kind === 'hana-serverless' || (db.credentials?.url && db.credentials?.identity)
20
+ if (!db.credentials?.sm_url && !db.credentials?.baseurl && !serverless) cds.error('No Service Manager credentials found. Make sure the application is bound to a BTP Service Manager instance.')
20
21
 
21
22
  const hana = require('./hana/hdi-ctnr-mgr').defaultInstance()
22
23
  exports.activated = 'HANA Database'
@@ -324,14 +325,10 @@ async function _deploy (req, _container, { skipExt = false, skipResources = fals
324
325
  if (cacheBindings) {
325
326
  // health-check credentials for DB connection, get uncached if stale
326
327
 
327
- let driver = 'hdb'
328
- const projectPackage = require(cds.root + '/package.json')
329
- const dependencies = {
330
- ...projectPackage.dependencies,
331
- ...(process.env.NODE_ENV !== 'production' && projectPackage.devDependencies),
332
- }
333
- if (dependencies.hdb) driver = 'hdb'
334
- if (dependencies['@sap/hana-client']) driver = '@sap/hana-client'
328
+ let driver
329
+ try { require.resolve('hdb'); driver = 'hdb' } catch { /* continue */ }
330
+ if (!driver) try { require.resolve('@sap/hana-client'); driver = '@sap/hana-client' } catch { /* continue */ }
331
+ if (!driver) cds.error('No HANA client driver found. Add hdb or @sap/hana-client to your sidecar dependencies.')
335
332
 
336
333
  const client = require(driver).createClient(container.credentials)
337
334
  const connect = promisify(client.connect.bind(client))
@@ -0,0 +1,212 @@
1
+ 'use strict'
2
+
3
+ const { Worker } = require('worker_threads')
4
+ const path = require('path')
5
+ const cds = require('@sap/cds')
6
+
7
+ const LOG = cds.log('mtx')
8
+ const WORKER_PATH = path.join(__dirname, 'job-worker.js')
9
+
10
+ const IDLE = 'idle'
11
+ const BUSY = 'busy'
12
+ const BOOTING = 'booting'
13
+
14
+ class DeploymentPool {
15
+
16
+ constructor(size) {
17
+ this.size = size
18
+ this.workers = [] // { worker, state, pending: Map<id, {resolve,reject}> }
19
+ this.waitQueue = [] // queued acquire requests: { resolve, reject }
20
+ this._idCounter = 0
21
+ this._shuttingDown = false
22
+ }
23
+
24
+ /**
25
+ * Spawn a new worker, bootstrap it, and add it to the pool.
26
+ * Returns a promise that resolves when the worker is ready.
27
+ */
28
+ _spawn() {
29
+ return new Promise((resolve, reject) => {
30
+ const worker = new Worker(WORKER_PATH, { env: process.env, workerData: { cdsEnv: cds.env, cdsRoot: cds.root } })
31
+ const entry = { worker, state: BOOTING, pending: new Map() }
32
+ this.workers.push(entry)
33
+
34
+ const onReady = (msg) => {
35
+ if (msg.ready) {
36
+ worker.off('message', onReady)
37
+ worker.off('error', onError)
38
+ entry.state = IDLE
39
+ worker.on('message', (msg) => this._onMessage(entry, msg))
40
+ worker.on('error', (err) => this._onError(entry, err))
41
+ worker.on('exit', (code) => this._onExit(entry, code))
42
+ resolve(entry)
43
+ } else if (msg.error) {
44
+ worker.off('message', onReady)
45
+ worker.off('error', onError)
46
+ this.workers = this.workers.filter(e => e !== entry)
47
+ reject(new Error(msg.error))
48
+ }
49
+ }
50
+
51
+ const onError = (err) => {
52
+ worker.off('message', onReady)
53
+ this.workers = this.workers.filter(e => e !== entry)
54
+ reject(err)
55
+ }
56
+
57
+ worker.on('message', onReady)
58
+ worker.on('error', onError)
59
+ })
60
+ }
61
+
62
+ /**
63
+ * Handle messages from a worker (command responses).
64
+ */
65
+ _onMessage(entry, { id, result, error }) {
66
+ const pending = entry.pending.get(id)
67
+ if (!pending) return
68
+ entry.pending.delete(id)
69
+ if (error) pending.reject(new Error(error))
70
+ else pending.resolve(result)
71
+ }
72
+
73
+ /**
74
+ * Handle worker errors.
75
+ */
76
+ _onError(entry, err) {
77
+ LOG.error('Deployment worker error:', err.message)
78
+ // Reject all pending tasks on this worker
79
+ for (const [, { reject }] of entry.pending) {
80
+ reject(new Error(`Worker error: ${err.message}`))
81
+ }
82
+ entry.pending.clear()
83
+ }
84
+
85
+ /**
86
+ * Handle worker exit — reject in-flight tasks and replace the worker.
87
+ */
88
+ _onExit(entry, code) {
89
+ this.workers = this.workers.filter(e => e !== entry)
90
+
91
+ // Reject any in-flight tasks
92
+ for (const [, { reject }] of entry.pending) {
93
+ reject(new Error(`Worker exited unexpectedly with code ${code}`))
94
+ }
95
+ entry.pending.clear()
96
+
97
+ // Do not replace workers during shutdown
98
+ if (this._shuttingDown) return
99
+
100
+ // Immediately replace the crashed worker
101
+ LOG.warn('Deployment worker exited with code', code, '- spawning replacement')
102
+ this._spawn().then(newEntry => {
103
+ // If there are queued requests waiting, serve them
104
+ if (this.waitQueue.length > 0 && newEntry.state === IDLE) {
105
+ newEntry.state = BUSY
106
+ const { resolve } = this.waitQueue.shift()
107
+ resolve(newEntry)
108
+ }
109
+ }).catch(err => {
110
+ LOG.error('Failed to spawn replacement worker:', err.message)
111
+ // If there are queued requests waiting, reject the first one
112
+ if (this.waitQueue.length > 0) {
113
+ const { reject } = this.waitQueue.shift()
114
+ reject(err)
115
+ }
116
+ })
117
+ }
118
+
119
+ /**
120
+ * Acquire an idle worker. If none available and pool not full, spawns a new one.
121
+ * If all workers are busy and pool is full, queues the request.
122
+ */
123
+ async acquire() {
124
+ // Try to find an idle worker
125
+ const idle = this.workers.find(e => e.state === IDLE)
126
+ if (idle) {
127
+ idle.state = BUSY
128
+ return idle
129
+ }
130
+
131
+ // Pool not full — spawn a new worker
132
+ if (this.workers.length < this.size) {
133
+ const entry = await this._spawn()
134
+ entry.state = BUSY
135
+ return entry
136
+ }
137
+
138
+ // All busy — wait in queue
139
+ return new Promise((resolve, reject) => {
140
+ this.waitQueue.push({ resolve, reject })
141
+ })
142
+ }
143
+
144
+ /**
145
+ * Release a worker back to idle state. Serves the next queued request if any.
146
+ */
147
+ release(entry) {
148
+ if (this.waitQueue.length > 0) {
149
+ entry.state = BUSY
150
+ const { resolve } = this.waitQueue.shift()
151
+ resolve(entry)
152
+ } else {
153
+ entry.state = IDLE
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Execute a service action on a worker.
159
+ * Acquires a worker, sends the command, waits for the result, releases the worker.
160
+ */
161
+ async exec(service, op, tenant, args) {
162
+ const entry = await this.acquire()
163
+ const id = ++this._idCounter
164
+ try {
165
+ const result = await new Promise((resolve, reject) => {
166
+ entry.pending.set(id, { resolve, reject })
167
+ entry.worker.postMessage({ id, service, op, tenant, args, cdsEnv: cds.env })
168
+ })
169
+ return result
170
+ } finally {
171
+ this.release(entry)
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Shut down all workers. Sends a shutdown message to each worker and waits for them to exit.
177
+ */
178
+ async shutdown() {
179
+ this._shuttingDown = true
180
+
181
+ // Reject all queued acquire requests
182
+ for (const { reject } of this.waitQueue) {
183
+ reject(new Error('Worker pool is shutting down'))
184
+ }
185
+ this.waitQueue = []
186
+
187
+ // Send shutdown message to all workers and wait for them to exit
188
+ await Promise.all(this.workers.map(entry => {
189
+ for (const [, { reject }] of entry.pending) {
190
+ reject(new Error('Worker pool is shutting down'))
191
+ }
192
+ entry.pending.clear()
193
+ entry.worker.postMessage({ shutdown: true })
194
+ return new Promise(resolve => entry.worker.once('exit', resolve))
195
+ }))
196
+ this.workers = []
197
+ }
198
+ }
199
+
200
+ let _pool
201
+
202
+ /**
203
+ * Returns the singleton DeploymentPool instance.
204
+ * @param {number} size - Pool size (number of workers)
205
+ */
206
+ module.exports = function getDeploymentPool(size) {
207
+ if (!_pool) {
208
+ _pool = new DeploymentPool(size)
209
+ cds.on('shutdown', async () => _pool.shutdown())
210
+ }
211
+ return _pool
212
+ }
@@ -0,0 +1,61 @@
1
+ 'use strict'
2
+
3
+ const { parentPort, workerData } = require('worker_threads')
4
+ const cds = require('@sap/cds')
5
+ const { _import, isfile, path } = cds.utils
6
+
7
+ if (workerData?.cdsRoot) cds.root = workerData.cdsRoot
8
+ if (workerData?.cdsEnv) cds.env.add(workerData.cdsEnv)
9
+
10
+ async function bootstrap() {
11
+ const services = [
12
+ '@sap/cds-mtxs/srv/deployment-service',
13
+ '@sap/cds-mtxs/srv/model-provider',
14
+ '@sap/cds-mtxs/srv/cf/saas-provisioning-service',
15
+ '@sap/cds-mtxs/srv/extensibility-service',
16
+ ]
17
+ await _local_cli_js()
18
+ cds.emit('bootstrap')
19
+ const model = await cds.load([...services, '@sap/cds-mtxs/db/extensions'])
20
+ cds.model = cds.compile.for.nodejs(model)
21
+ const unserved = !cds.services['cds.xt.DeploymentService']
22
+ if (unserved) await cds.serve(services)
23
+ await cds.plugins
24
+ await cds.emit('served', cds.services)
25
+ parentPort.postMessage({ ready: true })
26
+ }
27
+
28
+ async function _local_cli_js() {
29
+ const _local = file => isfile(file) || isfile(path.join(cds.env.folders.srv, file))
30
+ const cli_js = process.env.CDS_TYPESCRIPT && (_local('cli.ts') || _local('server.ts')) || _local('cli.js') || _local('server.js')
31
+ if (cli_js) await _import(cli_js)
32
+ }
33
+
34
+ parentPort.on('message', async (msg) => {
35
+ if (msg.shutdown) {
36
+ await cds.shutdown()
37
+ process.exit(0)
38
+ }
39
+ const { id, service, op, tenant, args, cdsEnv } = msg
40
+ if (cdsEnv) cds.env.add(cdsEnv)
41
+ const srv = cds.services[service]
42
+ if (!srv) {
43
+ parentPort.postMessage({ id, error: `Service ${service} not available` })
44
+ return
45
+ }
46
+ try {
47
+ const result = await srv[op](tenant, ...Object.values(args))
48
+ parentPort.postMessage({ id, result })
49
+ } catch (e) {
50
+ const error = e.message ?? 'Unknown error'
51
+ parentPort.postMessage({ id, error })
52
+ } finally {
53
+ // cds.db.disconnect(cds.env.requires.multitenancy.t0 ?? 't0')
54
+ // cds.db.disconnect(tenant)
55
+ }
56
+ })
57
+
58
+ bootstrap().catch(e => {
59
+ parentPort.postMessage({ error: `Bootstrap failed: ${e.message}` })
60
+ process.exit(1)
61
+ })
@@ -5,6 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
6
  The format is based on [Keep a Changelog](http://keepachangelog.com/).
7
7
 
8
+ ## 6.2.2 - 2026-08-11
9
+
10
+ ### Updated
11
+ - Updated `filter-node-package` dependency to 6.2.2
12
+ - Updated `mocha` dependency to 11.8.0
13
+ - Updated `diff` dependency to 9
14
+
8
15
  ## 6.2.1 - 2026-05-13
9
16
 
10
17
  ### Updated
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/xsenv",
3
- "version": "6.2.1",
3
+ "version": "6.2.2",
4
4
  "description": "Utility for easy setup and access of SAP HANA XS Advanced environment variables",
5
5
  "repository": {},
6
6
  "license": "SEE LICENSE IN LICENSE",
@@ -23,13 +23,13 @@
23
23
  "prepareRelease": "clean-packages -i"
24
24
  },
25
25
  "devDependencies": {
26
- "@eslint/js": "9.39.4",
26
+ "@eslint/js": "9.39.5",
27
27
  "@eslint/eslintrc": "3.3.5",
28
- "@babel/eslint-parser": "7.28.6",
28
+ "@babel/eslint-parser": "7.29.7",
29
29
  "c8": "11.0.0",
30
- "filter-node-package": "6.2.0",
30
+ "filter-node-package": "6.2.2",
31
31
  "lodash": "4.18.1",
32
- "mocha": "11.7.5",
32
+ "mocha": "11.8.0",
33
33
  "mock-fs": "5.5.0",
34
34
  "node-build": "^3.0.0",
35
35
  "node-style": "2.0.0",
@@ -43,7 +43,10 @@
43
43
  },
44
44
  "overrides": {
45
45
  "mocha": {
46
- "glob": "^13.0.0"
47
- }
46
+ "glob": "^13.0.0",
47
+ "serialize-javascript": "^7.0.0"
48
+ },
49
+ "diff": "^9.0.0",
50
+ "lodash": "4.18.1"
48
51
  }
49
52
  }
@@ -36,6 +36,8 @@ The parser is lenient and does not error. You should validate `type` and `parame
36
36
  #### Options
37
37
 
38
38
  - `parameters` (default: `true`): Set to `false` to skip parameters.
39
+ - `comma` (default: `false`): Set to `true` to stop on a comma. This can be used to parse the media range in an `Accept` header.
40
+ - `start` (default: `0`): Set index to start parsing from.
39
41
 
40
42
  ### contentType.format(obj)
41
43
 
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export interface ContentType {
10
10
  type: string;
11
+ index: number;
11
12
  parameters: Record<string, string>;
12
13
  }
13
14
  /**
@@ -18,7 +19,26 @@ export declare function format(obj: Partial<ContentType>): string;
18
19
  * Options for parsing a `Content-Type` header.
19
20
  */
20
21
  export interface ParseOptions {
22
+ /**
23
+ * Exit early on the first semicolon, returning only the type.
24
+ * This is useful for parsing the MIME from `Content-Type` headers.
25
+ *
26
+ * @default false
27
+ */
21
28
  parameters?: boolean;
29
+ /**
30
+ * Exits early on a comma, returning the first value and parameters.
31
+ * This is useful for parsing `Accept` headers.
32
+ *
33
+ * @default false
34
+ */
35
+ comma?: boolean;
36
+ /**
37
+ * The index to start parsing from.
38
+ *
39
+ * @default 0
40
+ */
41
+ start?: number;
22
42
  }
23
43
  /**
24
44
  * Parse a `Content-Type` header.