@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
|
@@ -8,8 +8,8 @@ import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/obje
|
|
|
8
8
|
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
|
|
9
9
|
import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
|
|
10
10
|
import _includesInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/includes';
|
|
11
|
-
import _concatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/concat';
|
|
12
11
|
import _URL from '@babel/runtime-corejs3/core-js-stable/url';
|
|
12
|
+
import _concatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/concat';
|
|
13
13
|
import fs$1 from 'node:fs';
|
|
14
14
|
import path, { parse } from 'node:path';
|
|
15
15
|
import omitEmpty from 'omit-empty-es';
|
|
@@ -28,11 +28,13 @@ import _possibleConstructorReturn from '@babel/runtime-corejs3/helpers/esm/possi
|
|
|
28
28
|
import _getPrototypeOf from '@babel/runtime-corejs3/helpers/esm/getPrototypeOf';
|
|
29
29
|
import _inherits from '@babel/runtime-corejs3/helpers/esm/inherits';
|
|
30
30
|
import _wrapNativeSuper from '@babel/runtime-corejs3/helpers/esm/wrapNativeSuper';
|
|
31
|
+
import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
|
|
31
32
|
import _trimInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/trim';
|
|
32
33
|
import _JSON$stringify from '@babel/runtime-corejs3/core-js-stable/json/stringify';
|
|
33
|
-
import
|
|
34
|
+
import path$1 from 'path';
|
|
34
35
|
import _reduceInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/reduce';
|
|
35
|
-
import
|
|
36
|
+
import _bindInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/bind';
|
|
37
|
+
import { f as formatEntryPointUriPathToResourceAccessKey, e as entryPointUriPathToResourceAccesses } from './formatters-5629a23b.esm.js';
|
|
36
38
|
import _Set from '@babel/runtime-corejs3/core-js-stable/set';
|
|
37
39
|
import _Array$isArray from '@babel/runtime-corejs3/core-js-stable/array/is-array';
|
|
38
40
|
import Ajv from 'ajv';
|
|
@@ -112,11 +114,10 @@ const isDynamicAwaitSupported = () => {
|
|
|
112
114
|
const isEsmModule = async cwd => {
|
|
113
115
|
const packagePath = path.join(cwd, 'package.json');
|
|
114
116
|
try {
|
|
115
|
-
var _JSON$parse;
|
|
116
117
|
const packageJSON = await fs.readFile(packagePath, {
|
|
117
118
|
encoding: 'utf-8'
|
|
118
119
|
});
|
|
119
|
-
return
|
|
120
|
+
return JSON.parse(packageJSON)?.type === 'module';
|
|
120
121
|
} catch (error) {
|
|
121
122
|
return false;
|
|
122
123
|
}
|
|
@@ -136,7 +137,7 @@ const createExplorerFor = async configFileName => {
|
|
|
136
137
|
const loaders = isDynamicAwaitSupported() || (await isEsmModule(process.cwd())) ? defaultLoaders : defaultLoadersSync;
|
|
137
138
|
return cosmiconfig(configFileName, {
|
|
138
139
|
searchStrategy: 'project',
|
|
139
|
-
searchPlaces: [
|
|
140
|
+
searchPlaces: [`${configFileName}.js`, `${configFileName}.cjs`, `${configFileName}.mjs`, `${configFileName}.ts`],
|
|
140
141
|
loaders: {
|
|
141
142
|
'.js': loaders['.js'],
|
|
142
143
|
'.cjs': loaders['.cjs'],
|
|
@@ -151,9 +152,9 @@ const getConfigPath = async () => {
|
|
|
151
152
|
const customApplicationConfigFile = await customApplicationExplorer.search();
|
|
152
153
|
const customViewConfigFile = await customViewExplorer.search();
|
|
153
154
|
if (!customApplicationConfigFile && !customViewConfigFile) {
|
|
154
|
-
throw new Error(
|
|
155
|
+
throw new Error(`Missing or invalid configuration file.`);
|
|
155
156
|
}
|
|
156
|
-
return
|
|
157
|
+
return customApplicationConfigFile?.filepath || customViewConfigFile?.filepath;
|
|
157
158
|
};
|
|
158
159
|
const loadConfig = async applicationPath => {
|
|
159
160
|
const customApplicationExplorer = await createExplorerFor('custom-application-config');
|
|
@@ -161,10 +162,10 @@ const loadConfig = async applicationPath => {
|
|
|
161
162
|
const customApplicationConfigFile = await customApplicationExplorer.search(applicationPath);
|
|
162
163
|
const customViewConfigFile = await customViewExplorer.search(applicationPath);
|
|
163
164
|
if ((!customApplicationConfigFile || !customApplicationConfigFile.config) && (!customViewConfigFile || !customViewConfigFile.config)) {
|
|
164
|
-
throw new MissingOrInvalidConfigError(
|
|
165
|
+
throw new MissingOrInvalidConfigError(`Missing or invalid configuration file.`);
|
|
165
166
|
}
|
|
166
167
|
if (customApplicationConfigFile && customViewConfigFile) {
|
|
167
|
-
throw new MissingOrInvalidConfigError(
|
|
168
|
+
throw new MissingOrInvalidConfigError(`Found configuration files for both Custom Application and Custom View. Please remove one of them.`);
|
|
168
169
|
}
|
|
169
170
|
return customViewConfigFile || customApplicationConfigFile;
|
|
170
171
|
};
|
|
@@ -183,6 +184,11 @@ const variableSyntax = /\${([ ~:\w.'",\-/()@]+?)}/g;
|
|
|
183
184
|
const envRefSyntax = /^env:/g;
|
|
184
185
|
const intlRefSyntax = /^intl:/g;
|
|
185
186
|
const filePathRefSyntax = /^path:/g;
|
|
187
|
+
|
|
188
|
+
// Safe regex pattern escaping function
|
|
189
|
+
const escapeRegExp = string => {
|
|
190
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
191
|
+
};
|
|
186
192
|
const hasVariablePlaceholder = valueOfEnvConfig => typeof valueOfEnvConfig === 'string' &&
|
|
187
193
|
// Using `{regex}.test()` might cause false positives if called multiple
|
|
188
194
|
// times on a global regular expression:
|
|
@@ -193,72 +199,103 @@ Boolean(valueOfEnvConfig.match(variableSyntax));
|
|
|
193
199
|
const isEnvVariablePlaceholder = valueOfPlaceholder => Boolean(valueOfPlaceholder.match(envRefSyntax));
|
|
194
200
|
const isIntlVariablePlaceholder = valueOfPlaceholder => Boolean(valueOfPlaceholder.match(intlRefSyntax));
|
|
195
201
|
const isFilePathVariablePlaceholder = valueOfPlaceholder => Boolean(valueOfPlaceholder.match(filePathRefSyntax));
|
|
196
|
-
const isStructuredJson = message =>
|
|
202
|
+
const isStructuredJson = message => message?.string !== undefined;
|
|
197
203
|
const substituteEnvVariablePlaceholder = (valueOfPlaceholder, matchedString, valueOfEnvConfig, loadingOptions) => {
|
|
198
204
|
const _valueOfPlaceholder$s = valueOfPlaceholder.split(':'),
|
|
199
205
|
_valueOfPlaceholder$s2 = _slicedToArray(_valueOfPlaceholder$s, 2),
|
|
200
206
|
requestedEnvVar = _valueOfPlaceholder$s2[1];
|
|
201
207
|
const hasEnvField = loadingOptions.processEnv.hasOwnProperty(requestedEnvVar);
|
|
202
208
|
if (!hasEnvField) {
|
|
203
|
-
|
|
204
|
-
throw new Error(_concatInstanceProperty(_context = "Missing environment variable '".concat(requestedEnvVar, "' specified in config as 'env:")).call(_context, requestedEnvVar, "'."));
|
|
209
|
+
throw new Error(`Missing environment variable '${requestedEnvVar}' specified in config as 'env:${requestedEnvVar}'.`);
|
|
205
210
|
}
|
|
206
|
-
|
|
207
|
-
return valueOfEnvConfig.replace(new RegExp("(".concat(escapedMatchedString, ")+"), 'g'), loadingOptions.processEnv[requestedEnvVar]);
|
|
211
|
+
return valueOfEnvConfig.replace(new RegExp(escapeRegExp(matchedString), 'g'), loadingOptions.processEnv[requestedEnvVar]);
|
|
208
212
|
};
|
|
209
213
|
const substituteIntlVariablePlaceholder = (valueOfPlaceholder, matchedString, valueOfEnvConfig, loadingOptions) => {
|
|
210
214
|
const _valueOfPlaceholder$s3 = valueOfPlaceholder.split(':'),
|
|
211
215
|
_valueOfPlaceholder$s4 = _slicedToArray(_valueOfPlaceholder$s3, 3),
|
|
212
216
|
locale = _valueOfPlaceholder$s4[1],
|
|
213
217
|
requestedIntlMessageId = _valueOfPlaceholder$s4[2];
|
|
214
|
-
const translationsFilePath = require.resolve(
|
|
215
|
-
paths: [
|
|
218
|
+
const translationsFilePath = require.resolve(`./i18n/data/${locale}.json`, {
|
|
219
|
+
paths: [`${loadingOptions.applicationPath}/src`, loadingOptions.applicationPath]
|
|
216
220
|
});
|
|
217
221
|
const translations = require(translationsFilePath);
|
|
218
222
|
const hasIntlMessage = translations.hasOwnProperty(requestedIntlMessageId);
|
|
219
223
|
if (!hasIntlMessage) {
|
|
220
|
-
|
|
221
|
-
throw new Error(_concatInstanceProperty(_context2 = _concatInstanceProperty(_context3 = "Missing message key '".concat(requestedIntlMessageId, "' specified in config as 'intl:")).call(_context3, locale, ":")).call(_context2, requestedIntlMessageId, "'."));
|
|
224
|
+
throw new Error(`Missing message key '${requestedIntlMessageId}' specified in config as 'intl:${locale}:${requestedIntlMessageId}'.`);
|
|
222
225
|
}
|
|
223
226
|
const translation = translations[requestedIntlMessageId];
|
|
224
227
|
const translationValue = isStructuredJson(translation) ? translation.string : translation;
|
|
225
|
-
|
|
226
|
-
return valueOfEnvConfig.replace(new RegExp("(".concat(escapedMatchedString, ")+"), 'g'), translationValue);
|
|
228
|
+
return valueOfEnvConfig.replace(new RegExp(escapeRegExp(matchedString), 'g'), translationValue);
|
|
227
229
|
};
|
|
228
230
|
const substituteFilePathVariablePlaceholder = (valueOfPlaceholder, matchedString, valueOfEnvConfig, loadingOptions) => {
|
|
229
231
|
const _valueOfPlaceholder$s5 = valueOfPlaceholder.split(':'),
|
|
230
232
|
_valueOfPlaceholder$s6 = _slicedToArray(_valueOfPlaceholder$s5, 2),
|
|
231
233
|
filePathOrModule = _valueOfPlaceholder$s6[1];
|
|
232
|
-
const
|
|
233
|
-
// Relative paths should be resolved from the application folder.
|
|
234
|
+
const resolvedPath = require.resolve(filePathOrModule, {
|
|
234
235
|
paths: [loadingOptions.applicationPath]
|
|
235
|
-
})
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
// Security check: Prevent path traversal attacks.
|
|
239
|
+
// require.resolve() already provides protection by only resolving modules
|
|
240
|
+
// accessible from the applicationPath. However, we add an extra layer to
|
|
241
|
+
// prevent access to sensitive system files outside the workspace.
|
|
242
|
+
const normalizedPath = path$1.normalize(resolvedPath);
|
|
243
|
+
const applicationPath = path$1.normalize(loadingOptions.applicationPath);
|
|
244
|
+
|
|
245
|
+
// Find workspace root by traversing up from applicationPath until we find
|
|
246
|
+
// package.json, pnpm-workspace.yaml, or reach root
|
|
247
|
+
let workspaceRoot = applicationPath;
|
|
248
|
+
let currentPath = applicationPath;
|
|
249
|
+
const rootPath = path$1.parse(currentPath).root;
|
|
250
|
+
while (currentPath !== rootPath) {
|
|
251
|
+
const hasPackageJson = fs$1.existsSync(path$1.join(currentPath, 'package.json'));
|
|
252
|
+
const hasWorkspaceConfig = fs$1.existsSync(path$1.join(currentPath, 'pnpm-workspace.yaml')) || fs$1.existsSync(path$1.join(currentPath, 'lerna.json'));
|
|
253
|
+
if (hasPackageJson) {
|
|
254
|
+
workspaceRoot = currentPath;
|
|
255
|
+
if (hasWorkspaceConfig) {
|
|
256
|
+
// Found workspace root
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
currentPath = path$1.dirname(currentPath);
|
|
261
|
+
}
|
|
262
|
+
const relativePath = path$1.relative(workspaceRoot, normalizedPath);
|
|
263
|
+
|
|
264
|
+
// Path is safe if it's within the workspace root.
|
|
265
|
+
// Use path.relative() to avoid string prefix vulnerabilities (e.g., "/app" vs "/app-evil")
|
|
266
|
+
const isSafePath = !_startsWithInstanceProperty(relativePath).call(relativePath, '..') && !path$1.isAbsolute(relativePath);
|
|
267
|
+
if (!isSafePath) {
|
|
268
|
+
throw new Error(`Access to files outside workspace directory is not allowed: ${filePathOrModule}`);
|
|
269
|
+
}
|
|
270
|
+
const content = fs$1.readFileSync(normalizedPath, {
|
|
236
271
|
encoding: 'utf-8'
|
|
237
272
|
});
|
|
238
|
-
|
|
239
|
-
return valueOfEnvConfig.replace(new RegExp("(".concat(escapedMatchedString, ")+"), 'g'), content);
|
|
273
|
+
return valueOfEnvConfig.replace(new RegExp(escapeRegExp(matchedString), 'g'), content);
|
|
240
274
|
};
|
|
241
275
|
const getValueOfPlaceholder = valueWithPlaceholder => valueWithPlaceholder.replace(variableSyntax, (_match, varName) => _trimInstanceProperty(varName).call(varName)).replace(/\s/g, '');
|
|
242
|
-
const substituteVariablePlaceholders = (config, loadingOptions) =>
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
276
|
+
const substituteVariablePlaceholders = (config, loadingOptions) => {
|
|
277
|
+
const result = JSON.parse(_JSON$stringify(config), (_key, value) => {
|
|
278
|
+
// Only strings are allowed
|
|
279
|
+
let substitutedValue = value;
|
|
280
|
+
if (hasVariablePlaceholder(substitutedValue)) {
|
|
281
|
+
const matchResult = substitutedValue.match(variableSyntax);
|
|
282
|
+
if (matchResult) {
|
|
283
|
+
_forEachInstanceProperty(matchResult).call(matchResult, matchedString => {
|
|
284
|
+
const valueOfPlaceholder = getValueOfPlaceholder(matchedString);
|
|
285
|
+
if (isEnvVariablePlaceholder(valueOfPlaceholder)) {
|
|
286
|
+
substitutedValue = substituteEnvVariablePlaceholder(valueOfPlaceholder, matchedString, substitutedValue, loadingOptions);
|
|
287
|
+
} else if (isIntlVariablePlaceholder(valueOfPlaceholder)) {
|
|
288
|
+
substitutedValue = substituteIntlVariablePlaceholder(valueOfPlaceholder, matchedString, substitutedValue, loadingOptions);
|
|
289
|
+
} else if (isFilePathVariablePlaceholder(valueOfPlaceholder)) {
|
|
290
|
+
substitutedValue = substituteFilePathVariablePlaceholder(valueOfPlaceholder, matchedString, substitutedValue, loadingOptions);
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
258
294
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
295
|
+
return substitutedValue;
|
|
296
|
+
});
|
|
297
|
+
return result;
|
|
298
|
+
};
|
|
262
299
|
|
|
263
300
|
var customApplicationSchemaJson = {
|
|
264
301
|
$schema: "http://json-schema.org/draft-07/schema",
|
|
@@ -929,13 +966,12 @@ const printErrors = errors => {
|
|
|
929
966
|
return 'No errors';
|
|
930
967
|
}
|
|
931
968
|
return _mapInstanceProperty(errors).call(errors, error => {
|
|
932
|
-
|
|
933
|
-
const baseMessage = _concatInstanceProperty(_context = "".concat(error.instancePath, " ")).call(_context, error.message);
|
|
969
|
+
const baseMessage = `${error.instancePath} ${error.message}`;
|
|
934
970
|
switch (error.keyword) {
|
|
935
971
|
case 'additionalProperties':
|
|
936
|
-
return
|
|
972
|
+
return `${baseMessage}: ${error.params.additionalProperty}`;
|
|
937
973
|
case 'enum':
|
|
938
|
-
return
|
|
974
|
+
return `${baseMessage}: ${error.params.allowedValues.toString()}`;
|
|
939
975
|
default:
|
|
940
976
|
return baseMessage;
|
|
941
977
|
}
|
|
@@ -948,8 +984,7 @@ const validateConfig = (configType, config) => {
|
|
|
948
984
|
} else if (configType === LOADED_CONFIG_TYPES.CUSTOM_VIEW) {
|
|
949
985
|
validation = validateCustomViewConfig;
|
|
950
986
|
} else {
|
|
951
|
-
|
|
952
|
-
throw new Error(_concatInstanceProperty(_context4 = "Invalid config type \"".concat(configType, "\", expected ")).call(_context4, _Object$keys(LOADED_CONFIG_TYPES).toString()));
|
|
987
|
+
throw new Error(`Invalid config type "${configType}", expected ${_Object$keys(LOADED_CONFIG_TYPES).toString()}`);
|
|
953
988
|
}
|
|
954
989
|
const isValid = validation(config);
|
|
955
990
|
if (!isValid) {
|
|
@@ -962,9 +997,9 @@ const validateEntryPointUriPath = config => {
|
|
|
962
997
|
}
|
|
963
998
|
};
|
|
964
999
|
const validateSubmenuLinks = config => {
|
|
965
|
-
var
|
|
1000
|
+
var _context;
|
|
966
1001
|
const uriPathSet = new _Set();
|
|
967
|
-
_forEachInstanceProperty(
|
|
1002
|
+
_forEachInstanceProperty(_context = config.submenuLinks).call(_context, _ref => {
|
|
968
1003
|
let uriPath = _ref.uriPath;
|
|
969
1004
|
if (uriPathSet.has(uriPath)) {
|
|
970
1005
|
throw new Error('Duplicate URI path. Every submenu link must have a unique URI path value');
|
|
@@ -973,64 +1008,63 @@ const validateSubmenuLinks = config => {
|
|
|
973
1008
|
});
|
|
974
1009
|
};
|
|
975
1010
|
const validateAdditionalOAuthScopes = config => {
|
|
976
|
-
var
|
|
1011
|
+
var _context2, _context3;
|
|
977
1012
|
const additionalPermissionNames = new _Set();
|
|
978
|
-
(
|
|
1013
|
+
((_context2 = config.additionalOAuthScopes) == null ? void 0 : _bindInstanceProperty(_context3 = Function.call).call(_context3, _forEachInstanceProperty(_context2), _context2))?.(_ref2 => {
|
|
979
1014
|
let name = _ref2.name,
|
|
980
1015
|
view = _ref2.view,
|
|
981
1016
|
manage = _ref2.manage;
|
|
982
1017
|
if ((_Array$isArray(view) && view.length === 0 || !view) && (_Array$isArray(manage) && manage.length === 0 || !manage)) {
|
|
983
|
-
throw new Error(
|
|
1018
|
+
throw new Error(`At least one OAuth Scope for permission group name "${name}" is required`);
|
|
984
1019
|
} else if (additionalPermissionNames.has(name)) {
|
|
985
|
-
throw new Error(
|
|
1020
|
+
throw new Error(`Duplicate additional permission group name "${name}". Every additional permission must have a unique name`);
|
|
986
1021
|
}
|
|
987
1022
|
if (!name.match(PERMISSION_GROUP_NAME_REGEX)) {
|
|
988
|
-
throw new Error(
|
|
1023
|
+
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`);
|
|
989
1024
|
}
|
|
990
1025
|
additionalPermissionNames.add(name);
|
|
991
1026
|
});
|
|
992
1027
|
};
|
|
993
1028
|
|
|
994
1029
|
function ownKeys$1(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
995
|
-
function _objectSpread$1(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
1030
|
+
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(_context6 = ownKeys$1(Object(t), !0)).call(_context6, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context7 = ownKeys$1(Object(t))).call(_context7, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
996
1031
|
|
|
997
1032
|
// The `uriPath` of each submenu link is supposed to be defined relative
|
|
998
1033
|
// to the `entryPointUriPath`. Computing the full path is done internally to keep
|
|
999
1034
|
// the configuration simple.
|
|
1000
1035
|
const computeUriPath = (uriPath, entryPointUriPath) => {
|
|
1001
|
-
var _context;
|
|
1002
1036
|
// In case the `uriPath` is only `/`, it means that the link is supposed to be
|
|
1003
1037
|
// treated the same as the main application path. In this case, the return value
|
|
1004
1038
|
// should not contain any unnecessary trailing slash and therefore we use the `entryPointUriPath`.
|
|
1005
1039
|
if (uriPath === '/') return entryPointUriPath;
|
|
1006
1040
|
// In case the `uriPath` is already configured including the `entryPointUriPath`,
|
|
1007
1041
|
// we return the `uriPath` as-is.
|
|
1008
|
-
if (_startsWithInstanceProperty(uriPath).call(uriPath,
|
|
1042
|
+
if (_startsWithInstanceProperty(uriPath).call(uriPath, `${entryPointUriPath}/`)) return uriPath;
|
|
1009
1043
|
// Return the full path including the `entryPointUriPath` as a prefix.
|
|
1010
|
-
return
|
|
1044
|
+
return `${entryPointUriPath}/${uriPath}`;
|
|
1011
1045
|
};
|
|
1012
1046
|
const getPermissions = appConfig => {
|
|
1013
|
-
var _context2,
|
|
1014
|
-
const additionalResourceAccessKeyToOauthScopeMap = _reduceInstanceProperty(
|
|
1047
|
+
var _context, _context2, _context3, _context4;
|
|
1048
|
+
const additionalResourceAccessKeyToOauthScopeMap = _reduceInstanceProperty(_context = appConfig.additionalOAuthScopes || []).call(_context, (previousOauthScope, _ref) => {
|
|
1015
1049
|
let name = _ref.name,
|
|
1016
1050
|
view = _ref.view,
|
|
1017
1051
|
manage = _ref.manage;
|
|
1018
1052
|
const formattedResourceKey = formatEntryPointUriPathToResourceAccessKey(name);
|
|
1019
1053
|
return _objectSpread$1(_objectSpread$1({}, previousOauthScope), {}, {
|
|
1020
|
-
[
|
|
1021
|
-
[
|
|
1054
|
+
[`view${formattedResourceKey}`]: view,
|
|
1055
|
+
[`manage${formattedResourceKey}`]: manage
|
|
1022
1056
|
});
|
|
1023
1057
|
}, {});
|
|
1024
|
-
const additionalPermissionNames = ((
|
|
1058
|
+
const additionalPermissionNames = ((_context2 = appConfig.additionalOAuthScopes) == null ? void 0 : _bindInstanceProperty(_context3 = Function.call).call(_context3, _mapInstanceProperty(_context2), _context2))?.(_ref2 => {
|
|
1025
1059
|
let name = _ref2.name;
|
|
1026
1060
|
return name;
|
|
1027
|
-
})
|
|
1061
|
+
}) || [];
|
|
1028
1062
|
const permissionKeys = entryPointUriPathToResourceAccesses(appConfig.entryPointUriPath ||
|
|
1029
1063
|
// In case the `entryPointUriPath` is not defined it is because the
|
|
1030
1064
|
// configuration is for a custom view. In this case we use the
|
|
1031
1065
|
// default entry point uri path.
|
|
1032
1066
|
CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH, additionalPermissionNames);
|
|
1033
|
-
const additionalPermissions = _mapInstanceProperty(
|
|
1067
|
+
const additionalPermissions = _mapInstanceProperty(_context4 = _Object$keys(additionalResourceAccessKeyToOauthScopeMap)).call(_context4, additionalResourceAccessKey => ({
|
|
1034
1068
|
name: permissionKeys[additionalResourceAccessKey],
|
|
1035
1069
|
oAuthScopes: additionalResourceAccessKeyToOauthScopeMap[additionalResourceAccessKey]
|
|
1036
1070
|
}));
|
|
@@ -1043,7 +1077,7 @@ const getPermissions = appConfig => {
|
|
|
1043
1077
|
}, ...additionalPermissions];
|
|
1044
1078
|
};
|
|
1045
1079
|
function transformCustomApplicationConfigToData(appConfig) {
|
|
1046
|
-
var
|
|
1080
|
+
var _context5;
|
|
1047
1081
|
validateEntryPointUriPath(appConfig);
|
|
1048
1082
|
validateSubmenuLinks(appConfig);
|
|
1049
1083
|
validateAdditionalOAuthScopes(appConfig);
|
|
@@ -1056,7 +1090,7 @@ function transformCustomApplicationConfigToData(appConfig) {
|
|
|
1056
1090
|
permissions: getPermissions(appConfig),
|
|
1057
1091
|
icon: appConfig.icon,
|
|
1058
1092
|
mainMenuLink: appConfig.mainMenuLink,
|
|
1059
|
-
submenuLinks: _mapInstanceProperty(
|
|
1093
|
+
submenuLinks: _mapInstanceProperty(_context5 = appConfig.submenuLinks).call(_context5, submenuLink => _objectSpread$1(_objectSpread$1({}, submenuLink), {}, {
|
|
1060
1094
|
uriPath: computeUriPath(submenuLink.uriPath, appConfig.entryPointUriPath)
|
|
1061
1095
|
}))
|
|
1062
1096
|
};
|
|
@@ -1081,12 +1115,11 @@ function transformConfigurationToData(configType, configuration) {
|
|
|
1081
1115
|
} else if (configType === LOADED_CONFIG_TYPES.CUSTOM_VIEW) {
|
|
1082
1116
|
return transformCustomViewConfigToData(configuration);
|
|
1083
1117
|
} else {
|
|
1084
|
-
throw new Error(
|
|
1118
|
+
throw new Error(`Invalid config type: ${configType}`);
|
|
1085
1119
|
}
|
|
1086
1120
|
}
|
|
1087
1121
|
|
|
1088
1122
|
const mapCloudIdentifierToApiUrl = key => {
|
|
1089
|
-
var _context;
|
|
1090
1123
|
switch (key) {
|
|
1091
1124
|
case CLOUD_IDENTIFIERS.GCP_AU:
|
|
1092
1125
|
return MC_API_URLS[CLOUD_IDENTIFIERS.GCP_AU];
|
|
@@ -1103,7 +1136,7 @@ const mapCloudIdentifierToApiUrl = key => {
|
|
|
1103
1136
|
default:
|
|
1104
1137
|
// We would probably never get to this point, as the JSON schema validation
|
|
1105
1138
|
// kicks in before.
|
|
1106
|
-
throw new Error(
|
|
1139
|
+
throw new Error(`Unknown cloud identifier "${key}". Supported values: ${_Object$values(CLOUD_IDENTIFIERS).toString()}`);
|
|
1107
1140
|
}
|
|
1108
1141
|
};
|
|
1109
1142
|
const getUniqueValues = function () {
|
|
@@ -1127,10 +1160,10 @@ const getOrThrow = (fn, errorMessage) => {
|
|
|
1127
1160
|
};
|
|
1128
1161
|
|
|
1129
1162
|
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
1130
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
1163
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context2 = ownKeys(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context3 = ownKeys(Object(t))).call(_context3, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
1131
1164
|
// TODO: make it configurable.
|
|
1132
1165
|
const developmentPort = 3001;
|
|
1133
|
-
const developmentAppUrl =
|
|
1166
|
+
const developmentAppUrl = `http://localhost:${developmentPort}`;
|
|
1134
1167
|
const getLoadedConfigurationType = configFileName => {
|
|
1135
1168
|
if (_includesInstanceProperty(configFileName).call(configFileName, 'custom-view-config')) {
|
|
1136
1169
|
return LOADED_CONFIG_TYPES.CUSTOM_VIEW;
|
|
@@ -1146,7 +1179,6 @@ const omitDevConfigIfEmpty = devConfig => {
|
|
|
1146
1179
|
};
|
|
1147
1180
|
const isCustomViewData = data => data.entryPointUriPath === undefined;
|
|
1148
1181
|
const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
1149
|
-
var _appConfig$env$develo;
|
|
1150
1182
|
let isProd = _ref.isProd,
|
|
1151
1183
|
configurationData = _ref.configurationData,
|
|
1152
1184
|
mcApiUrl = _ref.mcApiUrl,
|
|
@@ -1163,7 +1195,7 @@ const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
|
1163
1195
|
initialProjectKey:
|
|
1164
1196
|
// For the `account` application, we should unset the projectKey.
|
|
1165
1197
|
entryPointUriPath === 'account' ? undefined : appConfig.env.development.initialProjectKey
|
|
1166
|
-
},
|
|
1198
|
+
}, appConfig.env.development?.teamId && _objectSpread({
|
|
1167
1199
|
teamId: appConfig.env.development.teamId
|
|
1168
1200
|
}, isCustomViewData(configurationData) ? {
|
|
1169
1201
|
customViewId: configurationData.id
|
|
@@ -1171,12 +1203,11 @@ const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
|
1171
1203
|
applicationId: configurationData.id
|
|
1172
1204
|
})), {}, {
|
|
1173
1205
|
oAuthScopes: appConfig.oAuthScopes,
|
|
1174
|
-
additionalOAuthScopes: appConfig
|
|
1206
|
+
additionalOAuthScopes: appConfig?.additionalOAuthScopes
|
|
1175
1207
|
}));
|
|
1176
1208
|
if (isCustomViewData(configurationData)) {
|
|
1177
|
-
var _context;
|
|
1178
1209
|
const hostUriPath = appConfig.env.development.hostUriPath;
|
|
1179
|
-
const defaultHostUriPath = oidcConfig.initialProjectKey ?
|
|
1210
|
+
const defaultHostUriPath = oidcConfig.initialProjectKey ? `/${oidcConfig.initialProjectKey}/${entryPointUriPath}` : `/${entryPointUriPath}`;
|
|
1180
1211
|
const hostUrl = new _URL(hostUriPath || defaultHostUriPath, developmentAppUrl);
|
|
1181
1212
|
return omitDevConfigIfEmpty({
|
|
1182
1213
|
oidc: oidcConfig,
|
|
@@ -1198,7 +1229,6 @@ const getRuntimeEnvironmentConfigForDevelopment = _ref => {
|
|
|
1198
1229
|
});
|
|
1199
1230
|
};
|
|
1200
1231
|
const getRuntimeEnvironmentConfig = _ref2 => {
|
|
1201
|
-
var _context2;
|
|
1202
1232
|
let isProd = _ref2.isProd,
|
|
1203
1233
|
configurationData = _ref2.configurationData,
|
|
1204
1234
|
additionalAppEnv = _ref2.additionalAppEnv,
|
|
@@ -1217,7 +1247,7 @@ const getRuntimeEnvironmentConfig = _ref2 => {
|
|
|
1217
1247
|
// In development, we prefix the entry point with the "__local" prefix.
|
|
1218
1248
|
// This is important to determine to which URL the MC should redirect to
|
|
1219
1249
|
// after successful login.
|
|
1220
|
-
const applicationIdentifier = isProd ?
|
|
1250
|
+
const applicationIdentifier = isProd ? `${configurationData.id}:${entryPointUriPath}` : `__local:${entryPointUriPath}`;
|
|
1221
1251
|
const developmentConfig = getRuntimeEnvironmentConfigForDevelopment({
|
|
1222
1252
|
isProd,
|
|
1223
1253
|
configurationData,
|
|
@@ -1249,7 +1279,7 @@ const getRuntimeEnvironmentConfig = _ref2 => {
|
|
|
1249
1279
|
// again will result in returning the cached value.
|
|
1250
1280
|
let cachedConfig;
|
|
1251
1281
|
const processConfig = async function () {
|
|
1252
|
-
var
|
|
1282
|
+
var _context;
|
|
1253
1283
|
let _ref3 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
|
1254
1284
|
_ref3$disableCache = _ref3.disableCache,
|
|
1255
1285
|
disableCache = _ref3$disableCache === void 0 ? false : _ref3$disableCache,
|
|
@@ -1268,22 +1298,22 @@ const processConfig = async function () {
|
|
|
1268
1298
|
processEnv
|
|
1269
1299
|
});
|
|
1270
1300
|
const configurationData = transformConfigurationToData(configType, appConfig);
|
|
1271
|
-
const appEnvKey =
|
|
1301
|
+
const appEnvKey = processEnv.MC_APP_ENV ?? processEnv.NODE_ENV ?? 'development';
|
|
1272
1302
|
const isProd = getIsProd(processEnv);
|
|
1273
|
-
const additionalAppEnv =
|
|
1274
|
-
const revision =
|
|
1303
|
+
const additionalAppEnv = appConfig.additionalEnv ?? {};
|
|
1304
|
+
const revision = additionalAppEnv.revision ?? '';
|
|
1275
1305
|
|
|
1276
1306
|
// Parse all the supported URLs, which gets implicitly validated
|
|
1277
1307
|
|
|
1278
1308
|
const envAppUrl = isProd ? configurationData.url : developmentAppUrl;
|
|
1279
|
-
const appUrl = getOrThrow(() => new _URL(envAppUrl),
|
|
1309
|
+
const appUrl = getOrThrow(() => new _URL(envAppUrl), `Invalid application URL: "${envAppUrl}"`);
|
|
1280
1310
|
|
|
1281
1311
|
// Use `||` instead of `??` to include empty string values.
|
|
1282
1312
|
const envCdnUrl = isProd ? appConfig.env.production.cdnUrl || appUrl.href : developmentAppUrl;
|
|
1283
|
-
const cdnUrl = getOrThrow(() => new _URL(envCdnUrl),
|
|
1313
|
+
const cdnUrl = getOrThrow(() => new _URL(envCdnUrl), `Invalid application CDN URL: "${envCdnUrl}"`);
|
|
1284
1314
|
const mcApiUrl = getOrThrow(() => new _URL(
|
|
1285
1315
|
// Use `||` instead of `??` to include empty string values.
|
|
1286
|
-
appConfig.mcApiUrl || mapCloudIdentifierToApiUrl(appConfig.cloudIdentifier)),
|
|
1316
|
+
appConfig.mcApiUrl || mapCloudIdentifierToApiUrl(appConfig.cloudIdentifier)), `Invalid MC API URL: "${appConfig.mcApiUrl}"`);
|
|
1287
1317
|
cachedConfig = {
|
|
1288
1318
|
data: configurationData,
|
|
1289
1319
|
env: getRuntimeEnvironmentConfig({
|
|
@@ -1298,16 +1328,16 @@ const processConfig = async function () {
|
|
|
1298
1328
|
revision
|
|
1299
1329
|
}),
|
|
1300
1330
|
headers: _objectSpread(_objectSpread({}, appConfig.headers), {}, {
|
|
1301
|
-
csp: _objectSpread(_objectSpread({},
|
|
1331
|
+
csp: _objectSpread(_objectSpread({}, appConfig.headers?.csp), {}, {
|
|
1302
1332
|
// We need to make sure the URL we use in these CSP headers have a slash in the end,
|
|
1303
1333
|
// otherwise it might create an invalid value when application/CDN URL points to a
|
|
1304
1334
|
// non-root directory (ex: https://www.my-domain.com/app). This is a valid URL but from
|
|
1305
1335
|
// the CSP point of view, it will say only the file `app` can be used as a source, so
|
|
1306
1336
|
// any other file from that domain will be forbidden. Using the slash (ex: https://www.my-domain.com/app/)
|
|
1307
1337
|
// at the end it's like using a wildcard so anything 'below' `app` will be allowed.
|
|
1308
|
-
'connect-src': getUniqueValues(
|
|
1309
|
-
'script-src': getUniqueValues(
|
|
1310
|
-
'style-src': getUniqueValues(
|
|
1338
|
+
'connect-src': getUniqueValues(appConfig.headers?.csp?.['connect-src'], _concatInstanceProperty(_context = [mcApiUrl.origin]).call(_context, isProd ? [`${trimTrailingSlash(appUrl.href)}/`, `${trimTrailingSlash(cdnUrl.href)}/`] : [])),
|
|
1339
|
+
'script-src': getUniqueValues(appConfig.headers?.csp?.['script-src'], isProd ? [`${trimTrailingSlash(appUrl.href)}/`, `${trimTrailingSlash(cdnUrl.href)}/`] : []),
|
|
1340
|
+
'style-src': getUniqueValues(appConfig.headers?.csp?.['style-src'], isProd ? [`${trimTrailingSlash(appUrl.href)}/`, `${trimTrailingSlash(cdnUrl.href)}/`] : [])
|
|
1311
1341
|
})
|
|
1312
1342
|
})
|
|
1313
1343
|
};
|
|
@@ -12,7 +12,6 @@ var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
|
12
12
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
13
13
|
var _mapInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/map');
|
|
14
14
|
var _reduceInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/reduce');
|
|
15
|
-
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
16
15
|
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
17
16
|
var upperFirst = require('lodash/upperFirst');
|
|
18
17
|
var constants = require('@commercetools-frontend/constants');
|
|
@@ -29,12 +28,11 @@ var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$def
|
|
|
29
28
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
30
29
|
var _mapInstanceProperty__default = /*#__PURE__*/_interopDefault(_mapInstanceProperty);
|
|
31
30
|
var _reduceInstanceProperty__default = /*#__PURE__*/_interopDefault(_reduceInstanceProperty);
|
|
32
|
-
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
33
31
|
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
34
32
|
var upperFirst__default = /*#__PURE__*/_interopDefault(upperFirst);
|
|
35
33
|
|
|
36
34
|
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; }
|
|
37
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var
|
|
35
|
+
function _objectSpread(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(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(Object(t))).call(_context7, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
38
36
|
/**
|
|
39
37
|
* The function formats the `entryPointUriPath` to a resource access key.
|
|
40
38
|
* It makes the first character of the string and the next character after a special character an uppercase.
|
|
@@ -61,8 +59,8 @@ const formatEntryPointUriPathToResourceAccessKey = entryPointUriPath => {
|
|
|
61
59
|
// Regex below checking if the character is numeric.
|
|
62
60
|
// If the word after the hyphen is numeric, replace the hyphen with a forward slash.
|
|
63
61
|
// If not, omit the hyphen and uppercase the first character
|
|
64
|
-
if (i > 0 &&
|
|
65
|
-
return
|
|
62
|
+
if (i > 0 && /^\d+$/.test(word[0])) {
|
|
63
|
+
return `/${word}`;
|
|
66
64
|
}
|
|
67
65
|
return upperFirst__default["default"](word);
|
|
68
66
|
}).join('');
|
|
@@ -86,15 +84,14 @@ function entryPointUriPathToResourceAccesses(entryPointUriPath, permissionGroupN
|
|
|
86
84
|
var _context4;
|
|
87
85
|
const resourceAccessKey = constants.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH === entryPointUriPath ? '' : formatEntryPointUriPathToResourceAccessKey(entryPointUriPath);
|
|
88
86
|
const defaultResourceAccesses = {
|
|
89
|
-
view:
|
|
90
|
-
manage:
|
|
87
|
+
view: `view${resourceAccessKey}`,
|
|
88
|
+
manage: `manage${resourceAccessKey}`
|
|
91
89
|
};
|
|
92
|
-
const additionalResourceAccesses = _reduceInstanceProperty__default["default"](_context4 = permissionGroupNames
|
|
93
|
-
var _context5, _context6;
|
|
90
|
+
const additionalResourceAccesses = _reduceInstanceProperty__default["default"](_context4 = permissionGroupNames ?? []).call(_context4, (resourceAccesses, permissionGroupName) => {
|
|
94
91
|
const additionalResourceAccessKey = formatPermissionGroupNameToResourceAccessKey(permissionGroupName);
|
|
95
92
|
return _objectSpread(_objectSpread({}, resourceAccesses), {}, {
|
|
96
|
-
[
|
|
97
|
-
[
|
|
93
|
+
[`view${additionalResourceAccessKey}`]: `${defaultResourceAccesses.view}${additionalResourceAccessKey}`,
|
|
94
|
+
[`manage${additionalResourceAccessKey}`]: `${defaultResourceAccesses.manage}${additionalResourceAccessKey}`
|
|
98
95
|
});
|
|
99
96
|
}, {});
|
|
100
97
|
return _objectSpread(_objectSpread({}, defaultResourceAccesses), additionalResourceAccesses);
|
|
@@ -106,9 +103,9 @@ function computeCustomViewPermissionsKeys(permissionGroupNames) {
|
|
|
106
103
|
return entryPointUriPathToPermissionKeys(constants.CUSTOM_VIEW_HOST_ENTRY_POINT_URI_PATH, permissionGroupNames || []);
|
|
107
104
|
}
|
|
108
105
|
function entryPointUriPathToPermissionKeys(entryPointUriPath, permissionGroupNames) {
|
|
109
|
-
var
|
|
110
|
-
const resourceAccesses = entryPointUriPathToResourceAccesses(entryPointUriPath, permissionGroupNames
|
|
111
|
-
return _reduceInstanceProperty__default["default"](
|
|
106
|
+
var _context5;
|
|
107
|
+
const resourceAccesses = entryPointUriPathToResourceAccesses(entryPointUriPath, permissionGroupNames ?? []);
|
|
108
|
+
return _reduceInstanceProperty__default["default"](_context5 = _Object$entries__default["default"](resourceAccesses)).call(_context5, (permissionKeys, _ref) => {
|
|
112
109
|
let _ref2 = _slicedToArray(_ref, 2),
|
|
113
110
|
resourceAccessKey = _ref2[0],
|
|
114
111
|
resourceAccessValue = _ref2[1];
|