@sap/cds-dk 8.2.3 → 8.3.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 (51) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/bin/cds.js +5 -4
  3. package/bin/compile/index.js +6 -2
  4. package/bin/deploy/index.js +22 -3
  5. package/bin/import.js +24 -14
  6. package/bin/repl.js +21 -8
  7. package/bin/util/fuzzySearch.js +8 -5
  8. package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +1 -1
  9. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +1 -1
  10. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +1 -1
  11. package/lib/build/plugins/helm/files/subcharts/web-application/Chart.yaml +1 -1
  12. package/lib/build/plugins/helm/files/subcharts/web-application/templates/virtual-service.yaml +23 -12
  13. package/lib/build/plugins/helm/files/subcharts/web-application/values.schema.json +1 -1
  14. package/lib/build/plugins/helm/files/subcharts/web-application/values.yaml +2 -2
  15. package/lib/compile/to-mermaid.js +87 -0
  16. package/lib/import/common.js +2 -2
  17. package/lib/import/importapi.js +3 -3
  18. package/lib/import/openapi/importOpenAPI.js +42 -4
  19. package/lib/init/merge.js +2 -2
  20. package/lib/init/mvn.js +2 -2
  21. package/lib/init/projectReader.js +2 -0
  22. package/lib/init/registries/xs-app.js +10 -0
  23. package/lib/init/template/cf-manifest/index.js +2 -0
  24. package/lib/init/template/cloud-logging/files/mta.yaml.hbs +13 -2
  25. package/lib/init/template/cloud-logging/files/{package.json → package.json.hbs} +5 -1
  26. package/lib/init/template/cloud-logging/index.js +4 -3
  27. package/lib/init/template/data/as-csv.js +6 -0
  28. package/lib/init/template/data/as-json.js +8 -1
  29. package/lib/init/template/data/index.js +1 -1
  30. package/lib/init/template/destination/files/mta.yaml.hbs +5 -5
  31. package/lib/init/template/dynatrace/files/mta.yaml.hbs +22 -6
  32. package/lib/init/template/dynatrace/files/package.json.hbs +5 -2
  33. package/lib/init/template/dynatrace/files/values.yaml +15 -0
  34. package/lib/init/template/dynatrace/index.js +10 -5
  35. package/lib/init/template/handler/index.js +16 -1
  36. package/lib/init/template/helm/files/values.yaml.hbs +2 -2
  37. package/lib/init/template/helm/index.js +6 -1
  38. package/lib/init/template/html5-repo/files/app-package.json.hbs +3 -1
  39. package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +7 -0
  40. package/lib/init/template/html5-repo/index.js +3 -1
  41. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  42. package/lib/init/template/mta/index.js +2 -0
  43. package/lib/init/template/typer/index.js +2 -1
  44. package/lib/init/template/workzone-standard/files/manifest.json.hbs +15 -1
  45. package/lib/init/template/workzone-standard/files/mta.yaml.hbs +11 -2
  46. package/lib/init/template/workzone-standard/files/xs-app.json.hbs +18 -0
  47. package/lib/init/template/workzone-standard/index.js +25 -7
  48. package/lib/mtx/auth_manager.js +7 -5
  49. package/lib/mtx/util/errors.js +4 -4
  50. package/npm-shrinkwrap.json +36 -19
  51. package/package.json +1 -1
