@qrvey/widget-configurability 0.0.0-beta.4539 → 0.0.0-beta.4657

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 (42) hide show
  1. package/README.md +53 -0
  2. package/dist/cjs/index.js +12 -3
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/metadata/customization-metadata.js +241 -0
  5. package/dist/cjs/metadata/customization-metadata.js.map +1 -0
  6. package/dist/cjs/metadata/index.js +11 -0
  7. package/dist/cjs/metadata/index.js.map +1 -0
  8. package/dist/cjs/metadata/labels/chart-panel.labels.js +56 -0
  9. package/dist/cjs/metadata/labels/chart-panel.labels.js.map +1 -0
  10. package/dist/cjs/metadata/labels/dashboard.labels.js +207 -0
  11. package/dist/cjs/metadata/labels/dashboard.labels.js.map +1 -0
  12. package/dist/cjs/metadata/metadata.models.js +3 -0
  13. package/dist/cjs/metadata/metadata.models.js.map +1 -0
  14. package/dist/cjs/models/remote.models.js +3 -0
  15. package/dist/cjs/models/remote.models.js.map +1 -0
  16. package/dist/cjs/models/validation.models.js +3 -0
  17. package/dist/cjs/models/validation.models.js.map +1 -0
  18. package/dist/cjs/remote/remote-customization.loader.js +213 -0
  19. package/dist/cjs/remote/remote-customization.loader.js.map +1 -0
  20. package/dist/cjs/structural-manager.js +35 -2
  21. package/dist/cjs/structural-manager.js.map +1 -1
  22. package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
  23. package/dist/cjs/utils/defaults.helpers.js +3 -0
  24. package/dist/cjs/utils/defaults.helpers.js.map +1 -1
  25. package/dist/cjs/utils/layers.helpers.js +178 -0
  26. package/dist/cjs/utils/layers.helpers.js.map +1 -0
  27. package/dist/cjs/utils/logger.helpers.js +10 -0
  28. package/dist/cjs/utils/logger.helpers.js.map +1 -0
  29. package/dist/cjs/utils/scope.helpers.js +4 -1
  30. package/dist/cjs/utils/scope.helpers.js.map +1 -1
  31. package/dist/cjs/validation/customization.validator.js +366 -0
  32. package/dist/cjs/validation/customization.validator.js.map +1 -0
  33. package/dist/esm/index.mjs +842 -48
  34. package/dist/esm/index.mjs.map +1 -1
  35. package/dist/esm/metadata.mjs +2750 -0
  36. package/dist/esm/metadata.mjs.map +1 -0
  37. package/dist/types/customization.models-CCSWjfb2.d.ts +47 -0
  38. package/dist/types/index.d.ts +98 -68
  39. package/dist/types/metadata.d.ts +59 -0
  40. package/package.json +7 -1
  41. package/dist/cjs/utils/download-modal.helpers.js +0 -29
  42. package/dist/cjs/utils/download-modal.helpers.js.map +0 -1
@@ -128,6 +128,7 @@ var fontSizeMinMaxValue = /* @__PURE__ */ __name((minSize, maxSize) => (value) =
128
128
  return `${closestSize}px`;
129
129
  }, "fontSizeMinMaxValue");
130
130
  var fontColorValue = /* @__PURE__ */ __name((value) => {
131
+ if (typeof value !== "string") return void 0;
131
132
  const normalizedColor = value.toLowerCase();
132
133
  return normalizedColor;
133
134
  }, "fontColorValue");
@@ -1060,9 +1061,9 @@ __name(checkConditions, "checkConditions");
1060
1061
 
1061
1062
  // src/utils/merge.helpers.ts
