@timeax/digital-service-engine 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/index.cjs +364 -15
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +323 -200
- package/dist/core/index.d.ts +323 -200
- package/dist/core/index.js +362 -15
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.cjs +145 -56
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +407 -254
- package/dist/react/index.d.ts +407 -254
- package/dist/react/index.js +145 -56
- package/dist/react/index.js.map +1 -1
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +376 -245
- package/dist/schema/index.d.ts +376 -245
- package/dist/workspace/index.cjs +100 -23
- package/dist/workspace/index.cjs.map +1 -1
- package/dist/workspace/index.d.cts +165 -140
- package/dist/workspace/index.d.ts +165 -140
- package/dist/workspace/index.js +100 -23
- package/dist/workspace/index.js.map +1 -1
- package/package.json +106 -106
|
@@ -2,6 +2,146 @@ import * as React from 'react';
|
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
|
+
type TimeRangeEstimate = {
|
|
6
|
+
min_seconds?: number;
|
|
7
|
+
max_seconds?: number;
|
|
8
|
+
label?: string;
|
|
9
|
+
meta?: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
type SpeedEstimate = {
|
|
12
|
+
amount?: number;
|
|
13
|
+
per?: "minute" | "hour" | "day" | "week" | "month";
|
|
14
|
+
unit?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
meta?: Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
type ServiceEstimates = {
|
|
19
|
+
start?: TimeRangeEstimate;
|
|
20
|
+
speed?: SpeedEstimate;
|
|
21
|
+
average?: TimeRangeEstimate;
|
|
22
|
+
meta?: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
type ServiceFlag = {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
description: string;
|
|
27
|
+
meta?: Record<string, unknown>;
|
|
28
|
+
};
|
|
29
|
+
type IdType = string | number;
|
|
30
|
+
type ServiceFlags = Record<string, ServiceFlag>;
|
|
31
|
+
type DgpServiceCapability = {
|
|
32
|
+
id: IdType;
|
|
33
|
+
name?: string;
|
|
34
|
+
rate: number;
|
|
35
|
+
min?: number;
|
|
36
|
+
max?: number;
|
|
37
|
+
category?: string;
|
|
38
|
+
flags?: ServiceFlags;
|
|
39
|
+
estimates?: ServiceEstimates;
|
|
40
|
+
meta?: Record<string, unknown>;
|
|
41
|
+
[x: string]: any;
|
|
42
|
+
};
|
|
43
|
+
type DgpServiceMap = Record<string, DgpServiceCapability> & Record<number, DgpServiceCapability>;
|
|
44
|
+
|
|
45
|
+
type NodeRef$1 = {
|
|
46
|
+
kind: "tag";
|
|
47
|
+
id: string;
|
|
48
|
+
node: Tag;
|
|
49
|
+
} | {
|
|
50
|
+
kind: "field";
|
|
51
|
+
id: string;
|
|
52
|
+
node: Field;
|
|
53
|
+
} | {
|
|
54
|
+
kind: "option";
|
|
55
|
+
id: string;
|
|
56
|
+
node: FieldOption;
|
|
57
|
+
fieldId: string;
|
|
58
|
+
};
|
|
59
|
+
type NodeMap = Map<string, NodeRef$1>;
|
|
60
|
+
|
|
61
|
+
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";
|
|
62
|
+
type ValidationError = {
|
|
63
|
+
code: ValidationCode;
|
|
64
|
+
message: string;
|
|
65
|
+
severity: "error" | "warning" | "info";
|
|
66
|
+
nodeId?: string;
|
|
67
|
+
details?: Record<string, unknown> & {
|
|
68
|
+
affectedIds?: string[];
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
type ServiceWhereOp = "eq" | "neq" | "in" | "nin" | "exists" | "truthy" | "falsy" | "sw";
|
|
72
|
+
/**
|
|
73
|
+
* Host-extensible service filter clause.
|
|
74
|
+
* `path` should usually be "service.<prop>" or "service.meta.<prop>" etc.
|
|
75
|
+
*/
|
|
76
|
+
type ServiceWhereClause = {
|
|
77
|
+
path: string;
|
|
78
|
+
op?: ServiceWhereOp;
|
|
79
|
+
value?: unknown;
|
|
80
|
+
};
|
|
81
|
+
type DynamicRule = {
|
|
82
|
+
id: string;
|
|
83
|
+
label?: string;
|
|
84
|
+
scope: "global" | "visible_group";
|
|
85
|
+
subject: "services";
|
|
86
|
+
/**
|
|
87
|
+
* Package-level filter surface:
|
|
88
|
+
* - role/tag/field are core to the builder schema
|
|
89
|
+
* - where[] allows hosts to filter against extra service properties (handler_id/platform_id/type/key/category_id/etc.)
|
|
90
|
+
*/
|
|
91
|
+
filter?: {
|
|
92
|
+
role?: "base" | "utility" | "both";
|
|
93
|
+
tag_id?: string | string[];
|
|
94
|
+
field_id?: string | string[];
|
|
95
|
+
where?: ServiceWhereClause[];
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Projection is intentionally open:
|
|
99
|
+
* hosts may project custom service properties.
|
|
100
|
+
*/
|
|
101
|
+
projection?: "service.id" | "service.name" | "service.rate" | "service.min" | "service.max" | "service.category" | string;
|
|
102
|
+
op: "all_equal" | "unique" | "no_mix" | "all_true" | "any_true" | "max_count" | "min_count";
|
|
103
|
+
value?: number | boolean;
|
|
104
|
+
severity?: "error" | "warning";
|
|
105
|
+
message?: string;
|
|
106
|
+
};
|
|
107
|
+
type ValidatorOptions = {
|
|
108
|
+
serviceMap?: DgpServiceMap;
|
|
109
|
+
nodeMap?: NodeMap;
|
|
110
|
+
allowUnsafe?: boolean;
|
|
111
|
+
selectedOptionKeys?: string[];
|
|
112
|
+
globalUtilityGuard?: boolean;
|
|
113
|
+
policies?: DynamicRule[];
|
|
114
|
+
fallbackSettings?: FallbackSettings;
|
|
115
|
+
};
|
|
116
|
+
type RatePolicy = {
|
|
117
|
+
kind: "lte_primary";
|
|
118
|
+
} | {
|
|
119
|
+
kind: "within_pct";
|
|
120
|
+
pct: number;
|
|
121
|
+
} | {
|
|
122
|
+
kind: "at_least_pct_lower";
|
|
123
|
+
pct: number;
|
|
124
|
+
};
|
|
125
|
+
type FallbackSettings = {
|
|
126
|
+
/** Require fallbacks to satisfy tag constraints (dripfeed/refill/cancel) when a tag context is known. Default: true */
|
|
127
|
+
requireConstraintFit?: boolean;
|
|
128
|
+
/** Rate rule policy. Default: { kind: 'lte_primary' } i.e. candidate.rate <= primary.rate */
|
|
129
|
+
ratePolicy?: RatePolicy;
|
|
130
|
+
/** When multiple candidates remain, choose first (priority) or cheapest. Default: 'priority' */
|
|
131
|
+
selectionStrategy?: "priority" | "cheapest";
|
|
132
|
+
/** Validation mode: 'strict' → node-scoped violations reported as ValidationError; 'dev' → only collect diagnostics. Default: 'strict' */
|
|
133
|
+
mode?: "strict" | "dev";
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
type ServiceIdRef = number | string;
|
|
137
|
+
type NodeIdRef = string;
|
|
138
|
+
type ServiceFallback = {
|
|
139
|
+
/** Node-scoped fallbacks: prefer these when that node’s primary service fails */
|
|
140
|
+
nodes?: Record<NodeIdRef, ServiceIdRef[]>;
|
|
141
|
+
/** Primary→fallback list used when no node-scoped entry is present */
|
|
142
|
+
global?: Record<ServiceIdRef, ServiceIdRef[]>;
|
|
143
|
+
};
|
|
144
|
+
|
|
5
145
|
type PricingRole = "base" | "utility";
|
|
6
146
|
type FieldType = "custom" | (string & {});
|
|
7
147
|
/** ── Marker types (live inside meta; non-breaking) ───────────────────── */
|
|
@@ -100,14 +240,6 @@ type ServiceProps = {
|
|
|
100
240
|
name?: string;
|
|
101
241
|
notices?: ServicePropsNotice[];
|
|
102
242
|
};
|
|
103
|
-
type ServiceIdRef = number | string;
|
|
104
|
-
type NodeIdRef = string;
|
|
105
|
-
type ServiceFallback = {
|
|
106
|
-
/** Node-scoped fallbacks: prefer these when that node’s primary service fails */
|
|
107
|
-
nodes?: Record<NodeIdRef, ServiceIdRef[]>;
|
|
108
|
-
/** Primary→fallback list used when no node-scoped entry is present */
|
|
109
|
-
global?: Record<ServiceIdRef, ServiceIdRef[]>;
|
|
110
|
-
};
|
|
111
243
|
type NoticeType = "public" | "private";
|
|
112
244
|
type NoticeSeverity = "info" | "warning" | "error";
|
|
113
245
|
/**
|
|
@@ -327,137 +459,6 @@ type EditorSnapshot = {
|
|
|
327
459
|
meta?: Record<string, unknown>;
|
|
328
460
|
};
|
|
329
461
|
|
|
330
|
-
type TimeRangeEstimate = {
|
|
331
|
-
min_seconds?: number;
|
|
332
|
-
max_seconds?: number;
|
|
333
|
-
label?: string;
|
|
334
|
-
meta?: Record<string, unknown>;
|
|
335
|
-
};
|
|
336
|
-
type SpeedEstimate = {
|
|
337
|
-
amount?: number;
|
|
338
|
-
per?: "minute" | "hour" | "day" | "week" | "month";
|
|
339
|
-
unit?: string;
|
|
340
|
-
label?: string;
|
|
341
|
-
meta?: Record<string, unknown>;
|
|
342
|
-
};
|
|
343
|
-
type ServiceEstimates = {
|
|
344
|
-
start?: TimeRangeEstimate;
|
|
345
|
-
speed?: SpeedEstimate;
|
|
346
|
-
average?: TimeRangeEstimate;
|
|
347
|
-
meta?: Record<string, unknown>;
|
|
348
|
-
};
|
|
349
|
-
type ServiceFlag = {
|
|
350
|
-
enabled: boolean;
|
|
351
|
-
description: string;
|
|
352
|
-
meta?: Record<string, unknown>;
|
|
353
|
-
};
|
|
354
|
-
type IdType = string | number;
|
|
355
|
-
type ServiceFlags = Record<string, ServiceFlag>;
|
|
356
|
-
type DgpServiceCapability = {
|
|
357
|
-
id: IdType;
|
|
358
|
-
name?: string;
|
|
359
|
-
rate: number;
|
|
360
|
-
min?: number;
|
|
361
|
-
max?: number;
|
|
362
|
-
category?: string;
|
|
363
|
-
flags?: ServiceFlags;
|
|
364
|
-
estimates?: ServiceEstimates;
|
|
365
|
-
meta?: Record<string, unknown>;
|
|
366
|
-
[x: string]: any;
|
|
367
|
-
};
|
|
368
|
-
type DgpServiceMap = Record<string, DgpServiceCapability> & Record<number, DgpServiceCapability>;
|
|
369
|
-
|
|
370
|
-
type NodeRef$1 = {
|
|
371
|
-
kind: "tag";
|
|
372
|
-
id: string;
|
|
373
|
-
node: Tag;
|
|
374
|
-
} | {
|
|
375
|
-
kind: "field";
|
|
376
|
-
id: string;
|
|
377
|
-
node: Field;
|
|
378
|
-
} | {
|
|
379
|
-
kind: "option";
|
|
380
|
-
id: string;
|
|
381
|
-
node: FieldOption;
|
|
382
|
-
fieldId: string;
|
|
383
|
-
};
|
|
384
|
-
type NodeMap = Map<string, NodeRef$1>;
|
|
385
|
-
|
|
386
|
-
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";
|
|
387
|
-
type ValidationError = {
|
|
388
|
-
code: ValidationCode;
|
|
389
|
-
message: string;
|
|
390
|
-
severity: "error" | "warning" | "info";
|
|
391
|
-
nodeId?: string;
|
|
392
|
-
details?: Record<string, unknown> & {
|
|
393
|
-
affectedIds?: string[];
|
|
394
|
-
};
|
|
395
|
-
};
|
|
396
|
-
type ServiceWhereOp = "eq" | "neq" | "in" | "nin" | "exists" | "truthy" | "falsy" | "sw";
|
|
397
|
-
/**
|
|
398
|
-
* Host-extensible service filter clause.
|
|
399
|
-
* `path` should usually be "service.<prop>" or "service.meta.<prop>" etc.
|
|
400
|
-
*/
|
|
401
|
-
type ServiceWhereClause = {
|
|
402
|
-
path: string;
|
|
403
|
-
op?: ServiceWhereOp;
|
|
404
|
-
value?: unknown;
|
|
405
|
-
};
|
|
406
|
-
type DynamicRule = {
|
|
407
|
-
id: string;
|
|
408
|
-
label?: string;
|
|
409
|
-
scope: "global" | "visible_group";
|
|
410
|
-
subject: "services";
|
|
411
|
-
/**
|
|
412
|
-
* Package-level filter surface:
|
|
413
|
-
* - role/tag/field are core to the builder schema
|
|
414
|
-
* - where[] allows hosts to filter against extra service properties (handler_id/platform_id/type/key/category_id/etc.)
|
|
415
|
-
*/
|
|
416
|
-
filter?: {
|
|
417
|
-
role?: "base" | "utility" | "both";
|
|
418
|
-
tag_id?: string | string[];
|
|
419
|
-
field_id?: string | string[];
|
|
420
|
-
where?: ServiceWhereClause[];
|
|
421
|
-
};
|
|
422
|
-
/**
|
|
423
|
-
* Projection is intentionally open:
|
|
424
|
-
* hosts may project custom service properties.
|
|
425
|
-
*/
|
|
426
|
-
projection?: "service.id" | "service.name" | "service.rate" | "service.min" | "service.max" | "service.category" | string;
|
|
427
|
-
op: "all_equal" | "unique" | "no_mix" | "all_true" | "any_true" | "max_count" | "min_count";
|
|
428
|
-
value?: number | boolean;
|
|
429
|
-
severity?: "error" | "warning";
|
|
430
|
-
message?: string;
|
|
431
|
-
};
|
|
432
|
-
type ValidatorOptions = {
|
|
433
|
-
serviceMap?: DgpServiceMap;
|
|
434
|
-
nodeMap?: NodeMap;
|
|
435
|
-
allowUnsafe?: boolean;
|
|
436
|
-
selectedOptionKeys?: string[];
|
|
437
|
-
globalUtilityGuard?: boolean;
|
|
438
|
-
policies?: DynamicRule[];
|
|
439
|
-
fallbackSettings?: FallbackSettings;
|
|
440
|
-
};
|
|
441
|
-
type RatePolicy = {
|
|
442
|
-
kind: "lte_primary";
|
|
443
|
-
} | {
|
|
444
|
-
kind: "within_pct";
|
|
445
|
-
pct: number;
|
|
446
|
-
} | {
|
|
447
|
-
kind: "at_least_pct_lower";
|
|
448
|
-
pct: number;
|
|
449
|
-
};
|
|
450
|
-
type FallbackSettings = {
|
|
451
|
-
/** Require fallbacks to satisfy tag constraints (dripfeed/refill/cancel) when a tag context is known. Default: true */
|
|
452
|
-
requireConstraintFit?: boolean;
|
|
453
|
-
/** Rate rule policy. Default: { kind: 'lte_primary' } i.e. candidate.rate <= primary.rate */
|
|
454
|
-
ratePolicy?: RatePolicy;
|
|
455
|
-
/** When multiple candidates remain, choose first (priority) or cheapest. Default: 'priority' */
|
|
456
|
-
selectionStrategy?: "priority" | "cheapest";
|
|
457
|
-
/** Validation mode: 'strict' → node-scoped violations reported as ValidationError; 'dev' → only collect diagnostics. Default: 'strict' */
|
|
458
|
-
mode?: "strict" | "dev";
|
|
459
|
-
};
|
|
460
|
-
|
|
461
462
|
/** Options you can set on the builder (used for validation/visibility) */
|
|
462
463
|
type BuilderOptions = Omit<ValidatorOptions, "serviceMap"> & {
|
|
463
464
|
serviceMap?: DgpServiceMap;
|
|
@@ -630,10 +631,34 @@ declare class Selection {
|
|
|
630
631
|
currentTag(): string | undefined;
|
|
631
632
|
onChange(fn: Listener): () => void;
|
|
632
633
|
visibleGroup(): VisibleGroupResult;
|
|
634
|
+
/**
|
|
635
|
+
* Build a fieldId -> triggerKeys[] map from the current selection set.
|
|
636
|
+
*
|
|
637
|
+
* What counts as a "button selection" (trigger key):
|
|
638
|
+
* - field key where the field has button === true (e.g. "f:dripfeed")
|
|
639
|
+
* - option key (e.g. "o:fast")
|
|
640
|
+
* - composite key "fieldId::optionId" (e.g. "f:speed::o:fast")
|
|
641
|
+
*
|
|
642
|
+
* Grouping:
|
|
643
|
+
* - button-field trigger groups under its own fieldId
|
|
644
|
+
* - option/composite groups under the option's owning fieldId (from nodeMap)
|
|
645
|
+
*
|
|
646
|
+
* Deterministic:
|
|
647
|
+
* - preserves selection insertion order
|
|
648
|
+
* - de-dupes per field
|
|
649
|
+
*/
|
|
650
|
+
buttonSelectionsByFieldId(): Record<string, string[]>;
|
|
651
|
+
/**
|
|
652
|
+
* Returns only selection keys that are valid "trigger buttons":
|
|
653
|
+
* - field keys where field.button === true
|
|
654
|
+
* - option keys
|
|
655
|
+
* - composite keys "fieldId::optionId" (validated by optionId)
|
|
656
|
+
* Excludes tags and non-button fields.
|
|
657
|
+
*/
|
|
658
|
+
selectedButtons(): string[];
|
|
633
659
|
private emit;
|
|
634
660
|
private updateCurrentTagFrom;
|
|
635
661
|
private resolveTagContextId;
|
|
636
|
-
private selectedButtonTriggerIds;
|
|
637
662
|
private computeGroupForTag;
|
|
638
663
|
private addServiceByRole;
|
|
639
664
|
private findOptionById;
|
|
@@ -2,6 +2,146 @@ import * as React from 'react';
|
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
4
4
|
|
|
5
|
+
type TimeRangeEstimate = {
|
|
6
|
+
min_seconds?: number;
|
|
7
|
+
max_seconds?: number;
|
|
8
|
+
label?: string;
|
|
9
|
+
meta?: Record<string, unknown>;
|
|
10
|
+
};
|
|
11
|
+
type SpeedEstimate = {
|
|
12
|
+
amount?: number;
|
|
13
|
+
per?: "minute" | "hour" | "day" | "week" | "month";
|
|
14
|
+
unit?: string;
|
|
15
|
+
label?: string;
|
|
16
|
+
meta?: Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
type ServiceEstimates = {
|
|
19
|
+
start?: TimeRangeEstimate;
|
|
20
|
+
speed?: SpeedEstimate;
|
|
21
|
+
average?: TimeRangeEstimate;
|
|
22
|
+
meta?: Record<string, unknown>;
|
|
23
|
+
};
|
|
24
|
+
type ServiceFlag = {
|
|
25
|
+
enabled: boolean;
|
|
26
|
+
description: string;
|
|
27
|
+
meta?: Record<string, unknown>;
|
|
28
|
+
};
|
|
29
|
+
type IdType = string | number;
|
|
30
|
+
type ServiceFlags = Record<string, ServiceFlag>;
|
|
31
|
+
type DgpServiceCapability = {
|
|
32
|
+
id: IdType;
|
|
33
|
+
name?: string;
|
|
34
|
+
rate: number;
|
|
35
|
+
min?: number;
|
|
36
|
+
max?: number;
|
|
37
|
+
category?: string;
|
|
38
|
+
flags?: ServiceFlags;
|
|
39
|
+
estimates?: ServiceEstimates;
|
|
40
|
+
meta?: Record<string, unknown>;
|
|
41
|
+
[x: string]: any;
|
|
42
|
+
};
|
|
43
|
+
type DgpServiceMap = Record<string, DgpServiceCapability> & Record<number, DgpServiceCapability>;
|
|
44
|
+
|
|
45
|
+
type NodeRef$1 = {
|
|
46
|
+
kind: "tag";
|
|
47
|
+
id: string;
|
|
48
|
+
node: Tag;
|
|
49
|
+
} | {
|
|
50
|
+
kind: "field";
|
|
51
|
+
id: string;
|
|
52
|
+
node: Field;
|
|
53
|
+
} | {
|
|
54
|
+
kind: "option";
|
|
55
|
+
id: string;
|
|
56
|
+
node: FieldOption;
|
|
57
|
+
fieldId: string;
|
|
58
|
+
};
|
|
59
|
+
type NodeMap = Map<string, NodeRef$1>;
|
|
60
|
+
|
|
61
|
+
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";
|
|
62
|
+
type ValidationError = {
|
|
63
|
+
code: ValidationCode;
|
|
64
|
+
message: string;
|
|
65
|
+
severity: "error" | "warning" | "info";
|
|
66
|
+
nodeId?: string;
|
|
67
|
+
details?: Record<string, unknown> & {
|
|
68
|
+
affectedIds?: string[];
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
type ServiceWhereOp = "eq" | "neq" | "in" | "nin" | "exists" | "truthy" | "falsy" | "sw";
|
|
72
|
+
/**
|
|
73
|
+
* Host-extensible service filter clause.
|
|
74
|
+
* `path` should usually be "service.<prop>" or "service.meta.<prop>" etc.
|
|
75
|
+
*/
|
|
76
|
+
type ServiceWhereClause = {
|
|
77
|
+
path: string;
|
|
78
|
+
op?: ServiceWhereOp;
|
|
79
|
+
value?: unknown;
|
|
80
|
+
};
|
|
81
|
+
type DynamicRule = {
|
|
82
|
+
id: string;
|
|
83
|
+
label?: string;
|
|
84
|
+
scope: "global" | "visible_group";
|
|
85
|
+
subject: "services";
|
|
86
|
+
/**
|
|
87
|
+
* Package-level filter surface:
|
|
88
|
+
* - role/tag/field are core to the builder schema
|
|
89
|
+
* - where[] allows hosts to filter against extra service properties (handler_id/platform_id/type/key/category_id/etc.)
|
|
90
|
+
*/
|
|
91
|
+
filter?: {
|
|
92
|
+
role?: "base" | "utility" | "both";
|
|
93
|
+
tag_id?: string | string[];
|
|
94
|
+
field_id?: string | string[];
|
|
95
|
+
where?: ServiceWhereClause[];
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Projection is intentionally open:
|
|
99
|
+
* hosts may project custom service properties.
|
|
100
|
+
*/
|
|
101
|
+
projection?: "service.id" | "service.name" | "service.rate" | "service.min" | "service.max" | "service.category" | string;
|
|
102
|
+
op: "all_equal" | "unique" | "no_mix" | "all_true" | "any_true" | "max_count" | "min_count";
|
|
103
|
+
value?: number | boolean;
|
|
104
|
+
severity?: "error" | "warning";
|
|
105
|
+
message?: string;
|
|
106
|
+
};
|
|
107
|
+
type ValidatorOptions = {
|
|
108
|
+
serviceMap?: DgpServiceMap;
|
|
109
|
+
nodeMap?: NodeMap;
|
|
110
|
+
allowUnsafe?: boolean;
|
|
111
|
+
selectedOptionKeys?: string[];
|
|
112
|
+
globalUtilityGuard?: boolean;
|
|
113
|
+
policies?: DynamicRule[];
|
|
114
|
+
fallbackSettings?: FallbackSettings;
|
|
115
|
+
};
|
|
116
|
+
type RatePolicy = {
|
|
117
|
+
kind: "lte_primary";
|
|
118
|
+
} | {
|
|
119
|
+
kind: "within_pct";
|
|
120
|
+
pct: number;
|
|
121
|
+
} | {
|
|
122
|
+
kind: "at_least_pct_lower";
|
|
123
|
+
pct: number;
|
|
124
|
+
};
|
|
125
|
+
type FallbackSettings = {
|
|
126
|
+
/** Require fallbacks to satisfy tag constraints (dripfeed/refill/cancel) when a tag context is known. Default: true */
|
|
127
|
+
requireConstraintFit?: boolean;
|
|
128
|
+
/** Rate rule policy. Default: { kind: 'lte_primary' } i.e. candidate.rate <= primary.rate */
|
|
129
|
+
ratePolicy?: RatePolicy;
|
|
130
|
+
/** When multiple candidates remain, choose first (priority) or cheapest. Default: 'priority' */
|
|
131
|
+
selectionStrategy?: "priority" | "cheapest";
|
|
132
|
+
/** Validation mode: 'strict' → node-scoped violations reported as ValidationError; 'dev' → only collect diagnostics. Default: 'strict' */
|
|
133
|
+
mode?: "strict" | "dev";
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
type ServiceIdRef = number | string;
|
|
137
|
+
type NodeIdRef = string;
|
|
138
|
+
type ServiceFallback = {
|
|
139
|
+
/** Node-scoped fallbacks: prefer these when that node’s primary service fails */
|
|
140
|
+
nodes?: Record<NodeIdRef, ServiceIdRef[]>;
|
|
141
|
+
/** Primary→fallback list used when no node-scoped entry is present */
|
|
142
|
+
global?: Record<ServiceIdRef, ServiceIdRef[]>;
|
|
143
|
+
};
|
|
144
|
+
|
|
5
145
|
type PricingRole = "base" | "utility";
|
|
6
146
|
type FieldType = "custom" | (string & {});
|
|
7
147
|
/** ── Marker types (live inside meta; non-breaking) ───────────────────── */
|
|
@@ -100,14 +240,6 @@ type ServiceProps = {
|
|
|
100
240
|
name?: string;
|
|
101
241
|
notices?: ServicePropsNotice[];
|
|
102
242
|
};
|
|
103
|
-
type ServiceIdRef = number | string;
|
|
104
|
-
type NodeIdRef = string;
|
|
105
|
-
type ServiceFallback = {
|
|
106
|
-
/** Node-scoped fallbacks: prefer these when that node’s primary service fails */
|
|
107
|
-
nodes?: Record<NodeIdRef, ServiceIdRef[]>;
|
|
108
|
-
/** Primary→fallback list used when no node-scoped entry is present */
|
|
109
|
-
global?: Record<ServiceIdRef, ServiceIdRef[]>;
|
|
110
|
-
};
|
|
111
243
|
type NoticeType = "public" | "private";
|
|
112
244
|
type NoticeSeverity = "info" | "warning" | "error";
|
|
113
245
|
/**
|
|
@@ -327,137 +459,6 @@ type EditorSnapshot = {
|
|
|
327
459
|
meta?: Record<string, unknown>;
|
|
328
460
|
};
|
|
329
461
|
|
|
330
|
-
type TimeRangeEstimate = {
|
|
331
|
-
min_seconds?: number;
|
|
332
|
-
max_seconds?: number;
|
|
333
|
-
label?: string;
|
|
334
|
-
meta?: Record<string, unknown>;
|
|
335
|
-
};
|
|
336
|
-
type SpeedEstimate = {
|
|
337
|
-
amount?: number;
|
|
338
|
-
per?: "minute" | "hour" | "day" | "week" | "month";
|
|
339
|
-
unit?: string;
|
|
340
|
-
label?: string;
|
|
341
|
-
meta?: Record<string, unknown>;
|
|
342
|
-
};
|
|
343
|
-
type ServiceEstimates = {
|
|
344
|
-
start?: TimeRangeEstimate;
|
|
345
|
-
speed?: SpeedEstimate;
|
|
346
|
-
average?: TimeRangeEstimate;
|
|
347
|
-
meta?: Record<string, unknown>;
|
|
348
|
-
};
|
|
349
|
-
type ServiceFlag = {
|
|
350
|
-
enabled: boolean;
|
|
351
|
-
description: string;
|
|
352
|
-
meta?: Record<string, unknown>;
|
|
353
|
-
};
|
|
354
|
-
type IdType = string | number;
|
|
355
|
-
type ServiceFlags = Record<string, ServiceFlag>;
|
|
356
|
-
type DgpServiceCapability = {
|
|
357
|
-
id: IdType;
|
|
358
|
-
name?: string;
|
|
359
|
-
rate: number;
|
|
360
|
-
min?: number;
|
|
361
|
-
max?: number;
|
|
362
|
-
category?: string;
|
|
363
|
-
flags?: ServiceFlags;
|
|
364
|
-
estimates?: ServiceEstimates;
|
|
365
|
-
meta?: Record<string, unknown>;
|
|
366
|
-
[x: string]: any;
|
|
367
|
-
};
|
|
368
|
-
type DgpServiceMap = Record<string, DgpServiceCapability> & Record<number, DgpServiceCapability>;
|
|
369
|
-
|
|
370
|
-
type NodeRef$1 = {
|
|
371
|
-
kind: "tag";
|
|
372
|
-
id: string;
|
|
373
|
-
node: Tag;
|
|
374
|
-
} | {
|
|
375
|
-
kind: "field";
|
|
376
|
-
id: string;
|
|
377
|
-
node: Field;
|
|
378
|
-
} | {
|
|
379
|
-
kind: "option";
|
|
380
|
-
id: string;
|
|
381
|
-
node: FieldOption;
|
|
382
|
-
fieldId: string;
|
|
383
|
-
};
|
|
384
|
-
type NodeMap = Map<string, NodeRef$1>;
|
|
385
|
-
|
|
386
|
-
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";
|
|
387
|
-
type ValidationError = {
|
|
388
|
-
code: ValidationCode;
|
|
389
|
-
message: string;
|
|
390
|
-
severity: "error" | "warning" | "info";
|
|
391
|
-
nodeId?: string;
|
|
392
|
-
details?: Record<string, unknown> & {
|
|
393
|
-
affectedIds?: string[];
|
|
394
|
-
};
|
|
395
|
-
};
|
|
396
|
-
type ServiceWhereOp = "eq" | "neq" | "in" | "nin" | "exists" | "truthy" | "falsy" | "sw";
|
|
397
|
-
/**
|
|
398
|
-
* Host-extensible service filter clause.
|
|
399
|
-
* `path` should usually be "service.<prop>" or "service.meta.<prop>" etc.
|
|
400
|
-
*/
|
|
401
|
-
type ServiceWhereClause = {
|
|
402
|
-
path: string;
|
|
403
|
-
op?: ServiceWhereOp;
|
|
404
|
-
value?: unknown;
|
|
405
|
-
};
|
|
406
|
-
type DynamicRule = {
|
|
407
|
-
id: string;
|
|
408
|
-
label?: string;
|
|
409
|
-
scope: "global" | "visible_group";
|
|
410
|
-
subject: "services";
|
|
411
|
-
/**
|
|
412
|
-
* Package-level filter surface:
|
|
413
|
-
* - role/tag/field are core to the builder schema
|
|
414
|
-
* - where[] allows hosts to filter against extra service properties (handler_id/platform_id/type/key/category_id/etc.)
|
|
415
|
-
*/
|
|
416
|
-
filter?: {
|
|
417
|
-
role?: "base" | "utility" | "both";
|
|
418
|
-
tag_id?: string | string[];
|
|
419
|
-
field_id?: string | string[];
|
|
420
|
-
where?: ServiceWhereClause[];
|
|
421
|
-
};
|
|
422
|
-
/**
|
|
423
|
-
* Projection is intentionally open:
|
|
424
|
-
* hosts may project custom service properties.
|
|
425
|
-
*/
|
|
426
|
-
projection?: "service.id" | "service.name" | "service.rate" | "service.min" | "service.max" | "service.category" | string;
|
|
427
|
-
op: "all_equal" | "unique" | "no_mix" | "all_true" | "any_true" | "max_count" | "min_count";
|
|
428
|
-
value?: number | boolean;
|
|
429
|
-
severity?: "error" | "warning";
|
|
430
|
-
message?: string;
|
|
431
|
-
};
|
|
432
|
-
type ValidatorOptions = {
|
|
433
|
-
serviceMap?: DgpServiceMap;
|
|
434
|
-
nodeMap?: NodeMap;
|
|
435
|
-
allowUnsafe?: boolean;
|
|
436
|
-
selectedOptionKeys?: string[];
|
|
437
|
-
globalUtilityGuard?: boolean;
|
|
438
|
-
policies?: DynamicRule[];
|
|
439
|
-
fallbackSettings?: FallbackSettings;
|
|
440
|
-
};
|
|
441
|
-
type RatePolicy = {
|
|
442
|
-
kind: "lte_primary";
|
|
443
|
-
} | {
|
|
444
|
-
kind: "within_pct";
|
|
445
|
-
pct: number;
|
|
446
|
-
} | {
|
|
447
|
-
kind: "at_least_pct_lower";
|
|
448
|
-
pct: number;
|
|
449
|
-
};
|
|
450
|
-
type FallbackSettings = {
|
|
451
|
-
/** Require fallbacks to satisfy tag constraints (dripfeed/refill/cancel) when a tag context is known. Default: true */
|
|
452
|
-
requireConstraintFit?: boolean;
|
|
453
|
-
/** Rate rule policy. Default: { kind: 'lte_primary' } i.e. candidate.rate <= primary.rate */
|
|
454
|
-
ratePolicy?: RatePolicy;
|
|
455
|
-
/** When multiple candidates remain, choose first (priority) or cheapest. Default: 'priority' */
|
|
456
|
-
selectionStrategy?: "priority" | "cheapest";
|
|
457
|
-
/** Validation mode: 'strict' → node-scoped violations reported as ValidationError; 'dev' → only collect diagnostics. Default: 'strict' */
|
|
458
|
-
mode?: "strict" | "dev";
|
|
459
|
-
};
|
|
460
|
-
|
|
461
462
|
/** Options you can set on the builder (used for validation/visibility) */
|
|
462
463
|
type BuilderOptions = Omit<ValidatorOptions, "serviceMap"> & {
|
|
463
464
|
serviceMap?: DgpServiceMap;
|
|
@@ -630,10 +631,34 @@ declare class Selection {
|
|
|
630
631
|
currentTag(): string | undefined;
|
|
631
632
|
onChange(fn: Listener): () => void;
|
|
632
633
|
visibleGroup(): VisibleGroupResult;
|
|
634
|
+
/**
|
|
635
|
+
* Build a fieldId -> triggerKeys[] map from the current selection set.
|
|
636
|
+
*
|
|
637
|
+
* What counts as a "button selection" (trigger key):
|
|
638
|
+
* - field key where the field has button === true (e.g. "f:dripfeed")
|
|
639
|
+
* - option key (e.g. "o:fast")
|
|
640
|
+
* - composite key "fieldId::optionId" (e.g. "f:speed::o:fast")
|
|
641
|
+
*
|
|
642
|
+
* Grouping:
|
|
643
|
+
* - button-field trigger groups under its own fieldId
|
|
644
|
+
* - option/composite groups under the option's owning fieldId (from nodeMap)
|
|
645
|
+
*
|
|
646
|
+
* Deterministic:
|
|
647
|
+
* - preserves selection insertion order
|
|
648
|
+
* - de-dupes per field
|
|
649
|
+
*/
|
|
650
|
+
buttonSelectionsByFieldId(): Record<string, string[]>;
|
|
651
|
+
/**
|
|
652
|
+
* Returns only selection keys that are valid "trigger buttons":
|
|
653
|
+
* - field keys where field.button === true
|
|
654
|
+
* - option keys
|
|
655
|
+
* - composite keys "fieldId::optionId" (validated by optionId)
|
|
656
|
+
* Excludes tags and non-button fields.
|
|
657
|
+
*/
|
|
658
|
+
selectedButtons(): string[];
|
|
633
659
|
private emit;
|
|
634
660
|
private updateCurrentTagFrom;
|
|
635
661
|
private resolveTagContextId;
|
|
636
|
-
private selectedButtonTriggerIds;
|
|
637
662
|
private computeGroupForTag;
|
|
638
663
|
private addServiceByRole;
|
|
639
664
|
private findOptionById;
|