@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.
@@ -59,7 +59,7 @@ type NodeRef$1 = {
59
59
  };
60
60
  type NodeMap = Map<string, NodeRef$1>;
61
61
 
62
- type ValidationCode = "root_missing" | "cycle_in_tags" | "bad_bind_reference" | "duplicate_id" | "duplicate_tag_label" | "duplicate_field_name" | "label_missing" | "duplicate_visible_label" | "bad_option_key" | "option_include_exclude_conflict" | "service_field_missing_service_id" | "user_input_field_has_service_option" | "rate_mismatch_across_base" | "rate_coherence_violation" | "utility_without_base" | "unsupported_constraint" | "constraint_contradiction" | "custom_component_missing" | "policy_violation" | "field_unbound" | "constraint_overridden" | "unsupported_constraint_option" | "custom_component_unresolvable" | "quantity_multiple_markers" | "utility_with_service_id" | "utility_missing_rate" | "utility_invalid_mode" | "fallback_bad_node" | "fallback_unknown_service" | "fallback_cycle" | "fallback_no_primary" | "fallback_rate_violation" | "fallback_constraint_mismatch" | "fallback_no_tag_context" | "field_validation_invalid_rule" | "field_validation_invalid_op" | "field_validation_eval_missing_code" | "field_validation_between_missing_bounds" | "field_validation_match_missing_pattern";
62
+ type ValidationCode = "root_missing" | "cycle_in_tags" | "bad_bind_reference" | "duplicate_id" | "duplicate_tag_label" | "duplicate_field_name" | "label_missing" | "duplicate_visible_label" | "bad_option_key" | "option_include_exclude_conflict" | "service_field_missing_service_id" | "user_input_field_has_service_option" | "rate_mismatch_across_base" | "rate_coherence_violation" | "utility_without_base" | "unsupported_constraint" | "constraint_contradiction" | "custom_component_missing" | "policy_violation" | "field_unbound" | "constraint_overridden" | "unsupported_constraint_option" | "custom_component_unresolvable" | "quantity_multiple_markers" | "utility_with_service_id" | "utility_missing_rate" | "utility_invalid_mode" | "fallback_bad_node" | "fallback_unknown_service" | "fallback_cycle" | "fallback_no_primary" | "fallback_rate_violation" | "fallback_constraint_mismatch" | "fallback_no_tag_context" | "field_validation_invalid_rule" | "field_validation_invalid_op" | "field_validation_eval_missing_code" | "field_validation_between_missing_bounds" | "field_validation_match_missing_pattern" | "multiple_order_kinds_selected";
63
63
  type ValidationError = {
64
64
  code: ValidationCode;
65
65
  message: string;
@@ -255,6 +255,7 @@ type Tag = {
255
255
  };
256
256
  type ServiceProps = {
257
257
  order_for_tags?: Record<string, string[]>;
258
+ orderKinds?: Record<string, string>;
258
259
  filters: Tag[];
259
260
  fields: Field[];
260
261
  includes_for_buttons?: Record<string, string[]>;
@@ -1768,6 +1769,9 @@ declare class Editor {
1768
1769
  getFieldValidation(id: string): FieldValidationRule[] | undefined;
1769
1770
  setFieldValidation(id: string, rules: unknown): void;
1770
1771
  clearFieldValidation(id: string): void;
1772
+ setOrderKind(nodeId: string, kind: string): void;
1773
+ deleteOrderKind(nodeId: string): void;
1774
+ pruneKind(kind: string): number;
1771
1775
  getCatalog(): ServiceCatalogState | undefined;
1772
1776
  setCatalog(next?: ServiceCatalogState): void;
1773
1777
  clearCatalog(): void;
@@ -59,7 +59,7 @@ type NodeRef$1 = {
59
59
  };
60
60
  type NodeMap = Map<string, NodeRef$1>;
61
61
 
62
- type ValidationCode = "root_missing" | "cycle_in_tags" | "bad_bind_reference" | "duplicate_id" | "duplicate_tag_label" | "duplicate_field_name" | "label_missing" | "duplicate_visible_label" | "bad_option_key" | "option_include_exclude_conflict" | "service_field_missing_service_id" | "user_input_field_has_service_option" | "rate_mismatch_across_base" | "rate_coherence_violation" | "utility_without_base" | "unsupported_constraint" | "constraint_contradiction" | "custom_component_missing" | "policy_violation" | "field_unbound" | "constraint_overridden" | "unsupported_constraint_option" | "custom_component_unresolvable" | "quantity_multiple_markers" | "utility_with_service_id" | "utility_missing_rate" | "utility_invalid_mode" | "fallback_bad_node" | "fallback_unknown_service" | "fallback_cycle" | "fallback_no_primary" | "fallback_rate_violation" | "fallback_constraint_mismatch" | "fallback_no_tag_context" | "field_validation_invalid_rule" | "field_validation_invalid_op" | "field_validation_eval_missing_code" | "field_validation_between_missing_bounds" | "field_validation_match_missing_pattern";
62
+ type ValidationCode = "root_missing" | "cycle_in_tags" | "bad_bind_reference" | "duplicate_id" | "duplicate_tag_label" | "duplicate_field_name" | "label_missing" | "duplicate_visible_label" | "bad_option_key" | "option_include_exclude_conflict" | "service_field_missing_service_id" | "user_input_field_has_service_option" | "rate_mismatch_across_base" | "rate_coherence_violation" | "utility_without_base" | "unsupported_constraint" | "constraint_contradiction" | "custom_component_missing" | "policy_violation" | "field_unbound" | "constraint_overridden" | "unsupported_constraint_option" | "custom_component_unresolvable" | "quantity_multiple_markers" | "utility_with_service_id" | "utility_missing_rate" | "utility_invalid_mode" | "fallback_bad_node" | "fallback_unknown_service" | "fallback_cycle" | "fallback_no_primary" | "fallback_rate_violation" | "fallback_constraint_mismatch" | "fallback_no_tag_context" | "field_validation_invalid_rule" | "field_validation_invalid_op" | "field_validation_eval_missing_code" | "field_validation_between_missing_bounds" | "field_validation_match_missing_pattern" | "multiple_order_kinds_selected";
63
63
  type ValidationError = {
64
64
  code: ValidationCode;
65
65
  message: string;
@@ -255,6 +255,7 @@ type Tag = {
255
255
  };
256
256
  type ServiceProps = {
257
257
  order_for_tags?: Record<string, string[]>;
258
+ orderKinds?: Record<string, string>;
258
259
  filters: Tag[];
259
260
  fields: Field[];
260
261
  includes_for_buttons?: Record<string, string[]>;
@@ -1768,6 +1769,9 @@ declare class Editor {
1768
1769
  getFieldValidation(id: string): FieldValidationRule[] | undefined;
1769
1770
  setFieldValidation(id: string, rules: unknown): void;
1770
1771
  clearFieldValidation(id: string): void;
1772
+ setOrderKind(nodeId: string, kind: string): void;
1773
+ deleteOrderKind(nodeId: string): void;
1774
+ pruneKind(kind: string): number;
1771
1775
  getCatalog(): ServiceCatalogState | undefined;
1772
1776
  setCatalog(next?: ServiceCatalogState): void;
1773
1777
  clearCatalog(): void;
@@ -3484,6 +3484,7 @@ function normalise(input, opts = {}) {
3484
3484
  const excludes_for_buttons = toStringArrayMap(
3485
3485
  obj.excludes_for_buttons
3486
3486
  );
3487
+ const orderKinds = toStringMap(obj.orderKinds);
3487
3488
  const notices = toNoticeArray(obj.notices);
3488
3489
  let filters = rawFilters.map((t) => coerceTag(t, constraints));
3489
3490
  const fields = rawFields.map((f) => coerceField(f, defRole));
@@ -3495,6 +3496,7 @@ function normalise(input, opts = {}) {
3495
3496
  filters,
3496
3497
  fields,
3497
3498
  order_for_tags: obj.order_for_tags,
3499
+ ...isNonEmpty(orderKinds) && { orderKinds },
3498
3500
  ...isNonEmpty(includes_for_buttons) && { includes_for_buttons },
3499
3501
  ...isNonEmpty(excludes_for_buttons) && { excludes_for_buttons },
3500
3502
  ...fallbacks && (isNonEmpty(fallbacks.nodes) || isNonEmpty(fallbacks.global)) && {
@@ -3705,6 +3707,15 @@ function normaliseBindId(bind) {
3705
3707
  }
3706
3708
  return void 0;
3707
3709
  }
3710
+ function toStringMap(src) {
3711
+ if (!src || typeof src !== "object") return void 0;
3712
+ const out = {};
3713
+ for (const [k, v] of Object.entries(src)) {
3714
+ if (!k || typeof v !== "string") continue;
3715
+ out[k] = v;
3716
+ }
3717
+ return Object.keys(out).length ? out : void 0;
3718
+ }
3708
3719
  function toStringArrayMap(src) {
3709
3720
  if (!src || typeof src !== "object") return void 0;
3710
3721
  const out = {};
@@ -4523,6 +4534,129 @@ function validateOptionMaps(v) {
4523
4534
  }
4524
4535
  }
4525
4536
 
4537
+ // src/utils/order-kind.ts
4538
+ function normalizeSelectedTriggerKey(key, nodeMap) {
4539
+ if (!key) return void 0;
4540
+ const compositeIdx = key.indexOf("::");
4541
+ if (compositeIdx !== -1) {
4542
+ const fieldId = key.slice(0, compositeIdx).trim();
4543
+ const optionId = key.slice(compositeIdx + 2).trim();
4544
+ if (optionId) {
4545
+ const optionRef = nodeMap.get(optionId);
4546
+ if ((optionRef == null ? void 0 : optionRef.kind) === "option") {
4547
+ return { nodeId: optionRef.id, nodeKind: "option" };
4548
+ }
4549
+ }
4550
+ if (fieldId) {
4551
+ const fieldRef = nodeMap.get(fieldId);
4552
+ if ((fieldRef == null ? void 0 : fieldRef.kind) === "field") {
4553
+ return { nodeId: fieldRef.id, nodeKind: "field" };
4554
+ }
4555
+ }
4556
+ return void 0;
4557
+ }
4558
+ const ref = nodeMap.get(key);
4559
+ if (!ref) return void 0;
4560
+ if (ref.kind !== "field" && ref.kind !== "option") return void 0;
4561
+ return { nodeId: ref.id, nodeKind: ref.kind };
4562
+ }
4563
+ function normalizeSelectedOrderKindTriggers(selectedTriggerKeys, nodeMap) {
4564
+ if (!selectedTriggerKeys) return [];
4565
+ const out = [];
4566
+ const seen = /* @__PURE__ */ new Set();
4567
+ for (const rawKey of selectedTriggerKeys) {
4568
+ const key = String(rawKey != null ? rawKey : "");
4569
+ const normalized = normalizeSelectedTriggerKey(key, nodeMap);
4570
+ if (!normalized) continue;
4571
+ const dedupeKey = `${normalized.nodeKind}:${normalized.nodeId}`;
4572
+ if (seen.has(dedupeKey)) continue;
4573
+ seen.add(dedupeKey);
4574
+ out.push(normalized);
4575
+ }
4576
+ return out;
4577
+ }
4578
+ function resolveOrderKind(params) {
4579
+ var _a, _b;
4580
+ const nodeMap = (_a = params.nodeMap) != null ? _a : buildNodeMap(params.props);
4581
+ const orderKinds = (_b = params.props.orderKinds) != null ? _b : {};
4582
+ const normalizedSelected = normalizeSelectedOrderKindTriggers(
4583
+ params.selectedTriggerKeys,
4584
+ nodeMap
4585
+ );
4586
+ const selectedKindToSource = /* @__PURE__ */ new Map();
4587
+ const selectedNodeIdsForKinds = /* @__PURE__ */ new Map();
4588
+ for (const trigger of normalizedSelected) {
4589
+ const mappedKind = orderKinds[trigger.nodeId];
4590
+ if (typeof mappedKind !== "string") continue;
4591
+ if (!selectedKindToSource.has(mappedKind)) {
4592
+ selectedKindToSource.set(mappedKind, {
4593
+ nodeId: trigger.nodeId,
4594
+ nodeKind: trigger.nodeKind
4595
+ });
4596
+ }
4597
+ if (!selectedNodeIdsForKinds.has(mappedKind)) {
4598
+ selectedNodeIdsForKinds.set(mappedKind, /* @__PURE__ */ new Set());
4599
+ }
4600
+ selectedNodeIdsForKinds.get(mappedKind).add(trigger.nodeId);
4601
+ }
4602
+ const selectedKinds = Array.from(selectedKindToSource.keys());
4603
+ if (selectedKinds.length > 1) {
4604
+ const conflictingNodeIds = Array.from(selectedNodeIdsForKinds.values()).flatMap((ids) => Array.from(ids)).filter((id, idx, arr) => arr.indexOf(id) === idx);
4605
+ return {
4606
+ kind: null,
4607
+ source: null,
4608
+ error: "multiple_order_kinds_selected",
4609
+ conflictingKinds: selectedKinds,
4610
+ conflictingNodeIds
4611
+ };
4612
+ }
4613
+ if (selectedKinds.length === 1) {
4614
+ const selectedKind = selectedKinds[0];
4615
+ return {
4616
+ kind: selectedKind,
4617
+ source: selectedKindToSource.get(selectedKind)
4618
+ };
4619
+ }
4620
+ const activeTagId = params.activeTagId;
4621
+ if (activeTagId) {
4622
+ const tagKind = orderKinds[activeTagId];
4623
+ if (typeof tagKind === "string") {
4624
+ return {
4625
+ kind: tagKind,
4626
+ source: { nodeId: activeTagId, nodeKind: "tag" }
4627
+ };
4628
+ }
4629
+ }
4630
+ return { kind: null, source: null };
4631
+ }
4632
+
4633
+ // src/core/validate/steps/order-kinds.ts
4634
+ function validateOrderKinds(v) {
4635
+ var _a, _b, _c;
4636
+ const selectedTriggerKeys = Array.from((_a = v.selectedKeys) != null ? _a : []);
4637
+ if (!selectedTriggerKeys.length) return;
4638
+ const resolved = resolveOrderKind({
4639
+ props: v.props,
4640
+ selectedTriggerKeys,
4641
+ nodeMap: v.nodeMap
4642
+ });
4643
+ if (resolved.error !== "multiple_order_kinds_selected") return;
4644
+ const conflicts = (_b = resolved.conflictingKinds) != null ? _b : [];
4645
+ const affected = (_c = resolved.conflictingNodeIds) != null ? _c : [];
4646
+ v.errors.push({
4647
+ code: "multiple_order_kinds_selected",
4648
+ severity: "error",
4649
+ message: "Multiple selected triggers resolve to different order kinds. Select triggers that resolve to a single order kind.",
4650
+ details: withAffected(
4651
+ {
4652
+ conflictingKinds: conflicts,
4653
+ conflictingNodeIds: affected
4654
+ },
4655
+ affected
4656
+ )
4657
+ });
4658
+ }
4659
+
4526
4660
  // src/core/validate/steps/service-vs-input.ts
4527
4661
  function validateServiceVsUserInput(v) {
4528
4662
  for (const f of v.fields) {
@@ -5846,6 +5980,7 @@ var BuilderImpl = class {
5846
5980
  const out = {
5847
5981
  filters: this.props.filters.slice(),
5848
5982
  fields,
5983
+ ...this.props.orderKinds ? { orderKinds: this.props.orderKinds } : {},
5849
5984
  ...includes_for_buttons && { includes_for_buttons },
5850
5985
  ...excludes_for_buttons && { excludes_for_buttons },
5851
5986
  schema_version: (_e = this.props.schema_version) != null ? _e : "1.0",
@@ -6178,6 +6313,7 @@ function validate(props, ctx = {}) {
6178
6313
  validateStructure(v);
6179
6314
  validateIdentity(v);
6180
6315
  validateOptionMaps(v);
6316
+ validateOrderKinds(v);
6181
6317
  v.fieldsVisibleUnder = createFieldsVisibleUnder(v);
6182
6318
  const visSim = readVisibilitySimOpts(options);
6183
6319
  validateVisibility(v, visSim);
@@ -8100,6 +8236,88 @@ function normalizeQuantityRule(input) {
8100
8236
  return out;
8101
8237
  }
8102
8238
 
8239
+ // src/react/canvas/editor/editor-order-kinds.ts
8240
+ function normalizeKind(kind) {
8241
+ const next = String(kind != null ? kind : "").trim();
8242
+ if (!next) {
8243
+ throw new Error("setOrderKind: kind must be a non-empty string");
8244
+ }
8245
+ return next;
8246
+ }
8247
+ function assertCanonicalNodeId(ctx, nodeId) {
8248
+ const id = String(nodeId != null ? nodeId : "").trim();
8249
+ if (!id) throw new Error("setOrderKind: nodeId is required");
8250
+ if (id.includes("::")) {
8251
+ throw new Error(
8252
+ "setOrderKind: composite/internal trigger keys are not allowed; use canonical tag/field/option ids"
8253
+ );
8254
+ }
8255
+ if (!ctx.isTagId(id) && !ctx.isFieldId(id) && !ctx.isOptionId(id)) {
8256
+ throw new Error(
8257
+ `setOrderKind: node id '${id}' is not a known tag, field, or option`
8258
+ );
8259
+ }
8260
+ if (ctx.isFieldId(id)) {
8261
+ const node = ctx.getNode(id);
8262
+ if (node.kind !== "field" || !isActualButtonField(node.data)) {
8263
+ throw new Error(
8264
+ `setOrderKind: field '${id}' must be a button field without options`
8265
+ );
8266
+ }
8267
+ }
8268
+ }
8269
+ function setOrderKind(ctx, nodeId, kind) {
8270
+ const id = String(nodeId != null ? nodeId : "").trim();
8271
+ const nextKind = normalizeKind(kind);
8272
+ assertCanonicalNodeId(ctx, id);
8273
+ ctx.exec({
8274
+ name: "setOrderKind",
8275
+ do: () => ctx.patchProps((p) => {
8276
+ if (!p.orderKinds) p.orderKinds = {};
8277
+ p.orderKinds[id] = nextKind;
8278
+ }),
8279
+ undo: () => ctx.undo()
8280
+ });
8281
+ }
8282
+ function deleteOrderKind(ctx, nodeId) {
8283
+ const id = String(nodeId != null ? nodeId : "").trim();
8284
+ if (!id) return;
8285
+ ctx.exec({
8286
+ name: "deleteOrderKind",
8287
+ do: () => ctx.patchProps((p) => {
8288
+ if (!p.orderKinds || !Object.prototype.hasOwnProperty.call(p.orderKinds, id)) {
8289
+ return;
8290
+ }
8291
+ delete p.orderKinds[id];
8292
+ if (!Object.keys(p.orderKinds).length) {
8293
+ delete p.orderKinds;
8294
+ }
8295
+ }),
8296
+ undo: () => ctx.undo()
8297
+ });
8298
+ }
8299
+ function pruneOrderKind(ctx, kind) {
8300
+ const target = normalizeKind(kind);
8301
+ let removedCount = 0;
8302
+ ctx.exec({
8303
+ name: "pruneOrderKind",
8304
+ do: () => ctx.patchProps((p) => {
8305
+ if (!p.orderKinds) return;
8306
+ removedCount = 0;
8307
+ for (const [nodeId, mapped] of Object.entries(p.orderKinds)) {
8308
+ if (mapped !== target) continue;
8309
+ delete p.orderKinds[nodeId];
8310
+ removedCount++;
8311
+ }
8312
+ if (!Object.keys(p.orderKinds).length) {
8313
+ delete p.orderKinds;
8314
+ }
8315
+ }),
8316
+ undo: () => ctx.undo()
8317
+ });
8318
+ return removedCount;
8319
+ }
8320
+
8103
8321
  // src/react/canvas/editor/editor-relations.ts
8104
8322
  function wouldCreateTagCycle(_ctx, p, parentId, childId) {
8105
8323
  var _a, _b;
@@ -9080,6 +9298,15 @@ var Editor = class {
9080
9298
  clearFieldValidation(id) {
9081
9299
  return clearFieldValidation(this.moduleCtx(), id);
9082
9300
  }
9301
+ setOrderKind(nodeId, kind) {
9302
+ return setOrderKind(this.moduleCtx(), nodeId, kind);
9303
+ }
9304
+ deleteOrderKind(nodeId) {
9305
+ return deleteOrderKind(this.moduleCtx(), nodeId);
9306
+ }
9307
+ pruneKind(kind) {
9308
+ return pruneOrderKind(this.moduleCtx(), kind);
9309
+ }
9083
9310
  getCatalog() {
9084
9311
  return cloneDeep4(this.catalog);
9085
9312
  }