@sap/cds-dk 10.0.7 → 10.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/bin/add.js +7 -23
  3. package/bin/bind.js +10 -0
  4. package/bin/build.js +20 -34
  5. package/bin/cds.js +1 -1
  6. package/bin/compile/index.js +15 -41
  7. package/bin/completion/completionFs.js +11 -8
  8. package/bin/completion/index.js +592 -80
  9. package/bin/completion/scripts/cds.fish +568 -0
  10. package/bin/completion/scripts/cds.ps1 +329 -0
  11. package/bin/completion/scripts/cds.sh +261 -0
  12. package/bin/completion/scripts/cds.zsh +230 -0
  13. package/bin/completion/templates/cds-tmpl.fish +65 -0
  14. package/bin/completion/templates/cds-tmpl.ps1 +208 -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 +7 -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/export.js +35 -5
  25. package/bin/help/export.md +3 -0
  26. package/bin/help.js +1 -5
  27. package/bin/import.js +6 -0
  28. package/bin/init.js +5 -24
  29. package/bin/inspect.js +6 -0
  30. package/bin/login.js +26 -20
  31. package/bin/pull.js +19 -6
  32. package/bin/push.js +19 -6
  33. package/bin/up.js +14 -11
  34. package/{lib → bin}/upgrade/constants.js +1 -1
  35. package/bin/{upgrade.js → upgrade/index.js} +2 -2
  36. package/{lib → bin}/upgrade/preflight/consistency.js +1 -1
  37. package/{lib → bin}/upgrade/preflight/index.js +1 -1
  38. package/{lib → bin}/upgrade/steps/analyze/index.js +1 -1
  39. package/{lib → bin}/upgrade/steps/install.js +1 -1
  40. package/{lib → bin}/upgrade/steps/openrewrite.js +1 -1
  41. package/{lib → bin}/upgrade/steps/removals.js +1 -1
  42. package/{lib → bin}/upgrade/steps/rewrite.js +1 -1
  43. package/{lib → bin}/upgrade/steps/verify.js +1 -1
  44. package/{lib/upgrade/index.js → bin/upgrade/upgrade.js} +2 -2
  45. package/{lib → bin}/upgrade/util/pom.js +2 -2
  46. package/{lib → bin}/upgrade/util/prompt.js +1 -1
  47. package/bin/util/containerize.js +8 -4
  48. package/bin/version.js +10 -1
  49. package/{lib → bin}/watch/hot-reload.js +1 -1
  50. package/bin/{watch.js → watch/index.js} +17 -9
  51. package/{lib → bin}/watch/livereload-connect.js +1 -1
  52. package/{lib → bin}/watch/vite-watch.js +1 -1
  53. package/{lib → bin}/watch/watched.js +2 -2
  54. package/lib/build/constants.js +1 -1
  55. package/lib/build/plugins/fiori/index.js +31 -2
  56. package/lib/build/plugins/internal.js +4 -2
  57. package/lib/build/plugins/mtx-sidecar/index.js +7 -8
  58. package/lib/build/plugins/nodejs/index.js +64 -7
  59. package/lib/compile/to_asyncapi.js +1 -1
  60. package/lib/env/schema.js +16 -0
  61. package/lib/env/schemas/cds-rc.js +1 -76
  62. package/lib/import/importapi.js +2 -3
  63. package/lib/import/message.js +0 -2
  64. package/lib/init/constants.js +2 -1
  65. package/lib/init/index.js +2 -2
  66. package/lib/init/merge.js +123 -280
  67. package/lib/init/plugin.js +3 -1
  68. package/lib/init/projectReader.js +22 -6
  69. package/lib/init/registries/xs-app.js +3 -5
  70. package/lib/init/template/ai/files/mta.yaml.hbs +1 -1
  71. package/lib/init/template/ai/index.js +14 -2
  72. package/lib/init/template/ams/index.js +2 -2
  73. package/lib/init/template/app-frontend/files/containerize.yaml.hbs +2 -2
  74. package/lib/init/template/app-frontend/index.js +4 -4
  75. package/lib/init/template/application-logging/index.js +2 -2
  76. package/lib/init/template/approuter/files/package.json +1 -1
  77. package/lib/init/template/approuter/index.js +8 -3
  78. package/lib/init/template/attachments/files/package.json.hbs +1 -1
  79. package/lib/init/template/attachments/index.js +2 -2
  80. package/lib/init/template/audit-logging/index.js +2 -2
  81. package/lib/init/template/cloud-logging/files/package.json.hbs +4 -4
  82. package/lib/init/template/cloud-logging/index.js +2 -2
  83. package/lib/init/template/completion/completionSetup.js +36 -39
  84. package/lib/init/template/connectivity/index.js +2 -2
  85. package/lib/init/template/data/as-csv.js +15 -5
  86. package/lib/init/template/data/as-json.js +114 -42
  87. package/lib/init/template/data/index.js +16 -2
  88. package/lib/init/template/destination/index.js +2 -2
  89. package/lib/init/template/dynatrace/files/package.json.hbs +3 -3
  90. package/lib/init/template/dynatrace/index.js +2 -2
  91. package/lib/init/template/enterprise-messaging/index.js +2 -2
  92. package/lib/init/template/enterprise-messaging-shared/index.js +2 -2
  93. package/lib/init/template/extensibility/files/mta.yaml.hbs +11 -0
  94. package/lib/init/template/extensibility/files/xs-security.json.hbs +1 -1
  95. package/lib/init/template/extensibility/index.js +3 -3
  96. package/lib/init/template/github-actions/index.js +2 -2
  97. package/lib/init/template/hana/index.js +3 -2
  98. package/lib/init/template/hana-serverless/files/db/package.json +14 -0
  99. package/lib/init/template/hana-serverless/files/identity.values.yaml.hbs +10 -0
  100. package/lib/init/template/hana-serverless/files/mta.yaml.hbs +64 -0
  101. package/lib/init/template/hana-serverless/files/package.json.hbs +35 -0
  102. package/lib/init/template/hana-serverless/files/src/.hdiconfig +139 -0
  103. package/lib/init/template/hana-serverless/files/undeploy.json +7 -0
  104. package/lib/init/template/hana-serverless/files/values.yaml.hbs +18 -0
  105. package/lib/init/template/hana-serverless/index.js +184 -0
  106. package/lib/init/template/html5-repo/files/containerize.yaml.hbs +2 -2
  107. package/lib/init/template/html5-repo/files/mta.yaml.hbs +5 -0
  108. package/lib/init/template/html5-repo/index.js +18 -14
  109. package/lib/init/template/http/index.js +123 -26
  110. package/lib/init/template/ias/index.js +2 -2
  111. package/lib/init/template/kafka/index.js +2 -2
  112. package/lib/init/template/kyma/index.js +7 -5
  113. package/lib/init/template/malware-scanner/index.js +2 -2
  114. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  115. package/lib/init/template/multitenancy/index.js +18 -3
  116. package/lib/init/template/notifications/index.js +2 -2
  117. package/lib/init/template/portal/files/mta.yaml.hbs +4 -0
  118. package/lib/init/template/portal/index.js +13 -8
  119. package/lib/init/template/postgres/index.js +2 -2
  120. package/lib/init/template/redis/index.js +2 -2
  121. package/lib/init/template/sample/files/db/currencies.cds +2 -0
  122. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +1 -1
  123. package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +2 -2
  124. package/lib/init/template/workzone-standard/index.js +5 -5
  125. package/lib/init/template/xsuaa/index.js +20 -2
  126. package/lib/lint/eslintHelp.json +1 -1
  127. package/lib/mtx/auth_manager.js +103 -37
  128. package/lib/mtx/params.js +3 -2
  129. package/lib/mtx/settings_manager.js +45 -28
  130. package/lib/mtx/tenant_action.js +0 -1
  131. package/lib/mtx/util/credentials.js +62 -0
  132. package/node_modules/@sap/cds/CHANGELOG.md +57 -0
  133. package/node_modules/@sap/cds/app/index.js +5 -4
  134. package/node_modules/@sap/cds/eslint.config.mjs +1 -0
  135. package/node_modules/@sap/cds/lib/compile/minify.js +14 -10
  136. package/node_modules/@sap/cds/lib/env/cds-env.js +1 -1
  137. package/node_modules/@sap/cds/lib/env/cds-requires.js +22 -11
  138. package/node_modules/@sap/cds/lib/env/defaults.js +4 -1
  139. package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +5 -2
  140. package/node_modules/@sap/cds/lib/plugins.js +9 -5
  141. package/node_modules/@sap/cds/lib/req/spawn.js +1 -1
  142. package/node_modules/@sap/cds/lib/srv/srv-dispatch.js +1 -1
  143. package/node_modules/@sap/cds/lib/srv/srv-models.js +1 -1
  144. package/node_modules/@sap/cds/lib/utils/cds-utils.js +2 -1
  145. package/node_modules/@sap/cds/libx/_runtime/common/generic/assert.js +2 -3
  146. package/node_modules/@sap/cds/libx/_runtime/common/generic/auth/restrict.js +8 -1
  147. package/node_modules/@sap/cds/libx/_runtime/common/generic/crud.js +18 -8
  148. package/node_modules/@sap/cds/libx/_runtime/fiori/lean-draft.js +25 -17
  149. package/node_modules/@sap/cds/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +9 -3
  150. package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +4 -19
  151. package/node_modules/@sap/cds/libx/_runtime/remote/utils/LruCache.js +42 -0
  152. package/node_modules/@sap/cds/libx/_runtime/remote/utils/client.js +14 -4
  153. package/node_modules/@sap/cds/libx/_runtime/remote/utils/cloudSdkProvider.js +2 -9
  154. package/node_modules/@sap/cds/libx/_runtime/remote/utils/destinationClient.js +150 -0
  155. package/node_modules/@sap/cds/libx/_runtime/remote/utils/error.js +13 -0
  156. package/node_modules/@sap/cds/libx/_runtime/remote/utils/fetchClient.js +26 -18
  157. package/node_modules/@sap/cds/libx/_runtime/remote/utils/query.js +34 -23
  158. package/node_modules/@sap/cds/libx/_runtime/remote/utils/token.js +82 -0
  159. package/node_modules/@sap/cds/libx/_runtime/ucl/Service.js +36 -189
  160. package/node_modules/@sap/cds/libx/common/utils/streaming.js +16 -16
  161. package/node_modules/@sap/cds/libx/http/location.js +3 -3
  162. package/node_modules/@sap/cds/libx/odata/middleware/batch.js +16 -10
  163. package/node_modules/@sap/cds/libx/odata/middleware/metadata.js +9 -6
  164. package/node_modules/@sap/cds/libx/odata/middleware/service-document.js +1 -1
  165. package/node_modules/@sap/cds/libx/odata/parse/afterburner.js +19 -3
  166. package/node_modules/@sap/cds/libx/odata/parse/cqn2odata.js +83 -86
  167. package/node_modules/@sap/cds/libx/queue/SchedulingService.js +17 -2
  168. package/node_modules/@sap/cds/libx/queue/processing.js +1 -3
  169. package/node_modules/@sap/cds/libx/rest/RestAdapter.js +3 -7
  170. package/node_modules/@sap/cds/libx/rest/middleware/delete.js +3 -3
  171. package/node_modules/@sap/cds/libx/rest/middleware/parse.js +13 -8
  172. package/node_modules/@sap/cds/libx/rest/middleware/read.js +3 -3
  173. package/node_modules/@sap/cds/libx/rest/middleware/upsert.js +2 -2
  174. package/node_modules/@sap/cds/package.json +1 -1
  175. package/node_modules/@sap/cds-compiler/CHANGELOG.md +60 -8
  176. package/node_modules/@sap/cds-compiler/bin/cdsc.js +2 -2
  177. package/node_modules/@sap/cds-compiler/doc/IncompatibleChanges_v7.md +46 -19
  178. package/node_modules/@sap/cds-compiler/lib/api/main.js +10 -7
  179. package/node_modules/@sap/cds-compiler/lib/api/options.js +8 -2
  180. package/node_modules/@sap/cds-compiler/lib/base/csnRefs.js +5 -2
  181. package/node_modules/@sap/cds-compiler/lib/base/message-registry.js +4 -0
  182. package/node_modules/@sap/cds-compiler/lib/base/optionProcessor.js +12 -0
  183. package/node_modules/@sap/cds-compiler/lib/checks/enricher.js +1 -0
  184. package/node_modules/@sap/cds-compiler/lib/compiler/assert-consistency.js +8 -7
  185. package/node_modules/@sap/cds-compiler/lib/compiler/checks.js +3 -3
  186. package/node_modules/@sap/cds-compiler/lib/compiler/define.js +301 -75
  187. package/node_modules/@sap/cds-compiler/lib/compiler/dictionaries.js +2 -0
  188. package/node_modules/@sap/cds-compiler/lib/compiler/extend.js +40 -26
  189. package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +45 -60
  190. package/node_modules/@sap/cds-compiler/lib/compiler/propagator.js +16 -7
  191. package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +41 -15
  192. package/node_modules/@sap/cds-compiler/lib/compiler/shared.js +7 -6
  193. package/node_modules/@sap/cds-compiler/lib/compiler/tweak-assocs.js +62 -50
  194. package/node_modules/@sap/cds-compiler/lib/compiler/utils.js +29 -14
  195. package/node_modules/@sap/cds-compiler/lib/edm/edmAnnoPreprocessor.js +6 -5
  196. package/node_modules/@sap/cds-compiler/lib/gen/CdlGrammar.checksum +1 -1
  197. package/node_modules/@sap/cds-compiler/lib/gen/CdlParser.js +1119 -1109
  198. package/node_modules/@sap/cds-compiler/lib/gen/Dictionary.json +19 -3
  199. package/node_modules/@sap/cds-compiler/lib/json/from-csn.js +10 -16
  200. package/node_modules/@sap/cds-compiler/lib/json/to-csn.js +58 -39
  201. package/node_modules/@sap/cds-compiler/lib/main.d.ts +8 -0
  202. package/node_modules/@sap/cds-compiler/lib/main.js +1 -0
  203. package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +2 -0
  204. package/node_modules/@sap/cds-compiler/lib/parsers/AstBuildingParser.js +2 -1
  205. package/node_modules/@sap/cds-compiler/lib/parsers/XprTree.js +8 -0
  206. package/node_modules/@sap/cds-compiler/lib/render/toCdl.js +22 -1
  207. package/node_modules/@sap/cds-compiler/lib/render/toSql.js +17 -2
  208. package/node_modules/@sap/cds-compiler/lib/render/utils/common.js +6 -1
  209. package/node_modules/@sap/cds-compiler/lib/render/utils/operators.js +27 -0
  210. package/node_modules/@sap/cds-compiler/lib/render/utils/standardDatabaseFunctions.js +125 -3
  211. package/node_modules/@sap/cds-compiler/lib/tool-lib/revealInternalProperties.js +2 -1
  212. package/node_modules/@sap/cds-compiler/lib/transform/db/applyTransformations.js +3 -0
  213. package/node_modules/@sap/cds-compiler/lib/transform/db/associations.js +8 -2
  214. package/node_modules/@sap/cds-compiler/lib/transform/db/backlinks.js +22 -6
  215. package/node_modules/@sap/cds-compiler/lib/transform/db/constraints.js +62 -1
  216. package/node_modules/@sap/cds-compiler/lib/transform/effective/annotations.js +40 -0
  217. package/node_modules/@sap/cds-compiler/lib/transform/effective/main.js +1 -0
  218. package/node_modules/@sap/cds-compiler/lib/transform/forRelationalDB.js +6 -1
  219. package/node_modules/@sap/cds-compiler/lib/transform/translateAssocsToJoins.js +19 -8
  220. package/node_modules/@sap/cds-compiler/package.json +1 -1
  221. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +15 -0
  222. package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +34 -16
  223. package/node_modules/@sap/cds-mtxs/lib/utils.js +19 -4
  224. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  225. package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +1 -1
  226. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +22 -13
  227. package/node_modules/@sap/cds-mtxs/srv/model-provider.js +17 -2
  228. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +1 -1
  229. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +4 -8
  230. package/node_modules/@sap/xsenv/CHANGELOG.md +7 -0
  231. package/node_modules/@sap/xsenv/package.json +10 -7
  232. package/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  233. package/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  234. package/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  235. package/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  236. package/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  237. package/node_modules/hdb/cfg/VERSION +1 -1
  238. package/node_modules/hdb/lib/protocol/ClientInfo.js +16 -3
  239. package/node_modules/hdb/lib/protocol/Connection.js +1 -0
  240. package/node_modules/hdb/package.json +3 -2
  241. package/node_modules/negotiator/lib/accept.js +54 -0
  242. package/node_modules/negotiator/lib/charset.js +10 -34
  243. package/node_modules/negotiator/lib/encoding.js +9 -30
  244. package/node_modules/negotiator/lib/language.js +15 -36
  245. package/node_modules/negotiator/lib/mediaType.js +16 -134
  246. package/node_modules/negotiator/node_modules/content-type/LICENSE +22 -0
  247. package/node_modules/negotiator/node_modules/content-type/README.md +71 -0
  248. package/node_modules/negotiator/node_modules/content-type/dist/index.d.ts +46 -0
  249. package/node_modules/negotiator/node_modules/content-type/dist/index.js +176 -0
  250. package/node_modules/negotiator/node_modules/content-type/dist/index.js.map +1 -0
  251. package/node_modules/negotiator/node_modules/content-type/package.json +52 -0
  252. package/node_modules/negotiator/package.json +16 -10
  253. package/node_modules/qs/.github/THREAT_MODEL.md +3 -3
  254. package/node_modules/qs/CHANGELOG.md +15 -0
  255. package/node_modules/qs/README.md +19 -1
  256. package/node_modules/qs/dist/qs.js +21 -21
  257. package/node_modules/qs/eslint.config.mjs +1 -1
  258. package/node_modules/qs/lib/parse.js +3 -4
  259. package/node_modules/qs/lib/stringify.js +23 -8
  260. package/node_modules/qs/lib/utils.js +10 -3
  261. package/node_modules/qs/package.json +4 -4
  262. package/node_modules/qs/test/parse.js +192 -3
  263. package/node_modules/qs/test/stringify.js +317 -0
  264. package/node_modules/qs/test/utils.js +12 -0
  265. package/node_modules/type-is/node_modules/content-type/README.md +2 -0
  266. package/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  267. package/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  268. package/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  269. package/node_modules/type-is/node_modules/content-type/package.json +1 -1
  270. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  271. package/node_modules/ws/package.json +1 -1
  272. package/package.json +3 -3
  273. package/bin/completion/scripts/cds-bash.sh +0 -20
  274. package/bin/completion/scripts/cds-fish.fish +0 -13
  275. package/bin/completion/scripts/cds-ps.ps1 +0 -19
  276. package/bin/completion/scripts/cds-zsh.sh +0 -13
  277. package/lib/deploy/index.js +0 -25
  278. package/lib/import/asyncapi/importAsyncAPI.js +0 -33
  279. package/lib/import/asyncapi/index.js +0 -18
  280. package/lib/import/asyncapi/parserContext.js +0 -454
  281. package/lib/import/asyncapi/utils.js +0 -49
  282. package/node_modules/@sap/cds/libx/_runtime/ucl/queries.js +0 -61
  283. package/node_modules/negotiator/HISTORY.md +0 -114
  284. /package/{lib → bin}/upgrade/context.js +0 -0
  285. /package/{lib → bin}/upgrade/migrations/cds10/migrations.json +0 -0
  286. /package/{lib → bin}/upgrade/preflight/cds-version.js +0 -0
  287. /package/{lib → bin}/upgrade/preflight/project-type.js +0 -0
  288. /package/{lib → bin}/upgrade/steps/analyze/classification.js +0 -0
  289. /package/{lib → bin}/upgrade/steps/analyze/detector.js +0 -0
  290. /package/{lib → bin}/upgrade/steps/analyze/evaluator.js +0 -0
  291. /package/{lib → bin}/upgrade/steps/analyze/reporter.js +0 -0
  292. /package/{lib → bin}/upgrade/steps/analyze/setup.js +0 -0
  293. /package/{lib → bin}/upgrade/steps/analyze/utils/detection.js +0 -0
  294. /package/{lib → bin}/upgrade/steps/analyze/utils/files.js +0 -0
  295. /package/{lib → bin}/upgrade/steps/analyze/utils/grep.js +0 -0
  296. /package/{lib → bin}/upgrade/steps/analyze/utils/yaml.js +0 -0
  297. /package/{lib → bin}/upgrade/util/workspaces.js +0 -0
  298. /package/{lib → bin}/watch/esm-resolve-registration.js +0 -0
  299. /package/{lib → bin}/watch/livereload-server.js +0 -0
  300. /package/{lib → bin}/watch/node-watch.js +0 -0
  301. /package/{lib → bin}/watch/open.js +0 -0
  302. /package/{lib → bin}/watch/watcher.js +0 -0
