@sap/cds-dk 10.2.0 → 10.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/bind.js +5 -4
  3. package/bin/completion/scripts/cds.fish +4 -3
  4. package/bin/completion/scripts/cds.ps1 +4 -4
  5. package/bin/completion/scripts/cds.sh +4 -4
  6. package/bin/completion/scripts/cds.zsh +4 -4
  7. package/bin/debug.js +3 -3
  8. package/bin/deploy/index.js +2 -2
  9. package/bin/deploy/to-hana/hana.js +1 -1
  10. package/bin/deploy/to-hana/hdiDeployUtil.js +25 -14
  11. package/bin/up.js +3 -3
  12. package/bin/version.js +1 -1
  13. package/bin/watch/vite-watch.js +12 -6
  14. package/lib/bind/shared.js +1 -1
  15. package/lib/init/index.js +1 -0
  16. package/lib/init/projectReader.js +3 -2
  17. package/lib/init/template/approuter/files/values.yaml.hbs +0 -9
  18. package/lib/init/template/approuter/files/xs-app.json.hbs +0 -22
  19. package/lib/init/template/approuter/index.js +8 -9
  20. package/lib/init/template/html5-repo/index.js +12 -0
  21. package/lib/init/template/react/files/vite.config.{{extension}}.hbs +2 -3
  22. package/lib/init/template/react/index.js +1 -3
  23. package/lib/init/template/sample/files/app/index.html.hbs +18 -0
  24. package/lib/init/template/sample/index.js +1 -0
  25. package/lib/init/template/vue/files/vite.config.{{extension}}.hbs +2 -3
  26. package/lib/init/template/vue/index.js +1 -3
  27. package/lib/mtx/push.js +7 -1
  28. package/node_modules/@cap-js/asyncapi/README.md +4 -14
  29. package/node_modules/@cap-js/asyncapi/cds-plugin.js +12 -0
  30. package/node_modules/@cap-js/asyncapi/index.js +3 -2
  31. package/node_modules/@cap-js/asyncapi/lib/compile/components/messages/index.js +4 -2
  32. package/node_modules/@cap-js/asyncapi/lib/compile/components/schemas/definition.js +11 -1
  33. package/node_modules/@cap-js/asyncapi/lib/compile/components/schemas/utils.js +16 -0
  34. package/node_modules/@cap-js/asyncapi/lib/compile/utils.js +4 -3
  35. package/node_modules/@cap-js/asyncapi/lib/import/importAsyncAPI.js +34 -0
  36. package/node_modules/@cap-js/asyncapi/lib/import/index.js +18 -0
  37. package/node_modules/@cap-js/asyncapi/lib/import/message.js +9 -0
  38. package/node_modules/@cap-js/asyncapi/lib/import/parserContext.js +368 -0
  39. package/node_modules/@cap-js/asyncapi/lib/import/utils.js +85 -0
  40. package/node_modules/@cap-js/asyncapi/package.json +89 -1
  41. package/node_modules/@sap/cds/CHANGELOG.md +10 -0
  42. package/node_modules/@sap/cds/app/index.js +1 -1
  43. package/node_modules/@sap/cds/lib/env/schemas/cds-package.js +0 -2
  44. package/node_modules/@sap/cds/lib/env/schemas/cds-rc.js +3 -3
  45. package/node_modules/@sap/cds/lib/env/schemas/index.js +4 -4
  46. package/node_modules/@sap/cds/lib/utils/cds-utils.js +21 -8
  47. package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/connections.js +45 -39
  48. package/node_modules/@sap/cds/libx/odata/ODataAdapter.js +1 -1
  49. package/node_modules/@sap/cds/libx/queue/TaskRunner.js +22 -5
  50. package/node_modules/@sap/cds/package.json +1 -1
  51. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +8 -0
  52. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  53. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +57 -41
  54. package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +27 -12
  55. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +31 -25
  56. package/node_modules/body-parser/README.md +17 -13
  57. package/node_modules/body-parser/lib/read.js +74 -57
  58. package/node_modules/body-parser/lib/types/json.js +11 -11
  59. package/node_modules/body-parser/lib/types/urlencoded.js +5 -5
  60. package/node_modules/body-parser/lib/utils.js +0 -15
  61. package/node_modules/body-parser/package.json +7 -12
  62. package/node_modules/encodeurl/README.md +14 -0
  63. package/node_modules/encodeurl/index.js +5 -10
  64. package/node_modules/encodeurl/package.json +10 -6
  65. package/node_modules/on-finished/index.js +14 -2
  66. package/node_modules/on-finished/package.json +11 -7
  67. package/node_modules/qs/.editorconfig +1 -1
  68. package/node_modules/qs/CHANGELOG.md +87 -22
  69. package/node_modules/qs/README.md +63 -10
  70. package/node_modules/qs/dist/qs.js +17 -17
  71. package/node_modules/qs/eslint.config.mjs +61 -50
  72. package/node_modules/qs/lib/formats.js +7 -2
  73. package/node_modules/qs/lib/parse.js +29 -10
  74. package/node_modules/qs/lib/stringify.js +5 -3
  75. package/node_modules/qs/lib/utils.js +28 -9
  76. package/node_modules/qs/package.json +6 -6
  77. package/node_modules/qs/test/parse.js +335 -2
  78. package/node_modules/qs/test/stringify.js +222 -0
  79. package/node_modules/qs/test/utils.js +61 -3
  80. package/node_modules/semver/classes/range.js +2 -2
  81. package/node_modules/semver/internal/constants.js +30 -0
  82. package/node_modules/semver/internal/trim-comparator-whitespace.js +438 -0
  83. package/node_modules/semver/package.json +1 -1
  84. package/node_modules/ws/README.md +21 -29
  85. package/node_modules/ws/lib/buffer-util.js +13 -2
  86. package/node_modules/ws/lib/sender.js +4 -1
  87. package/node_modules/ws/lib/websocket.js +8 -3
  88. package/node_modules/ws/package.json +1 -1
  89. package/package.json +1 -1
  90. package/node_modules/on-finished/HISTORY.md +0 -98
