@sap/cds-dk 6.0.4 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/bin/add.js +29 -16
  3. package/bin/compile/index.js +6 -1
  4. package/bin/fix-redirects.js +4 -2
  5. package/bin/init.js +5 -0
  6. package/bin/login.js +8 -2
  7. package/bin/pull.js +58 -0
  8. package/bin/push.js +52 -0
  9. package/bin/subscribe.js +45 -0
  10. package/lib/bind/bindingUtil.js +1 -2
  11. package/lib/client/activate.js +1 -1
  12. package/lib/client/auth_manager.js +7 -3
  13. package/lib/client/extend.js +1 -1
  14. package/lib/client/helper/cf_helper.js +1 -0
  15. package/lib/client/helper/url_helper.js +7 -3
  16. package/lib/client/index.js +1 -1
  17. package/lib/client/params.js +4 -2
  18. package/lib/client/pull.js +51 -0
  19. package/lib/client/push.js +49 -0
  20. package/lib/client/settings_manager.js +74 -21
  21. package/lib/compile/openapi/csdl2openapi.js +135 -163
  22. package/lib/compile/openapi/index.js +0 -1
  23. package/lib/import/common.js +9 -1
  24. package/lib/import/odata/metadataconverter/MetadataConverter.js +17 -4
  25. package/lib/import/odata/v2parser.js +0 -1
  26. package/lib/import/odata/v4parser.js +103 -29
  27. package/lib/import/openapi/importOpenAPI.js +3 -3
  28. package/lib/init/constants.js +9 -3
  29. package/lib/init/template/_merging/registry-mta.js +290 -0
  30. package/lib/init/template/approuter/index.js +22 -32
  31. package/lib/init/template/auditlog/index.js +7 -9
  32. package/lib/init/template/extensibility/files/cds.package.json +7 -0
  33. package/lib/init/template/extensibility/files/cds.package.json.hbs +9 -0
  34. package/lib/init/template/extensibility/files/xs-security.json.hbs +26 -0
  35. package/lib/init/template/extensibility/index.js +48 -0
  36. package/lib/init/template/hana/files/java/cdsrc.json.hbs +1 -1
  37. package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +2 -2
  38. package/lib/init/template/hana/files/mta.yaml.hbs +10 -0
  39. package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +1 -1
  40. package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +2 -2
  41. package/lib/init/template/hana/index.js +74 -61
  42. package/lib/init/template/kibana-logging/index.js +31 -37
  43. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +14 -14
  44. package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
  45. package/lib/init/template/mta/index.js +13 -7
  46. package/lib/init/template/mtx/index.js +2 -142
  47. package/lib/init/template/multitenancy/files/cds.package.json +7 -0
  48. package/lib/init/template/multitenancy/files/cds.package.json.hbs +9 -0
  49. package/lib/init/template/{mtx → multitenancy}/files/dependencies.package.json +1 -1
  50. package/lib/init/template/multitenancy/files/java/.cdsrc.json +19 -0
  51. package/lib/init/template/multitenancy/files/java/package.json +31 -0
  52. package/lib/init/template/{mtx → multitenancy}/files/mta.yaml.hbs +13 -6
  53. package/lib/init/template/multitenancy/files/xs-security.json.hbs +18 -0
  54. package/lib/init/template/multitenancy/index.js +109 -0
  55. package/lib/init/template/nodejs/files/package.json.hbs +3 -0
  56. package/lib/init/template/templateBase.js +2 -1
  57. package/lib/init/template/toggles/files/cds.package.json +7 -0
  58. package/lib/init/template/toggles/files/cds.package.json.hbs +9 -0
  59. package/lib/init/template/toggles/index.js +24 -0
  60. package/lib/init/template/xsuaa/files/mta.yaml.hbs +10 -0
  61. package/lib/init/template/xsuaa/index.js +44 -33
  62. package/lib/init/util/projectReader.js +12 -7
  63. package/lib/init/util/templateUtil.js +112 -110
  64. package/lib/k8s/ChartAdder.js +11 -3
  65. package/lib/k8s/ChartBuilder.js +6 -0
  66. package/lib/k8s/buildModel.js +1 -3
  67. package/lib/k8s/connectivity/index.js +5 -5
  68. package/lib/k8s/deployment/index.js +2 -4
  69. package/lib/k8s/deployment/subchart/Chart.yaml +1 -1
  70. package/lib/k8s/deployment/subchart/templates/_helpers.tpl +22 -11
  71. package/lib/k8s/deployment/subchart/templates/deployment.yaml +12 -5
  72. package/lib/k8s/deployment/subchart/templates/network-policy.yaml +3 -1
  73. package/lib/k8s/deployment/subchart/templates/pod-disruption-budget.yaml +1 -1
  74. package/lib/k8s/deployment/subchart/values.md +812 -0
  75. package/lib/k8s/deployment/subchart/values.schema.json +125 -30
  76. package/lib/k8s/deployment/subchart/values.yaml +7 -3
  77. package/lib/k8s/hana-deployer/index.js +10 -0
  78. package/lib/k8s/hana-deployer/templates/hana-deployer-job.yaml +8 -0
  79. package/lib/k8s/html5-apps-deployer/index.js +10 -0
  80. package/lib/k8s/html5-apps-deployer/templates/html5-apps-deployer-job.yaml +8 -0
  81. package/lib/k8s/index.js +2 -2
  82. package/lib/k8s/resources/helm/chart/templates/_deployment_helpers.tpl +1 -159
  83. package/lib/k8s/resources/helm/chart/templates/_helpers.tpl +0 -33
  84. package/lib/k8s/resources/helm/chart/templates/_sapcp_helpers.tpl +1 -1
  85. package/lib/k8s/resources/helm/chart/values.schema.json +449 -0
  86. package/lib/lint/Linter.js +155 -158
  87. package/lib/lint/io.js +13 -5
  88. package/npm-shrinkwrap.json +510 -86
  89. package/package.json +5 -4
  90. package/lib/init/template/_merging/existences.js +0 -297
  91. package/lib/init/template/mtx/files/cds.package.json +0 -12
  92. package/lib/init/template/mtx/files/cds.package.json.hbs +0 -14
  93. package/lib/init/template/mtx/files/java/.cdsrc.json +0 -17
  94. package/lib/init/template/mtx/files/java/package.json +0 -43
  95. package/lib/init/template/mtx/files/java/server.js +0 -30
  96. package/lib/init/template/mtx/files/xs-security.json.hbs +0 -48
  97. package/lib/lint/.eslintrc.js +0 -3
@@ -9,9 +9,10 @@ const { getAppFromSuggestions, getAppName, getSubdomain } = require('./helper/cf
9
9
  const isBas = require('./helper/env_helper');
10
10
  const Logger = require('./helper/logging');
11
11
  const Question = require('./helper/question');
12
- const { defaultSchema, extractSubdomain, schemaRegex } = require('./helper/url_helper');
12
+ const { httpSchema, httpsSchema, extractSubdomain, schemaRegex, localhostRegex } = require('./helper/url_helper');
13
13
  const { ParamCollection, Persistence } = require('./params');
14
14
  const { capitalize } = require('./helper/string_helper');
15
+ const axios = require('axios');
15
16
 
16
17
  const CONFIG_SUBDIRS = {
17
18
  linux: '.config',
@@ -31,7 +32,8 @@ const KEYRING_DESC = {
31
32
  }
32
33
 
33
34
  const MTX_FULLY_QUALIFIED = 'com.sap.cds.mtx';
34
- const OAUTH_PATH = '/mtx/v1/oauth/token';
35
+ const OAUTH_PATH_OLD_MTX = '/mtx/v1/oauth/token';
36
+ const OAUTH_PATH_STREAMLINED_MTX = '/-/cds/login/token';
35
37
 
36
38
  const SETTINGS_DIR = path.join(os.homedir(), CONFIG_SUBDIRS[os.platform()] || '', MTX_FULLY_QUALIFIED);
37
39
  const SETTINGS_FILE = 'projects.json';
@@ -88,7 +90,7 @@ async function getSubdomainFromCfAndNotify(appName) {
88
90
  return subdomain;
89
91
  }
90
92
 
91
- function getTokenBaseUrl(params, renewUrl) {
93
+ async function getTokenBaseUrl(params, renewUrl) {
92
94
  if (params.has('tokenUrl') && !renewUrl) {
93
95
  return params.get('tokenUrl');
94
96
  }
@@ -96,8 +98,30 @@ function getTokenBaseUrl(params, renewUrl) {
96
98
  throw new Error('Failed to determine token URL: app URL not given');
97
99
  }
98
100
  const baseUrl = new URL(params.get('appUrl'));
99
- baseUrl.pathname = baseUrl.pathname.replace(/\/?$/, OAUTH_PATH);
100
- return baseUrl.toString();
101
+ const cleanPathname = pathname => baseUrl.pathname.replace(/\/?$/, pathname);
102
+ const getBaseUrl = pathname => {
103
+ const url = new URL(baseUrl.toString());
104
+ url.pathname = cleanPathname(pathname);
105
+ return url;
106
+ };
107
+
108
+ let existingPath;
109
+ const oauthPaths = [OAUTH_PATH_STREAMLINED_MTX/*, OAUTH_PATH_OLD_MTX*/]; // The old MTX does not support HEAD requests
110
+ for (const path of oauthPaths) {
111
+ try {
112
+ await axios.head(getBaseUrl(path).toString());
113
+ existingPath = path;
114
+ break;
115
+ } catch (e) {
116
+ if (e.response?.status === 404) {
117
+ continue;
118
+ } else {
119
+ throw Error(`Failed with root cause ${e.message}`);
120
+ }
121
+ }
122
+ }
123
+ existingPath = existingPath ?? OAUTH_PATH_OLD_MTX;
124
+ return getBaseUrl(existingPath).toString();
101
125
  }
102
126
 
103
127
  function getKeyringAccountName(params) {
@@ -134,7 +158,16 @@ class SettingsManager {
134
158
  static async saveSettings(params) {
135
159
  Logger.debug(`Saving settings for project ${params.get('projectFolder')}`);
136
160
 
137
- await this._saveToFile(params.get('projectFolder'), params.toValueMap(Persistence.setting));
161
+ const paramsMap = params.toValueMap(Persistence.setting);
162
+ if (localhostRegex.test(params.get('appUrl'))) {
163
+ Logger.log(`Saving username${(params.get('isEmptyPassword') ? ' and empty-password hint' : '')} with project settings.`);
164
+ } else {
165
+ // Save only against localhost for security reasons.
166
+ Logger.debug('Not saving username because app is not recognized to run on localhost.');
167
+ delete paramsMap.username;
168
+ delete paramsMap.isEmptyPassword;
169
+ }
170
+ await this._saveToFile(params.get('projectFolder'), paramsMap);
138
171
 
139
172
  if (!params.has('token')) {
140
173
  return;
@@ -173,15 +206,22 @@ class SettingsManager {
173
206
 
174
207
  static async updateUrls(params, logout, loadedAppUrl) {
175
208
  async function addAppUrlAndSubdomain() {
176
- if (params.has('appUrl') && !schemaRegex.test(params.get('appUrl'))) {
177
- params.set('appUrl', defaultSchema + params.get('appUrl'));
178
- Logger.debug(`Added schema to app URL: ${params.get('appUrl')}`);
209
+ if (params.has('appUrl')) {
210
+ const appUrl = params.get('appUrl');
211
+ if (!schemaRegex.test(appUrl)) {
212
+ if (localhostRegex.test(appUrl)) {
213
+ params.set('appUrl', httpSchema + appUrl);
214
+ } else {
215
+ params.set('appUrl', httpsSchema + appUrl);
216
+ }
217
+ Logger.debug(`Added schema to app URL: ${params.get('appUrl')}`);
218
+ }
179
219
  }
180
220
  if (!logout) {
181
221
  if (!params.has('appUrl')) {
182
222
  Logger.debug('App URL not given');
183
223
  await getAppUrlAndSubdomainFromSuggestions(params);
184
- } else if (!params.has('subdomain')) {
224
+ } else if (!params.has('subdomain') && !localhostRegex.test(params.get('appUrl'))) {
185
225
  Logger.debug('Subdomain not given');
186
226
  const appName = await getAppName(params.get('appUrl'));
187
227
  if (appName) {
@@ -193,24 +233,25 @@ class SettingsManager {
193
233
  throw new Error('App URL not given. Please specify it or log in to Cloud Foundry and repeat this command.');
194
234
  }
195
235
  if (!params.has('subdomain')) {
196
- params.set('subdomain', extractSubdomain(params.get('appUrl')));
197
- if (!params.has('subdomain')) {
236
+ const subdomain = extractSubdomain(params.get('appUrl'));
237
+ if (!subdomain) {
198
238
  throw new Error('Subdomain not given');
199
239
  }
200
- Logger.log(`Subdomain determined from app URL: ${params.get('subdomain')}`);
240
+ params.set('subdomain', subdomain);
241
+ Logger.log(`Subdomain determined from app URL: ${subdomain}`);
201
242
  }
202
243
  }
203
- function renewTokenUrl() {
244
+ async function renewTokenUrl() {
204
245
  const renewUrl = params.get('appUrl') !== loadedAppUrl;
205
246
  if (!params.get('tokenUrl') || renewUrl) {
206
- params.set('tokenUrl', getTokenBaseUrl(params, renewUrl));
247
+ params.set('tokenUrl', await getTokenBaseUrl(params, renewUrl));
207
248
  }
208
249
  }
209
250
 
210
251
  await addAppUrlAndSubdomain();
211
252
 
212
253
  if (!logout) {
213
- renewTokenUrl();
254
+ await renewTokenUrl();
214
255
  }
215
256
  }
216
257
 
@@ -236,13 +277,16 @@ class SettingsManager {
236
277
 
237
278
  static async addAuth(params, logout) {
238
279
  async function addPassword() {
239
- params.set('password', await Question.askQuestion('Password: ', undefined, true));
240
- if (params.get('password') === '') {
241
- throw new Error('Password cannot be empty');
280
+ if (params.get('isEmptyPassword')) {
281
+ params.set('password', '');
282
+ } else {
283
+ params.set('password', await Question.askQuestion('Password: ', undefined, true));
284
+ console.log();
242
285
  }
243
286
  }
244
287
  async function addClientSecret() {
245
288
  params.set('clientsecret', await Question.askQuestion('clientsecret: ', undefined, true));
289
+ console.log();
246
290
  if (params.get('clientsecret') === '') {
247
291
  throw new Error('clientsecret cannot be empty');
248
292
  }
@@ -250,7 +294,7 @@ class SettingsManager {
250
294
  async function addPasscode() {
251
295
  const prompt = `Passcode${params.get('passcodeUrl') ? ' (visit ' + params.get('passcodeUrl') + ' to generate)' : ''}: `;
252
296
  params.set('passcode', await Question.askQuestion(prompt, undefined, true));
253
- console.log(); // DON'T: process.stdout.write('\n');
297
+ console.log();
254
298
  if (params.get('passcode') === '') {
255
299
  throw new Error('Passcode cannot be empty');
256
300
  }
@@ -288,10 +332,19 @@ class SettingsManager {
288
332
  }
289
333
 
290
334
  if (params.has('username')) {
291
- if (!params.get('password') && !logout) {
335
+ if (!params.has('password') && !logout) {
292
336
  await addPassword();
293
337
  }
338
+ if (params.get('password') === '') {
339
+ params.set('isEmptyPassword', true);
340
+ // TODO check password only in production env
341
+ // throw new Error('Password cannot be empty');
342
+ } else {
343
+ params.delete('isEmptyPassword');
344
+ }
294
345
  return;
346
+ } else {
347
+ params.delete('isEmptyPassword');
295
348
  }
296
349
 
297
350
  if (params.get('clientid') && !params.get('clientsecret') && !logout) {