@timeax/digital-service-engine 0.0.1 → 0.0.2

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.
@@ -30,59 +30,9 @@ interface BaseFieldUI {
30
30
  name?: string;
31
31
  label: string;
32
32
  required?: boolean;
33
- /** Host-defined prop names → typed UI nodes */
34
- ui?: Record<string, Ui>;
35
33
  /** Host-defined prop names → runtime default values (untyped base) */
36
34
  defaults?: Record<string, unknown>;
37
35
  }
38
- type Ui = UiString | UiNumber | UiBoolean | UiAnyOf | UiArray | UiObject;
39
- /** string */
40
- interface UiString {
41
- type: "string";
42
- enum?: string[];
43
- minLength?: number;
44
- maxLength?: number;
45
- pattern?: string;
46
- format?: string;
47
- }
48
- /** number */
49
- interface UiNumber {
50
- type: "number";
51
- minimum?: number;
52
- maximum?: number;
53
- multipleOf?: number;
54
- }
55
- /** boolean */
56
- interface UiBoolean {
57
- type: "boolean";
58
- }
59
- /** enumerated choices */
60
- interface UiAnyOf {
61
- type: "anyOf";
62
- multiple?: boolean;
63
- items: Array<{
64
- type: "string" | "number" | "boolean";
65
- title?: string;
66
- description?: string;
67
- value: string | number | boolean;
68
- }>;
69
- }
70
- /** arrays: homogeneous (item) or tuple (items) */
71
- interface UiArray {
72
- type: "array";
73
- item?: Ui;
74
- items?: Ui[];
75
- minItems?: number;
76
- maxItems?: number;
77
- uniqueItems?: boolean;
78
- }
79
- /** objects: nested props */
80
- interface UiObject {
81
- type: "object";
82
- fields: Record<string, Ui>;
83
- required?: string[];
84
- order?: string[];
85
- }
86
36
  type FieldOption = {
87
37
  id: string;
88
38
  label: string;
@@ -143,6 +93,8 @@ type ServiceProps = {
143
93
  excludes_for_buttons?: Record<string, string[]>;
144
94
  schema_version?: string;
145
95
  fallbacks?: ServiceFallback;
96
+ name?: string;
97
+ notices?: ServicePropsNotice[];
146
98
  };
147
99
  type ServiceIdRef = number | string;
148
100
  type NodeIdRef = string;
@@ -152,6 +104,34 @@ type ServiceFallback = {
152
104
  /** Primary→fallback list used when no node-scoped entry is present */
153
105
  global?: Record<ServiceIdRef, ServiceIdRef[]>;
154
106
  };
107
+ type NoticeType = "public" | "private";
108
+ type NoticeSeverity = "info" | "warning" | "error";
109
+ /**
110
+ * “label” is lightweight + UI-friendly (best, sale, hot, etc).
111
+ * Others remain semantic / governance oriented.
112
+ */
113
+ type NoticeKind = "label" | "warning" | "deprecation" | "compat" | "migration" | "policy";
114
+ type NoticeTarget = {
115
+ scope: "global";
116
+ } | {
117
+ scope: "node";
118
+ node_kind: "tag" | "field" | "option";
119
+ node_id: string;
120
+ };
121
+ interface ServicePropsNotice {
122
+ id: string;
123
+ type: NoticeType;
124
+ kind: NoticeKind;
125
+ severity: NoticeSeverity;
126
+ target: NoticeTarget;
127
+ title: string;
128
+ description?: string;
129
+ reason?: string;
130
+ marked_at?: string;
131
+ icon?: string;
132
+ color?: string;
133
+ meta?: Record<string, unknown>;
134
+ }
155
135
 
156
136
  type NodeKind$1 = "tag" | "field" | "comment" | "option";
157
137
  type EdgeKind = "child" | "bind" | "include" | "exclude" | "error" | "anchor";
@@ -213,6 +193,123 @@ type DgpServiceCapability = {
213
193
  };
214
194
  type DgpServiceMap = Record<string, DgpServiceCapability> & Record<number, DgpServiceCapability>;
215
195
 
196
+ interface ButtonValue {
197
+ id: string;
198
+ value: string | number;
199
+ service_id?: number;
200
+ pricing_role?: "base" | "utility";
201
+ meta?: Record<string, unknown> & UtilityMark & WithQuantityDefault;
202
+ }
203
+ type Scalar = string | number | boolean | ButtonValue | null;
204
+ type UtilityMode = "flat" | "per_quantity" | "per_value" | "percent";
205
+ type QuantityRule = {
206
+ valueBy: "value" | "length" | "eval";
207
+ code?: string;
208
+ };
209
+ type UtilityLineItem = {
210
+ nodeId: string;
211
+ mode: UtilityMode;
212
+ rate: number;
213
+ inputs: {
214
+ quantity: number;
215
+ value?: Scalar | Scalar[];
216
+ valueBy?: "value" | "length" | "eval";
217
+ evalCodeUsed?: boolean;
218
+ };
219
+ };
220
+ type FallbackDiagnostics = {
221
+ scope: "node" | "global";
222
+ nodeId?: string;
223
+ primary: string | number;
224
+ candidate: string | number;
225
+ reasons: Array<"rate_violation" | "constraint_mismatch" | "unknown_service" | "ambiguous_context">;
226
+ };
227
+ type SnapshotContext = {
228
+ /** The single active tag id for this order */
229
+ tag: string;
230
+ /** Effective (post-propagation) constraints on that tag */
231
+ constraints: Partial<Record<"refill" | "cancel" | "dripfeed", boolean>>;
232
+ /**
233
+ * Per-node evaluation context:
234
+ * - For the active tag node itself: the same tag id.
235
+ * - For an option node: parent's field.bind_id must include this tag to be applicable; otherwise null.
236
+ * - For a field node (optional to include later): same rule as option, derived from field.bind_id.
237
+ */
238
+ nodeContexts: Record<string, string | null>;
239
+ /** Client pruning policy used (so server can mirror/compare). */
240
+ policy: {
241
+ ratePolicy: {
242
+ kind: "lte_primary" | "none";
243
+ thresholdPct?: number;
244
+ };
245
+ requireConstraintFit: boolean;
246
+ };
247
+ };
248
+ type OrderSnapshot = {
249
+ version: "1";
250
+ mode: "prod" | "dev";
251
+ builtAt: string;
252
+ selection: {
253
+ tag: string;
254
+ fields: Array<{
255
+ id: string;
256
+ type: string;
257
+ selectedOptions?: string[];
258
+ }>;
259
+ };
260
+ inputs: {
261
+ form: Record<string, Scalar | Scalar[]>;
262
+ selections: Record<string, string[]>;
263
+ };
264
+ quantity: number;
265
+ quantitySource: {
266
+ kind: "field" | "tag" | "option" | "default";
267
+ id?: string;
268
+ rule?: QuantityRule;
269
+ defaultedFromHost?: boolean;
270
+ };
271
+ min: number;
272
+ max: number;
273
+ services: Array<string | number>;
274
+ serviceMap: Record<string, Array<string | number>>;
275
+ fallbacks?: {
276
+ nodes?: Record<string, Array<string | number>>;
277
+ global?: Record<string | number, Array<string | number>>;
278
+ };
279
+ utilities?: UtilityLineItem[];
280
+ warnings?: {
281
+ utility?: Array<{
282
+ nodeId: string;
283
+ reason: string;
284
+ }>;
285
+ fallbacks?: FallbackDiagnostics[];
286
+ };
287
+ meta?: {
288
+ schema_version?: string;
289
+ workspaceId?: string;
290
+ builder?: {
291
+ commit?: string;
292
+ };
293
+ context?: SnapshotContext;
294
+ };
295
+ };
296
+
297
+ type NodeRef = {
298
+ kind: "tag";
299
+ id: string;
300
+ node: Tag;
301
+ } | {
302
+ kind: "field";
303
+ id: string;
304
+ node: Field;
305
+ } | {
306
+ kind: "option";
307
+ id: string;
308
+ node: FieldOption;
309
+ fieldId: string;
310
+ };
311
+ type NodeMap = Map<string, NodeRef>;
312
+
216
313
  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" | "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";
217
314
  type ValidationError = {
218
315
  code: ValidationCode;
@@ -261,6 +358,7 @@ type DynamicRule = {
261
358
  };
262
359
  type ValidatorOptions = {
263
360
  serviceMap?: DgpServiceMap;
361
+ nodeMap?: NodeMap;
264
362
  allowUnsafe?: boolean;
265
363
  selectedOptionKeys?: string[];
266
364
  globalUtilityGuard?: boolean;
@@ -294,7 +392,17 @@ type NormaliseOptions = {
294
392
  };
295
393
  declare function normalise(input: unknown, opts?: NormaliseOptions): ServiceProps;
296
394
 
395
+ /**
396
+ * Core synchronous validate.
397
+ */
297
398
  declare function validate(props: ServiceProps, ctx?: ValidatorOptions): ValidationError[];
399
+ /**
400
+ * UI-friendly async wrapper:
401
+ * - yields to microtask queue
402
+ * - then yields to the next animation frame (so paint can happen)
403
+ * - then runs validate()
404
+ */
405
+ declare function validateAsync(props: ServiceProps, ctx?: ValidatorOptions): Promise<ValidationError[]>;
298
406
 
299
407
  /** Options you can set on the builder (used for validation/visibility) */
300
408
  type BuilderOptions = Omit<ValidatorOptions, "serviceMap"> & {
@@ -338,6 +446,10 @@ interface Builder {
338
446
  description: string;
339
447
  value: string;
340
448
  }[];
449
+ isTagId(id: string): boolean;
450
+ isFieldId(id: string): boolean;
451
+ isOptionId(id: string): boolean;
452
+ getNodeMap(): NodeMap;
341
453
  }
342
454
  declare function createBuilder(opts?: BuilderOptions): Builder;
343
455
 
@@ -504,4 +616,30 @@ interface NodeIndex {
504
616
  }
505
617
  declare function createNodeIndex(builder: Builder): NodeIndex;
506
618
 
507
- export { type AncestryHit, type AnyNode, type Builder, type BuilderOptions, type FailedFallbackContext, type FieldNode, type NodeIndex, type NodeKind, type NormaliseOptions, type OptionNode, type RateCoherenceDiagnostic, type RelKind, type TagNode, type UnknownNode, type WithAncestry, collectFailedFallbacks, createBuilder, createNodeIndex, getEligibleFallbacks, normalise, resolveServiceFallback, validate, validateRateCoherenceDeep };
619
+ type BuildOrderSnapshotSettings = {
620
+ mode?: "prod" | "dev";
621
+ hostDefaultQuantity?: number;
622
+ /** Full fallback policy */
623
+ fallback?: FallbackSettings;
624
+ workspaceId?: string;
625
+ builderCommit?: string;
626
+ };
627
+ type BuildOrderSelection = {
628
+ /** Single active context (one tag) coming from Selection */
629
+ activeTagId: string;
630
+ /** Non-option inputs, keyed by fieldId (will be remapped to field.name in the payload) */
631
+ formValuesByFieldId: Record<string, Scalar | Scalar[]>;
632
+ /** Option selections, keyed by fieldId → optionId[] */
633
+ optionSelectionsByFieldId: Record<string, string[]>;
634
+ /**
635
+ * Selection visit order for options (optional, improves "first option wins primary" determinism).
636
+ * If omitted, iteration order falls back to Object.entries(optionSelectionsByFieldId).
637
+ */
638
+ optionTraversalOrder?: Array<{
639
+ fieldId: string;
640
+ optionId: string;
641
+ }>;
642
+ };
643
+ declare function buildOrderSnapshot(props: ServiceProps, builder: Builder, selection: BuildOrderSelection, services: DgpServiceMap, settings?: BuildOrderSnapshotSettings): OrderSnapshot;
644
+
645
+ export { type AncestryHit, type AnyNode, type Builder, type BuilderOptions, type FailedFallbackContext, type FieldNode, type NodeIndex, type NodeKind, type NormaliseOptions, type OptionNode, type RateCoherenceDiagnostic, type RelKind, type TagNode, type UnknownNode, type WithAncestry, buildOrderSnapshot, collectFailedFallbacks, createBuilder, createNodeIndex, getEligibleFallbacks, normalise, resolveServiceFallback, validate, validateAsync, validateRateCoherenceDeep };
@@ -30,59 +30,9 @@ interface BaseFieldUI {
30
30
  name?: string;
31
31
  label: string;
32
32
  required?: boolean;
33
- /** Host-defined prop names → typed UI nodes */
34
- ui?: Record<string, Ui>;
35
33
  /** Host-defined prop names → runtime default values (untyped base) */
36
34
  defaults?: Record<string, unknown>;
37
35
  }
38
- type Ui = UiString | UiNumber | UiBoolean | UiAnyOf | UiArray | UiObject;
39
- /** string */
40
- interface UiString {
41
- type: "string";
42
- enum?: string[];
43
- minLength?: number;
44
- maxLength?: number;
45
- pattern?: string;
46
- format?: string;
47
- }
48
- /** number */
49
- interface UiNumber {
50
- type: "number";
51
- minimum?: number;
52
- maximum?: number;
53
- multipleOf?: number;
54
- }
55
- /** boolean */
56
- interface UiBoolean {
57
- type: "boolean";
58
- }
59
- /** enumerated choices */
60
- interface UiAnyOf {
61
- type: "anyOf";
62
- multiple?: boolean;
63
- items: Array<{
64
- type: "string" | "number" | "boolean";
65
- title?: string;
66
- description?: string;
67
- value: string | number | boolean;
68
- }>;
69
- }
70
- /** arrays: homogeneous (item) or tuple (items) */
71
- interface UiArray {
72
- type: "array";
73
- item?: Ui;
74
- items?: Ui[];
75
- minItems?: number;
76
- maxItems?: number;
77
- uniqueItems?: boolean;
78
- }
79
- /** objects: nested props */
80
- interface UiObject {
81
- type: "object";
82
- fields: Record<string, Ui>;
83
- required?: string[];
84
- order?: string[];
85
- }
86
36
  type FieldOption = {
87
37
  id: string;
88
38
  label: string;
@@ -143,6 +93,8 @@ type ServiceProps = {
143
93
  excludes_for_buttons?: Record<string, string[]>;
144
94
  schema_version?: string;
145
95
  fallbacks?: ServiceFallback;
96
+ name?: string;
97
+ notices?: ServicePropsNotice[];
146
98
  };
147
99
  type ServiceIdRef = number | string;
148
100
  type NodeIdRef = string;
@@ -152,6 +104,34 @@ type ServiceFallback = {
152
104
  /** Primary→fallback list used when no node-scoped entry is present */
153
105
  global?: Record<ServiceIdRef, ServiceIdRef[]>;
154
106
  };
107
+ type NoticeType = "public" | "private";
108
+ type NoticeSeverity = "info" | "warning" | "error";
109
+ /**
110
+ * “label” is lightweight + UI-friendly (best, sale, hot, etc).
111
+ * Others remain semantic / governance oriented.
112
+ */
113
+ type NoticeKind = "label" | "warning" | "deprecation" | "compat" | "migration" | "policy";
114
+ type NoticeTarget = {
115
+ scope: "global";
116
+ } | {
117
+ scope: "node";
118
+ node_kind: "tag" | "field" | "option";
119
+ node_id: string;
120
+ };
121
+ interface ServicePropsNotice {
122
+ id: string;
123
+ type: NoticeType;
124
+ kind: NoticeKind;
125
+ severity: NoticeSeverity;
126
+ target: NoticeTarget;
127
+ title: string;
128
+ description?: string;
129
+ reason?: string;
130
+ marked_at?: string;
131
+ icon?: string;
132
+ color?: string;
133
+ meta?: Record<string, unknown>;
134
+ }
155
135
 
156
136
  type NodeKind$1 = "tag" | "field" | "comment" | "option";
157
137
  type EdgeKind = "child" | "bind" | "include" | "exclude" | "error" | "anchor";
@@ -213,6 +193,123 @@ type DgpServiceCapability = {
213
193
  };
214
194
  type DgpServiceMap = Record<string, DgpServiceCapability> & Record<number, DgpServiceCapability>;
215
195
 
196
+ interface ButtonValue {
197
+ id: string;
198
+ value: string | number;
199
+ service_id?: number;
200
+ pricing_role?: "base" | "utility";
201
+ meta?: Record<string, unknown> & UtilityMark & WithQuantityDefault;
202
+ }
203
+ type Scalar = string | number | boolean | ButtonValue | null;
204
+ type UtilityMode = "flat" | "per_quantity" | "per_value" | "percent";
205
+ type QuantityRule = {
206
+ valueBy: "value" | "length" | "eval";
207
+ code?: string;
208
+ };
209
+ type UtilityLineItem = {
210
+ nodeId: string;
211
+ mode: UtilityMode;
212
+ rate: number;
213
+ inputs: {
214
+ quantity: number;
215
+ value?: Scalar | Scalar[];
216
+ valueBy?: "value" | "length" | "eval";
217
+ evalCodeUsed?: boolean;
218
+ };
219
+ };
220
+ type FallbackDiagnostics = {
221
+ scope: "node" | "global";
222
+ nodeId?: string;
223
+ primary: string | number;
224
+ candidate: string | number;
225
+ reasons: Array<"rate_violation" | "constraint_mismatch" | "unknown_service" | "ambiguous_context">;
226
+ };
227
+ type SnapshotContext = {
228
+ /** The single active tag id for this order */
229
+ tag: string;
230
+ /** Effective (post-propagation) constraints on that tag */
231
+ constraints: Partial<Record<"refill" | "cancel" | "dripfeed", boolean>>;
232
+ /**
233
+ * Per-node evaluation context:
234
+ * - For the active tag node itself: the same tag id.
235
+ * - For an option node: parent's field.bind_id must include this tag to be applicable; otherwise null.
236
+ * - For a field node (optional to include later): same rule as option, derived from field.bind_id.
237
+ */
238
+ nodeContexts: Record<string, string | null>;
239
+ /** Client pruning policy used (so server can mirror/compare). */
240
+ policy: {
241
+ ratePolicy: {
242
+ kind: "lte_primary" | "none";
243
+ thresholdPct?: number;
244
+ };
245
+ requireConstraintFit: boolean;
246
+ };
247
+ };
248
+ type OrderSnapshot = {
249
+ version: "1";
250
+ mode: "prod" | "dev";
251
+ builtAt: string;
252
+ selection: {
253
+ tag: string;
254
+ fields: Array<{
255
+ id: string;
256
+ type: string;
257
+ selectedOptions?: string[];
258
+ }>;
259
+ };
260
+ inputs: {
261
+ form: Record<string, Scalar | Scalar[]>;
262
+ selections: Record<string, string[]>;
263
+ };
264
+ quantity: number;
265
+ quantitySource: {
266
+ kind: "field" | "tag" | "option" | "default";
267
+ id?: string;
268
+ rule?: QuantityRule;
269
+ defaultedFromHost?: boolean;
270
+ };
271
+ min: number;
272
+ max: number;
273
+ services: Array<string | number>;
274
+ serviceMap: Record<string, Array<string | number>>;
275
+ fallbacks?: {
276
+ nodes?: Record<string, Array<string | number>>;
277
+ global?: Record<string | number, Array<string | number>>;
278
+ };
279
+ utilities?: UtilityLineItem[];
280
+ warnings?: {
281
+ utility?: Array<{
282
+ nodeId: string;
283
+ reason: string;
284
+ }>;
285
+ fallbacks?: FallbackDiagnostics[];
286
+ };
287
+ meta?: {
288
+ schema_version?: string;
289
+ workspaceId?: string;
290
+ builder?: {
291
+ commit?: string;
292
+ };
293
+ context?: SnapshotContext;
294
+ };
295
+ };
296
+
297
+ type NodeRef = {
298
+ kind: "tag";
299
+ id: string;
300
+ node: Tag;
301
+ } | {
302
+ kind: "field";
303
+ id: string;
304
+ node: Field;
305
+ } | {
306
+ kind: "option";
307
+ id: string;
308
+ node: FieldOption;
309
+ fieldId: string;
310
+ };
311
+ type NodeMap = Map<string, NodeRef>;
312
+
216
313
  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" | "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";
217
314
  type ValidationError = {
218
315
  code: ValidationCode;
@@ -261,6 +358,7 @@ type DynamicRule = {
261
358
  };
262
359
  type ValidatorOptions = {
263
360
  serviceMap?: DgpServiceMap;
361
+ nodeMap?: NodeMap;
264
362
  allowUnsafe?: boolean;
265
363
  selectedOptionKeys?: string[];
266
364
  globalUtilityGuard?: boolean;
@@ -294,7 +392,17 @@ type NormaliseOptions = {
294
392
  };
295
393
  declare function normalise(input: unknown, opts?: NormaliseOptions): ServiceProps;
296
394
 
395
+ /**
396
+ * Core synchronous validate.
397
+ */
297
398
  declare function validate(props: ServiceProps, ctx?: ValidatorOptions): ValidationError[];
399
+ /**
400
+ * UI-friendly async wrapper:
401
+ * - yields to microtask queue
402
+ * - then yields to the next animation frame (so paint can happen)
403
+ * - then runs validate()
404
+ */
405
+ declare function validateAsync(props: ServiceProps, ctx?: ValidatorOptions): Promise<ValidationError[]>;
298
406
 
299
407
  /** Options you can set on the builder (used for validation/visibility) */
300
408
  type BuilderOptions = Omit<ValidatorOptions, "serviceMap"> & {
@@ -338,6 +446,10 @@ interface Builder {
338
446
  description: string;
339
447
  value: string;
340
448
  }[];
449
+ isTagId(id: string): boolean;
450
+ isFieldId(id: string): boolean;
451
+ isOptionId(id: string): boolean;
452
+ getNodeMap(): NodeMap;
341
453
  }
342
454
  declare function createBuilder(opts?: BuilderOptions): Builder;
343
455
 
@@ -504,4 +616,30 @@ interface NodeIndex {
504
616
  }
505
617
  declare function createNodeIndex(builder: Builder): NodeIndex;
506
618
 
507
- export { type AncestryHit, type AnyNode, type Builder, type BuilderOptions, type FailedFallbackContext, type FieldNode, type NodeIndex, type NodeKind, type NormaliseOptions, type OptionNode, type RateCoherenceDiagnostic, type RelKind, type TagNode, type UnknownNode, type WithAncestry, collectFailedFallbacks, createBuilder, createNodeIndex, getEligibleFallbacks, normalise, resolveServiceFallback, validate, validateRateCoherenceDeep };
619
+ type BuildOrderSnapshotSettings = {
620
+ mode?: "prod" | "dev";
621
+ hostDefaultQuantity?: number;
622
+ /** Full fallback policy */
623
+ fallback?: FallbackSettings;
624
+ workspaceId?: string;
625
+ builderCommit?: string;
626
+ };
627
+ type BuildOrderSelection = {
628
+ /** Single active context (one tag) coming from Selection */
629
+ activeTagId: string;
630
+ /** Non-option inputs, keyed by fieldId (will be remapped to field.name in the payload) */
631
+ formValuesByFieldId: Record<string, Scalar | Scalar[]>;
632
+ /** Option selections, keyed by fieldId → optionId[] */
633
+ optionSelectionsByFieldId: Record<string, string[]>;
634
+ /**
635
+ * Selection visit order for options (optional, improves "first option wins primary" determinism).
636
+ * If omitted, iteration order falls back to Object.entries(optionSelectionsByFieldId).
637
+ */
638
+ optionTraversalOrder?: Array<{
639
+ fieldId: string;
640
+ optionId: string;
641
+ }>;
642
+ };
643
+ declare function buildOrderSnapshot(props: ServiceProps, builder: Builder, selection: BuildOrderSelection, services: DgpServiceMap, settings?: BuildOrderSnapshotSettings): OrderSnapshot;
644
+
645
+ export { type AncestryHit, type AnyNode, type Builder, type BuilderOptions, type FailedFallbackContext, type FieldNode, type NodeIndex, type NodeKind, type NormaliseOptions, type OptionNode, type RateCoherenceDiagnostic, type RelKind, type TagNode, type UnknownNode, type WithAncestry, buildOrderSnapshot, collectFailedFallbacks, createBuilder, createNodeIndex, getEligibleFallbacks, normalise, resolveServiceFallback, validate, validateAsync, validateRateCoherenceDeep };