package/CHANGELOG.md CHANGED
@@ -6,6 +6,19 @@ This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/).
8
8
 
9
+ ## Version 10.2.1 - tbd
10
+
11
+ ### Fixed
12
+
13
+ - `cds watch` now falls back to globally installed Vite when it is unavailable locally.
14
+ - `cds push` now rejects extension projects without a non-empty string `name` in `package.json`.
15
+ - `cds add html5-repo approuter` opens React and sample UIs from the application root without Portal.
16
+ - `cds add approuter` uses each HTML5 Repository UI's own `xs-app.json` for UI routing and forwards remaining requests to the backend.
17
+ - `cds add approuter` uses TCP health probes on Kyma to avoid caching an empty HTML5 app list during deployment.
18
+ - `cds add` configures dependencies for all space-separated facets.
19
+ - `cds version` and `cds -v` now work on systems without the `which` command.
20
+ - `cds deploy --to hana` now retries intermittent HANA connection failures before TLS is established up to three times.
21
+
9
22
  ## Version 10.2.0 - 2026-10-21
10
23
 
11
24
  ### Added
package/bin/bind.js CHANGED
@@ -3,7 +3,7 @@ const { FILE } = require('./completion')
3
3
 
4
4
  module.exports = Object.assign(cds_bind, {
5
5
  staticCompletions: () => ({
6
- '--on': ['cf', 'k8s'],
6
+ '--on': ['cf', 'k8s', 'kyma'],
7
7
  '--for': ['development', 'production', 'hybrid'],
8
8
  '--out': FILE(),
9
9
  '--output-file': FILE(),
@@ -38,7 +38,7 @@ module.exports = Object.assign(cds_bind, {
38
38
 
39
39
  Profile to store binding information. Defaults to *hybrid*.
40
40
 
41
- *-n | --on* cf | k8s
41
+ *-n | --on* cf | k8s | kyma
42
42
 
43
43
  Target platform (Cloud Foundry or Kubernetes) to bind to.
44
44
  Defaults to *k8s* when Helm charts are present and no *mta.yaml* exists, otherwise *cf*.
@@ -95,8 +95,9 @@ const { readProject } = require('../lib/init/projectReader')
95
95
 
96
96
  async function cds_bind(args, options) {
97
97
  const { hasKyma, hasMta } = readProject()
98
- const onKyma = cds.cli.options.on === 'k8s' || (hasKyma && !hasMta && cds.cli.options.on !== 'cf')
99
- const { on = onKyma ? 'k8s' : 'cf', 'to-app-services': app, to, out, 'output-file': outputFile, exec, credentials } = options
98
+ const onKyma = ['k8s', 'kyma'].includes(cds.cli.options.on) || (hasKyma && !hasMta && cds.cli.options.on !== 'cf')
99
+ const { on: platform = onKyma ? 'k8s' : 'cf', 'to-app-services': app, to, out, 'output-file': outputFile, exec, credentials } = options
100
+ const on = platform === 'kyma' ? 'k8s' : platform
100
101
 
101
102
  if (exec) {
102
103
  process.env.CDS_ENV ??= 'hybrid'
@@ -95,7 +95,7 @@ complete -c cds -f -n '__fish_seen_subcommand_from bind y' -a '--out'
95
95
  complete -c cds -f -n '__fish_seen_subcommand_from bind y' -a '--output-file'
96
96
  complete -c cds -f -n '__fish_seen_subcommand_from bind y' -a '--to'
97
97
  complete -c cds -f -n '__fish_seen_subcommand_from bind y' -a '--to-app-services'
98
- complete -c cds -f -n '__fish_seen_subcommand_from bind y && __fish_prev_arg_in --on' -a 'cf k8s'
98
+ complete -c cds -f -n '__fish_seen_subcommand_from bind y && __fish_prev_arg_in --on' -a 'cf k8s kyma'
99
99
  complete -c cds -f -n '__fish_seen_subcommand_from bind y && __fish_prev_arg_in --for' -a 'development hybrid production'
100
100
  complete -c cds -f -n '__fish_seen_subcommand_from bindings' -a '--as'
101
101
  complete -c cds -f -n '__fish_seen_subcommand_from bindings && __fish_prev_arg_in --as' -a 'json yaml'
@@ -170,6 +170,7 @@ complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--cf'
170
170
  complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--force'
171
171
  complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--host'
172
172
  complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--k8s'
173
+ complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--kyma'
173
174
  complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--no-devtools'
174
175
  complete -c cds -f -n '__fish_seen_subcommand_from debug' -a '--port'
175
176
  complete -c cds -f -n '__fish_seen_subcommand_from deploy d && __fish_prev_arg_in --out' -a "(__fish_complete_path)"
@@ -195,7 +196,7 @@ complete -c cds -f -n '__fish_seen_subcommand_from deploy d && string match -q -
195
196
  complete -c cds -f -n '__fish_seen_subcommand_from deploy d && string match -q -- "-*" (commandline -ct)' -a '--with-mocks'
196
197
  complete -c cds -f -n '__fish_seen_subcommand_from deploy d && string match -q -- "-*" (commandline -ct)' -a '--xdry'
197
198
  complete -c cds -f -n '__fish_seen_subcommand_from deploy d && __fish_prev_arg_in --to' -a 'hana sqlite'
198
- complete -c cds -f -n '__fish_seen_subcommand_from deploy d && __fish_prev_arg_in --on' -a 'cf k8s'
199
+ complete -c cds -f -n '__fish_seen_subcommand_from deploy d && __fish_prev_arg_in --on' -a 'cf k8s kyma'
199
200
  complete -c cds -f -n '__fish_seen_subcommand_from deploy d && __fish_prev_arg_in --for' -a 'development hybrid production'
200
201
  complete -c cds -f -n '__fish_seen_subcommand_from env e' -a '--for'
201
202
  complete -c cds -f -n '__fish_seen_subcommand_from env e' -a '--json'
@@ -542,7 +543,7 @@ complete -c cds -f -n '__fish_seen_subcommand_from up && __fish_prev_arg_in --ov
542
543
  complete -c cds -f -n '__fish_seen_subcommand_from up' -a '--namespace'
543
544
  complete -c cds -f -n '__fish_seen_subcommand_from up' -a '--overlay'
544
545
  complete -c cds -f -n '__fish_seen_subcommand_from up' -a '--to'
545
- complete -c cds -f -n '__fish_seen_subcommand_from up && __fish_prev_arg_in --to' -a 'cf k8s'
546
+ complete -c cds -f -n '__fish_seen_subcommand_from up && __fish_prev_arg_in --to' -a 'cf k8s kyma'
546
547
  complete -c cds -f -n '__fish_seen_subcommand_from upgrade' -a '--at'
547
548
  complete -c cds -f -n '__fish_seen_subcommand_from upgrade' -a '--fix'
548
549
  complete -c cds -f -n '__fish_seen_subcommand_from upgrade' -a '--local'
@@ -49,7 +49,7 @@ $_CDS_COMPLETIONS = @{
49
49
  };
50
50
  '__optionValues' = @{
51
51
  'bind' = @{
52
- '--on' = @('cf', 'k8s');
52
+ '--on' = @('cf', 'k8s', 'kyma');
53
53
  '--for' = @('development', 'hybrid', 'production');
54
54
  '--out' = ':file';
55
55
  '--output-file' = ':file';
@@ -86,7 +86,7 @@ $_CDS_COMPLETIONS = @{
86
86
  };
87
87
  'deploy' = @{
88
88
  '--to' = @('hana', 'sqlite');
89
- '--on' = @('cf', 'k8s');
89
+ '--on' = @('cf', 'k8s', 'kyma');
90
90
  '--for' = @('development', 'hybrid', 'production');
91
91
  '--out' = ':file';
92
92
  '--vcap-file' = ':file:json';
@@ -165,7 +165,7 @@ $_CDS_COMPLETIONS = @{
165
165
  '--with' = ':dir'
166
166
  };
167
167
  'up' = @{
168
- '--to' = @('cf', 'k8s');
168
+ '--to' = @('cf', 'k8s', 'kyma');
169
169
  '--overlay' = ':file:mtaext'
170
170
  };
171
171
  'version' = @{
@@ -199,7 +199,7 @@ $_CDS_COMPLETIONS = @{
199
199
  'build' = @('--dest', '--for', '--log-level', '--no-clean', '--no-ws-pack', '--options-model', '--opts', '--project', '--src', '--ws', '--ws-pack');
200
200
  'compile' = @('--all', '--asyncapi:merged', '--beta', '--clean', '--conceptual', '--dest', '--dialect', '--docs', '--files', '--flavor', '--for', '--from', '--lang', '--locations', '--log-level', '--min', '--odata-version', '--openapi:config-file', '--openapi:diagram', '--openapi:servers', '--openapi:url', '--parse', '--plain', '--resolved', '--service', '--sort', '--sources', '--sql-dialect', '--to');
201
201
  'completion' = @('--add', '--curr', '--line', '--prev', '--profile', '--remove', '--shell');
202
- 'debug' = @('--cf', '--force', '--host', '--k8s', '--no-devtools', '--port');
202
+ 'debug' = @('--cf', '--force', '--host', '--k8s', '--kyma', '--no-devtools', '--port');
203
203
  'deploy' = @('--auto-undeploy', '--delta-from', '--dry', '--for', '--model-only', '--no-build', '--no-save', '--on', '--out', '--resolve-bindings', '--script', '--store-credentials', '--to', '--tunnel-address', '--vcap-file', '--with-auto-schema-evolution', '--with-mocks', '--xdry');
204
204
  'env' = @('--for', '--json', '--keys', '--list', '--mocked', '--process-env', '--properties', '--raw', '--resolve-bindings', '--sources');
205
205
  'eval' = @('--quiet', '--silent');
@@ -64,7 +64,7 @@ _completeCds()
64
64
  build) COMPREPLY=( $(compgen -W ""--dest" "--for" "--log-level" "--no-clean" "--no-ws-pack" "--options-model" "--opts" "--project" "--src" "--ws" "--ws-pack"" -- "$current") ) ;;
65
65
  compile) COMPREPLY=( $(compgen -W ""--all" "--asyncapi:merged" "--beta" "--clean" "--conceptual" "--dest" "--dialect" "--docs" "--files" "--flavor" "--for" "--from" "--lang" "--locations" "--log-level" "--min" "--odata-version" "--openapi:config-file" "--openapi:diagram" "--openapi:servers" "--openapi:url" "--parse" "--plain" "--resolved" "--service" "--sort" "--sources" "--sql-dialect" "--to"" -- "$current") ) ;;
66
66
  completion) COMPREPLY=( $(compgen -W ""--add" "--curr" "--line" "--prev" "--profile" "--remove" "--shell"" -- "$current") ) ;;
67
- debug) COMPREPLY=( $(compgen -W ""--cf" "--force" "--host" "--k8s" "--no-devtools" "--port"" -- "$current") ) ;;
67
+ debug) COMPREPLY=( $(compgen -W ""--cf" "--force" "--host" "--k8s" "--kyma" "--no-devtools" "--port"" -- "$current") ) ;;
68
68
  deploy) COMPREPLY=( $(compgen -W ""--auto-undeploy" "--delta-from" "--dry" "--for" "--model-only" "--no-build" "--no-save" "--on" "--out" "--resolve-bindings" "--script" "--store-credentials" "--to" "--tunnel-address" "--vcap-file" "--with-auto-schema-evolution" "--with-mocks" "--xdry"" -- "$current") ) ;;
69
69
  env) COMPREPLY=( $(compgen -W ""--for" "--json" "--keys" "--list" "--mocked" "--process-env" "--properties" "--raw" "--resolve-bindings" "--sources"" -- "$current") ) ;;
70
70
  eval) COMPREPLY=( $(compgen -W ""--quiet" "--silent"" -- "$current") ) ;;
@@ -102,7 +102,7 @@ _completeCds()
102
102
  case "$cmd" in
103
103
  bind)
104
104
  case "$previous" in
105
- --on) COMPREPLY=( $(compgen -W ""cf" "k8s"" -- "$current") ) ; return 0 ;;
105
+ --on) COMPREPLY=( $(compgen -W ""cf" "k8s" "kyma"" -- "$current") ) ; return 0 ;;
106
106
  --for) COMPREPLY=( $(compgen -W ""development" "production" "hybrid"" -- "$current") ) ; return 0 ;;
107
107
  --out) COMPREPLY=( $(compgen -f -- "$current") ) ; return 0 ;;