1062
1063
  function mergeDeep(obj1, obj2, settings) {
1063
- var _a, _b;
1064
+ var _a2, _b;
1064
1065
  const defaultSettings = {
1065
- mergeExistingValues: (_a = settings == null ? void 0 : settings.mergeExistingValues) != null ? _a : true,
1066
+ mergeExistingValues: (_a2 = settings == null ? void 0 : settings.mergeExistingValues) != null ? _a2 : true,
1066
1067
  mergeMissingProperties: (_b = settings == null ? void 0 : settings.mergeMissingProperties) != null ? _b : true
1067
1068
  };
1068
1069
  if (!isValid(obj1, obj2)) return objectCopy(obj1);
@@ -1111,6 +1112,164 @@ function isObject(value) {
1111
1112
  }
1112
1113
  __name(isObject, "isObject");
1113
1114
 
1115
+ // src/utils/layers.helpers.ts
1116
+ var SUBMODULES_KEY = "subModules";
1117
+ var isPlainObject = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]", "isPlainObject");
1118
+ var stringList = /* @__PURE__ */ __name((value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : void 0, "stringList");
1119
+ function normalizeCondition(value) {
1120
+ if (!isPlainObject(value)) return void 0;
1121
+ const { field, operator, value: conditionValue } = value;
1122
+ if (typeof field !== "string") return void 0;
1123
+ if (!allowedOperators.includes(operator)) return void 0;
1124
+ if (typeof conditionValue !== "string" && typeof conditionValue !== "number") return void 0;
1125
+ return {
1126
+ field,
1127
+ operator,
1128
+ value: conditionValue
1129
+ };
1130
+ }
1131
+ __name(normalizeCondition, "normalizeCondition");
1132
+ function normalizeSubmodules(value) {
1133
+ if (!isPlainObject(value)) return void 0;
1134
+ const result = {};
1135
+ Object.keys(value).forEach((name) => {
1136
+ const submodule = normalizeLayer(value[name]);
1137
+ if (submodule) result[name] = submodule;
1138
+ });
1139
+ return result;
1140
+ }
1141
+ __name(normalizeSubmodules, "normalizeSubmodules");
1142
+ function normalizeLayer(value, allowViews = true) {
1143
+ if (!isPlainObject(value)) return void 0;
1144
+ const layer = {};
1145
+ const remove = stringList(value.remove);
1146
+ const keep = stringList(value.keep);
1147
+ if (remove) layer.remove = remove;
1148
+ if (keep) layer.keep = keep;
1149
+ if (isPlainObject(value.defaults)) layer.defaults = value.defaults;
1150
+ const subModules = normalizeSubmodules(value.subModules);
1151
+ if (subModules) layer.subModules = subModules;
1152
+ if (Array.isArray(value.conditional)) {
1153
+ layer.conditional = value.conditional.flatMap((item) => {
1154
+ const condition = isPlainObject(item) ? normalizeCondition(item.condition) : void 0;
1155
+ const rest = condition ? normalizeLayer(item, false) : void 0;
1156
+ return condition && rest ? [
1157
+ __spreadProps(__spreadValues({}, rest), {
1158
+ condition
1159
+ })
1160
+ ] : [];
1161
+ });
1162
+ }
1163
+ if (allowViews && isPlainObject(value.views)) {
1164
+ const views = value.views;
1165
+ layer.views = {};
1166
+ Object.keys(views).forEach((view) => {
1167
+ const viewLayer = normalizeLayer(views[view], false);
1168
+ if (viewLayer) layer.views[view] = viewLayer;
1169
+ });
1170
+ }
1171
+ return layer;
1172
+ }
1173
+ __name(normalizeLayer, "normalizeLayer");
1174
+ function mergeDefaults(previous, next) {
1175
+ if (!isPlainObject(next)) return previous;
1176
+ return previous ? mergeDeep(previous, next) : next;
1177
+ }
1178
+ __name(mergeDefaults, "mergeDefaults");
1179
+ function mergeLayerDefaults(layers) {
1180
+ var _a2;
1181
+ const last = (_a2 = layers[layers.length - 1]) != null ? _a2 : {};
1182
+ const viewNames = new Set(layers.flatMap((layer) => {
1183
+ var _a3;
1184
+ return Object.keys((_a3 = layer.views) != null ? _a3 : {});
1185
+ }));
1186
+ const rootDefaults = layers.reduce((merged, layer) => mergeDefaults(merged, layer.defaults), void 0);
1187
+ const views = __spreadValues({}, last.views);
1188
+ viewNames.forEach((view) => {
1189
+ var _a3;
1190
+ const viewDefaults = layers.reduce((merged, layer) => {
1191
+ var _a4, _b;
1192
+ return mergeDefaults(mergeDefaults(merged, layer.defaults), (_b = (_a4 = layer.views) == null ? void 0 : _a4[view]) == null ? void 0 : _b.defaults);
1193
+ }, void 0);
1194
+ if (viewDefaults) {
1195
+ views[view] = __spreadProps(__spreadValues({}, (_a3 = last.views) == null ? void 0 : _a3[view]), {
1196
+ defaults: viewDefaults
1197
+ });
1198
+ }
1199
+ });
1200
+ const effective = __spreadValues({}, last);
1201
+ if (rootDefaults) effective.defaults = rootDefaults;
1202
+ if (viewNames.size) effective.views = views;
1203
+ return effective;
1204
+ }
1205
+ __name(mergeLayerDefaults, "mergeLayerDefaults");
1206
+ var isSubmodulesKey = /* @__PURE__ */ __name((key) => key === SUBMODULES_KEY || key.endsWith(`::${SUBMODULES_KEY}`), "isSubmodulesKey");
1207
+ var asItemObject = /* @__PURE__ */ __name((value) => isPlainObject(value) ? value : {}, "asItemObject");
1208
+ function intersectItem(current, other) {
1209
+ var _a2, _b, _c;
1210
+ const item = asItemObject(current);
1211
+ const otherItem = asItemObject(other);
1212
+ const childMap = item.childMap ? intersectViewMaps(item.childMap, (_a2 = otherItem.childMap) != null ? _a2 : {}) : void 0;
1213
+ const conditions = [
1214
+ ...(_b = otherItem.conditions) != null ? _b : [],
1215
+ ...(_c = item.conditions) != null ? _c : []
1216
+ ];
1217
+ const hasDefaults = !!item.defaults && Object.keys(item.defaults).length > 0;
1218
+ const hasChildMap = !!childMap && Object.keys(childMap).length > 0;
1219
+ if (!hasDefaults && !hasChildMap && !conditions.length) {
1220
+ return isPlainObject(current) ? true : current;
1221
+ }
1222
+ return __spreadValues(__spreadValues(__spreadValues({}, hasDefaults && {
1223
+ defaults: item.defaults
1224
+ }), hasChildMap && {
1225
+ childMap
1226
+ }), conditions.length && {
1227
+ conditions
1228
+ });
1229
+ }
1230
+ __name(intersectItem, "intersectItem");
1231
+ function intersectViewMaps(current, other) {
1232
+ const result = {};
1233
+ Object.keys(current).forEach((key) => {
1234
+ if (isSubmodulesKey(key)) {
1235
+ result[key] = current[key];
1236
+ } else if (key in other) {
1237
+ result[key] = intersectItem(current[key], other[key]);
1238
+ }
1239
+ });
1240
+ return result;
1241
+ }
1242
+ __name(intersectViewMaps, "intersectViewMaps");
1243
+ function collectSubmoduleLayers(maps) {
1244
+ const result = {};
1245
+ maps.forEach((map) => {
1246
+ Object.keys(map).filter(isSubmodulesKey).forEach((key) => {
1247
+ const collection = map[key];
1248
+ if (!isPlainObject(collection)) return;
1249
+ Object.keys(collection).forEach((name) => {
1250
+ var _a2, _b;
1251
+ const submodule = collection[name];
1252
+ if (!isPlainObject(submodule)) return;
1253
+ if (!Object.keys(submodule).length) return;
1254
+ result[key] = (_a2 = result[key]) != null ? _a2 : {};
1255
+ result[key][name] = [
1256
+ ...(_b = result[key][name]) != null ? _b : [],
1257
+ submodule
1258
+ ];
1259
+ });
1260
+ });
1261
+ });
1262
+ return Object.keys(result).length ? result : void 0;
1263
+ }
1264
+ __name(collectSubmoduleLayers, "collectSubmoduleLayers");
1265
+
1266
+ // src/utils/logger.helpers.ts
1267
+ var LOG_PREFIX = "[widget-configurability]";
1268
+ function logWarning(message) {
1269
+ console.warn(`${LOG_PREFIX} ${message}`);
1270
+ }
1271
+ __name(logWarning, "logWarning");
1272
+
1114
1273
  // src/utils/structural.helpers.ts
1115
1274
  function getWidgetStructure(config, customization, validationMap, options) {
1116
1275
  return calculateViewMap(config.baseStructure, customization, validationMap, __spreadProps(__spreadValues({}, options), {
@@ -1220,8 +1379,8 @@ function canInsertInCustomization(key, customization, validateKeepOption, keepAl
1220
1379
  }
1221
1380
  __name(canInsertInCustomization, "canInsertInCustomization");
1222
1381
  function evalInsertKey(key, { viewKeys, viewPrefix = "", hasKeepOption, keepAliases }, customization) {
1223
- var _a;
1224
- const customizationView = (_a = customization == null ? void 0 : customization.views) == null ? void 0 : _a[viewPrefix];
1382
+ var _a2;
1383
+ const customizationView = (_a2 = customization == null ? void 0 : customization.views) == null ? void 0 : _a2[viewPrefix];
1225
1384
  const custCanInsert = customization ? canInsertInCustomization(key, customization, hasKeepOption === "root", keepAliases) : {
1226
1385
  canInsert: true,
1227
1386
  conditionAffect: false
@@ -1352,9 +1511,9 @@ function getConditionsForKey(key, conditionMaps) {
1352
1511
  }
1353
1512
  __name(getConditionsForKey, "getConditionsForKey");
1354
1513
  function calculateConditions(config, customization, view, keepAliases) {
1355
- var _a, _b, _c;
1514
+ var _a2, _b, _c;
1356
1515
  const rootConditionals = customization == null ? void 0 : customization.conditional;
1357
- const viewConditionals = view ? (_b = (_a = customization == null ? void 0 : customization.views) == null ? void 0 : _a[view]) == null ? void 0 : _b.conditional : void 0;
1516
+ const viewConditionals = view ? (_b = (_a2 = customization == null ? void 0 : customization.views) == null ? void 0 : _a2[view]) == null ? void 0 : _b.conditional : void 0;
1358
1517
  if (!rootConditionals && !viewConditionals) return void 0;
1359
1518
  const customConditionals = [
1360
1519
  ...rootConditionals != null ? rootConditionals : [],
@@ -1370,16 +1529,16 @@ function calculateConditions(config, customization, view, keepAliases) {
1370
1529
  }
1371
1530
  __name(calculateConditions, "calculateConditions");
1372
1531
  function calculateSubmodules(config, customization, view) {
1373
- var _a, _b;
1374
- const viewSubmodules = view ? (_b = (_a = customization == null ? void 0 : customization.views) == null ? void 0 : _a[view]) == null ? void 0 : _b.subModules : void 0;
1532
+ var _a2, _b;
1533
+ const viewSubmodules = view ? (_b = (_a2 = customization == null ? void 0 : customization.views) == null ? void 0 : _a2[view]) == null ? void 0 : _b.subModules : void 0;
1375
1534
  const customRootSubmodules = customization == null ? void 0 : customization.subModules;
1376
1535
  const customSubmodules = viewSubmodules ? mergeObjects(customRootSubmodules, viewSubmodules) : customRootSubmodules;
1377
1536
  return mergeObjects(config.subModules, customSubmodules);
1378
1537
  }
1379
1538
  __name(calculateSubmodules, "calculateSubmodules");
1380
1539
  function calculateCustomDefaults(customization, view, validationMap, sanitize) {
1381
- var _a, _b, _c;
1382
- const viewDefaults = view ? (_b = (_a = customization == null ? void 0 : customization.views) == null ? void 0 : _a[view]) == null ? void 0 : _b.defaults : void 0;
1540
+ var _a2, _b, _c;
1541
+ const viewDefaults = view ? (_b = (_a2 = customization == null ? void 0 : customization.views) == null ? void 0 : _a2[view]) == null ? void 0 : _b.defaults : void 0;
1383
1542
  const customRootDefaults = (_c = customization == null ? void 0 : customization.defaults) != null ? _c : {};
1384
1543
  const defaultObj = viewDefaults ? mergeObjects(customRootDefaults, viewDefaults) : customRootDefaults;
1385
1544
  if (!defaultObj || !validationMap && !sanitize) return defaultObj;
@@ -1416,7 +1575,7 @@ function mapArrayKeys(configValue, { viewPrefix, pathPrefix }) {
1416
1575
  }
1417
1576
  __name(mapArrayKeys, "mapArrayKeys");
1418
1577
  function nodeHasKeepOption(configValue, customization, { viewPrefix, pathPrefix }) {
1419
- var _a;
1578
+ var _a2;
1420
1579
  if (!customization) return;
1421
1580
  const nodeKeys = Array.isArray(configValue) ? mapArrayKeys(configValue, {
1422
1581
  viewPrefix,
@@ -1424,7 +1583,7 @@ function nodeHasKeepOption(configValue, customization, { viewPrefix, pathPrefix
1424
1583
  }) : mapObjKeys(configValue, {
1425
1584
  pathPrefix
1426
1585
  });
1427
- const customizationView = viewPrefix ? (_a = customization == null ? void 0 : customization.views) == null ? void 0 : _a[viewPrefix] : void 0;
1586
+ const customizationView = viewPrefix ? (_a2 = customization == null ? void 0 : customization.views) == null ? void 0 : _a2[viewPrefix] : void 0;
1428
1587
  for (const key of nodeKeys) {
1429
1588
  if (keyIsIncludedInKeep(key, customization)) {
1430
1589
  return "root";
@@ -1480,9 +1639,9 @@ __name(calculatePermissionMapArray, "calculatePermissionMapArray");
1480
1639
 
1481
1640
  // src/structural-manager.ts
1482
1641
  function getWidgetConfig(widget, version) {
1483
- var _a;
1642
+ var _a2;
1484
1643
  const versionSet = version != null ? version : WidgetVersion.latest;
1485
- const widgetConfigurability = (_a = widgetConfigs[widget]) == null ? void 0 : _a[versionSet];
1644
+ const widgetConfigurability = (_a2 = widgetConfigs[widget]) == null ? void 0 : _a2[versionSet];
1486
1645
  if (!widgetConfigurability) {
1487
1646
  throw new Error(`No config found for widget ${widget} and version ${version}`);
1488
1647
  }
@@ -1490,20 +1649,45 @@ function getWidgetConfig(widget, version) {
1490
1649
  }
1491
1650
  __name(getWidgetConfig, "getWidgetConfig");
1492
1651
  function buildStructure(widget, customization, version, options) {
1493
- var _a;
1652
+ var _a2, _b;
1494
1653
  const config = getWidgetConfig(widget, version);
1495
- const validationMap = (_a = options == null ? void 0 : options.validationMap) != null ? _a : widgetValidators[widget];
1654
+ const validationMap = (_a2 = options == null ? void 0 : options.validationMap) != null ? _a2 : widgetValidators[widget];
1655
+ const layers = ((_b = options == null ? void 0 : options.layers) != null ? _b : []).map((layer) => normalizeLayer(layer)).filter((layer) => !!layer);
1656
+ if (layers.length) {
1657
+ try {
1658
+ return buildLayeredStructure(config, layers, customization, validationMap, options);
1659
+ } catch (error) {
1660
+ logWarning(`ignoring the ${widget} customization layers: ${error.message}`);
1661
+ }
1662
+ }
1496
1663
  const structureMap = getWidgetStructure(config, customization, validationMap, options);
1497
1664
  const rootDefaults = config.baseStructure.views ? void 0 : calculateRootDefaults(config.baseStructure, customization, validationMap, options == null ? void 0 : options.sanitize);
1498
1665
  return new WidgetStructureInstance(structureMap, rootDefaults);
1499
1666
  }
1500
1667
  __name(buildStructure, "buildStructure");
1668
+ function buildLayeredStructure(config, layers, customization, validationMap, options) {
1669
+ const inline = isPlainObject(customization) ? customization : {};
1670
+ const effective = mergeLayerDefaults([
1671
+ ...layers,
1672
+ inline
1673
+ ]);
1674
+ const engineOptions = {
1675
+ viewConditionals: options == null ? void 0 : options.viewConditionals
1676
+ };
1677
+ const layerMaps = layers.map((layer) => getWidgetStructure(config, layer, void 0, engineOptions));
1678
+ const structureMap = layerMaps.reduce((result, layerMap) => intersectViewMaps(result, layerMap), getWidgetStructure(config, effective, validationMap, options));
1679
+ const rootDefaults = config.baseStructure.views ? void 0 : calculateRootDefaults(config.baseStructure, effective, validationMap, options == null ? void 0 : options.sanitize);
1680
+ return new WidgetStructureInstance(structureMap, rootDefaults, collectSubmoduleLayers(layerMaps));
1681
+ }
1682
+ __name(buildLayeredStructure, "buildLayeredStructure");
1501
1683
  var _WidgetStructureInstance = class _WidgetStructureInstance {
1502
- constructor(viewMap, rootDefaults) {
1684
+ constructor(viewMap, rootDefaults, submoduleLayers) {
1503
1685
  __publicField(this, "viewMap");
1504
1686
  __publicField(this, "rootDefaults");
1687
+ __publicField(this, "submoduleLayers");
1505
1688
  this.viewMap = viewMap;
1506
1689
  this.rootDefaults = rootDefaults;
1690
+ this.submoduleLayers = submoduleLayers;
1507
1691
  }
1508
1692
  getValue(key) {
1509
1693
  return this.viewMap[key];
@@ -1526,6 +1710,14 @@ var _WidgetStructureInstance = class _WidgetStructureInstance {
1526
1710
  const value = this.getValue(key);
1527
1711
  return value == null ? void 0 : value[module2];
1528
1712
  }
1713
+ /**
1714
+ * Submodule customizations of the stored layers, to pass as layers when building the embedded widget (structureFromSubmodule).
1715
+ */
1716
+ getSubmoduleLayers(module2, view) {
1717
+ var _a2, _b;
1718
+ const key = `${view ? view + "::" : ""}subModules`;
1719
+ return (_b = (_a2 = this.submoduleLayers) == null ? void 0 : _a2[key]) == null ? void 0 : _b[module2];
1720
+ }
1529
1721
  getDefaults(key) {
1530
1722
  const value = this.getValue(key);
1531
1723
  if (!value || typeof value === "boolean" || typeof value === "string" || !value.defaults) return void 0;
@@ -1538,10 +1730,10 @@ var _WidgetStructureInstance = class _WidgetStructureInstance {
1538
1730
  * Re-roots a resolved section (`design::downloadModal`) as plain JSON another bundle can rebuild a structure from.
1539
1731
  */
1540
1732
  scope(prefixKey, options = {}) {
1541
- var _a;
1733
+ var _a2;
1542
1734
  const { widget, version, state } = options;
1543
1735
  const present = this.isVisible(prefixKey, state);
1544
- const sectionPath = (_a = prefixKey.split(STRUCTURE_VIEW_NAME_SEPARATOR).pop()) != null ? _a : prefixKey;
1736
+ const sectionPath = (_a2 = prefixKey.split(STRUCTURE_VIEW_NAME_SEPARATOR).pop()) != null ? _a2 : prefixKey;
1545
1737
  const namespace = options.defaultsNamespace === void 0 ? sectionPath.split(STRUCTURE_SECTION_NAME_SEPARATOR).pop() : options.defaultsNamespace;
1546
1738
  const sectionDefaults = present ? this.getDefaults(prefixKey) : void 0;
1547
1739
  const defaults = namespace ? sectionDefaults == null ? void 0 : sectionDefaults[namespace] : sectionDefaults;
@@ -1577,14 +1769,14 @@ __name(_WidgetStructureInstance, "WidgetStructureInstance");
1577
1769
  var WidgetStructureInstance = _WidgetStructureInstance;
1578
1770
 
1579
1771
  // src/utils/scope.helpers.ts
1580
- var isPlainObject = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isPlainObject");
1772
+ var isPlainObject2 = /* @__PURE__ */ __name((value) => typeof value === "object" && value !== null && !Array.isArray(value), "isPlainObject");
1581
1773
  function isWidgetStructureScope(value) {
1582
- return isPlainObject(value) && value.kind === WIDGET_STRUCTURE_SCOPE_KIND;
1774
+ return isPlainObject2(value) && value.kind === WIDGET_STRUCTURE_SCOPE_KIND;
1583
1775
  }
1584
1776
  __name(isWidgetStructureScope, "isWidgetStructureScope");
1585
1777
  function scopeToCustomization(scope) {
1586
- var _a;
1587
- const remove = scope.present ? Object.keys((_a = scope.map) != null ? _a : {}).filter((key) => scope.map[key] === false) : [
1778
+ var _a2;
1779
+ const remove = scope.present ? Object.keys((_a2 = scope.map) != null ? _a2 : {}).filter((key) => scope.map[key] === false) : [
1588
1780
  "*"
1589
1781
  ];
1590
1782
  return __spreadValues(__spreadValues({}, remove.length ? {
@@ -1602,8 +1794,8 @@ function extractCustomization(host, customization, prefixKey, target, options) {
1602
1794
  }
1603
1795
  __name(extractCustomization, "extractCustomization");
1604
1796
  function submoduleOf(input, module2, view) {
1605
- var _a, _b, _c, _d;
1606
- const root = (_a = input.subModules) == null ? void 0 : _a[module2];
1797
+ var _a2, _b, _c, _d;
1798
+ const root = (_a2 = input.subModules) == null ? void 0 : _a2[module2];
1607
1799
  const fromView = view ? (_d = (_c = (_b = input.views) == null ? void 0 : _b[view]) == null ? void 0 : _c.subModules) == null ? void 0 : _d[module2] : void 0;
1608
1800
  if (!fromView) return root;
1609
1801
  return root ? mergeDeep(root, fromView) : fromView;
@@ -1612,7 +1804,7 @@ __name(submoduleOf, "submoduleOf");
1612
1804
  function structureFrom(widget, input, view, version) {
1613
1805
  if (input === void 0 || input === null) return void 0;
1614
1806
  try {
1615
- if (!isPlainObject(input)) {
1807
+ if (!isPlainObject2(input)) {
1616
1808
  throw new Error("expected an object");
1617
1809
  }
1618
1810
  if ("kind" in input) {
@@ -1638,37 +1830,639 @@ function structureFrom(widget, input, view, version) {
1638
1830
  }
1639
1831
  __name(structureFrom, "structureFrom");
1640
1832
  function structureFromSubmodule(parent, module2, view, options) {
1833
+ var _a2;
1641
1834
  const widget = Object.keys(WIDGET_SUBMODULE_NAMES).find((key) => WIDGET_SUBMODULE_NAMES[key] === module2);
1642
1835
  if (!widget) {
1643
1836
  throw new Error(`No widget registered for the submodule ${module2}`);
1644
1837
  }
1645
- return buildStructure(widget, parent.getSubmodule(module2, view), void 0, options);
1838
+ const layers = parent.getSubmoduleLayers(module2, view);
1839
+ return buildStructure(widget, parent.getSubmodule(module2, view), void 0, layers ? __spreadProps(__spreadValues({}, options), {
1840
+ layers: [
1841
+ ...(_a2 = options == null ? void 0 : options.layers) != null ? _a2 : [],
1842
+ ...layers
1843
+ ]
1844
+ }) : options);
1646
1845
  }
1647
1846
  __name(structureFromSubmodule, "structureFromSubmodule");
1648
1847
 
1649
- // src/utils/download-modal.helpers.ts
1650
- function resolveDownloadModalConfig(structure, { organizationAvailable = true, subscribeOwnerAvailable = false } = {}) {
1651
- var _a;
1652
- const visible = /* @__PURE__ */ __name((key) => structure.isVisible(key), "visible");
1653
- const elements = {
1654
- banner: visible("qSubscribeBanner"),
1655
- owner: visible("qOwnerLabel"),
1656
- subscribeOwner: visible("qSubscribeOwner"),
1657
- organization: visible("qSubscribeOrganization"),
1658
- myself: visible("qSubscribeMyself"),
1659
- specificPeople: visible("qSubscribeSpecificPeople")
1848
+ // src/validation/customization.validator.ts
1849
+ var ROOT_PROPERTIES = [
1850
+ "remove",
1851
+ "keep",
1852
+ "defaults",
1853
+ "subModules",
1854
+ "conditional",
1855
+ "views"
1856
+ ];
1857
+ var VIEW_PROPERTIES = [
1858
+ "remove",
1859
+ "keep",
1860
+ "defaults",
1861
+ "subModules",
1862
+ "conditional"
1863
+ ];
1864
+ var CONDITIONAL_PROPERTIES = [
1865
+ "condition",
1866
+ "remove",
1867
+ "keep",
1868
+ "defaults",
1869
+ "subModules"
1870
+ ];
1871
+ var CONDITION_PROPERTIES = [
1872
+ "field",
1873
+ "operator",
1874
+ "value"
1875
+ ];
1876
+ var KEY_CHARS = /^[A-Za-z0-9_.-]+$/;
1877
+ var ROOT_SCOPE = "";
1878
+ var oneOf = /* @__PURE__ */ __name((values) => (value) => typeof value === "string" && values.includes(value) ? value : void 0, "oneOf");
1879
+ var DX_WRITE_VALIDATOR_MAP = {
1880
+ changeLayout: validateBoolean,
1881
+ removeElement: validateBoolean,
1882
+ dragElement: validateBoolean,
1883
+ resizeElement: validateBoolean,
1884
+ assetListViewMode: oneOf([
1885
+ "card",
1886
+ "table"
1887
+ ]),
1888
+ "downloadModal.exportVersion": oneOf([
1889
+ "saved",
1890
+ "unsaved"
1891
+ ])
1892
+ };
1893
+ var writeValidators = {
1894
+ [Widget.DASHBOARD]: __spreadValues(__spreadValues({}, widgetValidators[Widget.DASHBOARD]), DX_WRITE_VALIDATOR_MAP)
1895
+ };
1896
+ var keyCache = /* @__PURE__ */ new Map();
1897
+ function structureKeys(config) {
1898
+ const cached = keyCache.get(config);
1899
+ if (cached) return cached;
1900
+ const byView = /* @__PURE__ */ new Map([
1901
+ [
1902
+ ROOT_SCOPE,
1903
+ /* @__PURE__ */ new Set()
1904
+ ]
1905
+ ]);
1906
+ Object.keys(calculateViewMap(config.baseStructure)).forEach((entry) => {
1907
+ const separator = entry.indexOf(STRUCTURE_VIEW_NAME_SEPARATOR);
1908
+ const view = separator >= 0 ? entry.slice(0, separator) : ROOT_SCOPE;
1909
+ const key = separator >= 0 ? entry.slice(separator + STRUCTURE_VIEW_NAME_SEPARATOR.length) : entry;
1910
+ if (key === "subModules") return;
1911
+ if (!byView.has(view)) byView.set(view, /* @__PURE__ */ new Set());
1912
+ byView.get(view).add(key);
1913
+ byView.get(ROOT_SCOPE).add(key);
1914
+ });
1915
+ keyCache.set(config, byView);
1916
+ return byView;
1917
+ }
1918
+ __name(structureKeys, "structureKeys");
1919
+ function resolveConfig(widget, version) {
1920
+ const versions = widgetConfigs[widget];
1921
+ if (!versions) return void 0;
1922
+ if (!version) return versions[WidgetVersion.latest];
1923
+ const match = Object.keys(versions).find((key) => {
1924
+ var _a2;
1925
+ return key === version || ((_a2 = versions[key]) == null ? void 0 : _a2.version) === version;
1926
+ });
1927
+ return match ? versions[match] : void 0;
1928
+ }
1929
+ __name(resolveConfig, "resolveConfig");
1930
+ function createScope(widget, config) {
1931
+ var _a2, _b;
1932
+ return {
1933
+ widget,
1934
+ config,
1935
+ keys: structureKeys(config),
1936
+ views: Object.keys((_a2 = config.baseStructure.views) != null ? _a2 : {}),
1937
+ subModules: Object.keys((_b = config.baseStructure.subModules) != null ? _b : {})
1660
1938
  };
1661
- const schedule = visible("qScheduleOption");
1662
- const anyElement = elements.banner || elements.owner || subscribeOwnerAvailable && elements.subscribeOwner || organizationAvailable && elements.organization || elements.myself || elements.specificPeople;
1663
- return __spreadProps(__spreadValues({}, elements), {
1664
- schedule,
1665
- subscribe: schedule && visible("qSubscribeOption") && anyElement,
1666
- externalUsers: visible("qSubscribeExternalUsers"),
1667
- // A rejected value comes back undefined, which keeps the checkbox checked as it always started.
1668
- subscribeMyselfDefault: ((_a = structure.getRootDefaults()) == null ? void 0 : _a.subscribeMyself) !== false
1939
+ }
1940
+ __name(createScope, "createScope");
1941
+ function levenshtein(a, b) {
1942
+ const previous = Array.from({
1943
+ length: b.length + 1
1944
+ }, (_, i) => i);
1945
+ for (let i = 1; i <= a.length; i++) {
1946
+ let diagonal = previous[0];
1947
+ previous[0] = i;
1948
+ for (let j = 1; j <= b.length; j++) {
1949
+ const above = previous[j];
1950
+ previous[j] = Math.min(previous[j] + 1, previous[j - 1] + 1, diagonal + (a[i - 1] === b[j - 1] ? 0 : 1));
1951
+ diagonal = above;
1952
+ }
1953
+ }
1954
+ return previous[b.length];
1955
+ }
1956
+ __name(levenshtein, "levenshtein");
1957
+ function suggestKey(key, candidates) {
1958
+ const leaf = key.split(".").pop();
1959
+ let best;
1960
+ let bestDistance = Math.max(2, Math.floor(key.length * 0.3)) + 1;
1961
+ for (const candidate of candidates) {
1962
+ if (candidate.split(".").pop() === leaf && candidate !== key) return candidate;
1963
+ const distance = levenshtein(key.toLowerCase(), candidate.toLowerCase());
1964
+ if (distance < bestDistance) {
1965
+ best = candidate;
1966
+ bestDistance = distance;
1967
+ }
1968
+ }
1969
+ return best;
1970
+ }
1971
+ __name(suggestKey, "suggestKey");
1972
+ function formatCustomizationPath(path) {
1973
+ return path.reduce((result, part) => typeof part === "number" ? `${result}[${part}]` : result ? `${result}.${part}` : part, "");
1974
+ }
1975
+ __name(formatCustomizationPath, "formatCustomizationPath");
1976
+ var _a;
1977
+ var Collector = (_a = class {
1978
+ constructor() {
1979
+ __publicField(this, "errors", []);
1980
+ }
1981
+ add(path, code, message, suggestion) {
1982
+ this.errors.push(__spreadValues({
1983
+ path,
1984
+ code,
1985
+ severity: "error",
1986
+ message
1987
+ }, suggestion && {
1988
+ suggestion
1989
+ }));
1990
+ }
1991
+ }, __name(_a, "Collector"), _a);
1992
+ var describeScope = /* @__PURE__ */ __name((scope, view) => {
1993
+ const owner = scope.widget === Widget.DASHBOARD ? "" : ` of the ${scope.widget}`;
1994
+ if (view !== ROOT_SCOPE) return `in the ${view} view${owner}`;
1995
+ return scope.views.length ? `in any view${owner}` : `in the ${scope.widget} structure`;
1996
+ }, "describeScope");
1997
+ function patternError(pattern) {
1998
+ if (!pattern.trim()) return "Empty key";
1999
+ if (!pattern.includes("*")) {
2000
+ return KEY_CHARS.test(pattern) && !pattern.includes("..") ? void 0 : `Key '${pattern}' contains characters that are not allowed`;
2001
+ }
2002
+ if (pattern === "*") return void 0;
2003
+ const inner = pattern.replace(/^\*/, "").replace(/\*$/, "");
2004
+ if (!inner || inner.includes("*") || !KEY_CHARS.test(inner) || inner.includes("..")) {
2005
+ return `Pattern '${pattern}' is not a valid wildcard; use *text, text* or *text*`;
2006
+ }
2007
+ return void 0;
2008
+ }
2009
+ __name(patternError, "patternError");
2010
+ function validateKeyList(collector, value, path, scope, view) {
2011
+ var _a2;
2012
+ if (!Array.isArray(value)) {
2013
+ collector.add(path, "INVALID_TYPE", `'${path[path.length - 1]}' must be an array of keys`);
2014
+ return;
2015
+ }
2016
+ const keys = (_a2 = scope.keys.get(view)) != null ? _a2 : /* @__PURE__ */ new Set();
2017
+ value.forEach((item, index) => {
2018
+ const itemPath = [
2019
+ ...path,
2020
+ index
2021
+ ];
2022
+ if (typeof item !== "string") {
2023
+ collector.add(itemPath, "INVALID_TYPE", "Each key must be a string");
2024
+ return;
2025
+ }
2026
+ const invalid = patternError(item);
2027
+ if (invalid) {
2028
+ collector.add(itemPath, "INVALID_PATTERN", invalid);
2029
+ } else if (!item.includes("*") && !keys.has(item)) {
2030
+ collector.add(itemPath, "UNKNOWN_KEY", `Key '${item}' does not exist ${describeScope(scope, view)}`, suggestKey(item, keys));
2031
+ }
1669
2032
  });
1670
2033
  }
1671
- __name(resolveDownloadModalConfig, "resolveDownloadModalConfig");
2034
+ __name(validateKeyList, "validateKeyList");
2035
+ function safeValidate(validator, value) {
2036
+ try {
2037
+ return validator(value);
2038
+ } catch (e) {
2039
+ return void 0;
2040
+ }
2041
+ }
2042
+ __name(safeValidate, "safeValidate");
2043
+ function validateDefaultsObject(collector, value, path, validators) {
2044
+ if (!isPlainObject(value)) {
2045
+ collector.add(path, "INVALID_TYPE", "'defaults' must be an object");
2046
+ return;
2047
+ }
2048
+ const walk = /* @__PURE__ */ __name((node, parents) => {
2049
+ Object.keys(node).forEach((key) => {
2050
+ const keyPath = [
2051
+ ...parents,
2052
+ key
2053
+ ];
2054
+ const current = node[key];
2055
+ const validator = validators == null ? void 0 : validators[keyPath.join(".")];
2056
+ if (isPlainObject(current)) {
2057
+ walk(current, keyPath);
2058
+ } else if (validator && current !== void 0 && safeValidate(validator, current) === void 0) {
2059
+ collector.add([
2060
+ ...path,
2061
+ ...keyPath
2062
+ ], "INVALID_DEFAULT", `Default '${keyPath.join(".")}' does not accept the value ${JSON.stringify(current)}`);
2063
+ }
2064
+ });
2065
+ }, "walk");
2066
+ walk(value, []);
2067
+ }
2068
+ __name(validateDefaultsObject, "validateDefaultsObject");
2069
+ function validateProperties(collector, value, path, allowed) {
2070
+ Object.keys(value).filter((key) => !allowed.includes(key)).forEach((key) => collector.add([
2071
+ ...path,
2072
+ key
2073
+ ], "UNKNOWN_PROPERTY", `Property '${key}' is not part of the customization grammar; valid properties: ${allowed.join(", ")}`));
2074
+ }
2075
+ __name(validateProperties, "validateProperties");
2076
+ function validateCondition(collector, value, path) {
2077
+ if (!isPlainObject(value)) {
2078
+ collector.add(path, "INVALID_CONDITION", "A conditional needs a 'condition' object with field, operator and value");
2079
+ return;
2080
+ }
2081
+ validateProperties(collector, value, path, CONDITION_PROPERTIES);
2082
+ if (typeof value.field !== "string" || !value.field) {
2083
+ collector.add([
2084
+ ...path,
2085
+ "field"
2086
+ ], "INVALID_CONDITION", "The condition 'field' must be a non-empty string");
2087
+ }
2088
+ if (!allowedOperators.includes(value.operator)) {
2089
+ collector.add([
2090
+ ...path,
2091
+ "operator"
2092
+ ], "INVALID_CONDITION", `Unknown operator ${JSON.stringify(value.operator)}; valid operators: ${allowedOperators.join(", ")}`);
2093
+ }
2094
+ if (typeof value.value !== "string" && typeof value.value !== "number") {
2095
+ collector.add([
2096
+ ...path,
2097
+ "value"
2098
+ ], "INVALID_CONDITION", "The condition 'value' must be a string or a number");
2099
+ }
2100
+ }
2101
+ __name(validateCondition, "validateCondition");
2102
+ function validateBlock(collector, value, path, scope, view, allowed) {
2103
+ if (!isPlainObject(value)) {
2104
+ collector.add(path, "INVALID_TYPE", "A customization must be an object");
2105
+ return;
2106
+ }
2107
+ validateProperties(collector, value, path, allowed);
2108
+ const has = /* @__PURE__ */ __name((property) => property in value && allowed.includes(property), "has");
2109
+ if ("remove" in value) validateKeyList(collector, value.remove, [
2110
+ ...path,
2111
+ "remove"
2112
+ ], scope, view);
2113
+ if ("keep" in value) validateKeyList(collector, value.keep, [
2114
+ ...path,
2115
+ "keep"
2116
+ ], scope, view);
2117
+ if ("defaults" in value) {
2118
+ validateDefaultsObject(collector, value.defaults, [
2119
+ ...path,
2120
+ "defaults"
2121
+ ], writeValidators[scope.widget]);
2122
+ }
2123
+ if ("subModules" in value) validateSubmodules(collector, value.subModules, [
2124
+ ...path,
2125
+ "subModules"
2126
+ ], scope);
2127
+ if (has("conditional")) {
2128
+ if (!Array.isArray(value.conditional)) {
2129
+ collector.add([
2130
+ ...path,
2131
+ "conditional"
2132
+ ], "INVALID_TYPE", "'conditional' must be an array");
2133
+ } else {
2134
+ value.conditional.forEach((item, index) => {
2135
+ const itemPath = [
2136
+ ...path,
2137
+ "conditional",
2138
+ index
2139
+ ];
2140
+ if (!isPlainObject(item)) {
2141
+ collector.add(itemPath, "INVALID_CONDITION", "Each conditional must be an object");
2142
+ return;
2143
+ }
2144
+ validateCondition(collector, item.condition, [
2145
+ ...itemPath,
2146
+ "condition"
2147
+ ]);
2148
+ validateBlock(collector, item, itemPath, scope, view, CONDITIONAL_PROPERTIES);
2149
+ });
2150
+ }
2151
+ }
2152
+ if (has("views")) validateViews(collector, value.views, [
2153
+ ...path,
2154
+ "views"
2155
+ ], scope);
2156
+ }
2157
+ __name(validateBlock, "validateBlock");
2158
+ function validateViews(collector, value, path, scope) {
2159
+ if (!isPlainObject(value)) {
2160
+ collector.add(path, "INVALID_TYPE", "'views' must be an object");
2161
+ return;
2162
+ }
2163
+ Object.keys(value).forEach((view) => {
2164
+ if (!scope.views.includes(view)) {
2165
+ const valid = scope.views.length ? `valid views: ${scope.views.join(", ")}` : `the ${scope.widget} widget has no views`;
2166
+ collector.add([
2167
+ ...path,
2168
+ view
2169
+ ], "UNKNOWN_VIEW", `View '${view}' does not exist; ${valid}`);
2170
+ return;
2171
+ }
2172
+ validateBlock(collector, value[view], [
2173
+ ...path,
2174
+ view
2175
+ ], scope, view, VIEW_PROPERTIES);
2176
+ });
2177
+ }
2178
+ __name(validateViews, "validateViews");
2179
+ function validateSubmodules(collector, value, path, scope) {
2180
+ if (!isPlainObject(value)) {
2181
+ collector.add(path, "INVALID_TYPE", "'subModules' must be an object");
2182
+ return;
2183
+ }
2184
+ Object.keys(value).forEach((name) => {
2185
+ const subPath = [
2186
+ ...path,
2187
+ name
2188
+ ];
2189
+ if (!scope.subModules.includes(name)) {
2190
+ const valid = scope.subModules.length ? `valid submodules: ${scope.subModules.join(", ")}` : `the ${scope.widget} widget has no submodules`;
2191
+ collector.add(subPath, "UNKNOWN_SUBMODULE", `Submodule '${name}' does not exist; ${valid}`);
2192
+ return;
2193
+ }
2194
+ const widget = Object.keys(WIDGET_SUBMODULE_NAMES).find((key) => WIDGET_SUBMODULE_NAMES[key] === name);
2195
+ const config = widget ? resolveConfig(widget) : void 0;
2196
+ if (!widget || !config) {
2197
+ if (!isPlainObject(value[name])) {
2198
+ collector.add(subPath, "INVALID_TYPE", "A customization must be an object");
2199
+ }
2200
+ return;
2201
+ }
2202
+ validateBlock(collector, value[name], subPath, createScope(widget, config), ROOT_SCOPE, ROOT_PROPERTIES);
2203
+ });
2204
+ }
2205
+ __name(validateSubmodules, "validateSubmodules");
2206
+ function isEmptyCustomization(value) {
2207
+ if (!isPlainObject(value)) return true;
2208
+ const hasItems = /* @__PURE__ */ __name((list) => Array.isArray(list) && list.length > 0, "hasItems");
2209
+ if (hasItems(value.remove) || hasItems(value.keep)) return false;
2210
+ if (isPlainObject(value.defaults) && Object.keys(value.defaults).length) return false;
2211
+ const nested = [
2212
+ ...Array.isArray(value.conditional) ? value.conditional : [],
2213
+ ...isPlainObject(value.views) ? Object.values(value.views) : [],
2214
+ ...isPlainObject(value.subModules) ? Object.values(value.subModules) : []
2215
+ ];
2216
+ return nested.every(isEmptyCustomization);
2217
+ }
2218
+ __name(isEmptyCustomization, "isEmptyCustomization");
2219
+ function validateCustomization(widget, customization, options = {}) {
2220
+ const collector = new Collector();
2221
+ if (!widgetConfigs[widget]) {
2222
+ collector.add([], "UNKNOWN_WIDGET", `Widget '${widget}' has no customization structure`);
2223
+ return {
2224
+ valid: false,
2225
+ errors: collector.errors
2226
+ };
2227
+ }
2228
+ const config = resolveConfig(widget, options.version);
2229
+ if (!config) {
2230
+ collector.add([], "UNKNOWN_VERSION", `Structure version '${options.version}' does not exist for widget '${widget}'`);
2231
+ return {
2232
+ valid: false,
2233
+ errors: collector.errors
2234
+ };
2235
+ }
2236
+ validateBlock(collector, customization, [], createScope(widget, config), ROOT_SCOPE, ROOT_PROPERTIES);
2237
+ if (!collector.errors.length && !options.allowEmpty && isEmptyCustomization(customization)) {
2238
+ collector.add([], "EMPTY_CUSTOMIZATION", "The customization has no rules: add a remove, keep or defaults entry");
2239
+ }
2240
+ return {
2241
+ valid: collector.errors.length === 0,
2242
+ errors: collector.errors
2243
+ };
2244
+ }
2245
+ __name(validateCustomization, "validateCustomization");
2246
+
2247
+ // src/remote/remote-customization.loader.ts
2248
+ var CUSTOMIZATIONS_API_PATH = "/api/admin/v5/customizations/widgets";
2249
+ var DEFAULT_CUSTOMIZATION_ID = "default";
2250
+ var DEFAULT_TIMEOUT_MS = 1e4;
2251
+ var WIDGET_PATTERN = /^[a-z][a-z0-9-]{0,99}$/;
2252
+ var CONTEXT_PATTERN = /^[a-z][a-z0-9-]{0,99}$/;
2253
+ var CUSTOMIZATION_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_-]{0,99}$/;
2254
+ var TIMEOUT = Symbol("timeout");
2255
+ var requestCache = /* @__PURE__ */ new Map();
2256
+ function clearRemoteCustomizationCache() {
2257
+ requestCache.clear();
2258
+ }
2259
+ __name(clearRemoteCustomizationCache, "clearRemoteCustomizationCache");
2260
+ var isValidCustomizationId = /* @__PURE__ */ __name((value) => typeof value === "string" && CUSTOMIZATION_ID_PATTERN.test(value), "isValidCustomizationId");
2261
+ function baseUrl({ apiDomain, domain }) {
2262
+ return `${(apiDomain || domain || "").replace(/\/+$/, "")}${CUSTOMIZATIONS_API_PATH}`;
2263
+ }
2264
+ __name(baseUrl, "baseUrl");
2265
+ function buildHeaders({ apiKey, qvToken }) {
2266
+ const headers = {
2267
+ Accept: "application/json"
2268
+ };
2269
+ if (qvToken) headers.Authorization = `Bearer ${qvToken}`;
2270
+ if (apiKey) headers["x-api-key"] = apiKey;
2271
+ return headers;
2272
+ }
2273
+ __name(buildHeaders, "buildHeaders");
2274
+ var isDefinition = /* @__PURE__ */ __name((body) => isPlainObject(body) && isPlainObject(body.customization), "isDefinition");
2275
+ async function request(url, options) {
2276
+ var _a2, _b;
2277
+ const fetchFn = (_a2 = options.fetchFn) != null ? _a2 : globalThis.fetch;
2278
+ if (typeof fetchFn !== "function") {
2279
+ return {
2280
+ kind: "error",
2281
+ error: {
2282
+ code: "NETWORK",
2283
+ message: "fetch is not available"
2284
+ }
2285
+ };
2286
+ }
2287
+ const timeoutMs = (_b = options.timeoutMs) != null ? _b : DEFAULT_TIMEOUT_MS;
2288
+ const controller = typeof AbortController === "function" ? new AbortController() : void 0;
2289
+ let timer;
2290
+ const timeout = new Promise((_, reject) => {
2291
+ timer = setTimeout(() => {
2292
+ controller == null ? void 0 : controller.abort();
2293
+ reject(TIMEOUT);
2294
+ }, timeoutMs);
2295
+ });
2296
+ timeout.catch(() => void 0);
2297
+ try {
2298
+ const response = await Promise.race([
2299
+ fetchFn(url, {
2300
+ method: "GET",
2301
+ headers: buildHeaders(options),
2302
+ signal: controller == null ? void 0 : controller.signal
2303
+ }),
2304
+ timeout
2305
+ ]);
2306
+ if (response.status === 404) return {
2307
+ kind: "not-found"
2308
+ };
2309
+ if (!response.ok) {
2310
+ return {
2311
+ kind: "error",
2312
+ error: {
2313
+ code: "HTTP",
2314
+ status: response.status,
2315
+ message: `Request failed with status ${response.status}`
2316
+ }
2317
+ };
2318
+ }
2319
+ const body = await Promise.race([
2320
+ response.json(),
2321
+ timeout
2322
+ ]).catch((error) => {
2323
+ if (error === TIMEOUT) throw error;
2324
+ return void 0;
2325
+ });
2326
+ if (!isDefinition(body)) {
2327
+ return {
2328
+ kind: "error",
2329
+ error: {
2330
+ code: "INVALID_RESPONSE",
2331
+ message: "The response is not a customization definition"
2332
+ }
2333
+ };
2334
+ }
2335
+ return {
2336
+ kind: "found",
2337
+ definition: body
2338
+ };
2339
+ } catch (error) {
2340
+ return error === TIMEOUT ? {
2341
+ kind: "error",
2342
+ error: {
2343
+ code: "TIMEOUT",
2344
+ message: `No response after ${timeoutMs} ms`
2345
+ }
2346
+ } : {
2347
+ kind: "error",
2348
+ error: {
2349
+ code: "NETWORK",
2350
+ message: "The customization could not be requested"
2351
+ }
2352
+ };
2353
+ } finally {
2354
+ clearTimeout(timer);
2355
+ }
2356
+ }
2357
+ __name(request, "request");
2358
+ function cachedRequest(url, options) {
2359
+ const useCache = options.cache !== false;
2360
+ const cached = useCache ? requestCache.get(url) : void 0;
2361
+ if (cached) return cached;
2362
+ const pending = request(url, options).then((result) => {
2363
+ if (result.kind === "error") requestCache.delete(url);
2364
+ return result;
2365
+ });
2366
+ if (useCache) requestCache.set(url, pending);
2367
+ return pending;
2368
+ }
2369
+ __name(cachedRequest, "cachedRequest");
2370
+ var definitionUrl = /* @__PURE__ */ __name((options, id) => `${baseUrl(options)}/${encodeURIComponent(options.widget)}/${encodeURIComponent(id)}`, "definitionUrl");
2371
+ var contextUrl = /* @__PURE__ */ __name((options, context) => `${baseUrl(options)}/${encodeURIComponent(options.widget)}?context=${encodeURIComponent(context)}`, "contextUrl");
2372
+ async function loadDefault(options, foundStatus, explicit) {
2373
+ const result = await cachedRequest(definitionUrl(options, DEFAULT_CUSTOMIZATION_ID), options);
2374
+ if (result.kind === "found") return {
2375
+ status: foundStatus,
2376
+ definition: result.definition
2377
+ };
2378
+ if (result.kind === "not-found") {
2379
+ logWarning(`the ${DEFAULT_CUSTOMIZATION_ID} ${options.widget} customization was not found; no remote layer`);
2380
+ return {
2381
+ status: "none"
2382
+ };
2383
+ }
2384
+ if (!explicit) {
2385
+ logWarning(`the ${DEFAULT_CUSTOMIZATION_ID} ${options.widget} customization could not be read (${result.error.code}); no remote layer`);
2386
+ return {
2387
+ status: "none",
2388
+ error: result.error
2389
+ };
2390
+ }
2391
+ return {
2392
+ status: "error",
2393
+ error: result.error
2394
+ };
2395
+ }
2396
+ __name(loadDefault, "loadDefault");
2397
+ async function loadRemoteCustomization(options) {
2398
+ if (typeof (options == null ? void 0 : options.widget) !== "string" || !WIDGET_PATTERN.test(options.widget)) {
2399
+ return {
2400
+ status: "error",
2401
+ error: {
2402
+ code: "INVALID_INPUT",
2403
+ message: "Invalid widget"
2404
+ }
2405
+ };
2406
+ }
2407
+ if (!options.domain && !options.apiDomain) {
2408
+ return {
2409
+ status: "error",
2410
+ error: {
2411
+ code: "INVALID_INPUT",
2412
+ message: "A domain is required"
2413
+ }
2414
+ };
2415
+ }
2416
+ const { customizationId, context } = options;
2417
+ if (customizationId !== void 0 && customizationId !== null && customizationId !== "") {
2418
+ if (!isValidCustomizationId(customizationId)) {
2419
+ logWarning(`invalid customizationId; using ${DEFAULT_CUSTOMIZATION_ID}`);
2420
+ return loadDefault(options, "fallback", true);
2421
+ }
2422
+ const result = await cachedRequest(definitionUrl(options, customizationId), options);
2423
+ if (result.kind === "found") return {
2424
+ status: "found",
2425
+ definition: result.definition
2426
+ };
2427
+ if (result.kind === "error") return {
2428
+ status: "error",
2429
+ error: result.error
2430
+ };
2431
+ logWarning(`customization '${customizationId}' not found; using ${DEFAULT_CUSTOMIZATION_ID}`);
2432
+ return customizationId === DEFAULT_CUSTOMIZATION_ID ? {
2433
+ status: "none"
2434
+ } : loadDefault(options, "fallback", true);
2435
+ }
2436
+ if (context) {
2437
+ if (!CONTEXT_PATTERN.test(context)) {
2438
+ return {
2439
+ status: "error",
2440
+ error: {
2441
+ code: "INVALID_INPUT",
2442
+ message: "Invalid context"
2443
+ }
2444
+ };
2445
+ }
2446
+ const result = await cachedRequest(contextUrl(options, context), options);
2447
+ if (result.kind === "found") return {
2448
+ status: "found",
2449
+ definition: result.definition
2450
+ };
2451
+ if (result.kind === "error") return {
2452
+ status: "error",
2453
+ error: result.error
2454
+ };
2455
+ return loadDefault(options, "fallback", true);
2456
+ }
2457
+ return loadDefault(options, "found", false);
2458
+ }
2459
+ __name(loadRemoteCustomization, "loadRemoteCustomization");
2460
+ function remoteCustomizationLayers(result) {
2461
+ return (result == null ? void 0 : result.definition) ? [
2462
+ result.definition.customization
2463
+ ] : [];
2464
+ }
2465
+ __name(remoteCustomizationLayers, "remoteCustomizationLayers");
1672
2466
 
1673
2467
  // src/doc/dashboard.structure.doc.ts
1674
2468
  var dashboard_structure_doc_exports = {};
@@ -2286,6 +3080,6 @@ _ts_decorate([
2286
3080
  _ts_metadata("design:type", typeof SubModulesDto === "undefined" ? Object : SubModulesDto)
2287
3081
  ], BaseDashboardV1StructureDto.prototype, "subModules", void 0);
2288
3082
 
2289
- export { DOWNLOAD_MODAL_V1_DEFAULTS, DOWNLOAD_MODAL_V1_KEYS, DOWNLOAD_MODAL_VALIDATOR_MAP, DX_VALIDATOR_MAP, dashboard_structure_doc_exports as DashboardDoc, WIDGET_STRUCTURE_SCOPE_FORMAT, WIDGET_STRUCTURE_SCOPE_KIND, WIDGET_SUBMODULE_NAMES, Widget, WidgetStructureInstance, WidgetVersion, buildStructure, calculateRootDefaults, calculateViewMap, checkConditions, evaluateCondition, extractCustomization, getWidgetConfig, getWidgetStructure, hostKeepInheritance, isWidgetStructureScope, resolveDownloadModalConfig, scopeToCustomization, structureFrom, structureFromSubmodule, validateBoolean, validateDefaults };
3083
+ export { CUSTOMIZATIONS_API_PATH, DEFAULT_CUSTOMIZATION_ID, DOWNLOAD_MODAL_V1_DEFAULTS, DOWNLOAD_MODAL_V1_KEYS, DOWNLOAD_MODAL_VALIDATOR_MAP, DX_VALIDATOR_MAP, dashboard_structure_doc_exports as DashboardDoc, WIDGET_STRUCTURE_SCOPE_FORMAT, WIDGET_STRUCTURE_SCOPE_KIND, WIDGET_SUBMODULE_NAMES, Widget, WidgetStructureInstance, WidgetVersion, buildStructure, calculateRootDefaults, calculateViewMap, checkConditions, clearRemoteCustomizationCache, evaluateCondition, extractCustomization, formatCustomizationPath, getWidgetConfig, getWidgetStructure, hostKeepInheritance, isEmptyCustomization, isValidCustomizationId, isWidgetStructureScope, loadRemoteCustomization, remoteCustomizationLayers, scopeToCustomization, structureFrom, structureFromSubmodule, validateBoolean, validateCustomization, validateDefaults };
2290
3084
  //# sourceMappingURL=index.mjs.map
2291
3085
  //# sourceMappingURL=index.mjs.map