@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
@@ -35,11 +35,11 @@ module.exports = exports = {
35
35
  sql_simple_queries: 0,
36
36
  pre_compile_edmxs: false,
37
37
  live_reload: !production,
38
- in_memory_db: !production,
39
38
  test_data: !production,
40
39
  test_mocks: !production,
41
40
  with_mocks: !production,
42
41
  mocked_bindings: !production,
42
+ in_memory_db: true,
43
43
  // skip_unused: 'all',
44
44
  skip_unused: true,
45
45
  deploy_data_onconflict: 'insert',
@@ -223,6 +223,9 @@ module.exports = exports = {
223
223
 
224
224
  remote: {
225
225
  native_fetch: undefined,
226
+ timeout: '10s',
227
+ cache_size: 0,
228
+ cache_expiry_buffer: '5min',
226
229
  },
227
230
 
228
231
  }
@@ -3,6 +3,7 @@ const cds = require('../../index')
3
3
  module.exports = {
4
4
  _version: cds.version,
5
5
 
6
+ $id: 'cdsjsonschema://schemas/cds-rc.json',
6
7
  title: 'JSON schema for CDS configuration',
7
8
  $schema: 'https://json-schema.org/draft-07/schema',
8
9
  description: 'This is a JSON schema representation for CDS project configuration',
@@ -961,12 +962,14 @@ module.exports = {
961
962
  enum: [
962
963
  'hana',
963
964
  'sql',
964
- 'sqlite'
965
+ 'sqlite',
966
+ 'sqlite:memory'
965
967
  ],
966
968
  enumDescriptions: [
967
969
  'SAP HANA',
968
970
  'In-memory SQLite (development), SAP HANA (production)',
969
- 'File-based SQLite'
971
+ 'File-based SQLite',
972
+ 'In-memory SQLite'
970
973
  ]
971
974
  },
972
975
 
@@ -1,6 +1,12 @@
1
1
  const DEBUG = /\b(y|all|plugins)\b/.test(process.env.DEBUG) ? console : undefined // eslint-disable-line no-console
2
2
  const cds = require('.')
3
3
 
4
+ const prioritized = {
5
+ '@sap/cds-mtxs': true, // plugins may register handlers for mtxs services
6
+ '@cap-js/sqlite': true, // to enable override by @cap-js/ai
7
+ '@cap-js/telemetry': true // to allow better instrumentation
8
+ }
9
+
4
10
  /**
5
11
  * Fetch cds-plugins from project's package dependencies.
6
12
  * Called in cds.env to populate the plugins configuration
@@ -8,7 +14,7 @@ const cds = require('.')
8
14
  */
9
15
  exports.fetch = function (DEV = process.env.NODE_ENV !== 'production') {
10
16
  DEBUG?.time ('[cds.plugins] - fetched plugins in')
11
- const plugins = JSON.parse(process.env.CDS_PLUGINS||'{}')
17
+ let plugins = JSON.parse(process.env.CDS_PLUGINS||'{}')
12
18
  fetch_plugins_in (cds.home, false)
13
19
  fetch_plugins_in (cds.root, DEV)
14
20
  function fetch_plugins_in (root, dev) {
@@ -19,6 +25,8 @@ exports.fetch = function (DEV = process.env.NODE_ENV !== 'production') {
19
25
  plugins[each] = { impl }
20
26
  } catch { /* no cds-plugin.js */ }
21
27
  }
28
+ for (const each in prioritized)
29
+ if (each in plugins) plugins = Object.assign({ [each]: plugins[each] }, plugins)
22
30
  DEBUG?.timeEnd ('[cds.plugins] - fetched plugins in')
23
31
  return plugins
24
32
  }
@@ -30,10 +38,6 @@ exports.fetch = function (DEV = process.env.NODE_ENV !== 'production') {
30
38
  exports.activate = async function (plugins = cds.env?.plugins || exports.fetch()) {
31
39
  DEBUG?.time ('[cds.plugins] - loaded plugins in')
32
40
  const all = Object.entries(plugins), { local } = cds.utils
33
- const prioritized = {
34
- '@sap/cds-mtxs': true, // plugins may register handlers for mtxs services
35
- '@cap-js/telemetry': true // to allow better instrumentation
36
- }
37
41
  await Promise.all (all.map (([n,c]) => n in prioritized && _load(n,c)))
38
42
  await Promise.all (all.map (([n,c]) => n in prioritized || _load(n,c)))
39
43
  async function _load (plugin, conf) {
@@ -12,7 +12,7 @@ module.exports = function spawn (o, fn, /** @type {import('../index')} */ cds=th
12
12
  if (cds.model && (cds.env.requires.extensibility || cds.env.requires.toggles)) {
13
13
  const ctx = cds.context
14
14
  const ExtendedModels = require('../srv/srv-models') // the sentinel is automatically started when required
15
- cds.context.model = await ExtendedModels.model4(ctx.tenant, ctx.features)
15
+ cds.context.model = await cds.tx(() => ExtendedModels.model4(ctx.tenant, ctx.features))
16
16
  tx.model = cds.context.model
17
17
  }
18
18
  return Promise.resolve(fn(tx))
@@ -113,5 +113,5 @@ const _ensure_fqn = (x,p,srv, name = x[p]) => {
113
113
 
114
114
  const _unhandled = (srv,req) => {
115
115
  const event = req.event + (req.path ? ' ' + req.path : '')
116
- return req.reject (501, `Service "${srv.name}" has no handler for "${event}".`)
116
+ cds.error (501, `Service "${srv.name}" has no handler for "${event}".`)
117
117
  }
@@ -148,7 +148,7 @@ if (!extensibility) {
148
148
  // helper to get model for tenant/features
149
149
  const _is_extended = extensibility ? ()=> cds.db.exists('cds.xt.Extensions') : ()=> false
150
150
  const _get_model4 = async (tenant, features) => {
151
- const { 'cds.xt.ModelProviderService':mps } = cds.services
151
+ const mps = await cds.connect.to('cds.xt.ModelProviderService')
152
152
  const csn = await mps.getCsn (tenant, features)
153
153
  const nsn = cds.compile.for.nodejs(csn)
154
154
  if (cds.edmxs) await cds.compile.to.edmx.files ( csn,
@@ -389,7 +389,8 @@ exports.sh = function shell (cmd,..._) {
389
389
  */
390
390
  const ms4 = exports.ms4 = (ts, unit, u=unit) => {
391
391
  if (typeof ts === 'string') [,ts,u] = /(\d+) ?(\w*)/.exec(ts) || cds.error `Invalid time span format: ${ts}`
392
- return ts * ms4[u||unit||'ms'] || cds.error `Invalid time span unit: ${unit} in ${ts}`
392
+ const factor = ms4[u||unit||'ms'] || cds.error `Invalid time span unit: ${unit} in ${ts}`
393
+ return ts * factor
393
394
  }
394
395
 
395
396
  /**
@@ -132,9 +132,8 @@ module.exports = cds.service.impl(function () {
132
132
  // If error function was used in @assert expression -> use its output
133
133
  // Note: depending on DB, function result may be JavaScript object or JSON string
134
134
  if (typeof message === 'string') {
135
- if (message[0] === '{')
136
- message = JSON.parse(message) //> it's an error function result
137
- else return error //> it's a plain message string
135
+ if (message[0] !== '{' || message.startsWith('{i18n>')) return error //> it's a plain message string
136
+ message = JSON.parse(message) //> it's an error function result
138
137
  }
139
138
  let { targets = [], ...details } = message
140
139
  if (targets.length) details.target = targets.shift()
@@ -238,7 +238,14 @@ async function enforce_auth(req) {
238
238
  // REVISIT with cds^11
239
239
  // - remove compat_static_auth
240
240
  // - make check on CREATE/ NEW and unbound a compat opt-in
241
- if (cds.env.features.compat_static_auth || req.event in { CREATE: 1, NEW: 1 } || this.operations[req.event]) {
241
+ const boundAction = req.target?.actions?.[req.event]
242
+ if (
243
+ cds.env.features.compat_static_auth ||
244
+ req.event in { CREATE: 1, NEW: 1 } ||
245
+ this.operations[req.event] ||
246
+ // collection-bound actions have no instance to filter -> only a static where can apply
247
+ (boundAction && isBoundToCollection(boundAction))
248
+ ) {
242
249
  const staticAuthRestriction = _getStaticAuthRestrictions(resolvedApplicables)
243
250
  if (staticAuthRestriction.length > 0) {
244
251
  return _handleStaticAuthRestrictions(staticAuthRestriction, req)
@@ -2,6 +2,8 @@ const cds = require('../../cds')
2
2
  const { SELECT } = cds.ql
3
3
 
4
4
  module.exports = exports = cds.service.impl(function () {
5
+ const { parent_skip_auth } = cds.env.features
6
+
5
7
  // prettier-ignore
6
8
  this.on(['CREATE', 'READ', 'UPDATE', 'UPSERT', 'DELETE'], '*', async function handle_crud_requests(req) {
7
9
  if (!cds.db)
@@ -11,18 +13,26 @@ module.exports = exports = cds.service.impl(function () {
11
13
  if (req.target['@cds.persistence.skip'] === true && req.target['@cds.persistence.table'] !== true)
12
14
  return req.reject(501, `Entity "${req.target.name}" is annotated with "@cds.persistence.skip" and cannot be served generically.`)
13
15
 
14
- const { ref } = req.query.INSERT?.into || req.query.SELECT?.from || {}
15
- const check_parent = ref?.length > 1 ? SELECT.one(1).from({ ref: ref.slice(0, -1) }) : null
16
- if (check_parent && req.event === 'CREATE') (await check_parent) || req.reject(404)
17
- else if (req.target?._isSingleton) await handle_singleton_request(req)
18
- else if (req.query?.SELECT && req.locale) req.query.SELECT.localized ??= true
16
+ const { ref } = req.query?.INSERT?.into || req.query?.SELECT?.from || {}
17
+ const parent_exists_query = ref?.length > 1 && !('$parent' in (req.query?.elements ?? {}))
18
+ ? SELECT.one`1 as $parent`.from({ ref: ref.slice(0, -1) })
19
+ : null
20
+ const parent_readable_check = parent_exists_query
21
+ ? async () => (parent_skip_auth ? cds.db : this).run(parent_exists_query).catch(() => null)
22
+ : null
23
+
24
+ if (req.event === 'CREATE' && parent_readable_check != null) (await parent_readable_check()) || req.reject(404)
25
+
26
+ if (req.target?._isSingleton) await handle_singleton_request(req)
27
+
28
+ if (req.query?.SELECT && req.locale) req.query.SELECT.localized ??= true
19
29
 
20
30
  // REVISIT for cds^10: can we always use cds.db.dispatch(req)?
21
31
  const result = req.iterator && !req.objectMode
22
32
  ? await cds.db.dispatch(req)
23
33
  : await cds.run(req.query, req.data)
24
34
 
25
- return await exports._handle_result(req, result, check_parent)
35
+ return await exports._handle_result(req, result, parent_readable_check)
26
36
  })
27
37
  })
28
38
 
@@ -42,14 +52,14 @@ async function handle_singleton_request(req) {
42
52
  req.query.where(singleton)
43
53
  }
44
54
 
45
- async function new_behavior(req, result, parent) {
55
+ async function new_behavior(req, result, parent_readable_check) {
46
56
  const n = result?.affected ?? result?.length ?? result
47
57
 
48
58
  // prettier-ignore
49
59
  switch (req.event) {
50
60
  case 'READ':
51
61
  if (!n && req._etagValidationType === 'if-match') req.reject(412)
52
- if (!n) !parent || (await parent) || req.reject(404)
62
+ if (!n && parent_readable_check != null) (await parent_readable_check()) || req.reject(404)
53
63
  return result
54
64
  case 'INSERT': case 'CREATE':
55
65
  if (result.affected != null) return result //> db service returned [affected]
@@ -453,7 +453,7 @@ const compileUpdatedDraftMessages = (newMessages, persistedMessages, requestData
453
453
  if (!prefixRef) return null
454
454
 
455
455
  const draftMessageTargetPrefix = cds.odata.urlify(
456
- { SELECT: { from: { ref: prefixRef } } },
456
+ { query: { SELECT: { from: { ref: prefixRef } } }, subject: { ref: prefixRef } },
457
457
  { kind: 'odata-v4', model: txModel }
458
458
  ).path
459
459
 
@@ -483,7 +483,7 @@ const compileUpdatedDraftMessages = (newMessages, persistedMessages, requestData
483
483
  }
484
484
 
485
485
  message.prefix = cds.odata.urlify(
486
- { SELECT: { from: { ref: messagePrefixRef } } },
486
+ { query: { SELECT: { from: { ref: messagePrefixRef } } }, subject: { ref: messagePrefixRef } },
487
487
  { kind: 'odata-v4', model: txModel }
488
488
  ).path
489
489
 
@@ -1437,11 +1437,11 @@ const Read = {
1437
1437
 
1438
1438
  // TODO: This seems excessive ... how to compare more efficiently?
1439
1439
  const queryPrefixUrl = cds.odata.urlify(
1440
- { SELECT: { from: { ref: queryPrefixRef } } },
1440
+ { query: { SELECT: { from: { ref: queryPrefixRef } } }, subject: { ref: queryPrefixRef } },
1441
1441
  { kind: 'odata-v4', model: txModel }
1442
1442
  ).path
1443
1443
  const msgPrefixUrl = cds.odata.urlify(
1444
- { SELECT: { from: { ref: msgPrefixRef } } },
1444
+ { query: { SELECT: { from: { ref: msgPrefixRef } } }, subject: { ref: msgPrefixRef } },
1445
1445
  { kind: 'odata-v4', model: txModel }
1446
1446
  ).path
1447
1447
 
@@ -2443,7 +2443,7 @@ async function onCancel(req, next) {
2443
2443
 
2444
2444
  const prefixRef = _extractPrefixRef(req.query.DELETE.from.ref, queryRootEntity)
2445
2445
  const messageTargetPrefix = cds.odata.urlify(
2446
- { SELECT: { from: { ref: prefixRef } } },
2446
+ { query: { SELECT: { from: { ref: prefixRef } } }, subject: { ref: prefixRef } },
2447
2447
  { kind: 'odata-v4', model: req.context.tx.model }
2448
2448
  ).path
2449
2449
 
@@ -2570,6 +2570,7 @@ const _readAfterDraftAction = async function ({ req, payload, action }) {
2570
2570
  }
2571
2571
  }
2572
2572
 
2573
+ // prettier-ignore
2573
2574
  module.exports = cds.service.impl(function () {
2574
2575
  if (!this.entities?.DraftAdministrativeData) return
2575
2576
 
@@ -2577,14 +2578,17 @@ module.exports = cds.service.impl(function () {
2577
2578
  Object.defineProperty(this, '_datasource', { value: cds.db })
2578
2579
 
2579
2580
  // Extend the AppService's API by draft specific functions
2580
- this.new = (draft, key) => ({
2581
- then: (r, e) => this.send('NEW', draft, key).then(r, e),
2582
- for: key => this.send('EDIT', typeof draft === 'string' ? draft.replace(/\.drafts$/, '') : draft.actives, key)
2583
- })
2584
- this.edit = (active, key) => this.send('EDIT', active, key)
2585
- this.save = (draft, key) => this.send('SAVE', draft, key)
2586
- this.cancel = (draft, key) => this.send('CANCEL', draft, key)
2587
- this.discard = (draft, key) => this.send('DISCARD', draft, key)
2581
+ this.new = function (draft, key) {
2582
+ return {
2583
+ then: (r, e) => this.send('NEW', draft, key).then(r, e),
2584
+ for: key => this.send('EDIT', typeof draft === 'string' ? draft.replace(/\.drafts$/, '') : draft.actives, key)
2585
+ }
2586
+ }
2587
+
2588
+ this.edit = function (active, key) { return this.send('EDIT', active, key) }
2589
+ this.save = function (draft, key) { return this.send('SAVE', draft, key) }
2590
+ this.cancel = function (draft, key) { return this.send('CANCEL', draft, key) }
2591
+ this.discard = function (draft, key) { return this.send('DISCARD', draft, key) }
2588
2592
 
2589
2593
  // Override the AppService's handle function
2590
2594
  this.handle = !cds.env.features.legacy_srv_results
@@ -2596,9 +2600,13 @@ module.exports = cds.service.impl(function () {
2596
2600
  return Array.isArray(res) && 'affected' in res ? req.data : res
2597
2601
  }
2598
2602
 
2599
- this.on('NEW', '*', onNew.bind(this))
2600
- this.on('EDIT', '*', onEdit.bind(this))
2601
- this.on('CANCEL', '*', onCancel.bind(this))
2602
- this.on('draftPrepare', '*', onPrepare.bind(this))
2603
+ // NOTE: These handler registrations MUST use inline functions
2604
+ // NOTE: > Arrow functions or functions bound with `.bind` will
2605
+ // NOTE: > ... not be able to access the context tx from `this`
2606
+ this.on('NEW', '*', function (req, next) { return onNew.call(this, req, next) })
2607
+ this.on('EDIT', '*', function (req, next) { return onEdit.call(this, req, next) })
2608
+ this.on('CANCEL', '*', function (req, next) { return onCancel.call(this, req, next) })
2609
+ this.on('draftPrepare', '*', function (req, next) { return onPrepare.call(this, req, next) })
2603
2610
  })
2611
+
2604
2612
  module.exports.compileUpdatedDraftMessages = compileUpdatedDraftMessages
@@ -20,16 +20,18 @@ class EndpointRegistry {
20
20
  this.webhookCallbacks = new Map()
21
21
  this.deployCallbacks = new Map()
22
22
 
23
- const _IS_SECURED = !!(
23
+ const _HAS_APP_AUTH = !!(
24
24
  cds.env.requires.auth &&
25
25
  (cds.env.requires.auth.impl || !(cds.env.requires.auth.kind in { mocked: 1, 'mocked-auth': 1 }))
26
26
  )
27
+ const _HAS_MESSAGING_XSUAA = !!cds.env.requires.messaging?.xsuaa
28
+ const _IS_SECURED = _HAS_APP_AUTH || _HAS_MESSAGING_XSUAA
27
29
  const _IS_PRODUCTION = process.env.NODE_ENV === 'production'
28
30
 
29
31
  cds.app.use(basePath, cds.middlewares.context())
30
32
  if (_IS_SECURED) {
31
33
  // unofficial XSUAA fallback
32
- if (cds.env.requires.messaging?.xsuaa) {
34
+ if (_HAS_MESSAGING_XSUAA) {
33
35
  cds.app.use(basePath, _xsuaa_fallback())
34
36
  } else {
35
37
  cds.app.use(basePath, cds.middlewares.auth())
@@ -38,7 +40,11 @@ class EndpointRegistry {
38
40
  cds.app.use(basePath, (_req, _res, next) => {
39
41
  next(cds.context.user._is_anonymous ? 401 : undefined)
40
42
  })
41
- } else if (_IS_PRODUCTION) LOG.warn('Messaging endpoints not secured')
43
+ } else if (_IS_PRODUCTION) {
44
+ throw new Error(
45
+ 'Messaging endpoints require authentication in production. Configure cds.requires.auth or cds.requires.messaging.xsuaa.'
46
+ )
47
+ }
42
48
 
43
49
  cds.app.use(basePath, express.json({ type: 'application/*+json' }))
44
50
  cds.app.use(basePath, express.json())
@@ -1,10 +1,5 @@
1
1
  const cds = require('../cds')
2
- const {
3
- getCloudSdk,
4
- getCloudSdkConnectivity,
5
- getCloudSdkResilience,
6
- shouldUseCloudSdk
7
- } = require('./utils/cloudSdkProvider')
2
+ const { getCloudSdk, getCloudSdkResilience, shouldUseCloudSdk } = require('./utils/cloudSdkProvider')
8
3
  const { run } = require('./utils/client')
9
4
  const { extractRequestConfig } = require('./utils/query')
10
5
  const { hasAliasedColumns } = require('./utils/data')
@@ -171,13 +166,6 @@ const _isSelectWithAliasedColumns = q => q?.SELECT && !q._transitions && q.SELEC
171
166
 
172
167
  const resolvedTargetOfQuery = q => q?._transitions?.at(-1)?.target
173
168
 
174
- const _resolveSelectionStrategy = selectionStrategy => {
175
- const { DestinationSelectionStrategies } = getCloudSdkConnectivity()
176
- const strategy = DestinationSelectionStrategies[selectionStrategy]
177
- if (typeof strategy !== 'function') cds.error`Unsupported destination selection strategy "${selectionStrategy}".`
178
- return strategy
179
- }
180
-
181
169
  const _getKind = options => {
182
170
  let kind = options.credentials?.kind ?? options.kind
183
171
  if (typeof kind === 'object') {
@@ -206,9 +194,6 @@ class RemoteService extends cds.Service {
206
194
  this.datasource = this.options.datasource
207
195
 
208
196
  this.destinationOptions = this.options.destinationOptions || {}
209
- if (typeof this.destinationOptions.selectionStrategy === 'string') {
210
- this.destinationOptions.selectionStrategy = _resolveSelectionStrategy(this.destinationOptions.selectionStrategy)
211
- }
212
197
 
213
198
  if (this.options.credentials.destination) this.destination = this.options.credentials.destination
214
199
  else this.destination = _getDestination(this.definition?.name ?? this.datasource, this.options.credentials)
@@ -223,7 +208,7 @@ class RemoteService extends cds.Service {
223
208
 
224
209
  // This is required for BAS creating remote services only for events
225
210
  // Middlewares are created at time of the first request, on the fly
226
- if (shouldUseCloudSdk(this.destination)) {
211
+ if (shouldUseCloudSdk()) {
227
212
  this.middlewares = {
228
213
  timeout: getCloudSdkResilience().timeout(this.requestTimeout),
229
214
  csrf: this.csrf && getCloudSdk().csrf(this.csrf)
@@ -249,7 +234,7 @@ class RemoteService extends cds.Service {
249
234
  if (typeof this.destination === 'object' && !this.destination.url)
250
235
  cds.error`"url" or "destination" property must be configured in "credentials" of "${this.name}".`
251
236
 
252
- const requestConfig = extractRequestConfig(req, query, this)
237
+ const requestConfig = extractRequestConfig(req, this)
253
238
  requestConfig.headers = _getHeaders(requestConfig.headers, req)
254
239
 
255
240
  if (this.kind === 'hcql' && req.iterator && !req.objectMode)
@@ -284,7 +269,7 @@ class RemoteService extends cds.Service {
284
269
  if (jwt) additionalOptions.jwt = jwt
285
270
 
286
271
  const csrfConfig = requestConfig._autoBatchedGet ? this.csrfInBatch : this.csrf
287
- if (shouldUseCloudSdk(this.destination)) {
272
+ if (shouldUseCloudSdk()) {
288
273
  // Mount resilience and csrf middlewares for SAP Cloud SDK
289
274
  requestConfig.middleware = [this.middlewares.timeout]
290
275
  if (csrfConfig && this.middlewares.csrf) requestConfig.middleware.push(this.middlewares.csrf)
@@ -0,0 +1,42 @@
1
+ /**
2
+ * LRU cache backed by Map insertion order.
3
+ * On get/set the entry is moved to the MRU end; the LRU entry (first key) is
4
+ * evicted when the map is full. `maxSize = 0` means unlimited.
5
+ */
6
+ class LruCache {
7
+ /** @param {number} [maxSize=0] Maximum number of entries; 0 = unlimited. */
8
+ constructor(maxSize = 0) {
9
+ this._map = new Map()
10
+ this._maxSize = maxSize
11
+ }
12
+
13
+ /** @param {*} key Cache key. */
14
+ get(key) {
15
+ const value = this._map.get(key)
16
+ if (value !== undefined) {
17
+ this._map.delete(key)
18
+ this._map.set(key, value)
19
+ }
20
+ return value
21
+ }
22
+
23
+ /**
24
+ * @param {*} key Cache key. `null` and `undefined` are ignored.
25
+ * @param {*} value Value to store.
26
+ * @param {number} [ttl] Time-to-live in milliseconds. Entry is auto-deleted after this duration.
27
+ */
28
+ set(key, value, ttl) {
29
+ if (key == null) return
30
+ this._map.delete(key)
31
+ if (this._maxSize > 0 && this._map.size >= this._maxSize) this._map.delete(this._map.keys().next().value)
32
+ this._map.set(key, value)
33
+ if (ttl > 0) setTimeout(() => this._map.delete(key), ttl).unref()
34
+ }
35
+
36
+ /** @param {*} key Cache key. */
37
+ delete(key) {
38
+ this._map.delete(key)
39
+ }
40
+ }
41
+
42
+ module.exports = { LruCache }
@@ -1,7 +1,7 @@
1
1
  const cds = require('../../cds')
2
2
  const LOG = cds.log('remote')
3
3
 
4
- const { getCloudSdk, shouldUseCloudSdk } = require('./cloudSdkProvider')
4
+ const { getCloudSdk, getCloudSdkConnectivity, shouldUseCloudSdk } = require('./cloudSdkProvider')
5
5
  const { executeHttpRequest: fetchExecuteHttpRequest } = require('./fetchClient')
6
6
 
7
7
  const SANITIZE_VALUES = process.env.NODE_ENV === 'production' && cds.env.log.sanitize_values !== false
@@ -27,7 +27,6 @@ const _sanitizeHeaders = headers => {
27
27
  }
28
28
 
29
29
  const _executeHttpRequest = async ({ requestConfig, destination, destinationOptions, jwt }) => {
30
- const useCloudSdk = shouldUseCloudSdk(destination)
31
30
  if (typeof destination === 'string') {
32
31
  destination = { destinationName: destination, ...destinationOptions }
33
32
  if (destination.jwt === undefined) destination.jwt = jwt
@@ -48,7 +47,7 @@ const _executeHttpRequest = async ({ requestConfig, destination, destinationOpti
48
47
  const maxBodyLength = cds.env?.remote?.max_body_length
49
48
  if (maxBodyLength) requestConfig.maxBodyLength = maxBodyLength
50
49
 
51
- if (useCloudSdk) {
50
+ if (shouldUseCloudSdk()) {
52
51
  const { executeHttpRequestWithOrigin } = getCloudSdk()
53
52
  // cloud sdk requires a new mechanism to differentiate the priority of headers
54
53
  // "custom" keeps the highest priority as before
@@ -56,6 +55,15 @@ const _executeHttpRequest = async ({ requestConfig, destination, destinationOpti
56
55
  ...requestConfig,
57
56
  headers: { custom: { ...requestConfig.headers } }
58
57
  }
58
+ // selectionStrategy is kept as a plain string in destinationOptions;
59
+ // Cloud SDK needs the corresponding function — resolve it lazily here
60
+ if (typeof destination.selectionStrategy === 'string') {
61
+ const { DestinationSelectionStrategies } = getCloudSdkConnectivity()
62
+ const strategy = DestinationSelectionStrategies[destination.selectionStrategy]
63
+ if (typeof strategy !== 'function')
64
+ cds.error`Unsupported destination selection strategy "${destination.selectionStrategy}".`
65
+ destination = { ...destination, selectionStrategy: strategy }
66
+ }
59
67
  if (LOG._debug) LOG.debug('Executing via @sap-cloud-sdk/http-client.')
60
68
  return executeHttpRequestWithOrigin(destination, sdkConfig, { fetchCsrfToken: false })
61
69
  }
@@ -270,8 +278,10 @@ module.exports.run = async (requestConfig, options) => {
270
278
 
271
279
  if (kind === 'hcql') {
272
280
  if (response.headers?.['content-type']?.includes('application/octet-stream')) return response.data
273
- let { data = [], affected } = response.data
281
+ let { data = [], affected, $count } = response.data
274
282
  if (affected !== undefined) data.affected = affected
283
+ if ($count == null && response.headers['x-total-count']) $count = Number(response.headers['x-total-count'])
284
+ if ($count !== undefined) data.$count = $count
275
285
  return data
276
286
  }
277
287
 
@@ -1,5 +1,4 @@
1
1
  const cds = require('../../cds')
2
- const { findLocalDestinations } = require('./fetchClient')
3
2
 
4
3
  const _require = module => {
5
4
  try {
@@ -39,14 +38,8 @@ const isCloudSdkInstalled = () => {
39
38
  return _cloudSdkInstalled
40
39
  }
41
40
 
42
- const shouldUseCloudSdk = destination => {
43
- // Native node fetch for named destinations is supported only if locally resolvable via process.env.destinations
44
- const _destination = typeof destination === 'string' ? findLocalDestinations(destination)[0] : destination
45
- if (!_destination?.url) return true
46
- if (_destination.authentication && !(_destination.authentication in { NoAuthentication: 1, BasicAuthentication: 1 }))
47
- return true
48
- // here, it would be _possible_ to use native fetch
49
- // explicit config?
41
+ const shouldUseCloudSdk = () => {
42
+ // Explicit config takes priority
50
43
  if (cds.env.remote?.native_fetch != null) return !cds.env.remote.native_fetch
51
44
  // if cloud sdk is there, use it
52
45
  return isCloudSdkInstalled()