@@ -1,5 +1,5 @@
1
1
  const cds = require('../cds');
2
- const { SettingsManager } = require('./settings_manager');
2
+ const { SettingsManager, OAUTH_PATH, OAUTH_PATH_LEGACY_TOKEN } = require('./settings_manager');
3
3
  const { ParamCollection } = require('./params');
4
4
  const { getMessage } = require('./util/logging');
5
5
  const { buildResponseError, buildNetworkError, parseResponseBody } = require('./util/request');
@@ -39,28 +39,107 @@ function reqParams(method, params) {
39
39
  const url = params.get('tokenUrl');
40
40
  const d = {};
41
41
  const ignored = {};
42
- if (params.has('subdomain')) {
43
- d.subdomain = params.get('subdomain');
44
- }
45
- if (params.has('refreshToken')) {
46
- d.refresh_token = params.get('refreshToken');
47
- const param = ['passcode', 'clientid'].find(param => params.has(param));
48
- if (param) {
49
- ignored[param] = 'refresh token is present';
42
+ const headers = { 'content-type': 'application/x-www-form-urlencoded' };
43
+ const tls = {};
44
+ if (params.get('directUaa')) {
45
+ d.grant_type = 'client_credentials';
46
+ d.client_id = params.get('clientid');
47
+ if (params.has('key')) {
48
+ tls.cert = params.get('certificate');
49
+ tls.key = params.get('key');
50
+ } else {
51
+ const encoded = Buffer.from(`${params.get('clientid')}:${params.get('clientsecret')}`).toString('base64');
52
+ headers.Authorization = `Basic ${encoded}`;
53
+ }
54
+ } else {
55
+ if (params.has('subdomain')) {
56
+ d.subdomain = params.get('subdomain');
57
+ }
58
+ if (params.has('refreshToken')) {
59
+ d.refresh_token = params.get('refreshToken');
60
+ const param = ['passcode', 'clientid'].find(param => params.has(param));
61
+ if (param) {
62
+ ignored[param] = 'refresh token is present';
63
+ }
64
+ } else if (params.has('passcode')) {
65
+ d.passcode = params.get('passcode');
66
+ } else if (params.has('clientsecret')) {
67
+ d.clientid = params.get('clientid');
68
+ d.clientsecret = params.get('clientsecret');
50
69
  }
51
- } else if (params.has('passcode')) {
52
- d.passcode = params.get('passcode');
53
- } else if (params.has('clientsecret')) {
54
- d.clientid = params.get('clientid');
55
- d.clientsecret = params.get('clientsecret');
56
- } else if (params.has('key')) {
57
- d.clientid = params.get('clientid');
58
- d.key = params.get('key');
59
70
  }
60
71
  const data = new URLSearchParams(d).toString();
61
- return method === 'post'
62
- ? { url, data, ignored }
63
- : { url: `${url}?${data}`, data: undefined, ignored };
72
+ const req = method === 'post'
73
+ ? { url, data, method, headers, ...tls }
74
+ : { url: `${url}?${data}`, data: undefined, method, headers, ...tls };
75
+ return { req, ignored };
76
+ }
77
+
78
+ function toResponse(res, body) {
79
+ const status = res.statusCode;
80
+ return {
81
+ ok: status >= 200 && status < 300,
82
+ status,
83
+ statusText: res.statusMessage ?? '',
84
+ headers: { get: name => res.headers[name.toLowerCase()] },
85
+ json: async () => JSON.parse(body),
86
+ text: async () => body
87
+ };
88
+ }
89
+
90
+ function postTokenViaMtls(url, data, headers, { cert, key }) {
91
+ const https = require('node:https');
92
+ const u = new URL(url);
93
+ return new Promise((resolve, reject) => {
94
+ const request = https.request({
95
+ hostname: u.hostname,
96
+ port: u.port || 443,
97
+ path: `${u.pathname}${u.search}`,
98
+ method: 'POST',
99
+ headers,
100
+ cert,
101
+ key
102
+ }, res => {
103
+ let body = '';
104
+ res.setEncoding('utf8');
105
+ res.on('data', chunk => { body += chunk; });
106
+ res.on('end', () => resolve(toResponse(res, body)));
107
+ });
108
+ request.on('error', reject);
109
+ if (data) {
110
+ request.write(data);
111
+ }
112
+ request.end();
113
+ });
114
+ }
115
+
116
+ async function postTokenTo(req, params) {
117
+ const { url, data, method, headers, cert, key } = req;
118
+ DEBUG?.(`Getting authentication token from ${method.toUpperCase()} ${params.obfuscateQueryParams(url)}`);
119
+ const response = cert
120
+ ? await postTokenViaMtls(url, data, headers, { cert, key })
121
+ : await fetch(url, {
122
+ method: method.toUpperCase(),
123
+ body: data,
124
+ headers
125
+ });
126
+ if (!response.ok) {
127
+ throw await buildResponseError(method, url, response);
128
+ }
129
+ return parseResponseBody(response);
130
+ }
131
+
132
+ async function postToken(req, params) {
133
+ try {
134
+ return await postTokenTo(req, params);
135
+ } catch (e) {
136
+ if (e.status !== 404 || !req.url.includes(OAUTH_PATH)) {
137
+ throw e;
138
+ }
139
+ req.url = req.url.replace(OAUTH_PATH, OAUTH_PATH_LEGACY_TOKEN);
140
+ DEBUG?.(`Token endpoint not found, retrying against legacy path ${params.obfuscateQueryParams(req.url)}`);
141
+ return postTokenTo(req, params);
142
+ }
64
143
  }
65
144
 
66
145
  async function fetchToken(params) {
@@ -71,29 +150,16 @@ async function fetchToken(params) {
71
150
  let responseData, error;
72
151
  const method = 'post';
73
152
  do {
74
- const { url, data, ignored } = reqParams(method, params);
153
+ const { req, ignored } = reqParams(method, params);
75
154
  if (Object.keys(ignored).length) {
76
155
  console.log(`Ignoring parameters for fetching token: ${Object.entries(ignored).map(([param, reason]) => `${param} (${reason})`).join(', ')}.`);
77
156
  }
78
- DEBUG?.(`Getting authentication token from ${method.toUpperCase()} ${params.obfuscateQueryParams(url)}`);
79
157
  error = undefined;
80
158
  try {
81
- const response = await fetch(url, {
82
- method: method.toUpperCase(),
83
- body: data,
84
- headers: { 'content-type': 'application/x-www-form-urlencoded' }
85
- });
86
- if (!response.ok) {
87
- throw await buildResponseError(method, url, response);
88
- }
89
- responseData = await parseResponseBody(response);
159
+ responseData = await postToken(req, params);
90
160
  break;
91
161
  } catch (e) {
92
- if (e.status) {
93
- error = e;
94
- } else {
95
- error = buildNetworkError(method, url, e);
96
- }
162
+ error = e.status ? e : buildNetworkError(method, req.url, e);
97
163
  DEBUG?.(`HTTP status ${error.status}`);
98
164
  if (params.has('refreshToken')) {
99
165
  DEBUG?.('Discarding invalid refresh token');
@@ -122,7 +188,7 @@ async function fetchToken(params) {
122
188
  message += `. Ensure the client credentials are correct`;
123
189
  }
124
190
  } else {
125
- message = 'error on token request';
191
+ message = 'token request failed';
126
192
  }
127
193
  throw new Error(message + '.', { cause: error });
128
194
  }
package/lib/mtx/params.js CHANGED
@@ -178,7 +178,8 @@ class BasicParams {
178
178
  this.password = new Param('password', undefined, { obfuscate: ObfuscationLevel.full });
179
179
  this.clientid = new Param('clientid', undefined);
180
180
  this.clientsecret = new Param('clientsecret', undefined, { obfuscate: ObfuscationLevel.partial });
181
- this.key = new Param('key', undefined, { obfuscate: ObfuscationLevel.partial }); // private key of client certificate
181
+ this.certificate = new Param('certificate', undefined, { obfuscate: ObfuscationLevel.partial }); // client certificate for mTLS
182
+ this.key = new Param('key', undefined, { obfuscate: ObfuscationLevel.partial }); // private key of the client certificate
182
183
  this.tokenStorage = new Param('tokenStorage', undefined, { allowedValues: ['plain', 'keyring'] });
183
184
  this.clearOtherTokenStorage = new Param('clearOtherTokenStorage', false, { internal: true });
184
185
  this.plain = new Param('plain', false, { internal: true }); // for backward compatibility - superseded by tokenStorage
@@ -195,7 +196,6 @@ class BasicParams {
195
196
  }
196
197
  }
197
198
 
198
- // TODO pass these as extra arguments to lib functions
199
199
  /**
200
200
  * All known params including those needed for specific commands.
201
201
  */
@@ -216,6 +216,7 @@ class AllParams extends BasicParams {
216
216
 
217
217
  // `login` PARAMS
218
218
  this.skipToken = new Param('skipToken', false, { internal: true });
219
+ this.directUaa = new Param('directUaa', false, { internal: true }); // client-credentials login goes directly to the authorization server
219
220
  this.saveRefreshToken = new Param('saveRefreshToken', false, { internal: true });
220
221
 
221
222
  // `logout` PARAMS
@@ -34,9 +34,10 @@ const KEYRING_DESC = {
34
34
  };
35
35
 
36
36
  const MTX_FULLY_QUALIFIED = 'com.sap.cds.mtx';
37
- const OAUTH_PATH_LEGACY = '/mtx/v1/oauth/token';
38
- const OAUTH_PATH = '/-/cds/login/token';
39
- const OAUTH_META_PATH = '/-/cds/login/authorization-metadata';
37
+ const OAUTH_PATH_LEGACY_TOKEN = '/-/cds/login/token';
38
+ const OAUTH_PATH = '/-/cds/login/grant';
39
+ const OAUTH_META_PATH = '/-/cds/login/grant-metadata';
40
+ const OAUTH_UAA_PATH = '/oauth/token';
40
41
 
41
42
  const SETTINGS_DIR = path.join(os.homedir(), CONFIG_SUBDIRS[os.platform()] || '', MTX_FULLY_QUALIFIED);
42
43
  const SETTINGS_FILE = 'projects.json';
@@ -102,12 +103,40 @@ async function getTokenUrl(params, renewUrl) {
102
103
  if (!params.has('appUrl')) {
103
104
  throw 'Failed to determine token URL: app URL not given';
104
105
  }
106
+ if (params.has('clientid')) {
107
+ return deriveUaaTokenUrl(params);
108
+ }
105
109
  return appUrlWith(OAUTH_PATH, params);
106
110
  }
107
111
 
108
- async function fetchPasscodeUrl(params) {
112
+ function uaaTokenUrl(passcodeUrl, { mtls } = {}) {
113
+ const url = new URL(passcodeUrl);
114
+ url.pathname = url.pathname.replace(/\/passcode\/*$/, '').replace(/\/+$/, '') + OAUTH_UAA_PATH;
115
+ url.search = '';
116
+ if (mtls) {
117
+ url.hostname = url.hostname.replace(/\.authentication\./, '.authentication.cert.');
118
+ }
119
+ return url.toString();
120
+ }
121
+
122
+ async function deriveUaaTokenUrl(params) {
123
+ const mtls = params.has('key');
124
+ const metadata = await fetchAuthMetadata(params);
125
+ const announced = mtls ? metadata?.cert_token_url : metadata?.token_url;
126
+ const passcodeUrl = metadata?.passcode_url;
127
+ const tokenUrl = announced ?? (passcodeUrl && uaaTokenUrl(passcodeUrl, { mtls }));
128
+ if (!tokenUrl) {
129
+ throw 'Cannot determine the authorization server for client-credentials login. ' +
130
+ 'Ensure MTX is running with extensibility enabled and up to date.';
131
+ }
132
+ params.set('directUaa', true);
133
+ DEBUG?.(`Derived authorization-server token URL for ${mtls ? 'mTLS' : 'client-credentials'} login: ${tokenUrl}`);
134
+ return tokenUrl;
135
+ }
136
+
137
+ async function fetchAuthMetadata(params) {
109
138
  let fetchUrl = appUrlWith(OAUTH_META_PATH, params);
110
- DEBUG?.(`Trying to get passcode URL from GET`, fetchUrl);
139
+ DEBUG?.(`Trying to get authorization metadata from GET`, fetchUrl);
111
140
  if (params.has('subdomain')) {
112
141
  const u = new URL(fetchUrl);
113
142
  u.searchParams.set('subdomain', params.get('subdomain'));
@@ -124,10 +153,10 @@ async function fetchPasscodeUrl(params) {
124
153
  if (error.status === 404) {
125
154
  DEBUG?.(`Request unsupported by server, ignoring (${error.message.replace(/ *Details:.*/s, '')})`);
126
155
  } else if (error.status) {
127
- DEBUG?.(getMessage(`Getting passcode URL failed`, { error }));
156
+ DEBUG?.(getMessage(`Getting authorization metadata failed`, { error }));
128
157
  } else {
129
158
  const netError = buildNetworkError('GET', fetchUrl, error);
130
- DEBUG?.(getMessage(`Getting passcode URL failed`, { error: netError }));
159
+ DEBUG?.(getMessage(`Getting authorization metadata failed`, { error: netError }));
131
160
  }
132
161
  return undefined;
133
162
  }
@@ -139,7 +168,7 @@ async function fetchPasscodeUrl(params) {
139
168
  DEBUG?.(`Unsupported signed metadata received. Since these should take precedence, ignoring response.`);
140
169
  return undefined;
141
170
  }
142
- return responseData.passcode_url;
171
+ return responseData;
143
172
  }
144
173
 
145
174
  function getKeyringAccountName(params) {
@@ -289,8 +318,9 @@ class SettingsManager {
289
318
  }
290
319
  async function updateTokenUrl() {
291
320
  const tokenUrl = secure(params.get('tokenUrl'), 'token URL');
321
+ const machineLogin = params.has('clientid');
292
322
  const renewUrl = !logout && !params.get('skipToken')
293
- && (!tokenUrl || tokenUrl.includes('//-/cds') || tokenUrl.includes(OAUTH_PATH_LEGACY)
323
+ && (machineLogin || !tokenUrl || tokenUrl.includes('//-/cds') || !tokenUrl.includes(OAUTH_PATH)
294
324
  || params.get('appUrl') !== loadedSettings.get('appUrl')
295
325
  || params.get('subdomain') !== loadedSettings.get('subdomain'));
296
326
  if (renewUrl) {
@@ -303,7 +333,6 @@ class SettingsManager {
303
333
  }
304
334
  }
305
335
  }
306
-
307
336
  await updateAppUrl();
308
337
  await updateTokenUrl();
309
338
  }
@@ -353,16 +382,9 @@ class SettingsManager {
353
382
  throw 'Clientsecret cannot be empty';
354
383
  }
355
384
  }
356
- async function addKey() {
357
- params.set('key', await Question.askQuestion('key: ', undefined, true));
358
- console.log();
359
- if (params.get('key') === '') {
360
- throw 'Key cannot be empty';
361
- }
362
- }
363
385
  async function addPasscode() {
364
386
  if (!params.has('passcodeUrl')) {
365
- const passcodeUrl = await fetchPasscodeUrl(params);
387
+ const passcodeUrl = (await fetchAuthMetadata(params))?.passcode_url;
366
388
  if (passcodeUrl) {
367
389
  params.set('passcodeUrl', passcodeUrl);
368
390
  }
@@ -440,15 +462,8 @@ class SettingsManager {
440
462
  return;
441
463
  }
442
464
 
443
- if (params.get('clientid') && !logout) {
444
- if (params.has('key')) {
445
- if (params.get('key') === 'ask') {
446
- params.delete('key');
447
- await addKey();
448
- }
449
- } else if (!params.has('clientsecret')) {
450
- await addClientSecret();
451
- }
465
+ if (params.get('clientid') && !logout && !params.has('clientsecret') && !params.has('key')) {
466
+ await addClientSecret();
452
467
  }
453
468
 
454
469
  await addAuthSettings();
@@ -714,5 +729,7 @@ class SettingsManager {
714
729
  module.exports = {
715
730
  SettingsManager,
716
731
  other,
717
- notifyLogin
732
+ notifyLogin,
733
+ OAUTH_PATH,
734
+ OAUTH_PATH_LEGACY_TOKEN
718
735
  };
@@ -20,7 +20,6 @@ const DEFAULT_LOCALHOST_PASSWORD = '';
20
20
 
21
21
  module.exports = class TenantAction {
22
22
 
23
- // TODO JSDoc
24
23
  /**
25
24
  * @param command {string} the command to execute: 'subscribe', 'upgrade' or 'unsubscribe'
26
25
  */
@@ -0,0 +1,62 @@
1
+ const CLIENT_ID_ENV = 'CDS_LOGIN_CLIENT_ID';
2
+ const CLIENT_SECRET_ENV = 'CDS_LOGIN_CLIENT_SECRET';
3
+ const CLIENT_CERT_ENV = 'CDS_LOGIN_CLIENT_CERT';
4
+ const CLIENT_KEY_ENV = 'CDS_LOGIN_CLIENT_KEY';
5
+
6
+ function clientId(inlineId) {
7
+ const clientid = inlineId ?? process.env[CLIENT_ID_ENV];
8
+ if (!clientid) {
9
+ throw `Client ID required: pass it as --client <id> or via the ${CLIENT_ID_ENV} environment variable.`;
10
+ }
11
+ return clientid;
12
+ }
13
+
14
+ function splitFirst(value, separator) {
15
+ const i = value.indexOf(separator);
16
+ return i === -1 ? [value, undefined] : [value.slice(0, i), value.slice(i + separator.length)];
17
+ }
18
+
19
+ /**
20
+ * Resolve `--client` credentials, each part falling back to the environment
21
+ * (`CDS_LOGIN_CLIENT_ID`/`CDS_LOGIN_CLIENT_SECRET`). Splits on the first colon only;
22
+ * an empty client ID (`:secret`) is rejected.
23
+ * @returns {{ clientid?: string, clientsecret?: string }}
24
+ */
25
+ function clientCredentials(clientOption) {
26
+ if (!clientOption) {
27
+ return {};
28
+ }
29
+ const [id, secret] = typeof clientOption === 'string' ? splitFirst(clientOption, ':') : [];
30
+ return { clientid: clientId(id), clientsecret: secret ?? process.env[CLIENT_SECRET_ENV] };
31
+ }
32
+
33
+ /**
34
+ * Resolve `--mtls` credentials: client ID inline or from `CDS_LOGIN_CLIENT_ID`,
35
+ * certificate and key only from `CDS_LOGIN_CLIENT_CERT`/`CDS_LOGIN_CLIENT_KEY`.
36
+ * An inline `:key` is rejected.
37
+ * @returns {{ clientid?: string, certificate?: string, key?: string }}
38
+ */
39
+ function clientCertificate(mtlsOption) {
40
+ if (!mtlsOption) {
41
+ return {};
42
+ }
43
+ if (typeof mtlsOption === 'string' && mtlsOption.includes(':')) {
44
+ throw `The client key cannot be passed on the command line. Pass only the client ID as --mtls <id>, and provide the certificate and key via the ${CLIENT_CERT_ENV} and ${CLIENT_KEY_ENV} environment variables.`;
45
+ }
46
+ const id = typeof mtlsOption === 'string' ? mtlsOption : undefined;
47
+ const certificate = process.env[CLIENT_CERT_ENV];
48
+ const key = process.env[CLIENT_KEY_ENV];
49
+ if (!certificate || !key) {
50
+ throw `Client certificate and key required: set the ${CLIENT_CERT_ENV} and ${CLIENT_KEY_ENV} environment variables.`;
51
+ }
52
+ return { clientid: clientId(id), certificate, key };
53
+ }
54
+
55
+ module.exports = {
56
+ clientCredentials,
57
+ clientCertificate,
58
+ CLIENT_ID_ENV,
59
+ CLIENT_SECRET_ENV,
60
+ CLIENT_CERT_ENV,
61
+ CLIENT_KEY_ENV
62
+ };
@@ -4,6 +4,49 @@
4
4
  - The format is based on [Keep a Changelog](https://keepachangelog.com/).
5
5
  - This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## Version 10.1.0 - 2026-09-02
8
+
9
+ ### Added
10
+
11
+ - New `sqlite:memory` preset for `cds.requires.db` runs an in-memory SQLite database, now also in production
12
+ - New `hana-serverless` kind for `cds.requires.db` connects to a HANA Cloud serverless instance (Beta)
13
+ - Node.js-native `fetch` client now resolves named destinations through the SAP BTP Destination service for `NoAuthentication`, `BasicAuthentication`, and `OAuth2ClientCredentials` (proxy type `Internet` only) (beta)
14
+
15
+ ### Changed
16
+
17
+ - `cds.spawn` uses dedicated, short-lived transaction for fetching extended models
18
+ - Messaging webhook endpoints are no longer registered anonymously in production when neither `cds.requires.auth` nor `cds.requires.messaging.xsuaa` is configured.
19
+ - UCL tenant mapping notification handlers will be scheduled as `tenant: receiverTenant` instead of anonymously
20
+
21
+ ### Fixed
22
+
23
+ - `@assert` messages using `{i18n>...}` placeholders are no longer mistaken for structured `error(...)` results
24
+ - JSON `$batch` requests now reject invalid `atomicityGroup` identifiers
25
+ - Scheduling a task via `srv.schedule(...).after(<delay>)` or `.every(<interval>)` with a delay above Node's 32-bit `setTimeout` limit (~24.8 days, e.g. `.after('30d')`) no longer emits a `TimeoutOverflowWarning` or fires almost immediately. Such delays are now armed as chained timers, so the task still fires at its exact scheduled time.
26
+ - OData requests with unknown key names in the key predicate (e.g. `Books(ID=1,sad=2)`) are now rejected with `400 Bad Request` instead of causing a `500` error
27
+ - `cds-rc.js` schema now has a `$id` so `jsonschema` 1.5 resolves internal `$ref`s correctly
28
+ - REST `HEAD` responses now report byte-accurate `Content-Length` headers for Unicode JSON payloads
29
+ - Query properties like `limit` and `recurse` are no longer lost when forwarded to remote services
30
+ - `cds.requires.<name>.service = <name>` (a required service naming itself) no longer fails with a spurious `conflicts with` error on server start
31
+ - `UPDATE` and `DELETE` remote-service-queries, that use `.where` instead of a key to specify their subject, will throw
32
+ - Navigating to or creating under a parent protected by an instance-based `@restrict.where` now returns `404` when the parent is not readable
33
+ - A static `@restrict.where` on a collection-bound action is now enforced, rejecting callers who do not satisfy the condition — previously it was silently ignored
34
+
35
+ ### Removed
36
+
37
+ - UCL GraphQL interface adapter as dead code after UCL deprecated the GraphQL on-boarding flow
38
+
39
+ ## Version 10.0.6 - 2026-08-18
40
+
41
+ ### Fixed
42
+
43
+ - `$apply=filter(...)/groupby(...)/aggregate($count)` with non-UTC `DateTimeOffset` filter values now returns correct results on HANA
44
+ - Generated index page now uses relative hrefs, fixing links when served behind an approuter with a path prefix
45
+ - `$batch` sub-requests returned an empty body and headers when `@opentelemetry/instrumentation-express` (or any instrumentation that wraps Express handlers to arity 2) was active
46
+ - `cds.xt.ModelProviderService` can be served in mtx sidecar
47
+ - Modeled service events were not properly ignored in OData adapter
48
+ - Generic handler for draft-specific actions not correctly being bound to the transaction context
49
+
7
50
  ## Version 10.0.5 - 2026-07-28
8
51
 
9
52
  ### Fixed
@@ -143,6 +186,20 @@
143
186
  - Internal `_initial` phase
144
187
  - Removed support for `async activate()` functions returned from `cds-plugin.js` modules, which was never documented, and deprecated since Oct 2023. If you need to run async code during plugin loading, just return a promise as default export.
145
188
 
189
+ ## Version 9.9.3 - 2026-07-21
190
+
191
+ ### Fixed
192
+
193
+ - Fixed context propagation for local app and remote service calls
194
+
195
+ ## Version 9.9.2 - 2026-06-29
196
+
197
+ ### Fixed
198
+
199
+ - `srv.model` propagation in extensibility scenarios
200
+ - Restored `err.target:'in'` during draft activation with `cds.fiori.draft_messages=false` to avoid the `MULTIPLE_ERRORS` popup
201
+ - `resolveView` prioritizes the original foreign key `parent_ID` if exposed multiple times, e.g., through `*, parent.ID as parentId`
202
+
146
203
  ## Version 9.9.1 - 2026-04-29
147
204
 
148
205
  ### Fixed
@@ -2,7 +2,8 @@ const cds = require('../lib')
2
2
  const { find, path, fs } = cds.utils
3
3
 
4
4
  const odata = endpoint => endpoint.kind.startsWith('odata')
5
- const metadata = endpoint => odata(endpoint) ? `<span>/</span> <a href="${endpoint.path}/$metadata"><span>$metadata</span></a>` : ``
5
+ const rel = path => path.replace(/^\//, '')
6
+ const metadata = endpoint => odata(endpoint) ? `<span>/</span> <a href="${rel(endpoint.path)}/$metadata"><span>$metadata</span></a>` : ``
6
7
  const asHtmlId = s => s.replace(/[.:/$&?@]/g, '_').toLowerCase()
7
8
 
8
9
  module.exports = { get html(){
@@ -22,12 +23,12 @@ module.exports = { get html(){
22
23
  .map (({srv, endpoint}) => `
23
24
  <div id="${asHtmlId(srv.name)}-${endpoint.kind}">
24
25
  <h3 class="header">
25
- <a href="${endpoint.path}"><span>${endpoint.path}</span></a>${metadata(endpoint)} ${_moreLinks(srv, endpoint, undefined, false)}
26
+ <a href="${rel(endpoint.path)}"><span>${endpoint.path}</span></a>${metadata(endpoint)} ${_moreLinks(srv, endpoint, undefined, false)}
26
27
  </h3>
27
28
  <ul>${_entities_in(srv).map (e => `
28
29
  <li id="${asHtmlId(srv.name)}-${endpoint.kind}-${asHtmlId(e)}">
29
30
  <div>
30
- <a href="${endpoint.path}/${e.replace(/\./g, '_')}"><span>${e}</span></a>
31
+ <a href="${rel(endpoint.path)}/${e.replace(/\./g, '_')}"><span>${e}</span></a>
31
32
  </div>
32
33
  ${_moreLinks(srv, endpoint, e)}
33
34
  </li>`).join('')}
@@ -35,7 +36,7 @@ module.exports = { get html(){
35
36
  <ul>${_operations_in(srv).map (e => `
36
37
  <li id="${asHtmlId(srv.name)}-${endpoint.kind}-${asHtmlId(e.name)}" class="operation">
37
38
  <div>
38
- <a href="${endpoint.path}/${e.name}" title="${endpoint.path}/${e.name}"><span>${e.name} ${e.params}</span></a>
39
+ <a href="${rel(endpoint.path)}/${e.name}" title="${endpoint.path}/${e.name}"><span>${e.name} ${e.params}</span></a>
39
40
  </div>
40
41
  </li>`).join('')}
41
42
  </ul>
@@ -80,6 +80,7 @@ export const tests = { name: '@cap/eslint/tests',
80
80
  languageOptions: {
81
81
  globals: {
82
82
  mocha: 'readonly',
83
+ vi: 'readonly',
83
84
  jest: 'readonly',
84
85
  expect: 'readonly',
85
86
  describe: 'writable',
@@ -17,7 +17,7 @@ class Minifier {
17
17
  if (skip_unused === 'services') o.services = 'all'
18
18
  const all = new Map (Object.entries( this.defs ??= csn.definitions || {} ))
19
19
  const children = (n,fn,pre=n+'.') => { for (let [n,d] of all) if (n.startsWith(pre)) fn (n,d) }
20
- const keep = (d,kinds) => d.kind in kinds || _can_minify(d)
20
+ const _keep = (d,kinds) => d.kind in kinds || d['@cds.minify'] === false
21
21
  const _own = o.keep ??= { entity:1, type:1, event:1, action:1, function:1 }
22
22
  const _ext = { event:1, action:1, function:1 }
23
23
  const kept = this.kept = csn.definitions = {}
@@ -31,16 +31,23 @@ class Minifier {
31
31
  }
32
32
  } else {
33
33
  // Otherwise first mark all external services and their children as initially skipped
34
- for (let [s,d] of all) if (d.kind === 'service' && _skip_service(s,d)) {
35
- skipped[s] = 0; children (s, (c,d) => keep(d,_ext) ? this.keep(c,d,s) : skipped[c] = s) // used later on in this.keep()
34
+ for (let [s,d] of all) if (d.kind === 'service' && d['@cds.external'] >= 2) {
35
+ if (d['@cds.minify'] === false) continue
36
+ else skipped[s] = 0
37
+ children (s, (c,d) => _keep(d,_ext) ? this.keep(c,d,s) : skipped[c] = s) // used later on in this.keep()
36
38
  }
37
39
  // Then keep all own services and their children
38
- for (let [s,d] of all) if (d.kind === 'service' && !(s in skipped)) {
39
- this.keep(s,d); children (s, (c,d) => keep(d,_own) ? this.keep(c,d) : skipped[c] = 0)
40
+ for (let [s,d] of all) if (d.kind === 'service') {
41
+ if (s in skipped) continue
42
+ else this.keep(s,d)
43
+ children (s, (c,d) => _keep(d,_own) ? this.keep(c,d) : skipped[c] = 0)
40
44
  }
41
45
  // Also keep remaining non-service entities
42
- for (let [e,d] of all) if (d.kind === 'entity' || !_can_minify(d)) {
43
- e in kept || e in skipped || _skip_entity(e,d) || this.keep(e,d)
46
+ for (let [e,d] of all) if (d.kind === 'entity' || d['@cds.minify'] === false) {
47
+ if (e in skipped || e in kept) continue //> skip already kept or skipped definitions
48
+ if (d['@cds.persistence.skip'] === 'if-unused') continue //> skip initially, they are kept by reference if used
49
+ if (e.endsWith('.texts')) continue //> skip texts entities, they are kept by reference if used
50
+ else this.keep(e,d)
44
51
  }
45
52
  }
46
53
 
@@ -106,7 +113,4 @@ class Minifier {
106
113
 
107
114
  }
108
115
 
109
- const _skip_service = (s,d) => (d['@cds.external'] >= 2) && _can_minify(d)
110
- const _skip_entity = (e,d) => (d['@cds.external'] >= 2 || d['@cds.persistence.skip'] === 'if-unused') && _can_minify(d) || e.endsWith('.texts')
111
- const _can_minify = d => d['@cds.minify'] !== false
112
116
  exports.Minifier = Minifier
@@ -524,7 +524,7 @@ function _merge (dst, src, _profiles) {
524
524
  }
525
525
  else if (v !== undefined) dst[p] = v
526
526
  }
527
- if (profiled.length > 0 && !_profiles.has('production')) {
527
+ if (profiled.length > 1 && !_profiles.has('production')) {
528
528
  const profiles = Array.from(_profiles)
529
529
  profiled.sort((a,b) => profiles.indexOf(b.profile) - profiles.indexOf(a.profile))
530
530
  }
@@ -24,7 +24,8 @@ exports = module.exports = {
24
24
  _resolved() {
25
25
  const requires = { __proto__: this }
26
26
  for (let [name,e] of Object.entries(this)) if (e.service) {
27
- if (!(e.service in requires) || e.override || e.service !== name) requires[e.service] = { ...e, name }
27
+ if (e.service === name) continue
28
+ if (!(e.service in requires) || e.override) requires[e.service] = { ...e, name }
28
29
  else throw new Error (`Config 'cds.requires.${name}.service = ${e.service}' conflicts with 'cds.requires.${e.service}'`)
29
30
  }
30
31
  return requires
@@ -127,9 +128,10 @@ const _db_data = {
127
128
 
128
129
  const _databases = {
129
130
 
130
- "db-defaults": { kind: 'sql', ..._db_data }, //> applied only for cds.requires.db: true
131
-
131
+ "db-defaults": { kind: 'sql', ..._db_data }, //> applied only for cds.requires.db: true
132
+
132
133
  "sql": {
134
+ // REVISIT: should be '[development]': { kind: 'sqlite:memory' },
133
135
  '[development]': { kind: 'sqlite', credentials: { url: ':memory:' } },
134
136
  '[production]': { kind: 'hana' },
135
137
  },
@@ -138,22 +140,33 @@ const _databases = {
138
140
  impl: '@cap-js/sqlite', credentials: { url: 'db.sqlite' },
139
141
  ..._db_data,
140
142
  },
143
+ "sqlite:memory": {
144
+ kind: 'sqlite', credentials: { url: ':memory:' },
145
+ },
141
146
  "hana": {
142
147
  impl: '@cap-js/hana',
143
148
  ..._db_data,
144
149
  },
145
150
  "hana-cloud": {
146
- kind: 'hana', "deploy-format": "hdbtable",
151
+ kind: 'hana',
152
+ "deploy-format": "hdbtable", //> REVISIT: still needed?
153
+ },
154
+ "hana-serverless": {
155
+ kind: 'hana',
156
+ serverless: true,
157
+ vcap: { label: 'hana-cloud', plan: 'serverless' },
158
+ dialect: "hana", //> REVISIT: why needed?
159
+ "deploy-format": "hdbtable", //> REVISIT: still needed?
147
160
  },
161
+
148
162
  "sql-mt": { // For compatibility only
149
163
  '[development]': { kind: 'sqlite' },
150
164
  '[production]': { kind: 'hana-mt' },
151
165
  },
152
166
  "hana-mt": { // For compatibility only
153
- kind: 'hana', "deploy-format": "hdbtable",
154
- "vcap": {
155
- "label": "service-manager"
156
- }
167
+ kind: 'hana',
168
+ "vcap": { "label": "service-manager" },
169
+ "deploy-format": "hdbtable", //> REVISIT: still needed?
157
170
  },
158
171
  }
159
172
 
@@ -277,12 +290,10 @@ const _messaging = {
277
290
  const _platform_services = {
278
291
 
279
292
  ucl: {
280
- model: '@sap/cds/srv/ucl-service.cds',
293
+ model: '@sap/cds/srv/ucl-service.cds'
281
294
  // REVISIT: how to configure such that a cds.connect.to('ucl') returns the already initialized UCLService?
282
295
  // service: 'UCLService',
283
296
  // impl: `${_runtime}/ucl/Service.js`,
284
- // REVISIT: remove default as only needed for push mode
285
- vcap: { label: 'xsuaa' }
286
297
  },
287
298
 
288
299
  destinations: {