108
108
  --output-file) COMPREPLY=( $(compgen -f -- "$current") ) ; return 0 ;;
@@ -143,7 +143,7 @@ _completeCds()
143
143
  deploy)
144
144
  case "$previous" in
145
145
  --to) COMPREPLY=( $(compgen -W ""sqlite" "hana"" -- "$current") ) ; return 0 ;;
146
- --on) COMPREPLY=( $(compgen -W ""cf" "k8s"" -- "$current") ) ; return 0 ;;
146
+ --on) COMPREPLY=( $(compgen -W ""cf" "k8s" "kyma"" -- "$current") ) ; return 0 ;;
147
147
  --for) COMPREPLY=( $(compgen -W ""development" "production" "hybrid"" -- "$current") ) ; return 0 ;;
148
148
  --out) COMPREPLY=( $(compgen -f -- "$current") ) ; return 0 ;;
149
149
  --vcap-file) COMPREPLY=( $(compgen -f -- "$current" | grep -E '\.(json)$') ) ; return 0 ;;
@@ -218,7 +218,7 @@ _completeCds()
218
218
  esac ;;
219
219
  up)
220
220
  case "$previous" in
221
- --to) COMPREPLY=( $(compgen -W ""cf" "k8s"" -- "$current") ) ; return 0 ;;
221
+ --to) COMPREPLY=( $(compgen -W ""cf" "k8s" "kyma"" -- "$current") ) ; return 0 ;;
222
222
  --overlay) COMPREPLY=( $(compgen -f -- "$current" | grep -E '\.(mtaext)$') ) ; return 0 ;;
223
223
  esac ;;
224
224
  version)
@@ -61,7 +61,7 @@ _completeCds() {
61
61
  build) compadd -S '' -- "--dest" "--for" "--log-level" "--no-clean" "--no-ws-pack" "--options-model" "--opts" "--project" "--src" "--ws" "--ws-pack" ;;
62
62
  compile) compadd -S '' -- "--all" "--asyncapi:merged" "--beta" "--clean" "--conceptual" "--dest" "--dialect" "--docs" "--files" "--flavor" "--for" "--from" "--lang" "--locations" "--log-level" "--min" "--odata-version" "--openapi:config-file" "--openapi:diagram" "--openapi:servers" "--openapi:url" "--parse" "--plain" "--resolved" "--service" "--sort" "--sources" "--sql-dialect" "--to" ;;
63
63
  completion) compadd -S '' -- "--add" "--curr" "--line" "--prev" "--profile" "--remove" "--shell" ;;
64
- debug) compadd -S '' -- "--cf" "--force" "--host" "--k8s" "--no-devtools" "--port" ;;
64
+ debug) compadd -S '' -- "--cf" "--force" "--host" "--k8s" "--kyma" "--no-devtools" "--port" ;;
65
65
  deploy) compadd -S '' -- "--auto-undeploy" "--delta-from" "--dry" "--for" "--model-only" "--no-build" "--no-save" "--on" "--out" "--resolve-bindings" "--script" "--store-credentials" "--to" "--tunnel-address" "--vcap-file" "--with-auto-schema-evolution" "--with-mocks" "--xdry" ;;
66
66
  env) compadd -S '' -- "--for" "--json" "--keys" "--list" "--mocked" "--process-env" "--properties" "--raw" "--resolve-bindings" "--sources" ;;
67
67
  eval) compadd -S '' -- "--quiet" "--silent" ;;
@@ -95,7 +95,7 @@ _completeCds() {
95
95
  case "$cmd" in
96
96
  bind)
97
97
  case "$previous" in
98
- --on) compadd -S '' -- "cf" "k8s" ; return ;;
98
+ --on) compadd -S '' -- "cf" "k8s" "kyma" ; return ;;
99
99
  --for) compadd -S '' -- "development" "hybrid" "production" ; return ;;
100
100
  --out) compstate[nomatches]='' ; _path_files ; return ;;
101
101
  --output-file) compstate[nomatches]='' ; _path_files ; return ;;
@@ -136,7 +136,7 @@ _completeCds() {
136
136
  deploy)