@@ -89,10 +89,12 @@ module.exports = new class ProjectReader {
89
89
  * @property {boolean} hasApprouter Indicates if the project uses the SAP Application Router.
90
90
  * @property {boolean} hasHtml5Repo Indicates if the project uses the SAP BTP HTML5 Application Repository.
91
91
  * @property {boolean} hasPortal Indicates if the project uses the SAP Cloud Portal service.
92
+ * @property {boolean} hasWorkzone Indicates if the project uses the SAP Build Work Zone service.
92
93
  * @property {boolean} hasDestination Indicates if the project uses the SAP BTP Destination service.
93
94
  * @property {boolean} hasMTXRoute Indicates if the approuter should have a multitenant route.
94
95
  * @property {boolean} hasMTXRouteJava Indicates if the approuter should have a multitenant subscription route (java).
95
96
  * @property {boolean} hasMalwareScanner Indicates if the project uses the SAP Malware Scanning service.
97
+ * @property {boolean} hasDynatrace Indicates if the project uses Dynatrace.
96
98
  *
97
99
  */
98
100
 
@@ -0,0 +1,10 @@
1
+
2
+
3
+ const odataApi = {
4
+ in: 'routes',
5
+ where: { target: '/odata/$1' }
6
+ }
7
+
8
+ module.exports = {
9
+ odataApi
10
+ }
@@ -3,6 +3,7 @@ const cds = require('../../../cds')
3
3
  const { exists } = require('../../../cds').utils
4
4
  const { readProject } = require('../../projectReader')
5
5
  const { renderAndCopy } = require('../../template')
6
+ const mvn = require('../../mvn')
6
7
  const MANIFEST_FILE = 'manifest.yml'
7
8
  const SERVICES_MANIFEST_FILE = 'services-manifest.yml'
8
9
 
@@ -29,5 +30,6 @@ module.exports = class CfManifestTemplate extends require('../../plugin') {
29
30
  async run() {
30
31
  const project = readProject()
31
32
  await renderAndCopy(join(__dirname, 'files'), cds.root, project)
33
+ if (project.isJava) await mvn.add('CF')
32
34
  }
33
35
  }
@@ -3,6 +3,17 @@ modules:
3
3
  - name: {{appName}}-srv
4
4
  type: {{language}}
5
5
  path: {{& srvPath}}
6
+ {{#isJava}}
7
+ properties:
8
+ JBP_CONFIG_JAVA_OPTS:
9
+ from_environment: false
10
+ java_opts: >
11
+ -javaagent:META-INF/.sap_java_buildpack/otel_agent/opentelemetry-javaagent.jar
12
+ -Dotel.javaagent.extensions=META-INF/.sap_java_buildpack/otel_agent_extension/otel-agent-ext-java.jar
13
+ OTEL_METRICS_EXPORTER: cloud-logging
14
+ OTEL_TRACES_EXPORTER: cloud-logging
15
+ OTEL_LOGS_EXPORTER: none
16
+ {{/isJava}}
6
17
  requires:
7
18
  - name: {{appName}}-cloud-logging
8
19
  - name: {{appName}}-mtx
@@ -21,5 +32,5 @@ resources:
21
32
  service: cloud-logging
22
33
  service-plan: {{cloudLoggingServicePlan}}
23
34
  config:
24
- ingest_otlp:
25
- enabled: true
35
+ ingest_otlp:
36
+ enabled: true
@@ -8,7 +8,11 @@
8
8
  },
9
9
  "cds": {
10
10
  "requires": {
11
- "telemetry": "to-cloud-logging"
11
+ "[{{profile}}]": {
12
+ "telemetry": {
13
+ "kind": "to-cloud-logging"
14
+ }
15
+ }
12
16
  }
13
17
  }
14
18
  }
@@ -30,9 +30,10 @@ module.exports = class extends require('../../plugin') {
30
30
  }
31
31
 
32
32
  async run() {
33
- const { hasTelemetry } = readProject()
34
- if (cds.cli.options['with-telemetry'] || hasTelemetry) {
35
- await merge(__dirname, 'files/package.json').into('package.json')
33
+ const project = readProject(), { hasTelemetry, isNodejs } = project
34
+ if (isNodejs && (cds.cli.options['with-telemetry'] || hasTelemetry)) {
35
+ project.profile ??= 'production'
36
+ await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
36
37
  await sort('package.json', 'dependencies')
37
38
  }
38
39
  }
@@ -39,6 +39,12 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
39
39
  }
40
40
  record.push(...Object.values(value))
41
41
  }
