@timeax/digital-service-engine 0.2.4 → 0.2.5

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.
@@ -730,6 +730,7 @@ function normalise(input, opts = {}) {
730
730
  const excludes_for_buttons = toStringArrayMap(
731
731
  obj.excludes_for_buttons
732
732
  );
733
+ const orderKinds = toStringMap(obj.orderKinds);
733
734
  const notices = toNoticeArray(obj.notices);
734
735
  let filters = rawFilters.map((t) => coerceTag(t, constraints));
735
736
  const fields = rawFields.map((f) => coerceField(f, defRole));
@@ -741,6 +742,7 @@ function normalise(input, opts = {}) {
741
742
  filters,
742
743
  fields,
743
744
  order_for_tags: obj.order_for_tags,
745
+ ...isNonEmpty(orderKinds) && { orderKinds },
744
746
  ...isNonEmpty(includes_for_buttons) && { includes_for_buttons },
745
747
  ...isNonEmpty(excludes_for_buttons) && { excludes_for_buttons },
746
748
  ...fallbacks && (isNonEmpty(fallbacks.nodes) || isNonEmpty(fallbacks.global)) && {
@@ -951,6 +953,15 @@ function normaliseBindId(bind) {
951
953
  }
952
954
  return void 0;
953
955
  }
956
+ function toStringMap(src) {
957
+ if (!src || typeof src !== "object") return void 0;
958
+ const out = {};
959
+ for (const [k, v] of Object.entries(src)) {
960
+ if (!k || typeof v !== "string") continue;
961
+ out[k] = v;
962
+ }
963
+ return Object.keys(out).length ? out : void 0;
964
+ }
954
965
  function toStringArrayMap(src) {
955
966
  if (!src || typeof src !== "object") return void 0;
956
967
  const out = {};
@@ -1769,6 +1780,129 @@ function validateOptionMaps(v) {
1769
1780
  }
1770
1781
  }
1771
1782
 
1783
+ // src/utils/order-kind.ts
1784
+ function normalizeSelectedTriggerKey(key, nodeMap) {
1785
+ if (!key) return void 0;
1786
+ const compositeIdx = key.indexOf("::");
1787
+ if (compositeIdx !== -1) {
1788
+ const fieldId = key.slice(0, compositeIdx).trim();
1789
+ const optionId = key.slice(compositeIdx + 2).trim();
1790
+ if (optionId) {
1791
+ const optionRef = nodeMap.get(optionId);
1792
+ if ((optionRef == null ? void 0 : optionRef.kind) === "option") {
1793
+ return { nodeId: optionRef.id, nodeKind: "option" };
1794
+ }
1795
+ }
1796
+ if (fieldId) {
1797
+ const fieldRef = nodeMap.get(fieldId);
1798
+ if ((fieldRef == null ? void 0 : fieldRef.kind) === "field") {
1799
+ return { nodeId: fieldRef.id, nodeKind: "field" };
1800
+ }
1801
+ }
1802
+ return void 0;
1803
+ }
1804
+ const ref = nodeMap.get(key);
1805
+ if (!ref) return void 0;
1806
+ if (ref.kind !== "field" && ref.kind !== "option") return void 0;
1807
+ return { nodeId: ref.id, nodeKind: ref.kind };
1808
+ }
1809
+ function normalizeSelectedOrderKindTriggers(selectedTriggerKeys, nodeMap) {
1810
+ if (!selectedTriggerKeys) return [];
1811
+ const out = [];
1812
+ const seen = /* @__PURE__ */ new Set();
1813
+ for (const rawKey of selectedTriggerKeys) {
1814
+ const key = String(rawKey != null ? rawKey : "");
1815
+ const normalized = normalizeSelectedTriggerKey(key, nodeMap);
1816
+ if (!normalized) continue;
1817
+ const dedupeKey = `${normalized.nodeKind}:${normalized.nodeId}`;
1818
+ if (seen.has(dedupeKey)) continue;
1819
+ seen.add(dedupeKey);
1820
+ out.push(normalized);
1821
+ }
1822
+ return out;
1823
+ }
1824
+ function resolveOrderKind(params) {
1825
+ var _a, _b;
1826
+ const nodeMap = (_a = params.nodeMap) != null ? _a : buildNodeMap(params.props);
1827
+ const orderKinds = (_b = params.props.orderKinds) != null ? _b : {};
1828
+ const normalizedSelected = normalizeSelectedOrderKindTriggers(
1829
+ params.selectedTriggerKeys,
1830
+ nodeMap
1831
+ );
1832
+ const selectedKindToSource = /* @__PURE__ */ new Map();
1833
+ const selectedNodeIdsForKinds = /* @__PURE__ */ new Map();
1834
+ for (const trigger of normalizedSelected) {
1835
+ const mappedKind = orderKinds[trigger.nodeId];
1836
+ if (typeof mappedKind !== "string") continue;
1837
+ if (!selectedKindToSource.has(mappedKind)) {
1838
+ selectedKindToSource.set(mappedKind, {
1839
+ nodeId: trigger.nodeId,
1840
+ nodeKind: trigger.nodeKind
1841
+ });
1842
+ }
1843
+ if (!selectedNodeIdsForKinds.has(mappedKind)) {
1844
+ selectedNodeIdsForKinds.set(mappedKind, /* @__PURE__ */ new Set());
1845
+ }
1846
+ selectedNodeIdsForKinds.get(mappedKind).add(trigger.nodeId);
1847
+ }
1848
+ const selectedKinds = Array.from(selectedKindToSource.keys());
1849
+ if (selectedKinds.length > 1) {
1850
+ const conflictingNodeIds = Array.from(selectedNodeIdsForKinds.values()).flatMap((ids) => Array.from(ids)).filter((id, idx, arr) => arr.indexOf(id) === idx);
1851
+ return {
1852
+ kind: null,
1853
+ source: null,
1854
+ error: "multiple_order_kinds_selected",
1855
+ conflictingKinds: selectedKinds,
1856
+ conflictingNodeIds
1857
+ };
1858
+ }
1859
+ if (selectedKinds.length === 1) {
1860
+ const selectedKind = selectedKinds[0];
1861
+ return {
1862
+ kind: selectedKind,
1863
+ source: selectedKindToSource.get(selectedKind)
1864
+ };
1865
+ }
1866
+ const activeTagId = params.activeTagId;
1867
+ if (activeTagId) {
1868
+ const tagKind = orderKinds[activeTagId];
1869
+ if (typeof tagKind === "string") {
1870
+ return {
1871
+ kind: tagKind,
1872
+ source: { nodeId: activeTagId, nodeKind: "tag" }
1873
+ };
1874
+ }
1875
+ }
1876
+ return { kind: null, source: null };
1877
+ }
1878
+
1879
+ // src/core/validate/steps/order-kinds.ts
1880
+ function validateOrderKinds(v) {
1881
+ var _a, _b, _c;
1882
+ const selectedTriggerKeys = Array.from((_a = v.selectedKeys) != null ? _a : []);
1883
+ if (!selectedTriggerKeys.length) return;
1884
+ const resolved = resolveOrderKind({
1885
+ props: v.props,
1886
+ selectedTriggerKeys,
1887
+ nodeMap: v.nodeMap
1888
+ });
1889
+ if (resolved.error !== "multiple_order_kinds_selected") return;
1890
+ const conflicts = (_b = resolved.conflictingKinds) != null ? _b : [];
1891
+ const affected = (_c = resolved.conflictingNodeIds) != null ? _c : [];
1892
+ v.errors.push({
1893
+ code: "multiple_order_kinds_selected",
1894
+ severity: "error",
1895
+ message: "Multiple selected triggers resolve to different order kinds. Select triggers that resolve to a single order kind.",
1896
+ details: withAffected(
1897
+ {
1898
+ conflictingKinds: conflicts,
1899
+ conflictingNodeIds: affected
1900
+ },
1901
+ affected
1902
+ )
1903
+ });
1904
+ }
1905
+
1772
1906
  // src/core/validate/steps/service-vs-input.ts
1773
1907
  function validateServiceVsUserInput(v) {
1774
1908
  for (const f of v.fields) {
@@ -3097,6 +3231,7 @@ var BuilderImpl = class {
3097
3231
  const out = {
3098
3232
  filters: this.props.filters.slice(),
3099
3233
  fields,
3234
+ ...this.props.orderKinds ? { orderKinds: this.props.orderKinds } : {},
3100
3235
  ...includes_for_buttons && { includes_for_buttons },
3101
3236
  ...excludes_for_buttons && { excludes_for_buttons },
3102
3237
  schema_version: (_e = this.props.schema_version) != null ? _e : "1.0",
@@ -3429,6 +3564,7 @@ function validate(props, ctx = {}) {
3429
3564
  validateStructure(v);
3430
3565
  validateIdentity(v);
3431
3566
  validateOptionMaps(v);
3567
+ validateOrderKinds(v);
3432
3568
  v.fieldsVisibleUnder = createFieldsVisibleUnder(v);
3433
3569
  const visSim = readVisibilitySimOpts(options);
3434
3570
  validateVisibility(v, visSim);
@@ -4777,6 +4913,13 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
4777
4913
  fieldById
4778
4914
  );
4779
4915
  const { min, max } = resolveMinMax(servicesList, services);
4916
+ const maybeNodeMap = typeof builder.getNodeMap === "function" ? builder.getNodeMap() : void 0;
4917
+ const resolvedOrderKind = resolveOrderKind({
4918
+ props,
4919
+ activeTagId: tagId,
4920
+ selectedTriggerKeys: selectedButtonKeys,
4921
+ nodeMap: maybeNodeMap
4922
+ });
4780
4923
  const prunedFallbacks = pruneFallbacksConservative(
4781
4924
  props.fallbacks,
4782
4925
  { tagId, constraints: tagConstraints, serviceMap, servicesList },
@@ -4832,6 +4975,8 @@ function buildOrderSnapshot(props, builder, selection, services, settings = {})
4832
4975
  },
4833
4976
  min,
4834
4977
  max: max != null ? max : min,
4978
+ orderKind: resolvedOrderKind.kind,
4979
+ orderKindSource: resolvedOrderKind.source,
4835
4980
  quantity,
4836
4981
  quantitySource,
4837
4982
  services: servicesList,
@@ -6853,6 +6998,88 @@ function normalizeQuantityRule(input) {
6853
6998
  return out;
6854
6999
  }
6855
7000
 
7001
+ // src/react/canvas/editor/editor-order-kinds.ts
7002
+ function normalizeKind(kind) {
7003
+ const next = String(kind != null ? kind : "").trim();
7004
+ if (!next) {
7005
+ throw new Error("setOrderKind: kind must be a non-empty string");
7006
+ }
7007
+ return next;
7008
+ }
7009
+ function assertCanonicalNodeId(ctx, nodeId) {
7010
+ const id = String(nodeId != null ? nodeId : "").trim();
7011
+ if (!id) throw new Error("setOrderKind: nodeId is required");
7012
+ if (id.includes("::")) {
7013
+ throw new Error(
7014
+ "setOrderKind: composite/internal trigger keys are not allowed; use canonical tag/field/option ids"
7015
+ );
7016
+ }
7017
+ if (!ctx.isTagId(id) && !ctx.isFieldId(id) && !ctx.isOptionId(id)) {
7018
+ throw new Error(
7019
+ `setOrderKind: node id '${id}' is not a known tag, field, or option`
7020
+ );
7021
+ }
7022
+ if (ctx.isFieldId(id)) {
7023
+ const node = ctx.getNode(id);
7024
+ if (node.kind !== "field" || !isActualButtonField(node.data)) {
7025
+ throw new Error(
7026
+ `setOrderKind: field '${id}' must be a button field without options`
7027
+ );
7028
+ }
7029
+ }
7030
+ }
7031
+ function setOrderKind(ctx, nodeId, kind) {
7032
+ const id = String(nodeId != null ? nodeId : "").trim();
7033
+ const nextKind = normalizeKind(kind);
7034
+ assertCanonicalNodeId(ctx, id);
7035
+ ctx.exec({
7036
+ name: "setOrderKind",
7037
+ do: () => ctx.patchProps((p) => {
7038
+ if (!p.orderKinds) p.orderKinds = {};
7039
+ p.orderKinds[id] = nextKind;
7040
+ }),
7041
+ undo: () => ctx.undo()
7042
+ });
7043
+ }
7044
+ function deleteOrderKind(ctx, nodeId) {
7045
+ const id = String(nodeId != null ? nodeId : "").trim();
7046
+ if (!id) return;
7047
+ ctx.exec({
7048
+ name: "deleteOrderKind",
7049
+ do: () => ctx.patchProps((p) => {
7050
+ if (!p.orderKinds || !Object.prototype.hasOwnProperty.call(p.orderKinds, id)) {
7051
+ return;
7052
+ }
7053
+ delete p.orderKinds[id];
7054
+ if (!Object.keys(p.orderKinds).length) {
7055
+ delete p.orderKinds;
7056
+ }
7057
+ }),
7058
+ undo: () => ctx.undo()
7059
+ });
7060
+ }
7061
+ function pruneOrderKind(ctx, kind) {
7062
+ const target = normalizeKind(kind);
7063
+ let removedCount = 0;
7064
+ ctx.exec({
7065
+ name: "pruneOrderKind",
7066
+ do: () => ctx.patchProps((p) => {
7067
+ if (!p.orderKinds) return;
7068
+ removedCount = 0;
7069
+ for (const [nodeId, mapped] of Object.entries(p.orderKinds)) {
7070
+ if (mapped !== target) continue;
7071
+ delete p.orderKinds[nodeId];
7072
+ removedCount++;
7073
+ }
7074
+ if (!Object.keys(p.orderKinds).length) {
7075
+ delete p.orderKinds;
7076
+ }
7077
+ }),
7078
+ undo: () => ctx.undo()
7079
+ });
7080
+ return removedCount;
7081
+ }
7082
+
6856
7083
  // src/react/canvas/editor/editor-relations.ts
6857
7084
  function wouldCreateTagCycle(_ctx, p, parentId, childId) {
6858
7085
  var _a, _b;
@@ -7833,6 +8060,15 @@ var Editor = class {
7833
8060
  clearFieldValidation(id) {
7834
8061
  return clearFieldValidation(this.moduleCtx(), id);
7835
8062
  }
8063
+ setOrderKind(nodeId, kind) {
8064
+ return setOrderKind(this.moduleCtx(), nodeId, kind);
8065
+ }
8066
+ deleteOrderKind(nodeId) {
8067
+ return deleteOrderKind(this.moduleCtx(), nodeId);
8068
+ }
8069
+ pruneKind(kind) {
8070
+ return pruneOrderKind(this.moduleCtx(), kind);
8071
+ }
7836
8072
  getCatalog() {
7837
8073
  return (0, import_lodash_es4.cloneDeep)(this.catalog);
7838
8074
  }