137
137
  case "$previous" in
138
138
  --to) compadd -S '' -- "hana" "sqlite" ; return ;;
139
- --on) compadd -S '' -- "cf" "k8s" ; return ;;
139
+ --on) compadd -S '' -- "cf" "k8s" "kyma" ; return ;;
140
140
  --for) compadd -S '' -- "development" "hybrid" "production" ; return ;;
141
141
  --out) compstate[nomatches]='' ; _path_files ; return ;;
142
142
  --vcap-file) compstate[nomatches]='' ; _path_files -g '*.json' ; return ;;
@@ -211,7 +211,7 @@ _completeCds() {
211
211
  esac ;;
212
212
  up)
213
213
  case "$previous" in
214
- --to) compadd -S '' -- "cf" "k8s" ; return ;;
214
+ --to) compadd -S '' -- "cf" "k8s" "kyma" ; return ;;
215
215
  --overlay) compstate[nomatches]='' ; _path_files -g '*.mtaext' ; return ;;
216
216
  esac ;;
217
217
  version)
package/bin/debug.js CHANGED
@@ -1,7 +1,7 @@
1
1
  module.exports = Object.assign(debug, {
2
2
  options: ['--port', '--host', '--no-devtools'],
3
3
  shortcuts: ['-p', '-h', undefined, '-f'],
4
- flags: ['--force', '--k8s', '--cf'],
4
+ flags: ['--force', '--k8s', '--cf', '--kyma'],
5
5
  help: `
6
6
  # SYNOPSIS
7
7
 
@@ -36,7 +36,7 @@ module.exports = Object.assign(debug, {
36
36
 
37
37
  Force Cloud Foundry mode.
38
38
 
39
- *--k8s*
39
+ *--k8s* | *--kyma*
40
40
 
41
41
  Force Kubernetes mode. Use env vars KUBE_NAMESPACE or NAMESPACE to select a namespace.
42
42
 
@@ -71,7 +71,7 @@ async function debug() {
71
71
  let attempts = 0
72
72
 
73
73
  const { hasKyma, hasMta } = readProject()
74
- const onKyma = cds.cli.options.k8s || hasKyma && !hasMta && !cds.cli.options.cf
74
+ const onKyma = cds.cli.options.k8s || cds.cli.options.kyma || hasKyma && !hasMta && !cds.cli.options.cf
75
75
 
76
76
  if (!appName) { // local app
77
77
  if (cds.env['project-nature'] === 'java') {
@@ -4,7 +4,7 @@ const { options, flags, shortcuts } = require('./options');
4
4
  module.exports = Object.assign(deploy, {
5
5
  staticCompletions: () => ({
6
6
  '--to': ['sqlite', 'hana'],
7
- '--on': ['cf', 'k8s'],
7
+ '--on': ['cf', 'k8s', 'kyma'],
8
8
  '--for': ['development', 'production', 'hybrid'],
9
9
  '--out': FILE(),
10
10
  '--vcap-file': FILE('json'),
@@ -58,7 +58,7 @@ module.exports = Object.assign(deploy, {
58
58
  Write the DDL statements to the given file.
59
59
  Not available in combination with '--to hana'.
60
60
 
61
- *--on* | *-n* cf|k8s
61
+ *--on* | *-n* cf|k8s|kyma
62
62
 
63
63
  The target platform.
64
64
  Defaults to *k8s* when Helm charts are present and no *mta.yaml* exists, otherwise *cf*.
@@ -149,7 +149,7 @@ Therefore, specifying the CDS model is not required when calling 'cds deploy'.`;
149
149
 
150
150
  const { readProject } = require('../../../lib/init/projectReader')
151
151
  const { hasKyma, hasMta } = readProject()
152
- const onKyma = cds.cli.options.on === 'k8s' || (hasKyma && !hasMta && cds.cli.options.on !== 'cf')
152
+ const onKyma = ['k8s', 'kyma'].includes(cds.cli.options.on) || (hasKyma && !hasMta && cds.cli.options.on !== 'cf')
153
153
  if (onKyma) {
154
154
  const cp = require('node:child_process')
155
155
 
@@ -39,20 +39,31 @@ module.exports = new class HdiDeployUtil {
39
39
  if (options.use_hdb === false) options.use_hdb = undefined
40
40
  deployerEnv.HDI_DEPLOY_OPTIONS = JSON.stringify(options)
41
41
 
42
- return await new Promise((resolve, reject) => {
43
- deploy(dbDir, deployerEnv, (error, response) => {
44
- if (error) return reject(error)
45
- if (response?.exitCode) {
46
- let message = `HDI deployment failed with exit code ${response.exitCode}.`
47
- if (response.signal) message += `. ${response.signal}`
48
- return reject(new Error(message))
49
- }
50
- return resolve()
51
- }, {
52
- stderrCB: buffer => console.error(buffer.toString()),
53
- stdoutCB: buffer => console.log(buffer.toString())
54
- })
55
- })
42
+ for (let attempt = 0; ; attempt++) {
43
+ const response = await new Promise((resolve, reject) => {
44
+ deploy(dbDir, deployerEnv, (error, response) => {
45
+ if (error) return reject(error)
46
+ resolve(response)
47
+ }, {
48
+ stderrCB: buffer => console.error(buffer.toString()),
49
+ stdoutCB: buffer => console.log(buffer.toString())
50
+ })
51
+ })
52
+ if (!response?.exitCode) return
53
+
54
+ const errors = response.deployerMessages?.filter(({ severity }) => severity === 'ERROR')
55
+ const retryable = errors?.length && errors.every(({ message }) =>
56
+ /Could not connect to any host:.*Client network socket disconnected before secure TLS connection was established/.test(message))
57
+ if (attempt >= 3 || response.signal || !retryable) {
58
+ let message = `HDI deployment failed with exit code ${response.exitCode}.`
59
+ if (response.signal) message += `. ${response.signal}`
60
+ throw new Error(message)
61
+ }
62
+
63
+ const delay = 2000 * 2 ** attempt
64
+ console.warn(`HANA connection interrupted before TLS was established. Retrying HDI deployment in ${delay / 1000}s (${attempt + 1}/3).`)
65
+ await new Promise(resolve => setTimeout(resolve, delay))
66
+ }
56
67
  }
57
68
 
58
69
  _loadHdiDeployLib(cwd) {
package/bin/up.js CHANGED
@@ -2,7 +2,7 @@ const { FILE } = require('./completion');
2
2
 
3
3
  module.exports = Object.assign(up, {
4
4
  staticCompletions: () => ({
5
- '--to': ['cf', 'k8s'],
5
+ '--to': ['cf', 'k8s', 'kyma'],
6
6
  '--overlay': FILE('mtaext')
7
7
  }),
8
8
  options: ['--to', '--namespace', '--overlay'],
@@ -17,7 +17,7 @@ module.exports = Object.assign(up, {
17
17
 
18
18
  # OPTIONS
19
19
 
20
- *-2* | *--to* cf|k8s
20
+ *-2* | *--to* cf|k8s|kyma
21
21
 
22
22
  The platform to deploy to.
23
23
 
@@ -124,7 +124,7 @@ const _mtaextForOverlay = overlay => {
124
124
  async function up() {
125
125
  const project = readProject()
126
126
  const { approuterPath, html5DeployerPath, apps, appName, hasApprouter, hasXsuaa, isMonorepoMicroservice, hasKyma, hasMta, k8s } = project
127
- const toKyma = cds.cli.options.to === 'k8s' || hasKyma && !hasMta, toCf = !toKyma
127
+ const toKyma = ['k8s', 'kyma'].includes(cds.cli.options.to) || hasKyma && !hasMta, toCf = !toKyma
128
128
 
129
129
  if (cds.cli.options.overlay && toKyma) {
130
130
  console.log(warn(`Ignoring --overlay ${cds.cli.options.overlay} (Cloud Foundry only)`))
package/bin/version.js CHANGED
@@ -84,7 +84,7 @@ async function node_versions(o) {
84
84
  // Call npm root and npm ls in parallel...
85
85
  const [ [npm_version], [npm_exec], [npm_root_g],[npm_root_l], lines ] = await Promise.all ([
86
86
  $`npm --version`,
87
- process.platform === 'win32' ? $`where npm.cmd` : $`which npm`,
87
+ process.platform === 'win32' ? $`where npm.cmd` : $`command -v npm`,
88
88
  $`npm root --global`,
89
89
  $`npm root --local`,
90
90
  $`npm ls -lp ${
@@ -35,15 +35,21 @@ async function findViteApps() {
35
35
  }
36
36
 
37
37
  async function loadCreateServer(fromPath) {
38
+ let vitePath
38
39
  try {
39
- const vitePath = require.resolve('vite', { paths: [fromPath] })
40
- return (await import(pathToFileURL(vitePath).href)).createServer
41
- } catch(e) {
40
+ vitePath = require.resolve('vite', { paths: [fromPath] })
41
+ } catch (e) {
42
+ if (e.code !== 'MODULE_NOT_FOUND') throw e
43
+ const globalRoot = require('node:child_process').execSync('npm root -g', { cwd: require('node:os').tmpdir() }).toString().trim()
44
+ try {
45
+ vitePath = require.resolve('vite', { paths: [globalRoot] })
46
+ } catch (e) {
42
47
  if (e.code !== 'MODULE_NOT_FOUND') throw e
43
- /* try next path */
48
+ const relative = path.relative(cds.root, fromPath)
49
+ throw `[cds] - Found Vite app in ${relative}, but package "vite" is not installed. Run ${BOLD}npm install -g vite${RESET} to install it.`
50
+ }
44
51
  }
45
- const relative = path.relative(cds.root, fromPath)
46
- throw `[cds] - Found Vite app in ${relative}, but package "vite" is not installed. Run ${BOLD}npm install vite --prefix ${relative}${RESET} to install it.`
52
+ return (await import(pathToFileURL(vitePath).href)).createServer
47
53
  }
48
54
 
49
55
  function collectServicePrefixes() {
@@ -39,7 +39,7 @@ const PreferredKinds = {
39
39
 
40
40
  async function bind(options = {}) {
41
41
  const { hasKyma, hasMta } = readProject()
42
- const onKyma = cds.cli.options.on === 'k8s' || (hasKyma && !hasMta && cds.cli.options.on !== 'cf')
42
+ const onKyma = ['k8s', 'kyma'].includes(cds.cli.options.on) || (hasKyma && !hasMta && cds.cli.options.on !== 'cf')
43
43
  options.on = onKyma ? 'k8s' : 'cf'
44
44
 
45
45
  let on
package/lib/init/index.js CHANGED
@@ -142,6 +142,7 @@ module.exports = class CDSGenerator {
142
142
  validate.projectFolder(this.cwd)
143
143
  }
144
144
  const plugins = command === COMMAND_INIT ? options.add : new Set(facets)
145
+ options.add = plugins
145
146
  await this._fillTemplateList(plugins)
146
147
 
147
148
  const cmds = Object.values(OPTIONS)
@@ -142,8 +142,9 @@ module.exports = new class ProjectReader {
142
142
  isdir(path.join(cds.root, cds.env.folders.app, e)) && isApp(e)
143
143
  )
144
144
  return apps.map((app, i) => {
145
- const manifestPath = path.resolve(cds.root, cds.env.folders.app, app, 'webapp/manifest.json')
146
- const manifest = exists(manifestPath) ? JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) : {}
145
+ const manifestPath = ['webapp/manifest.json', 'public/manifest.json', 'manifest.json']
146
+ .map(p => path.resolve(cds.root, cds.env.folders.app, app, p)).find(exists)
147
+ const manifest = manifestPath ? JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) : {}
147
148
  const inbounds = manifest?.['sap.app']?.crossNavigation?.inbounds
148
149
  const [firstInbound] = Object.values(inbounds ?? { intent: { semanticObject: 'Books', action: 'display' } })
149
150
  const vizId = firstInbound.semanticObject + '-' + firstInbound.action
@@ -16,20 +16,11 @@ approuter:
16
16
  ephemeral-storage: 1G
17
17
  cpu: 500m
18
18
  memory: 500M
19
- {{^hasMultitenancy}}
20
- health:
21
- liveness:
22
- path: /
23
- readiness:
24
- path: /
25
- {{/hasMultitenancy}}
26
- {{#hasMultitenancy}}
27
19
  health:
28
20
  liveness:
29
21
  path: ""
30
22
  readiness:
31
23
  path: ""
32
- {{/hasMultitenancy}}
33
24
  {{=<% %>=}}
34
25
  envFrom:
35
26
  - configMapRef:
@@ -2,9 +2,6 @@
2
2
  {{#hasPortal}}
3
3
  "welcomeFile": "/cp.portal",
4
4
  {{/hasPortal}}
5
- {{#hasHtml5Repo}}
6
- "authenticationMethod": "route",
7
- {{/hasHtml5Repo}}
8
5
  "routes": [
9
6
  {{#hasMTXRoute}}
10
7
  {
@@ -20,30 +17,11 @@
20
17
  "authenticationType": "none"
21
18
  },
22
19
  {{/hasMTXRouteJava}}
23
- {{#hasHtml5Repo}}
24
- {
25
- "source": "^/?odata/(.*)$",
26
- "target": "/odata/$1",
27
- "destination": "srv-api",
28
- {{^hasIas}}{{#hasXsuaa}}"authenticationType": "xsuaa",{{/hasXsuaa}}{{/hasIas}}
29
- {{#hasIas}}"authenticationType": "ias",{{/hasIas}}
30
- "csrfProtection": true
31
- },
32
- {
33
- "source": "^(.*)$",
34
- "target": "$1",
35
- "service": "html5-apps-repo-rt"{{^hasIas}}{{#hasXsuaa}},
36
- "authenticationType": "xsuaa"{{/hasXsuaa}}{{/hasIas}}{{#hasIas}},
37
- "authenticationType": "ias"{{/hasIas}}
38
- }
39
- {{/hasHtml5Repo}}
40
- {{^hasHtml5Repo}}
41
20
  {
42
21
  "source": "^/(.*)$",
43
22
  "target": "$1",
44
23
  "destination": "srv-api",
45
24
  "csrfProtection": true
46
25
  }
47
- {{/hasHtml5Repo}}
48
26
  ]
49
27
  }
@@ -11,7 +11,6 @@ const {
11
11
  approuterMTXRoute,
12
12
  approuterMTXRouteJava // xs-app.json config
13
13
  } = require('../../registries/mta')
14
- const { srvApi, html5RepoApi } = require('../../registries/xs-app')
15
14
  const KymaTemplate = require('../kyma')
16
15
 
17
16
  module.exports = class ApprouterTemplate extends require('../../plugin') {
@@ -36,7 +35,7 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
36
35
  const project = readProject(facet)
37
36
  const {
38
37
  isNodejs, isJava,
39
- hasMTXRoute, hasMTXRouteJava, hasMultitenancy, hasHtml5Repo,
38
+ hasMTXRoute, hasMTXRouteJava, hasMultitenancy,
40
39
  affected, srv, approuterPath
41
40
  } = project
42
41
 
@@ -89,15 +88,15 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
89
88
  await merge(__dirname, '/files/containerize.yaml.hbs').into('containerize.yaml', { with: project, additions })
90
89
  }
91
90
 
92
- if (affected('approuter', 'html5-repo', 'xsuaa', 'ias', 'multitenancy', 'extensibility', 'kyma', 'portal')) {
91
+ if (affected('approuter', 'html5-repo', 'multitenancy', 'extensibility', 'portal')) {
93
92
  const xsAppPath = join(approuterPath, 'xs-app.json')
94
- const additions = hasMTXRoute ? [{ ...approuterMTXRoute, at: 0 }] : []
93
+ const additions = [{ in: 'routes', where: { source: '^/(.*)$', destination: 'srv-api' } }]
94
+ if (hasMTXRoute) additions.push({ ...approuterMTXRoute, at: 0 })
95
95
  if (hasMTXRouteJava) additions.push({ ...approuterMTXRouteJava, at: 0 })
96
- const deletions = []
97
- if (hasHtml5Repo) {
98
- additions.push(srvApi, html5RepoApi)
99
- deletions.push({ item: { in: 'routes', where: { source: '^/(.*)$' } } })
100
- }
96
+ const deletions = [
97
+ { item: { in: 'routes', where: { source: '^/?odata/(.*)$', target: '/odata/$1', destination: 'srv-api' } } },
98
+ { item: { in: 'routes', where: { source: '^(.*)$', target: '$1', service: 'html5-apps-repo-rt' } } }
99
+ ]
101
100
  await merge(__dirname, 'files/xs-app.json.hbs').into(xsAppPath, { project, additions, deletions })
102
101
  }
103
102
  }
@@ -91,6 +91,18 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
91
91
  }
92
92
  }
93
93
 
94
+ if (affected('approuter', 'html5-repo', 'sample', 'react', 'vue', 'portal')) {
95
+ const app = project.apps.find(a => a.app === 'browse') ?? project.apps[0]
96
+ if (app) {
97
+ const xsAppPath = join(project.approuterPath, 'xs-app.json')
98
+ const xsApp = await read(xsAppPath)
99
+ const welcomeFile = `/${app.manifestAppId.replace(/[.-]/g, '')}/index.html`
100
+ if (!xsApp.welcomeFile || ['/fiori-apps.html', welcomeFile].includes(xsApp.welcomeFile)) {
101
+ await merge({ welcomeFile: project.hasPortal ? '/cp.portal' : welcomeFile }).into(xsAppPath, { forceOverwrite: true })
102
+ }
103
+ }
104
+ }
105
+
94
106
  if (affected('multitenancy')) {
95
107
  await merge({ cds: { requires: { 'html5-host': true } } }).into('mtx/sidecar/package.json')
96
108
  }
@@ -1,8 +1,7 @@
1
- import { defineConfig } from 'vite'
2
1
  import AdmZip from 'adm-zip'
3
2
  import react from '@vitejs/plugin-react'
4
3
 
5
- export default defineConfig({
4
+ export default {
6
5
  base: '{{{base}}}',
7
6
  plugins: [react(), {
8
7
  name: 'zip-dist', // zipping ./dist is required for BTP HTML5 repo or Application Frontend deployment
@@ -17,4 +16,4 @@ export default defineConfig({
17
16
  '/odata': 'http://localhost:4004'
18
17
  }
19
18
  }
20
- })
19
+ }
@@ -1,5 +1,5 @@
1
1
  const cds = require('../../../cds')
2
- const { path, sh: $ } = cds.utils
2
+ const { path } = cds.utils
3
3
  const { renderAndCopy } = require('../../template')
4
4
  const { merge } = require('../../merge')
5
5
  const { readProject } = require('../../projectReader')
@@ -50,7 +50,5 @@ module.exports = class ReactTemplate extends require('../../plugin') {
50
50
  if (typescript) await renderAndCopy(path.join(__dirname, 'typescript'), target, { modelsPath })
51
51
  await merge({ scripts: { watch: 'cds watch --exclude app/' }, workspaces: ['app/*'] }).into('package.json')
52
52
  if (typescript) await merge({ compilerOptions: { noEmit: true }, exclude: ['app'] }).into('tsconfig.json')
53
- const root = cds.cli.command === 'init' ? cds.cli.argv[0] : cds.root
54
- await $`npm i --prefix ${root}`
55
53
  }
56
54
  }
@@ -0,0 +1,18 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>{{appName}}</title>
7
+ <style>html, body, body > div, #container, #container-uiarea { height: 100%; }</style>
8
+ <script id="sap-ui-bootstrap" src="https://ui5.sap.com/resources/sap-ui-core.js"
9
+ data-sap-ui-theme="sap_horizon"
10
+ data-sap-ui-compat-version="edge"
11
+ data-sap-ui-async="true"
12
+ data-sap-ui-on-init="module:sap/ui/core/ComponentSupport"
13
+ data-sap-ui-resourceroots='{"{{appName}}.{{app}}":"./"}'></script>
14
+ </head>
15
+ <body class="sapUiBody">
16
+ <div data-sap-ui-component data-name="{{appName}}.{{app}}" data-id="container" data-settings='{"id":"{{app}}"}'></div>
17
+ </body>
18
+ </html>
@@ -35,6 +35,7 @@ module.exports = class SampleTemplate extends require('../../plugin') {
35
35
  for (const uiApp of ['admin-books', 'admin-authors', 'browse', 'genres']) {
36
36
  project.app = uiApp
37
37
  await renderAndCopy(join(__dirname, 'files/app', uiApp), join(app, uiApp), project)
38
+ await renderAndCopy(join(__dirname, 'files/app/index.html.hbs'), join(app, uiApp, 'webapp/index.html'), project)
38
39
  }
39
40
  await Promise.all([
40
41
  copy(join(__dirname, 'files/app/common.cds')).to(app, 'common.cds'),
@@ -1,8 +1,7 @@
1
- import { defineConfig } from 'vite'
2
1
  import AdmZip from 'adm-zip'
3
2
  import vue from '@vitejs/plugin-vue'
4
3
 
5
- export default defineConfig({
4
+ export default {
6
5
  base: '{{{base}}}',
7
6
  plugins: [vue(), {
8
7
  name: 'zip-dist', // zipping ./dist is required for BTP HTML5 repo or Application Frontend deployment
@@ -17,4 +16,4 @@ export default defineConfig({
17
16
  '/odata': 'http://localhost:4004'
18
17
  }
19
18
  }
20
- })
19
+ }
@@ -1,5 +1,5 @@
1
1
  const cds = require('../../../cds')
2
- const { path, sh: $ } = cds.utils
2
+ const { path } = cds.utils
3
3
  const { renderAndCopy } = require('../../template')
4
4
  const { merge } = require('../../merge')
5
5
  const { readProject } = require('../../projectReader')
@@ -48,7 +48,5 @@ module.exports = class VueTemplate extends require('../../plugin') {
48
48
  if (typescript) await renderAndCopy(path.join(__dirname, 'typescript'), target)
49
49
  await merge({ scripts: { watch: 'cds watch --exclude app/' }, workspaces: ['app/*'] }).into('package.json')
50
50
  if (typescript) await merge({ compilerOptions: { noEmit: true }, exclude: ['app'] }).into('tsconfig.json')
51
- const root = cds.cli.command === 'init' ? cds.cli.argv[0] : cds.root
52
- await $`npm i --prefix ${root}`
53
51
  }
54
52
  }