42
+ else if (element.is_struct) {
43
+ if (i === 0) {
44
+ header.push(...Object.keys(value).map(structField => name + '_' + structField))
45
+ }
46
+ record.push(...Object.values(value))
47
+ }
42
48
  else {
43
49
  if (i === 0) header.push(name)
44
50
  if (Array.isArray(value)) { // `array of` / `many`
@@ -121,9 +121,16 @@ function dataForField(element, entity, csn, record, data, parentEntity, depth, r
121
121
  else if (element.items?.type) // `array of` / `many` with simple type
122
122
  return [ dataForField(element.items, entity, csn, record, data, null, depth+1, referenceData) ]
123
123
 
124
+ if (element.is_struct) {
125
+ let struct = {}
126
+ for (const el of element.elements) {
127
+ struct[el.name] = dataForField(el, entity, csn, record, data, null, depth+1, referenceData)
128
+ }
129
+ return struct
130
+ }
131
+
124
132
  const type = element._type || element.type
125
133
  switch (type) {
126
- case undefined: return
127
134
  case 'cds.Time':
128
135
  return '22:59:53'
129
136
 
@@ -67,7 +67,7 @@ module.exports = class DataTemplate extends require('../../plugin') {
67
67
  : getDefaultTargetFolder(env)
68
68
  dest = resolve(cds.root, dest)
69
69
 
70
- let csn = await cds.load(cds.env.roots) // normal CSN
70
+ let csn = await cds.load([cds.env.roots, join(`${cds.env.folders.srv}`, `external`) ]) // normal CSN. Default paths and models imported with `cds import`
71
71
  // Skip of unused reuse entities like Language, Country, Currency
72
72
  csn = cds.minify(csn)
73
73
  csn = cds.reflect(csn) // reflected model (adds additional helper functions)
@@ -31,14 +31,14 @@ resources:
31
31
  destinations:
32
32
  - Name: {{appName}}-srv-api
33
33
  URL: ~{srv-api/srv-url}
34
- Authentication: OAuth2UserTokenExchange
34
+ Authentication: NoAuthentication
35
35
  Type: HTTP
36
36
  ProxyType: Internet
37
37
  HTML5.ForwardAuthToken: true
38
38
  HTML5.DynamicDestination: true
39
- - Authentication: NoAuthentication
40
- Name: ui5
41
- ProxyType: Internet
42
- Type: HTTP
39
+ - Name: ui5
43
40
  URL: https://ui5.sap.com
41
+ Authentication: NoAuthentication
42
+ Type: HTTP
43
+ ProxyType: Internet
44
44
  {{/hasHtml5Repo}}
@@ -3,8 +3,28 @@ modules:
3
3
  - name: {{appName}}-srv
4
4
  type: {{language}}
5
5
  path: {{& srvPath}}
6
+ {{#isJava}}
7
+ properties:
8
+ JBP_CONFIG_JAVA_OPTS:
9
+ from_environment: false
10
+ java_opts: >
11
+ -javaagent:META-INF/.sap_java_buildpack/otel_agent/opentelemetry-javaagent.jar
12
+ -Dotel.javaagent.extensions=META-INF/.sap_java_buildpack/otel_agent_extension/otel-agent-ext-java.jar
13
+ -Dotel.javaagent.extension.sap.cf.binding.dynatrace.metrics.token-name=ingest_apitoken
14
+ OTEL_METRICS_EXPORTER: dynatrace
15
+ OTEL_TRACES_EXPORTER: none
16
+ OTEL_LOGS_EXPORTER: none
17
+ {{/isJava}}
6
18
  requires:
7
19
  - name: {{appName}}-dynatrace
20
+ parameters:
21
+ config:
22
+ tokens:
23
+ - name: ingest_apitoken
24
+ scopes:
25
+ - openTelemetryTrace.ingest
26
+ - metrics.ingest
27
+
8
28
  - name: {{appName}}-mtx
9
29
  type: nodejs
10
30
  path: {{#isNodejs}}gen/{{/isNodejs}}mtx/sidecar
@@ -15,10 +35,6 @@ resources:
15
35
  type: org.cloudfoundry.managed-service
16
36
  parameters:
17
37
  service: dynatrace
18
- service-plan: standard
38
+ service-plan: environment
19
39
  config:
20
- tokens:
21
- - name: ingest_apitoken
22
- scopes:
23
- - openTelemetryTrace.ingest
24
- - metrics.ingest
40
+ environment_name: {{appName}}
@@ -2,13 +2,16 @@
2
2
  "dependencies": {
3
3
  "@cap-js/telemetry": ">=0",
4
4
  "@opentelemetry/exporter-metrics-otlp-proto": "^0"{{#hasHelm}},
5
- "@opentelemetry/exporter-trace-otlp-proto": "^0",
6
5
  "@opentelemetry/host-metrics": "^0"
7
6
  {{/hasHelm}}
8
7
  },
9
8
  "cds": {
10
9
  "requires": {
11
- "telemetry": "to-dynatrace"
10
+ "[{{profile}}]": {
11
+ "telemetry": {
12
+ "kind": "to-dynatrace"
13
+ }
14
+ }
12
15
  }
13
16
  }
14
17
  }
@@ -0,0 +1,15 @@
1
+ srv:
2
+ bindings:
3
+ dynatrace:
4
+ serviceInstanceName: dynatrace
5
+ parameters:
6
+ tokens:
7
+ - name: ingest_apitoken
8
+ scopes:
9
+ - openTelemetryTrace.ingest
10
+ - metrics.ingest
11
+ dynatrace:
12
+ serviceOfferingName: dynatrace
13
+ servicePlanName: environment
14
+ parameters:
15
+ environment_name: DYNATRACE # (Mandatory) maximum of 16 characters and can only comprise of uppercase letters and digits.
@@ -10,20 +10,21 @@ module.exports = class extends require('../../plugin') {
10
10
  }
11
11
 
12
12
  async canRun() {
13
- const { hasMta, hasHelm, hasHelmUnifiedRuntime } = readProject()
14
- if ((hasHelmUnifiedRuntime || hasHelm) && !hasMta) throw `'cds add dynatrace' is not available for Kyma yet`
15
13
  return true
16
14
  }
17
15
 
18
16
  async run() {
19
17
  const project = readProject()
20
- await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
21
- await sort('package.json', 'dependencies')
18
+ if (project.isNodejs) {
19
+ project.profile ??= 'production'
20
+ await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
21
+ await sort('package.json', 'dependencies')
22
+ }
22
23
  }
23
24
 
24
25
  async combine() {
25
26
  const project = readProject()
26
- const { hasMta, isJava, hasMultitenancy, srvPath } = project
27
+ const { hasMta, hasHelm, hasHelmUnifiedRuntime, isJava, hasMultitenancy, srvPath } = project
27
28
 
28
29
  if (hasMta) {
29
30
  const dynatrace = {
@@ -51,5 +52,9 @@ module.exports = class extends require('../../plugin') {
51
52
  with: project, additions, relationships
52
53
  })
53
54
  }
55
+
56
+ if (hasHelm || hasHelmUnifiedRuntime) {
57
+ await merge(__dirname, 'files', 'values.yaml').into('chart/values.yaml')
58
+ }
54
59
  }
55
60
  }
@@ -5,7 +5,22 @@ const mvn = require('../../mvn')
5
5
  module.exports = class Handler extends require('../../plugin') {
6
6
 
7
7
  static help() {
8
- return 'add handler stubs'
8
+ return 'add handler stubs for actions and functions (Java)'
9
+ }
10
+
11
+ options() {
12
+ return {
13
+ 'filter': {
14
+ type: 'string',
15
+ short: 'f',
16
+ help: `Filter actions or functions by name prefix. Regular expressions are not supported.`
17
+ },
18
+ 'out': {
19
+ type: 'string',
20
+ short: 'o',
21
+ help: 'Specify a custom output directory inside the `handlers` directory. The default is `handlers`.'
22
+ }
23
+ }
9
24
  }
10
25
 
11
26
  canRun() {
@@ -26,6 +26,6 @@ srv:
26
26
  memory: {{#isJava}}1G{{/isJava}}{{^isJava}}500M{{/isJava}}
27
27
  health:
28
28
  liveness:
29
- path: {{#isJava}}/actuator/health{{/isJava}}{{^isJava}}/health{{/isJava}}
29
+ path: {{#isJava}}/actuator/health/liveness{{/isJava}}{{^isJava}}/health{{/isJava}}
30
30
  readiness:
31
- path: {{#isJava}}/actuator/health{{/isJava}}{{^isJava}}/health{{/isJava}}
31
+ path: {{#isJava}}/actuator/health/readiness{{/isJava}}{{^isJava}}/health{{/isJava}}
@@ -5,6 +5,7 @@ const { readProject } = require('../../projectReader')
5
5
  const { merge } = require('../../merge')
6
6
  const { ask4 } = require('../../../util/question')
7
7
  const { execSync } = require('child_process')
8
+ const { mvn } = require('../../add')
8
9
 
9
10
  module.exports = class HelmTemplate extends require('../../plugin') {
10
11
 
@@ -90,10 +91,11 @@ module.exports = class HelmTemplate extends require('../../plugin') {
90
91
  await merge(__dirname, 'files/Chart.yaml.hbs').into('chart/Chart.yaml', { with: project })
91
92
  await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
92
93
  await this._mergeDependency('web-application', 'srv')
94
+ if (project.isJava) await mvn.add('k8s')
93
95
  }
94
96
 
95
97
  async combine() {
96
- const { hasDestination, hasEnterpriseMessaging, hasEnterpriseMessagingShared, hasHana, hasMultitenancy, hasXsuaa, hasHtml5Repo, hasApprouter, hasKafka, hasAttachments, hasPortal, hasMalwareScanner } = readProject()
98
+ const { hasDestination, hasEnterpriseMessaging, hasEnterpriseMessagingShared, hasHana, hasMultitenancy, hasXsuaa, hasHtml5Repo, hasApprouter, hasKafka, hasAttachments, hasPortal, hasMalwareScanner, hasDynatrace } = readProject()
97
99
 
98
100
  if (hasApprouter) {
99
101
  await this._mergeDependency('web-application', 'approuter')
@@ -140,6 +142,9 @@ module.exports = class HelmTemplate extends require('../../plugin') {
140
142
  if (hasMalwareScanner) {
141
143
  await this._mergeDependency('service-instance', 'malware-scanner')
142
144
  }
145
+ if (hasDynatrace) {
146
+ await this._mergeDependency('service-instance', 'dynatrace')
147
+ }
143
148
  }
144
149
 
145
150
  async _mergeDependency(name, alias) {
@@ -8,11 +8,13 @@
8
8
  "start": "ui5 serve"
9
9
  },
10
10
  "devDependencies": {
11
- "@ui5/cli": "^3",
11
+ {{#hasWorkzone}}"@sap/ui5-builder-webide-extension": "^1.1.9",{{/hasWorkzone}}
12
+ "@ui5/cli": "^4",
12
13
  "ui5-task-zipper": "^3"
13
14
  },
14
15
  "ui5": {
15
16
  "dependencies": [
17
+ {{#hasWorkzone}}"@sap/ui5-builder-webide-extension",{{/hasWorkzone}}
16
18
  "ui5-task-zipper"
17
19
  ]
18
20
  }
@@ -13,6 +13,13 @@ builder:
13
13
  - "/test/**"
14
14
  - "/localService/**"
15
15
  customTasks:
16
+ {{#hasWorkzone}}
17
+ - name: webide-extension-task-updateManifestJson
18
+ afterTask: replaceVersion
19
+ configuration:
20
+ appFolder: webapp
21
+ destDir: dist
22
+ {{/hasWorkzone}}
16
23
  - name: ui5-task-zipper
17
24
  afterTask: generateVersionInfo
18
25
  configuration:
@@ -2,6 +2,7 @@ const { join } = require('path')
2
2
  const { readProject } = require('../../projectReader')
3
3
  const { merge } = require('../../merge')
4
4
  const { srv4, html5RepoHost, html5Runtime, appDeployer, approuter, mtxSidecar4 } = require('../../registries/mta')
5
+ const { odataApi } = require('../../registries/xs-app')
5
6
 
6
7
  module.exports = class Html5RepoTemplate extends require('../../plugin') {
7
8
 
@@ -52,7 +53,8 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
52
53
 
53
54
  await Promise.all(apps.map(async ({app}) => {
54
55
  project.app = app
55
- await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { project })
56
+ const additions = [odataApi]
57
+ await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { with: project, additions })
56
58
  }))
57
59
 
58
60
  if (hasMultitenancy) {
@@ -29,7 +29,7 @@ modules:
29
29
  parameters:
30
30
  buildpack: sap_java_buildpack_jakarta
31
31
  readiness-health-check-type: http
32
- readiness-health-check-http-endpoint: /actuator/health
32
+ readiness-health-check-http-endpoint: /actuator/health/readiness
33
33
  properties:
34
34
  SPRING_PROFILES_ACTIVE: cloud,sandbox
35
35
  JBP_CONFIG_COMPONENTS: "jres: ['com.sap.xs.java.buildpack.jre.SAPMachineJRE']"
@@ -5,6 +5,7 @@ const { bold } = require('../../../util/term')
5
5
  const { copyRenderedYAML } = require('../../../util/fs')
6
6
  const { readProject } = require('../../projectReader')
7
7
  const { merge, sort } = require('../../merge')
8
+ const { mvn } = require('../../add')
8
9
 
9
10
  module.exports = class MtaTemplate extends require('../../plugin') {
10
11
 
@@ -23,6 +24,7 @@ module.exports = class MtaTemplate extends require('../../plugin') {
23
24
  }
24
25
  await merge(__dirname, 'files/package.json').into('package.json')
25
26
  await sort('package.json', 'devDependencies')
27
+ if (project.isJava) await mvn.add('cf')
26
28
  }
27
29
 
28
30
  async finalize() {
@@ -1,7 +1,7 @@
1
1
  const { join } = require('path')
2
2
  const { readProject } = require('../../projectReader')
3
3
  const { merge, mergeGitignore } = require('../../merge')
4
- const { warn, dim } = require('../../../util/term')
4
+ const { warn, dim, bold } = require('../../../util/term')
5
5
  const { TYPER } = require('../../constants').OPTIONS
6
6
  const { exists, read } = require('../../../cds').utils
7
7
 
@@ -30,6 +30,7 @@ module.exports = class TyperTemplate extends require('../../plugin') {
30
30
  await merge(template('package.json')).into('package.json')
31
31
  await mergeGitignore('.gitignore', template('gitignore'))
32
32
  console.log(dim(` Adding '@cds-models' to .gitignore to ignore generated types`)) // REVISIT: other facets are silent wrt. what they change
33
+ console.log(dim(' Added new dependencies to the project. Run ') + bold('npm i') + dim(' to install.'))
33
34
  try {
34
35
  await merge(source).into(target)
35
36
  } catch (e) {
@@ -1,6 +1,20 @@
1
1
  {
2
+ "sap.app": {
3
+ "crossNavigation": {
4
+ "inbounds": {
5
+ "{{uiApp}}-display": {
6
+ "semanticObject": "{{uiApp}}",
7
+ "action": "display",
8
+ "signature": {
9
+ "parameters": {},
10
+ "additionalParameters": "allowed"
11
+ }
12
+ }
13
+ }
14
+ }
15
+ },
2
16
  "sap.cloud": {
3
17
  "public": true,
4
- "service": "{{appName}}.service"
18
+ "service": "{{strippedAppName}}.service"
5
19
  }
6
20
  }
@@ -1,5 +1,13 @@
1
1
  ---
2
2
  modules:
3
+ - name: {{appName}}-srv
4
+ type: {{language}}
5
+ path: {{& srvPath}}
6
+ provides:
7
+ - name: srv-api # required by consumers of CAP services (e.g. approuter)
8
+ properties:
9
+ srv-url: ${default-url}
10
+
3
11
  - name: {{appName}}-destinations
4
12
  type: com.sap.application.content
5
13
  requires:
@@ -25,13 +33,14 @@ modules:
25
33
  - Name: {{appName}}-html5-repository
26
34
  ServiceInstanceName: {{appName}}-html5-repo-host
27
35
  ServiceKeyName: {{appName}}-html5-repo-host-key
28
- sap.cloud.service: {{appName}}.service
36
+ sap.cloud.service: {{strippedAppName}}.service
29
37
  - Name: {{appName}}-auth
30
38
  Authentication: OAuth2UserTokenExchange
31
39
  ServiceInstanceName: {{appName}}-auth
32
40
  ServiceKeyName: {{appName}}-auth-key
33
- sap.cloud.service: {{appName}}.service
41
+ sap.cloud.service: {{strippedAppName}}.service
34
42
 
43
+ resources:
35
44
  - name: {{appName}}-destination
36
45
  type: org.cloudfoundry.managed-service
37
46
  parameters:
@@ -0,0 +1,18 @@
1
+ {
2
+ "authenticationMethod": "route",
3
+ "routes": [
4
+ {
5
+ "source": "^/?odata/(.*)$",
6
+ "target": "/odata/$1",
7
+ "destination": "{{appName}}-srv-api",
8
+ {{#hasXsuaa}}"authenticationType": "xsuaa",{{/hasXsuaa}}
9
+ "csrfProtection": true
10
+ },
11
+ {
12
+ "source": "^(.*)$",
13
+ "target": "$1",
14
+ "service": "html5-apps-repo-rt"{{#hasXsuaa}},
15
+ "authenticationType": "xsuaa"{{/hasXsuaa}}
16
+ }
17
+ ]
18
+ }
@@ -2,7 +2,8 @@ const cds = require('../../../cds')
2
2
  const { readProject } = require('../../projectReader')
3
3
  const { merge } = require('../../merge')
4
4
  const { join } = require('path')
5
- const { destination, destinations } = require('../../registries/mta')
5
+ const { destination, destinations, srv4 } = require('../../registries/mta')
6
+ const { odataApi } = require('../../registries/xs-app')
6
7
 
7
8
  module.exports = class extends require('../../plugin') {
8
9
 
@@ -28,19 +29,36 @@ module.exports = class extends require('../../plugin') {
28
29
  async run() {
29
30
  const project = readProject()
30
31
  const { appUIPaths, appPath } = project
31
- await Promise.all(appUIPaths.map(p =>
32
- merge(__dirname, 'files/manifest.json.hbs').into(join(appPath, p, 'webapp/manifest.json'), { project })
33
- ))
32
+ await Promise.all(appUIPaths.map(p => {
33
+ project.uiApp = p
34
+ return merge(__dirname, 'files/manifest.json.hbs').into(join(appPath, p, 'webapp/manifest.json'), { project })
35
+ }))
34
36
  await merge({ cds: { requires: { workzone: true } } }).into('package.json')
35
37
  }
36
38
 
37
39
  async combine() {
38
40
  const project = readProject()
39
- const { hasMta } = project
41
+ const { hasMta, srvPath, apps, appPath } = project
42
+
43
+ await Promise.all(apps.map(async ({app}) => {
44
+ const additions = [odataApi]
45
+ const overwrites = [{
46
+ item: [odataApi, 'destination'],
47
+ withValue: `${project.appName}-srv-api`
48
+ }]
49
+ project.app = app
50
+ await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { with: project, additions, overwrites })
51
+ }))
40
52
 
41
53
  if (hasMta) {
42
- const additions = [destinations, destination]
43
- await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { with: project, additions })
54
+ const srv = srv4(srvPath)
55
+ const additions = [srv, destinations, destination,
56
+ {
57
+ in: [destination, 'requires'],
58
+ where: { name: 'srv-api' }
59
+ }
60
+ ]
61
+ await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { with: project, additions })
44
62
  }
45
63
  }
46
64
  }
@@ -67,7 +67,7 @@ function reqParams(method, params) {
67
67
  }
68
68
 
69
69
  async function fetchToken(params) {
70
- if (params.has('token') || !(params.has('refreshToken') || params.has('passcode') || !params.has('passcodeUrl'))) {
70
+ if (params.has('token') || !(params.has('refreshToken') || params.has('passcode') || params.has('clientid') || !params.has('passcodeUrl'))) {
71
71
  return;
72
72
  }
73
73
 
@@ -99,18 +99,20 @@ async function fetchToken(params) {
99
99
  if (error) {
100
100
  let message;
101
101
  if (REASONS.invalid_scope.test(error.message)) {
102
- message = 'token has invalid scope. Check if your user has the required roles';
102
+ message = 'token has invalid scope. Ensure your user has the required roles';
103
103
  } else if (error.status === 404) {
104
- message = 'token endpoint not found. Check if MTX is running with extensibility enabled';
104
+ message = 'token endpoint not found. Ensure that MTX is running with extensibility enabled';
105
105
  } else if (error.message.includes('<html')) { // should already be caught when fetching passcode URL
106
- message = 'HTML response received. Check if route to MTX is configured correctly in App Router';
106
+ message = 'HTML response received. Ensure the route to MTX is configured correctly in App Router';
107
107
  } else if (error.status === 401) {
108
108
  message = `invalid credentials`;
109
109
  if (params.has('passcode')) {
110
- message += `. Check if passcode is correct`;
110
+ message += `. Ensure the passcode is correct`;
111
111
  if (params.has('passcodeUrl')) {
112
112
  message += `. Passcode URL: ${params.get('passcodeUrl')}`;
113
113
  }
114
+ } else if (params.has('clientid')) {
115
+ message += `. Ensure the client credentials are correct`;
114
116
  }
115
117
  } else {
116
118
  message = 'error on token request';
@@ -5,11 +5,11 @@ function handleHttpError(error, params, { url, command } = {}) {
5
5
  const prefix = `Request to ${url} failed`;
6
6
  switch (error.status) {
7
7
  case 401:
8
- throw getMessage(`${prefix}: invalid authentication.\nRetry with valid passcode${
9
- params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''
10
- } or username/password (required if SaaS app is configured with mocked-auth).`, { error, command });
8
+ throw getMessage(`${prefix}: invalid authentication` + (
9
+ params.has('username') ? `. Ensure that username and password are correct` : ''
10
+ ), { error, command });
11
11
  case 403:
12
- throw getMessage(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command });
12
+ throw getMessage(prefix + ': insufficient authorization. Ensure the user has all necessary roles.', { error, command });
13
13
  case 404:
14
14
  throw getMessage(prefix + ': resource not found.', { error, command });
15
15
  case 422: