@commercetools-frontend/application-config 25.0.0 → 25.2.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.
- package/dist/commercetools-frontend-application-config.cjs.dev.js +128 -96
- package/dist/commercetools-frontend-application-config.cjs.prod.js +128 -96
- package/dist/commercetools-frontend-application-config.esm.js +124 -94
- package/dist/{formatters-2a857809.cjs.prod.js → formatters-4515015b.cjs.prod.js} +11 -14
- package/dist/{formatters-80a6c235.esm.js → formatters-5629a23b.esm.js} +11 -13
- package/dist/{formatters-a09672cf.cjs.dev.js → formatters-5a68b5ac.cjs.dev.js} +11 -14
- package/package.json +4 -4
- package/ssr/dist/commercetools-frontend-application-config-ssr.cjs.dev.js +1 -2
- package/ssr/dist/commercetools-frontend-application-config-ssr.cjs.prod.js +1 -2
- package/ssr/dist/commercetools-frontend-application-config-ssr.esm.js +1 -2
|
@@ -12,8 +12,8 @@ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/ob
|
|
|
12
12
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
13
13
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
14
14
|
var _includesInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/includes');
|
|
15
|
-
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
16
15
|
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
16
|
+
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
17
17
|
var fs$1 = require('node:fs');
|
|
18
18
|
var path = require('node:path');
|
|
19
19
|
var omitEmpty = require('omit-empty-es');
|
|
@@ -31,11 +31,13 @@ var _possibleConstructorReturn = require('@babel/runtime-corejs3/helpers/possibl
|
|
|
31
31
|
var _getPrototypeOf = require('@babel/runtime-corejs3/helpers/getPrototypeOf');
|
|
32
32
|
var _inherits = require('@babel/runtime-corejs3/helpers/inherits');
|
|
33
33
|
var _wrapNativeSuper = require('@babel/runtime-corejs3/helpers/wrapNativeSuper');
|
|
34
|
+
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
34
35
|
var _trimInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/trim');
|
|
35
36
|
var _JSON$stringify = require('@babel/runtime-corejs3/core-js-stable/json/stringify');
|
|
36
|
-
var
|
|
37
|
+
var path$1 = require('path');
|
|
37
38
|
var _reduceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/reduce');
|
|
38
|
-
var
|
|
39
|
+
var _bindInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/bind');
|
|
40
|
+
var formatters = require('./formatters-5a68b5ac.cjs.dev.js');
|
|
39
41
|
var _Set = require('@babel/runtime-corejs3/core-js-stable/set');
|
|
40
42
|
var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-array');
|
|
41
43
|
var Ajv = require('ajv');
|
|
@@ -57,8 +59,8 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
|
|
|
57
59
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
58
60
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
59
61
|
var _includesInstanceProperty__default = /*#__PURE__*/_interopDefault(_includesInstanceProperty);
|
|
60
|
-
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
61
62
|
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
63
|
+
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
62
64
|
var fs__default$1 = /*#__PURE__*/_interopDefault(fs$1);
|
|
63
65
|
var path__default = /*#__PURE__*/_interopDefault(path);
|
|
64
66
|
var omitEmpty__default = /*#__PURE__*/_interopDefault(omitEmpty);
|
|
@@ -66,10 +68,12 @@ var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstancePro
|
|
|
66
68
|
var _parseInt__default = /*#__PURE__*/_interopDefault(_parseInt);
|
|
67
69
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
68
70
|
var _Reflect$construct__default = /*#__PURE__*/_interopDefault(_Reflect$construct);
|
|
71
|
+
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
69
72
|
var _trimInstanceProperty__default = /*#__PURE__*/_interopDefault(_trimInstanceProperty);
|
|
70
73
|
var _JSON$stringify__default = /*#__PURE__*/_interopDefault(_JSON$stringify);
|
|
71
|
-
var
|
|
74
|
+
var path__default$1 = /*#__PURE__*/_interopDefault(path$1);
|
|
72
75
|
var _reduceInstanceProperty__default = /*#__PURE__*/_interopDefault(_reduceInstanceProperty);
|
|
76
|
+
var _bindInstanceProperty__default = /*#__PURE__*/_interopDefault(_bindInstanceProperty);
|
|
73
77
|
var _Set__default = /*#__PURE__*/_interopDefault(_Set);
|
|
74
78
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
75
79
|
var Ajv__default = /*#__PURE__*/_interopDefault(Ajv);
|
|
@@ -146,11 +150,10 @@ const isDynamicAwaitSupported = () => {
|
|
|
146
150
|
const isEsmModule = async cwd => {
|
|
147
151
|
const packagePath = path__default["default"].join(cwd, 'package.json');
|
|
148
152
|
try {
|
|
149
|
-
var _JSON$parse;
|
|
150
153
|
const packageJSON = await fs__default["default"].readFile(packagePath, {
|
|
151
154
|
encoding: 'utf-8'
|
|
152
155
|
});
|
|
153
|
-
return
|
|
156
|
+
return JSON.parse(packageJSON)?.type === 'module';
|
|
154
157
|
} catch (error) {
|
|
155
158
|
return false;
|
|
156
159
|
}
|
|
@@ -170,7 +173,7 @@ const createExplorerFor = async configFileName => {
|
|
|
170
173
|
const loaders = isDynamicAwaitSupported() || (await isEsmModule(process.cwd())) ? cosmiconfig.defaultLoaders : cosmiconfig.defaultLoadersSync;
|
|
171
174
|
return cosmiconfig.cosmiconfig(configFileName, {
|
|
172
175
|
searchStrategy: 'project',
|
|
173
|
-
searchPlaces: [
|
|
176
|
+
searchPlaces: [`${configFileName}.js`, `${configFileName}.cjs`, `${configFileName}.mjs`, `${configFileName}.ts`],
|
|
174
177
|
loaders: {
|
|
175
178
|
'.js': loaders['.js'],
|
|
176
179
|
'.cjs': loaders['.cjs'],
|
|
@@ -185,9 +188,9 @@ const getConfigPath = async () => {
|
|
|
185
188
|
const customApplicationConfigFile = await customApplicationExplorer.search();
|
|
186
189
|
const customViewConfigFile = await customViewExplorer.search();
|
|
187
190
|
if (!customApplicationConfigFile && !customViewConfigFile) {
|
|
188
|
-
throw new Error(
|
|
191
|
+
throw new Error(`Missing or invalid configuration file.`);
|
|
189
192
|
}
|
|
190
|
-
return
|
|
193
|
+
return customApplicationConfigFile?.filepath || customViewConfigFile?.filepath;
|
|
191
194
|
};
|
|
192
195
|
const loadConfig = async applicationPath => {
|
|
193
196
|
const customApplicationExplorer = await createExplorerFor('custom-application-config');
|
|
@@ -195,10 +198,10 @@ const loadConfig = async applicationPath => {
|
|
|
195
198
|
const customApplicationConfigFile = await customApplicationExplorer.search(applicationPath);
|
|
196
199
|
const customViewConfigFile = await customViewExplorer.search(applicationPath);
|
|
197
200
|
if ((!customApplicationConfigFile || !customApplicationConfigFile.config) && (!customViewConfigFile || !customViewConfigFile.config)) {
|
|
198
|
-
throw new MissingOrInvalidConfigError(
|
|
201
|
+
throw new MissingOrInvalidConfigError(`Missing or invalid configuration file.`);
|
|
199
202
|
}
|
|
200
203
|
if (customApplicationConfigFile && customViewConfigFile) {
|
|
201
|
-
throw new MissingOrInvalidConfigError(
|
|
204
|
+
throw new MissingOrInvalidConfigError(`Found configuration files for both Custom Application and Custom View. Please remove one of them.`);
|
|
202
205
|
}
|
|
203
206
|
return customViewConfigFile || customApplicationConfigFile;
|
|
204
207
|
};
|
|
@@ -217,6 +220,11 @@ const variableSyntax = /\${([ ~:\w.'",\-/()@]+?)}/g;
|
|
|
217
220
|
const envRefSyntax = /^env:/g;
|
|
218
221
|
const intlRefSyntax = /^intl:/g;
|
|
219
222
|
const filePathRefSyntax = /^path:/g;
|
|
223
|
+
|
|
224
|
+
// Safe regex pattern escaping function
|
|
225
|
+
const escapeRegExp = string => {
|
|
226
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
227
|
+
};
|
|
220
228
|
const hasVariablePlaceholder = valueOfEnvConfig => typeof valueOfEnvConfig === 'string' &&
|
|
221
229
|
// Using `{regex}.test()` might cause false positives if called multiple
|
|
222
230
|
// times on a global regular expression:
|
|
@@ -227,72 +235,103 @@ Boolean(valueOfEnvConfig.match(variableSyntax));
|
|
|
227
235
|
const isEnvVariablePlaceholder = valueOfPlaceholder => Boolean(valueOfPlaceholder.match(envRefSyntax));
|
|
228
236
|
const isIntlVariablePlaceholder = valueOfPlaceholder => Boolean(valueOfPlaceholder.match(intlRefSyntax));
|
|
229
237
|
const isFilePathVariablePlaceholder = valueOfPlaceholder => Boolean(valueOfPlaceholder.match(filePathRefSyntax));
|
|
230
|
-
const isStructuredJson = message =>
|
|
238
|
+
const isStructuredJson = message => message?.string !== undefined;
|
|
231
239
|
const substituteEnvVariablePlaceholder = (valueOfPlaceholder, matchedString, valueOfEnvConfig, loadingOptions) => {
|
|
232
240
|
const _valueOfPlaceholder$s = valueOfPlaceholder.split(':'),
|
|
233
241
|
_valueOfPlaceholder$s2 = _slicedToArray(_valueOfPlaceholder$s, 2),
|
|
234
242
|
requestedEnvVar = _valueOfPlaceholder$s2[1];
|
|
235
243
|
const hasEnvField = loadingOptions.processEnv.hasOwnProperty(requestedEnvVar);
|
|
236
244
|
if (!hasEnvField) {
|
|
237
|
-
|
|
238
|
-
throw new Error(_concatInstanceProperty__default["default"](_context = "Missing environment variable '".concat(requestedEnvVar, "' specified in config as 'env:")).call(_context, requestedEnvVar, "'."));
|
|
245
|
+
throw new Error(`Missing environment variable '${requestedEnvVar}' specified in config as 'env:${requestedEnvVar}'.`);
|
|
239
246
|
}
|
|
240
|
-
|
|
241
|
-
return valueOfEnvConfig.replace(new RegExp("(".concat(escapedMatchedString, ")+"), 'g'), loadingOptions.processEnv[requestedEnvVar]);
|
|
247
|
+
return valueOfEnvConfig.replace(new RegExp(escapeRegExp(matchedString), 'g'), loadingOptions.processEnv[requestedEnvVar]);
|
|
242
248
|
};
|
|
243
249
|
const substituteIntlVariablePlaceholder = (valueOfPlaceholder, matchedString, valueOfEnvConfig, loadingOptions) => {
|
|
244
250
|
const _valueOfPlaceholder$s3 = valueOfPlaceholder.split(':'),
|
|
245
251
|
_valueOfPlaceholder$s4 = _slicedToArray(_valueOfPlaceholder$s3, 3),
|
|
246
252
|
locale = _valueOfPlaceholder$s4[1],
|
|
247
253
|
requestedIntlMessageId = _valueOfPlaceholder$s4[2];
|
|
248
|
-
const translationsFilePath = require.resolve(
|
|
249
|
-
paths: [
|
|
254
|
+
const translationsFilePath = require.resolve(`./i18n/data/${locale}.json`, {
|
|
255
|
+
paths: [`${loadingOptions.applicationPath}/src`, loadingOptions.applicationPath]
|
|
250
256
|
});
|
|
251
257
|
const translations = require(translationsFilePath);
|
|
252
258
|
const hasIntlMessage = translations.hasOwnProperty(requestedIntlMessageId);
|
|
253
259
|
if (!hasIntlMessage) {
|
|
254
|
-
|
|
255
|
-
throw new Error(_concatInstanceProperty__default["default"](_context2 = _concatInstanceProperty__default["default"](_context3 = "Missing message key '".concat(requestedIntlMessageId, "' specified in config as 'intl:")).call(_context3, locale, ":")).call(_context2, requestedIntlMessageId, "'."));
|
|
260
|
+
throw new Error(`Missing message key '${requestedIntlMessageId}' specified in config as 'intl:${locale}:${requestedIntlMessageId}'.`);
|
|
256
261
|
}
|
|
257
262
|
const translation = translations[requestedIntlMessageId];
|
|
258
263
|
const translationValue = isStructuredJson(translation) ? translation.string : translation;
|
|
259
|
-
|
|
260
|
-
return valueOfEnvConfig.replace(new RegExp("(".concat(escapedMatchedString, ")+"), 'g'), translationValue);
|
|
264
|
+
return valueOfEnvConfig.replace(new RegExp(escapeRegExp(matchedString), 'g'), translationValue);
|
|
261
265
|
};
|
|
262
266
|
const substituteFilePathVariablePlaceholder = (valueOfPlaceholder, matchedString, valueOfEnvConfig, loadingOptions) => {
|
|
263
267
|
const _valueOfPlaceholder$s5 = valueOfPlaceholder.split(':'),
|
|
264
268
|
_valueOfPlaceholder$s6 = _slicedToArray(_valueOfPlaceholder$s5, 2),
|
|
265
269
|
filePathOrModule = _valueOfPlaceholder$s6[1];
|
|
266
|
-
const
|
|
267
|
-
// Relative paths should be resolved from the application folder.
|
|
270
|
+
const resolvedPath = require.resolve(filePathOrModule, {
|
|
268
271
|
paths: [loadingOptions.applicationPath]
|
|
269
|
-
})
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// Security check: Prevent path traversal attacks.
|
|
275
|
+
// require.resolve() already provides protection by only resolving modules
|
|
276
|
+
// accessible from the applicationPath. However, we add an extra layer to
|
|
277
|
+
// prevent access to sensitive system files outside the workspace.
|
|
278
|
+
const normalizedPath = path__default$1["default"].normalize(resolvedPath);
|
|
279
|
+
const applicationPath = path__default$1["default"].normalize(loadingOptions.applicationPath);
|
|
280
|
+
|
|
281
|
+
// Find workspace root by traversing up from applicationPath until we find
|
|
282
|
+
// package.json, pnpm-workspace.yaml, or reach root
|
|
283
|
+
let workspaceRoot = applicationPath;
|
|
284
|
+
let currentPath = applicationPath;
|
|
285
|
+
const rootPath = path__default$1["default"].parse(currentPath).root;
|
|
286
|
+
while (currentPath !== rootPath) {
|
|
287
|
+
const hasPackageJson = fs__default$1["default"].existsSync(path__default$1["default"].join(currentPath, 'package.json'));
|
|
288
|
+
const hasWorkspaceConfig = fs__default$1["default"].existsSync(path__default$1["default"].join(currentPath, 'pnpm-workspace.yaml')) || fs__default$1["default"].existsSync(path__default$1["default"].join(currentPath, 'lerna.json'));
|
|
289
|
+
if (hasPackageJson) {
|
|
290
|
+
workspaceRoot = currentPath;
|
|
291
|
+
if (hasWorkspaceConfig) {
|
|
292
|
+
// Found workspace root
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
currentPath = path__default$1["default"].dirname(currentPath);
|
|
297
|
+
}
|
|
298
|
+
const relativePath = path__default$1["default"].relative(workspaceRoot, normalizedPath);
|
|
299
|
+
|
|
300
|
+
// Path is safe if it's within the workspace root.
|
|
301
|
+
// Use path.relative() to avoid string prefix vulnerabilities (e.g., "/app" vs "/app-evil")
|
|
302
|
+
const isSafePath = !_startsWithInstanceProperty__default["default"](relativePath).call(relativePath, '..') && !path__default$1["default"].isAbsolute(relativePath);
|
|
303
|
+
if (!isSafePath) {
|
|
304
|
+
throw new Error(`Access to files outside workspace directory is not allowed: ${filePathOrModule}`);
|
|
305
|
+
}
|
|
306
|
+
const content = fs__default$1["default"].readFileSync(normalizedPath, {
|
|
270
307
|
encoding: 'utf-8'
|
|
271
308
|
});
|
|
272
|
-
|
|
273
|
-
return valueOfEnvConfig.replace(new RegExp("(".concat(escapedMatchedString, ")+"), 'g'), content);
|
|
309
|
+
return valueOfEnvConfig.replace(new RegExp(escapeRegExp(matchedString), 'g'), content);
|
|
274
310
|
};
|
|
275
311
|
const getValueOfPlaceholder = valueWithPlaceholder => valueWithPlaceholder.replace(variableSyntax, (_match, varName) => _trimInstanceProperty__default["default"](varName).call(varName)).replace(/\s/g, '');
|
|
276
|
-
const substituteVariablePlaceholders = (config, loadingOptions) =>
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
312
|
+
const substituteVariablePlaceholders = (config, loadingOptions) => {
|
|
313
|
+
const result = JSON.parse(_JSON$stringify__default["default"](config), (_key, value) => {
|
|
314
|
+
// Only strings are allowed
|
|
315
|
+
let substitutedValue = value;
|
|
316
|
+
if (hasVariablePlaceholder(substitutedValue)) {
|
|
317
|
+
const matchResult = substitutedValue.match(variableSyntax);
|
|
318
|
+
if (matchResult) {
|
|
319
|
+
_forEachInstanceProperty__default["default"](matchResult).call(matchResult, matchedString => {
|
|
320
|
+
const valueOfPlaceholder = getValueOfPlaceholder(matchedString);
|
|
321
|
+
if (isEnvVariablePlaceholder(valueOfPlaceholder)) {
|
|
322
|
+
substitutedValue = substituteEnvVariablePlaceholder(valueOfPlaceholder, matchedString, substitutedValue, loadingOptions);
|
|
323
|
+
} else if (isIntlVariablePlaceholder(valueOfPlaceholder)) {
|
|
324
|
+
substitutedValue = substituteIntlVariablePlaceholder(valueOfPlaceholder, matchedString, substitutedValue, loadingOptions);
|
|
325
|
+
} else if (isFilePathVariablePlaceholder(valueOfPlaceholder)) {
|
|
326
|
+
substitutedValue = substituteFilePathVariablePlaceholder(valueOfPlaceholder, matchedString, substitutedValue, loadingOptions);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
}
|
|
292
330
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
331
|
+
return substitutedValue;
|
|
332
|
+
});
|
|
333
|
+
return result;
|
|
334
|
+
};
|
|
296
335
|
|
|
297
336
|
var customApplicationSchemaJson = {
|
|
298
337
|
$schema: "http://json-schema.org/draft-07/schema",
|
|
@@ -963,13 +1002,12 @@ const printErrors = errors => {
|
|
|
963
1002
|
return 'No errors';
|
|
964
1003
|
}
|
|
965
1004
|
return _mapInstanceProperty__default["default"](errors).call(errors, error => {
|
|
966
|
-
|
|
967
|
-
const baseMessage = _concatInstanceProperty__default["default"](_context = "".concat(error.instancePath, " ")).call(_context, error.message);
|
|
1005
|
+
const baseMessage = `${error.instancePath} ${error.message}`;
|
|
968
1006
|
switch (error.keyword) {
|
|
969
1007
|
case 'additionalProperties':
|
|
970
|
-
return
|
|
1008
|
+
return `${baseMessage}: ${error.params.additionalProperty}`;
|
|
971
1009
|
case 'enum':
|
|
972
|
-
return
|
|
1010
|
+
return `${baseMessage}: ${error.params.allowedValues.toString()}`;
|
|
973
1011
|
default:
|
|
974
1012
|
return baseMessage;
|
|
975
1013
|
}
|
|
@@ -982,8 +1020,7 @@ const validateConfig = (configType, config) => {
|
|
|
982
1020
|
} else if (configType === LOADED_CONFIG_TYPES.CUSTOM_VIEW) {
|
|
983
1021
|
validation = validateCustomViewConfig;
|
|
984
1022
|
} else {
|
|
985
|
-
|
|
986
|
-
throw new Error(_concatInstanceProperty__default["default"](_context4 = "Invalid config type \"".concat(configType, "\", expected ")).call(_context4, _Object$keys__default["default"](LOADED_CONFIG_TYPES).toString()));
|
|
1023
|
+
throw new Error(`Invalid config type "${configType}", expected ${_Object$keys__default["default"](LOADED_CONFIG_TYPES).toString()}`);
|
|
987
1024
|
}
|
|
988
1025
|
const isValid = validation(config);
|
|
989
1026
|
if (!isValid) {
|
|
@@ -996,9 +1033,9 @@ const validateEntryPointUriPath = config => {
|
|
|
996
1033
|
}
|
|
997
1034
|
};
|
|
998
1035
|
const validateSubmenuLinks = config => {
|
|
999
|
-
var
|
|
1036
|
+
var _context;
|
|
1000
1037
|
const uriPathSet = new _Set__default["default"]();
|
|
1001
|
-
_forEachInstanceProperty__default["default"](
|
|
1038
|
+
_forEachInstanceProperty__default["default"](_context = config.submenuLinks).call(_context, _ref => {
|
|
1002
1039
|
let uriPath = _ref.uriPath;
|
|
1003
1040
|
if (uriPathSet.has(uriPath)) {
|
|
1004
1041
|
throw new Error('Duplicate URI path. Every submenu link must have a unique URI path value');
|
|
@@ -1007,64 +1044,63 @@ const validateSubmenuLinks = config => {
|
|
|
1007
1044
|
});
|
|
1008
1045
|
};
|
|
1009
1046
|
const validateAdditionalOAuthScopes = config => {
|
|
1010
|
-
var
|
|
1047
|
+
var _context2, _context3;
|
|
1011
1048
|
const additionalPermissionNames = new _Set__default["default"]();
|
|
1012
|
-
(
|
|
1049
|
+
((_context2 = config.additionalOAuthScopes) == null ? void 0 : _bindInstanceProperty__default["default"](_context3 = Function.call).call(_context3, _forEachInstanceProperty__default["default"](_context2), _context2))?.(_ref2 => {
|
|
1013
1050
|
let name = _ref2.name,
|
|
1014
1051
|
view = _ref2.view,
|
|
1015
1052
|
manage = _ref2.manage;
|
|
1016
1053
|
if ((_Array$isArray__default["default"](view) && view.length === 0 || !view) && (_Array$isArray__default["default"](manage) && manage.length === 0 || !manage)) {
|
|
1017
|
-
throw new Error(
|
|
1054
|
+
throw new Error(`At least one OAuth Scope for permission group name "${name}" is required`);
|
|
1018
1055
|
} else if (additionalPermissionNames.has(name)) {
|
|
1019
|
-
throw new Error(
|
|
1056
|
+
throw new Error(`Duplicate additional permission group name "${name}". Every additional permission must have a unique name`);
|
|
1020
1057
|
}
|
|
1021
1058
|
if (!name.match(constants.PERMISSION_GROUP_NAME_REGEX)) {
|
|
1022
|
-
throw new Error(
|
|
1059
|
+
throw new Error(`Additional permission group name "${name}" is invalid. The value may be between 2 and 64 characters and only contain alphabetic lowercase characters and non-consecutive hyphens. Leading and trailing hyphens are also not allowed`);
|
|
1023
1060
|
}
|
|
1024
1061
|
additionalPermissionNames.add(name);
|
|
1025
1062
|
});
|
|
1026
1063
|
};
|
|
1027
1064
|
|
|
1028
1065
|
function ownKeys$1(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
1029
|
-
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
1066
|
+
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var _context6, _context7; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context6 = ownKeys$1(Object(t), !0)).call(_context6, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context7 = ownKeys$1(Object(t))).call(_context7, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
1030
1067
|
|
|
1031
1068
|
// The `uriPath` of each submenu link is supposed to be defined relative
|
|
1032
1069
|
// to the `entryPointUriPath`. Computing the full path is done internally to keep
|
|
1033
1070
|
// the configuration simple.
|
|
1034
1071
|
const computeUriPath = (uriPath, entryPointUriPath) => {
|
|
1035
|
-
var _context;
|
|
1036
1072
|
// In case the `uriPath` is only `/`, it means that the link is supposed to be
|
|
1037
1073
|
// treated the same as the main application path. In this case, the return value
|
|
1038
1074
|
// should not contain any unnecessary trailing slash and therefore we use the `entryPointUriPath`.
|
|
1039
1075
|
if (uriPath === '/') return entryPointUriPath;
|
|
1040
1076
|
// In case the `uriPath` is already configured including the `entryPointUriPath`,
|
|
1041
1077
|
// we return the `uriPath` as-is.
|
|
1042
|
-
if (_startsWithInstanceProperty__default["default"](uriPath).call(uriPath,
|
|
1078
|
+
if (_startsWithInstanceProperty__default["default"](uriPath).call(uriPath, `${entryPointUriPath}/`)) return uriPath;
|
|
1043
1079
|
// Return the full path including the `entryPointUriPath` as a prefix.
|
|
1044
|
-
return
|
|
1080
|
+
return `${entryPointUriPath}/${uriPath}`;
|
|
1045
1081
|
};
|
|
1046
1082
|
const getPermissions = appConfig => {
|
|
1047
|
-
var _context2,
|
|
1048
|
-
const additionalResourceAccessKeyToOauthScopeMap = _reduceInstanceProperty__default["default"](
|
|
1083
|
+
var _context, _context2, _context3, _context4;
|
|
1084
|
+
const additionalResourceAccessKeyToOauthScopeMap = _reduceInstanceProperty__default["default"](_context = appConfig.additionalOAuthScopes || []).call(_context, (previousOauthScope, _ref) => {
|
|
1049
1085
|
let name = _ref.name,
|
|
1050
1086
|
view = _ref.view,
|
|
1051
1087
|
manage = _ref.manage;
|
|
1052
1088
|
const formattedResourceKey = formatters.formatEntryPointUriPathToResourceAccessKey(name);
|
|
1053
1089
|
return _objectSpread$1(_objectSpread$1({}, previousOauthScope), {}, {
|
|
1054
|
-
[
|
|
1055
|
-
[
|
|
1090
|
+
[`view${formattedResourceKey}`]: view,
|
|
1091
|
+
[`manage${formattedResourceKey}`]: manage
|
|
1056
1092
|
});
|
|
1057
1093
|
}, {});
|
|
1058
|
-
const additionalPermissionNames = ((
|
|
1094
|
+
const additionalPermissionNames = ((_context2 = appConfig.additionalOAuthScopes) == null ? void 0 : _bindInstanceProperty__default["default"](_context3 = Function.call).call(_context3, _mapInstanceProperty__default["default"](_context2), _context2))?.(_ref2 => {
|
|
1059
1095
|
let name = _ref2.name;
|
|
1060
1096
|
return name;
|
|
1061
|
-
})
|
|
1097
|
+
}) || [];
|
|
1062
1098
|
const permissionKeys = formatters.entryPointUriPathToResourceAccesses(appConfig.entryPointUriPath ||
|
|
1063
1099
|
// In case the `entryPointUriPath` is not defined it is because the
|
|
1064
1100
|
// configuration is for a custom view. In this case we use the
|
|
1065
1101
|
// default entry point uri path.
|
|
1066
1102
|
constants.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH, additionalPermissionNames);
|
|
1067
|
-
const additionalPermissions = _mapInstanceProperty__default["default"](
|
|
1103
|
+
const additionalPermissions = _mapInstanceProperty__default["default"](_context4 = _Object$keys__default["default"](additionalResourceAccessKeyToOauthScopeMap)).call(_context4, additionalResourceAccessKey => ({
|
|
1068
1104
|
name: permissionKeys[additionalResourceAccessKey],
|
|
1069
1105
|
oAuthScopes: additionalResourceAccessKeyToOauthScopeMap[additionalResourceAccessKey]
|
|
1070
1106
|
}));
|
|
@@ -1077,7 +1113,7 @@ const getPermissions = appConfig => {
|
|
|
1077
1113
|
}, ...additionalPermissions];
|
|
1078
1114
|
};
|
|
1079
1115
|
function transformCustomApplicationConfigToData(appConfig) {
|
|
1080
|
-
var
|
|
1116
|
+
var _context5;
|
|
1081
1117
|
validateEntryPointUriPath(appConfig);
|
|
1082
1118
|
validateSubmenuLinks(appConfig);
|
|
1083
1119
|
validateAdditionalOAuthScopes(appConfig);
|
|
@@ -1090,7 +1126,7 @@ function transformCustomApplicationConfigToData(appConfig) {
|
|
|
1090
1126
|
permissions: getPermissions(appConfig),
|
|
1091
1127
|
icon: appConfig.icon,
|
|
1092
1128
|
mainMenuLink: appConfig.mainMenuLink,
|
|
1093
|
-
submenuLinks: _mapInstanceProperty__default["default"](
|
|
1129
|
+
submenuLinks: _mapInstanceProperty__default["default"](_context5 = appConfig.submenuLinks).call(_context5, submenuLink => _objectSpread$1(_objectSpread$1({}, submenuLink), {}, {
|
|
1094
1130
|
uriPath: computeUriPath(submenuLink.uriPath, appConfig.entryPointUriPath)
|
|
1095
1131
|
}))
|
|
1096
1132
|
};
|
|
@@ -1115,12 +1151,11 @@ function transformConfigurationToData(configType, configuration) {
|
|
|
1115
1151
|
} else if (configType === LOADED_CONFIG_TYPES.CUSTOM_VIEW) {
|
|
1116
1152
|
return transformCustomViewConfigToData(configuration);
|
|
1117
1153
|
} else {
|
|
1118
|
-
throw new Error(
|
|
1154
|
+
throw new Error(`Invalid config type: ${configType}`);
|
|
1119
1155
|
}
|
|
1120
1156
|
}
|
|
1121
1157
|
|
|
1122
1158
|
const mapCloudIdentifierToApiUrl = key => {
|
|
1123
|
-
var _context;
|
|
1124
1159
|
switch (key) {
|
|
1125
1160
|
case CLOUD_IDENTIFIERS.GCP_AU:
|
|
1126
1161
|
return MC_API_URLS[CLOUD_IDENTIFIERS.GCP_AU];
|
|
@@ -1137,7 +1172,7 @@ const mapCloudIdentifierToApiUrl = key => {
|
|
|
1137
1172
|
default:
|
|
1138
1173
|
// We would probably never get to this point, as the JSON schema validation
|
|
1139
1174
|
// kicks in before.
|
|
1140
|
-
throw new Error(
|
|
1175
|
+
throw new Error(`Unknown cloud identifier "${key}". Supported values: ${_Object$values__default["default"](CLOUD_IDENTIFIERS).toString()}`);
|
|
1141
1176
|
}
|
|
1142
1177
|
};
|
|
1143
1178
|
const getUniqueValues = function () {
|
|
@@ -1161,10 +1196,10 @@ const getOrThrow = (fn, errorMessage) => {
|
|
|
1161
1196
|
};
|
|
1162
1197
|
|
|
1163
1198
|
function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
1164
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
1199
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context3 = ownKeys(Object(t))).call(_context3, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
1165
1200
|
// TODO: make it configurable.
|
|
1166
1201
|
const developmentPort = 3001;
|
|
1167
|
-
const developmentAppUrl =
|
|
1202
|
+
const developmentAppUrl = `http://localhost:${developmentPort}`;
|
|
1168
1203
|
const getLoadedConfigurationType = configFileName => {
|
|
1169
1204
|
if (_includesInstanceProperty__default["default"](configFileName).call(configFileName, 'custom-view-config')) {
|
|
1170
1205
|
return LOADED_CONFIG_TYPES.CUSTOM_VIEW;
|
|
@@ -1180,7 +1215,6 @@ const omitDevConfigIfEmpty = devConfig => {
|
|
|
1180
1215
|
};
|
|
1181
1216
|
const isCustomViewData = data => data.entryPointUriPath === undefined;
|
|
1182
1217
|
const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
1183
|
-
var _appConfig$env$develo;
|
|
1184
1218
|
let isProd = _ref.isProd,
|
|
1185
1219
|
configurationData = _ref.configurationData,
|
|
1186
1220
|
mcApiUrl = _ref.mcApiUrl,
|
|
@@ -1197,7 +1231,7 @@ const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
|
1197
1231
|
initialProjectKey:
|
|
1198
1232
|
// For the `account` application, we should unset the projectKey.
|
|
1199
1233
|
entryPointUriPath === 'account' ? undefined : appConfig.env.development.initialProjectKey
|
|
1200
|
-
},
|
|
1234
|
+
}, appConfig.env.development?.teamId && _objectSpread({
|
|
1201
1235
|
teamId: appConfig.env.development.teamId
|
|
1202
1236
|
}, isCustomViewData(configurationData) ? {
|
|
1203
1237
|
customViewId: configurationData.id
|
|
@@ -1205,12 +1239,11 @@ const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
|
1205
1239
|
applicationId: configurationData.id
|
|
1206
1240
|
})), {}, {
|
|
1207
1241
|
oAuthScopes: appConfig.oAuthScopes,
|
|
1208
|
-
additionalOAuthScopes: appConfig
|
|
1242
|
+
additionalOAuthScopes: appConfig?.additionalOAuthScopes
|
|
1209
1243
|
}));
|
|
1210
1244
|
if (isCustomViewData(configurationData)) {
|
|
1211
|
-
var _context;
|
|
1212
1245
|
const hostUriPath = appConfig.env.development.hostUriPath;
|
|
1213
|
-
const defaultHostUriPath = oidcConfig.initialProjectKey ?
|
|
1246
|
+
const defaultHostUriPath = oidcConfig.initialProjectKey ? `/${oidcConfig.initialProjectKey}/${entryPointUriPath}` : `/${entryPointUriPath}`;
|
|
1214
1247
|
const hostUrl = new _URL__default["default"](hostUriPath || defaultHostUriPath, developmentAppUrl);
|
|
1215
1248
|
return omitDevConfigIfEmpty({
|
|
1216
1249
|
oidc: oidcConfig,
|
|
@@ -1232,7 +1265,6 @@ const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
|
1232
1265
|
});
|
|
1233
1266
|
};
|
|
1234
1267
|
const getRuntimeEnvironmentConfig = _ref2 => {
|
|
1235
|
-
var _context2;
|
|
1236
1268
|
let isProd = _ref2.isProd,
|
|
1237
1269
|
configurationData = _ref2.configurationData,
|
|
1238
1270
|
additionalAppEnv = _ref2.additionalAppEnv,
|
|
@@ -1251,7 +1283,7 @@ const getRuntimeEnvironmentConfig = _ref2 => {
|
|
|
1251
1283
|
// In development, we prefix the entry point with the "__local" prefix.
|
|
1252
1284
|
// This is important to determine to which URL the MC should redirect to
|
|
1253
1285
|
// after successful login.
|
|
1254
|
-
const applicationIdentifier = isProd ?
|
|
1286
|
+
const applicationIdentifier = isProd ? `${configurationData.id}:${entryPointUriPath}` : `__local:${entryPointUriPath}`;
|
|
1255
1287
|
const developmentConfig = getRuntimeEnvironmentConfigForDevelopment({
|
|
1256
1288
|
isProd,
|
|
1257
1289
|
configurationData,
|
|
@@ -1283,7 +1315,7 @@ const getRuntimeEnvironmentConfig = _ref2 => {
|
|
|
1283
1315
|
// again will result in returning the cached value.
|
|
1284
1316
|
let cachedConfig;
|
|
1285
1317
|
const processConfig = async function () {
|
|
1286
|
-
var
|
|
1318
|
+
var _context;
|
|
1287
1319
|
let _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
1288
1320
|
_ref3$disableCache = _ref3.disableCache,
|
|
1289
1321
|
disableCache = _ref3$disableCache === void 0 ? false : _ref3$disableCache,
|
|
@@ -1302,22 +1334,22 @@ const processConfig = async function () {
|
|
|
1302
1334
|
processEnv
|
|
1303
1335
|
});
|
|
1304
1336
|
const configurationData = transformConfigurationToData(configType, appConfig);
|
|
1305
|
-
const appEnvKey =
|
|
1337
|
+
const appEnvKey = processEnv.MC_APP_ENV ?? processEnv.NODE_ENV ?? 'development';
|
|
1306
1338
|
const isProd = getIsProd(processEnv);
|
|
1307
|
-
const additionalAppEnv =
|
|
1308
|
-
const revision =
|
|
1339
|
+
const additionalAppEnv = appConfig.additionalEnv ?? {};
|
|
1340
|
+
const revision = additionalAppEnv.revision ?? '';
|
|
1309
1341
|
|
|
1310
1342
|
// Parse all the supported URLs, which gets implicitly validated
|
|
1311
1343
|
|
|
1312
1344
|
const envAppUrl = isProd ? configurationData.url : developmentAppUrl;
|
|
1313
|
-
const appUrl = getOrThrow(() => new _URL__default["default"](envAppUrl),
|
|
1345
|
+
const appUrl = getOrThrow(() => new _URL__default["default"](envAppUrl), `Invalid application URL: "${envAppUrl}"`);
|
|
1314
1346
|
|
|
1315
1347
|
// Use `||` instead of `??` to include empty string values.
|
|
1316
1348
|
const envCdnUrl = isProd ? appConfig.env.production.cdnUrl || appUrl.href : developmentAppUrl;
|
|
1317
|
-
const cdnUrl = getOrThrow(() => new _URL__default["default"](envCdnUrl),
|
|
1349
|
+
const cdnUrl = getOrThrow(() => new _URL__default["default"](envCdnUrl), `Invalid application CDN URL: "${envCdnUrl}"`);
|
|
1318
1350
|
const mcApiUrl = getOrThrow(() => new _URL__default["default"](
|
|
1319
1351
|
// Use `||` instead of `??` to include empty string values.
|
|
1320
|
-
appConfig.mcApiUrl || mapCloudIdentifierToApiUrl(appConfig.cloudIdentifier)),
|
|
1352
|
+
appConfig.mcApiUrl || mapCloudIdentifierToApiUrl(appConfig.cloudIdentifier)), `Invalid MC API URL: "${appConfig.mcApiUrl}"`);
|
|
1321
1353
|
cachedConfig = {
|
|
1322
1354
|
data: configurationData,
|
|
1323
1355
|
env: getRuntimeEnvironmentConfig({
|
|
@@ -1332,16 +1364,16 @@ const processConfig = async function () {
|
|
|
1332
1364
|
revision
|
|
1333
1365
|
}),
|
|
1334
1366
|
headers: _objectSpread(_objectSpread({}, appConfig.headers), {}, {
|
|
1335
|
-
csp: _objectSpread(_objectSpread({},
|
|
1367
|
+
csp: _objectSpread(_objectSpread({}, appConfig.headers?.csp), {}, {
|
|
1336
1368
|
// We need to make sure the URL we use in these CSP headers have a slash in the end,
|
|
1337
1369
|
// otherwise it might create an invalid value when application/CDN URL points to a
|
|
1338
1370
|
// non-root directory (ex: https://www.my-domain.com/app). This is a valid URL but from
|
|
1339
1371
|
// the CSP point of view, it will say only the file `app` can be used as a source, so
|
|
1340
1372
|
// any other file from that domain will be forbidden. Using the slash (ex: https://www.my-domain.com/app/)
|
|
1341
1373
|
// at the end it's like using a wildcard so anything 'below' `app` will be allowed.
|
|
1342
|
-
'connect-src': getUniqueValues(
|
|
1343
|
-
'script-src': getUniqueValues(
|
|
1344
|
-
'style-src': getUniqueValues(
|
|
1374
|
+
'connect-src': getUniqueValues(appConfig.headers?.csp?.['connect-src'], _concatInstanceProperty__default["default"](_context = [mcApiUrl.origin]).call(_context, isProd ? [`${trimTrailingSlash(appUrl.href)}/`, `${trimTrailingSlash(cdnUrl.href)}/`] : [])),
|
|
1375
|
+
'script-src': getUniqueValues(appConfig.headers?.csp?.['script-src'], isProd ? [`${trimTrailingSlash(appUrl.href)}/`, `${trimTrailingSlash(cdnUrl.href)}/`] : []),
|
|
1376
|
+
'style-src': getUniqueValues(appConfig.headers?.csp?.['style-src'], isProd ? [`${trimTrailingSlash(appUrl.href)}/`, `${trimTrailingSlash(cdnUrl.href)}/`] : [])
|
|
1345
1377
|
})
|
|
1346
1378
|
})
|
|
1347
1379
|
};
|