@texuli/spec 0.3.0 → 0.4.0

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 (46) hide show
  1. package/README.md +80 -14
  2. package/dist/build.d.ts +5 -0
  3. package/dist/build.js +1 -0
  4. package/dist/canonical.js +20 -13
  5. package/dist/catalog.d.ts +9 -3
  6. package/dist/catalog.js +7 -1
  7. package/dist/codegen/index.d.ts +2 -2
  8. package/dist/codegen/index.js +2 -2
  9. package/dist/codegen/kotlin.d.ts +6 -0
  10. package/dist/codegen/kotlin.js +80 -8
  11. package/dist/conformance.d.ts +11 -2
  12. package/dist/conformance.js +93 -2
  13. package/dist/contract.d.ts +112 -0
  14. package/dist/contract.js +196 -0
  15. package/dist/dialect.d.ts +10 -1
  16. package/dist/dialect.js +6 -1
  17. package/dist/generated/typescript/blueprint.d.ts +103 -5
  18. package/dist/generated/typescript/blueprint.js +1 -1
  19. package/dist/generated/typescript/catalog-schema.d.ts +35 -0
  20. package/dist/generated/typescript/catalog-schema.js +1 -1
  21. package/dist/generated/typescript/diagnostics.d.ts +10 -1
  22. package/dist/generated/typescript/diagnostics.js +1 -1
  23. package/dist/generated/typescript/manifest.js +1 -1
  24. package/dist/generated/typescript/vocabulary.d.ts +152 -4
  25. package/dist/generated/typescript/vocabulary.js +27 -2
  26. package/dist/generated/typescript/workflow.d.ts +84 -0
  27. package/dist/generated/typescript/workflow.js +3 -0
  28. package/dist/index.d.ts +13 -5
  29. package/dist/index.js +9 -3
  30. package/dist/migrations/0.2.0-0.3.0.d.ts +7 -0
  31. package/dist/migrations/0.2.0-0.3.0.js +10 -0
  32. package/dist/migrations/0.3.0-0.4.0.d.ts +9 -0
  33. package/dist/migrations/0.3.0-0.4.0.js +12 -0
  34. package/dist/migrations/index.d.ts +15 -0
  35. package/dist/migrations/index.js +53 -0
  36. package/dist/migrations/types.d.ts +14 -0
  37. package/dist/migrations/types.js +1 -0
  38. package/dist/surface.d.ts +60 -0
  39. package/dist/surface.js +162 -0
  40. package/dist/validate.d.ts +89 -14
  41. package/dist/validate.js +725 -64
  42. package/dist/version.d.ts +1 -1
  43. package/dist/version.js +1 -1
  44. package/dist/workflow.d.ts +15 -0
  45. package/dist/workflow.js +256 -0
  46. package/package.json +13 -1
@@ -1,10 +1,14 @@
1
1
  /** The built catalog this vocabulary was projected from. */
2
- export declare const SPEC_CATALOG_HASH = "b073e30b4c8b1a30b3ef3ccb372e552d2d88e584616b74591c6c32923b471376";
2
+ export declare const SPEC_CATALOG_HASH = "8a449985d45c7bfd1dc2285f3513dfd6ca0e3e38260c0a541fdb7b17e9213006";
3
3
  /** Every closed component id, sorted. */
4
- export declare const SPEC_COMPONENT_IDS: readonly ["alert", "alert-dialog", "analytics-grid", "app-nav", "badge", "banner", "blocks-code", "blocks-data", "blocks-diagram", "blocks-embed", "blocks-interactive", "blocks-map", "blocks-media", "blocks-structure", "blocks-text", "breadcrumb", "button", "button-group", "callout", "card", "charts-area", "charts-bar", "charts-bubble", "charts-bullet", "charts-canvas-renderer", "charts-cartesian", "charts-combo", "charts-donut", "charts-funnel", "charts-gauge", "charts-geo-map", "charts-geo-point-map", "charts-heatmap", "charts-line", "charts-network", "charts-pie", "charts-progress-ring", "charts-sankey", "charts-scatter", "charts-sparkline", "charts-stacked-bar", "charts-sunburst", "charts-treemap", "checkbox", "chip", "code", "combobox", "command-palette", "content-layout", "context-menu", "context-menu-trigger", "deck-slide", "description", "detail-panel", "dialog", "drawer", "dropdown-menu", "dropdown-menu-content", "dropdown-menu-item", "dropdown-menu-trigger", "empty-state", "error-state", "field", "field-error", "form", "hover-card", "hover-card-content", "icon-button", "inline-text", "input", "input-group", "kbd", "kpi", "label", "layout-auth-split", "layout-blog", "layout-card", "layout-chrome", "layout-dashboard-grid", "layout-deck", "layout-doc", "layout-docs", "layout-drawer", "layout-dual-sidebar", "layout-editorial", "layout-grid", "layout-host", "layout-landing", "layout-marketing", "layout-page", "layout-pricing", "layout-settings", "layout-sidebar", "layout-top-nav", "layout-wizard", "media-composition-canvas", "media-composition-svg", "media-image", "menubar", "menubar-trigger", "multi-select", "nav-icon", "navigation-menu", "pagination", "popover", "popover-content", "radio", "radio-group", "responsive-modal", "screen-outlet", "select", "select-content", "select-group", "select-item", "select-label", "select-portal", "select-separator", "select-trigger", "select-value", "select-viewport", "sheet", "sidebar", "split-view", "stat", "stepper", "switch", "table", "tag", "text-counter", "textarea", "timeline", "toaster", "tooltip"];
4
+ export declare const SPEC_COMPONENT_IDS: readonly ["action-form", "alert", "alert-dialog", "analytics-grid", "app-nav", "badge", "banner", "blocks-code", "blocks-data", "blocks-diagram", "blocks-embed", "blocks-interactive", "blocks-map", "blocks-media", "blocks-structure", "blocks-text", "breadcrumb", "button", "button-group", "callout", "card", "charts-area", "charts-bar", "charts-bubble", "charts-bullet", "charts-canvas-renderer", "charts-cartesian", "charts-combo", "charts-donut", "charts-funnel", "charts-gauge", "charts-geo-map", "charts-geo-point-map", "charts-heatmap", "charts-line", "charts-network", "charts-pie", "charts-progress-ring", "charts-sankey", "charts-scatter", "charts-sparkline", "charts-stacked-bar", "charts-sunburst", "charts-treemap", "chat-message", "chat-thread", "checkbox", "chip", "code", "combobox", "command-palette", "content-layout", "context-menu", "context-menu-trigger", "control-choice", "control-filter", "control-slider", "control-toggle", "data-board", "data-calendar", "data-files", "data-grid", "data-map", "data-timeline", "data-tree-view", "deck-slide", "description", "detail-panel", "dialog", "drawer", "dropdown-menu", "dropdown-menu-content", "dropdown-menu-item", "dropdown-menu-trigger", "empty-state", "error-state", "field", "field-error", "flow-action", "flow-view", "form", "form-field", "form-submit", "host-region", "hover-card", "hover-card-content", "icon-button", "inline-text", "input", "input-group", "kbd", "kpi", "label", "layout-auth-split", "layout-blog", "layout-card", "layout-chrome", "layout-dashboard-grid", "layout-deck", "layout-doc", "layout-docs", "layout-drawer", "layout-dual-sidebar", "layout-editorial", "layout-grid", "layout-host", "layout-landing", "layout-marketing", "layout-page", "layout-pricing", "layout-row", "layout-settings", "layout-sidebar", "layout-split", "layout-stack", "layout-tile", "layout-top-nav", "layout-wizard", "media-composition-canvas", "media-composition-svg", "media-image", "menubar", "menubar-trigger", "multi-select", "nav-icon", "navigation-menu", "pagination", "popover", "popover-content", "radio", "radio-group", "responsive-modal", "screen-outlet", "select", "select-content", "select-group", "select-item", "select-label", "select-portal", "select-separator", "select-trigger", "select-value", "select-viewport", "sheet", "sidebar", "sortable-list", "split-view", "stat", "stepper", "switch", "table", "tag", "text-counter", "textarea", "timeline", "toaster", "tooltip", "workflow-graph"];
5
5
  export type SpecComponentId = (typeof SPEC_COMPONENT_IDS)[number];
6
6
  /** The props a blueprint may set on each component (platform extensions left out). */
7
7
  export interface SpecComponentProps {
8
+ 'action-form': {
9
+ action: string;
10
+ label: string;
11
+ };
8
12
  alert: {
9
13
  actionHref?: string;
10
14
  actionLabel?: string;
@@ -365,6 +369,15 @@ export interface SpecComponentProps {
365
369
  title: string;
366
370
  width?: number;
367
371
  };
372
+ 'chat-message': {
373
+ at?: string;
374
+ author: string;
375
+ role: 'user' | 'agent' | 'system';
376
+ text?: string;
377
+ };
378
+ 'chat-thread': {
379
+ label?: string;
380
+ };
368
381
  checkbox: {
369
382
  checked?: boolean;
370
383
  defaultChecked?: boolean;
@@ -434,12 +447,82 @@ export interface SpecComponentProps {
434
447
  'context-menu-trigger': {
435
448
  disabled?: boolean;
436
449
  };
450
+ 'control-choice': {
451
+ label: string;
452
+ state: string;
453
+ };
454
+ 'control-filter': {
455
+ label: string;
456
+ placeholder?: string;
457
+ state: string;
458
+ };
459
+ 'control-slider': {
460
+ label: string;
461
+ state: string;
462
+ step?: number;
463
+ };
464
+ 'control-toggle': {
465
+ label: string;
466
+ state: string;
467
+ };
468
+ 'data-board': {
469
+ columns: readonly unknown[];
470
+ density?: 'comfortable' | 'compact';
471
+ items: readonly unknown[];
472
+ label: string;
473
+ lanes?: readonly unknown[];
474
+ };
475
+ 'data-calendar': {
476
+ anchor?: string;
477
+ events: readonly unknown[];
478
+ label: string;
479
+ locale?: string;
480
+ readOnly?: boolean;
481
+ timeZone?: string;
482
+ view?: 'month' | 'week' | 'day' | 'agenda';
483
+ };
484
+ 'data-files': {
485
+ density?: 'comfortable' | 'compact';
486
+ entries: readonly unknown[];
487
+ label: string;
488
+ layout?: 'grid' | 'list';
489
+ };
490
+ 'data-grid': {
491
+ caption: string;
492
+ columns: readonly unknown[];
493
+ density?: 'compact' | 'default' | 'comfortable';
494
+ rows: readonly unknown[];
495
+ searchable?: boolean;
496
+ selectable?: boolean;
497
+ };
498
+ 'data-map': {
499
+ label: string;
500
+ listPlacement?: 'side' | 'below';
501
+ markers: readonly unknown[];
502
+ };
503
+ 'data-timeline': {
504
+ dependencies?: readonly unknown[];
505
+ label: string;
506
+ locale?: string;
507
+ tasks: readonly unknown[];
508
+ zoom?: 'day' | 'week' | 'month' | 'quarter';
509
+ };
510
+ 'data-tree-view': {
511
+ checkboxes?: boolean;
512
+ density?: 'comfortable' | 'compact';
513
+ items: readonly unknown[];
514
+ label: string;
515
+ };
437
516
  'deck-slide': {
517
+ component?: Readonly<Record<string, unknown>>;
518
+ layout?: string;
438
519
  master?: 'title' | 'section' | 'content' | 'two-column' | 'media-left' | 'media-right' | 'quote' | 'closing';
439
520
  notes?: string;
521
+ props?: Readonly<Record<string, unknown>>;
440
522
  slideId: string;
523
+ steps?: readonly unknown[];
441
524
  title?: string;
442
- transition?: 'none' | 'fade' | 'fade-up';
525
+ transition?: 'none' | 'fade' | 'fade-up' | 'slide' | 'zoom' | 'morph';
443
526
  };
444
527
  description: Record<string, never>;
445
528
  'detail-panel': {
@@ -506,11 +589,40 @@ export interface SpecComponentProps {
506
589
  'field-error': {
507
590
  show?: boolean;
508
591
  };
592
+ 'flow-action': {
593
+ event: string;
594
+ label: string;
595
+ };
596
+ 'flow-view': {
597
+ label?: string;
598
+ name: string;
599
+ };
509
600
  form: {
510
601
  errors?: Readonly<Record<string, unknown>>;
511
602
  layout?: 'stack' | 'grid';
512
603
  noValidate?: boolean;
513
604
  };
605
+ 'form-field': {
606
+ autocomplete?: 'off' | 'name' | 'given-name' | 'family-name' | 'nickname' | 'email' | 'tel' | 'organization' | 'organization-title' | 'street-address' | 'address-level1' | 'address-level2' | 'postal-code' | 'country-name' | 'language' | 'url';
607
+ kind?: 'text' | 'email' | 'tel' | 'number' | 'multiline';
608
+ label: string;
609
+ max?: number;
610
+ maxLength?: number;
611
+ min?: number;
612
+ minLength?: number;
613
+ name: string;
614
+ pattern?: 'email' | 'phone' | 'postal-code' | 'digits' | 'slug';
615
+ placeholder?: string;
616
+ required?: boolean;
617
+ state: string;
618
+ };
619
+ 'form-submit': {
620
+ label: string;
621
+ };
622
+ 'host-region': {
623
+ label: string;
624
+ name: string;
625
+ };
514
626
  'hover-card': {
515
627
  open?: boolean;
516
628
  };
@@ -600,13 +712,17 @@ export interface SpecComponentProps {
600
712
  storageKey?: string;
601
713
  };
602
714
  'layout-deck': {
603
- aspect?: '16:9' | '4:3' | '1:1';
715
+ aspect?: '16:9' | '4:3' | '9:16' | '1:1';
604
716
  description?: string;
605
717
  locale?: string;
606
718
  masters?: readonly unknown[];
719
+ motion?: 'full' | 'subtle' | 'none';
720
+ navigation?: Readonly<Record<string, unknown>>;
721
+ outline?: Readonly<Record<string, unknown>>;
607
722
  settings?: Readonly<Record<string, unknown>>;
608
723
  slides?: readonly unknown[];
609
724
  title?: string;
725
+ transition?: 'none' | 'fade' | 'fade-up' | 'slide' | 'zoom' | 'morph';
610
726
  };
611
727
  'layout-doc': {
612
728
  title?: string;
@@ -671,6 +787,11 @@ export interface SpecComponentProps {
671
787
  plans?: readonly unknown[];
672
788
  title?: string;
673
789
  };
790
+ 'layout-row': {
791
+ align?: 'start' | 'center' | 'end' | 'stretch';
792
+ gap?: 'none' | 'small' | 'medium' | 'large';
793
+ wrap?: boolean;
794
+ };
674
795
  'layout-settings': {
675
796
  active?: string;
676
797
  backLabel?: string;
@@ -689,6 +810,18 @@ export interface SpecComponentProps {
689
810
  skipLabel?: string;
690
811
  storageKey?: string;
691
812
  };
813
+ 'layout-split': {
814
+ gap?: 'none' | 'small' | 'medium' | 'large';
815
+ ratio?: '1:1' | '1:2' | '2:1' | '1:3' | '3:1';
816
+ };
817
+ 'layout-stack': {
818
+ gap?: 'none' | 'small' | 'medium' | 'large';
819
+ };
820
+ 'layout-tile': {
821
+ rowSpan?: number;
822
+ span?: number;
823
+ title?: string;
824
+ };
692
825
  'layout-top-nav': {
693
826
  closeLabel?: string;
694
827
  menuLabel?: string;
@@ -767,6 +900,7 @@ export interface SpecComponentProps {
767
900
  variant?: 'outline' | 'soft';
768
901
  };
769
902
  'nav-icon': {
903
+ icon: string;
770
904
  label?: string;
771
905
  };
772
906
  'navigation-menu': {
@@ -874,16 +1008,24 @@ export interface SpecComponentProps {
874
1008
  sections?: readonly unknown[];
875
1009
  variant?: 'default' | 'inset';
876
1010
  };
1011
+ 'sortable-list': {
1012
+ itemDetail?: string;
1013
+ itemLabel?: string;
1014
+ label: string;
1015
+ reorder: Readonly<Record<string, unknown>>;
1016
+ };
877
1017
  'split-view': {
878
1018
  detailActive?: boolean;
879
1019
  detailLabel?: string;
880
1020
  listLabel?: string;
881
1021
  };
882
1022
  stat: {
1023
+ delta?: string;
883
1024
  hint?: string;
884
1025
  label: string;
885
1026
  positive?: 'up' | 'down';
886
1027
  trend?: 'up' | 'down' | 'neutral';
1028
+ value: string;
887
1029
  variant?: 'elevated' | 'flat';
888
1030
  };
889
1031
  stepper: {
@@ -969,4 +1111,10 @@ export interface SpecComponentProps {
969
1111
  side?: 'top' | 'right' | 'bottom' | 'left';
970
1112
  sideOffset?: number;
971
1113
  };
1114
+ 'workflow-graph': {
1115
+ flow?: 'LR' | 'TB';
1116
+ graph: Readonly<Record<string, unknown>>;
1117
+ label: string;
1118
+ mode?: 'view' | 'edit';
1119
+ };
972
1120
  }
@@ -1,9 +1,10 @@
1
1
  // Generated by @texuli/spec from catalog/components.json. Do not edit: run the spec generator.
2
- // Spec 0.2.0, digest d9eccaba1826e7d87648a4a33787d873245592dda843607a10b2c68a77f1806f
2
+ // Spec 0.4.0, digest fac29f542b16ddb78ab401c508e5b8346f655991c56e25aa811f4931661a8cb3
3
3
  /** The built catalog this vocabulary was projected from. */
4
- export const SPEC_CATALOG_HASH = 'b073e30b4c8b1a30b3ef3ccb372e552d2d88e584616b74591c6c32923b471376';
4
+ export const SPEC_CATALOG_HASH = '8a449985d45c7bfd1dc2285f3513dfd6ca0e3e38260c0a541fdb7b17e9213006';
5
5
  /** Every closed component id, sorted. */
6
6
  export const SPEC_COMPONENT_IDS = [
7
+ 'action-form',
7
8
  'alert',
8
9
  'alert-dialog',
9
10
  'analytics-grid',
@@ -47,6 +48,8 @@ export const SPEC_COMPONENT_IDS = [
47
48
  'charts-stacked-bar',
48
49
  'charts-sunburst',
49
50
  'charts-treemap',
51
+ 'chat-message',
52
+ 'chat-thread',
50
53
  'checkbox',
51
54
  'chip',
52
55
  'code',
@@ -55,6 +58,17 @@ export const SPEC_COMPONENT_IDS = [
55
58
  'content-layout',
56
59
  'context-menu',
57
60
  'context-menu-trigger',
61
+ 'control-choice',
62
+ 'control-filter',
63
+ 'control-slider',
64
+ 'control-toggle',
65
+ 'data-board',
66
+ 'data-calendar',
67
+ 'data-files',
68
+ 'data-grid',
69
+ 'data-map',
70
+ 'data-timeline',
71
+ 'data-tree-view',
58
72
  'deck-slide',
59
73
  'description',
60
74
  'detail-panel',
@@ -68,7 +82,12 @@ export const SPEC_COMPONENT_IDS = [
68
82
  'error-state',
69
83
  'field',
70
84
  'field-error',
85
+ 'flow-action',
86
+ 'flow-view',
71
87
  'form',
88
+ 'form-field',
89
+ 'form-submit',
90
+ 'host-region',
72
91
  'hover-card',
73
92
  'hover-card-content',
74
93
  'icon-button',
@@ -95,8 +114,12 @@ export const SPEC_COMPONENT_IDS = [
95
114
  'layout-marketing',
96
115
  'layout-page',
97
116
  'layout-pricing',
117
+ 'layout-row',
98
118
  'layout-settings',
99
119
  'layout-sidebar',
120
+ 'layout-split',
121
+ 'layout-stack',
122
+ 'layout-tile',
100
123
  'layout-top-nav',
101
124
  'layout-wizard',
102
125
  'media-composition-canvas',
@@ -126,6 +149,7 @@ export const SPEC_COMPONENT_IDS = [
126
149
  'select-viewport',
127
150
  'sheet',
128
151
  'sidebar',
152
+ 'sortable-list',
129
153
  'split-view',
130
154
  'stat',
131
155
  'stepper',
@@ -137,4 +161,5 @@ export const SPEC_COMPONENT_IDS = [
137
161
  'timeline',
138
162
  'toaster',
139
163
  'tooltip',
164
+ 'workflow-graph',
140
165
  ];
@@ -0,0 +1,84 @@
1
+ export type WorkflowId = string;
2
+ /** Display text: no control characters and no bidirectional overrides or isolates. */
3
+ export type WorkflowLabel = string;
4
+ export type WorkflowCoordinate = number;
5
+ export interface WorkflowPosition {
6
+ x: WorkflowCoordinate;
7
+ y: WorkflowCoordinate;
8
+ }
9
+ export interface WorkflowSize {
10
+ width: number;
11
+ height: number;
12
+ }
13
+ export interface WorkflowPort {
14
+ id: WorkflowId;
15
+ direction: 'in' | 'out';
16
+ label?: WorkflowLabel;
17
+ /** Ports with a kind connect only to ports of the same kind. */
18
+ kind?: string;
19
+ /** Whether the port takes more than one edge. */
20
+ multiple?: boolean;
21
+ }
22
+ export interface WorkflowField {
23
+ name: string;
24
+ label?: WorkflowLabel;
25
+ kind: 'string' | 'number' | 'boolean' | 'enum';
26
+ required?: boolean;
27
+ enumValues?: readonly string[];
28
+ /** For string fields; 2000 when omitted. */
29
+ maxLength?: number;
30
+ }
31
+ export interface WorkflowNodeType {
32
+ id: WorkflowId;
33
+ label: WorkflowLabel;
34
+ category?: WorkflowLabel;
35
+ ports: readonly WorkflowPort[];
36
+ fields?: readonly WorkflowField[];
37
+ }
38
+ export interface WorkflowNode {
39
+ id: WorkflowId;
40
+ type: WorkflowId;
41
+ label: WorkflowLabel;
42
+ position: WorkflowPosition;
43
+ size?: WorkflowSize;
44
+ group?: WorkflowId;
45
+ /** Field values by field name: scalars of the field kind. */
46
+ data?: Readonly<Record<string, unknown>>;
47
+ locked?: boolean;
48
+ }
49
+ export interface WorkflowEndpoint {
50
+ node: WorkflowId;
51
+ port: WorkflowId;
52
+ }
53
+ export interface WorkflowEdge {
54
+ id: WorkflowId;
55
+ from: WorkflowEndpoint;
56
+ to: WorkflowEndpoint;
57
+ label?: WorkflowLabel;
58
+ }
59
+ export interface WorkflowGroup {
60
+ id: WorkflowId;
61
+ label: WorkflowLabel;
62
+ position?: WorkflowPosition;
63
+ size?: WorkflowSize;
64
+ }
65
+ export interface WorkflowViewport {
66
+ x: WorkflowCoordinate;
67
+ y: WorkflowCoordinate;
68
+ zoom: number;
69
+ }
70
+ /**
71
+ * A workflow graph as data (ADR-008): closed node types with typed ports and fields, nodes, edges
72
+ * between declared ports, optional groups and a cycle policy. At most 500 nodes and 2,000 edges.
73
+ * Ids, references, field values, port directions and cycles are checked by validateWorkflowGraph.
74
+ */
75
+ export interface WorkflowGraph {
76
+ version: 1;
77
+ nodeTypes: readonly WorkflowNodeType[];
78
+ nodes: readonly WorkflowNode[];
79
+ edges: readonly WorkflowEdge[];
80
+ groups?: readonly WorkflowGroup[];
81
+ /** forbid makes the graph acyclic (a self-loop counts); omitted means allow. */
82
+ cycles?: 'allow' | 'forbid';
83
+ viewport?: WorkflowViewport;
84
+ }
@@ -0,0 +1,3 @@
1
+ // Generated by @texuli/spec from schemas/workflow.schema.json. Do not edit: run the spec generator.
2
+ // Spec 0.4.0, digest fac29f542b16ddb78ab401c508e5b8346f655991c56e25aa811f4931661a8cb3
3
+ export {};
package/dist/index.d.ts CHANGED
@@ -1,17 +1,25 @@
1
1
  /**
2
2
  * `@texuli/spec` — the schema-first blueprint contract (spec/Compose design
3
3
  * B1), runtime half: the generated types and vocabulary, the dialect
4
- * validator, the target-neutral blueprint validator and deterministic
5
- * hashing. Build-time generation and the conformance harness live in
6
- * `@texuli/spec/codegen`. Framework-free: no DOM, no Svelte and no Node APIs.
4
+ * validator, the target-neutral blueprint validator, the 0.3.0 interaction
5
+ * contract (bindings, closed actions, events) and deterministic hashing.
6
+ * Opt-in subpaths keep the root small: `@texuli/spec/workflow` (the workflow
7
+ * graph validator, passed in `SpecDocuments.validateWorkflowGraph`) and
8
+ * `@texuli/spec/migrate` (envelope migrations). Build-time generation and the
9
+ * conformance harness live in `@texuli/spec/codegen`. Framework-free: no DOM,
10
+ * no Svelte and no Node APIs.
7
11
  */
8
12
  export type * from './generated/typescript/blueprint.js';
9
13
  export type * from './generated/typescript/catalog-schema.js';
10
14
  export type * from './generated/typescript/diagnostics.js';
11
15
  export type * from './generated/typescript/manifest.js';
12
16
  export { SPEC_CATALOG_HASH, SPEC_COMPONENT_IDS, type SpecComponentId, type SpecComponentProps, } from './generated/typescript/vocabulary.js';
17
+ export type * from './generated/typescript/workflow.js';
13
18
  export { canonicalJson, sha256 } from './canonical.js';
14
19
  export { CAPABILITIES, type Capability, type SpecPropKind, WEB_ONLY_KINDS, WEB_ONLY_PROP_NAMES, } from './catalog.js';
15
- export { checkSchemaDocument, DIALECT_KEYWORDS, DIALECT_TYPES, DIALECT_URI, type DialectType, type Schema, type SchemaIssue, validateInstance, } from './dialect.js';
16
- export { type SpecDocuments, validateBlueprint, validateTree, } from './validate.js';
20
+ export { ACTION_FIELDS, contractRoot, DATA_BINDING_KEY, SPEC_ACTION_OPS, SPEC_EVENT_NAMES, SPEC_LIMITS, SPEC_PATTERNS, SPEC_PROP_REFS, SPEC_STATE_TYPES, type SpecActionOp, type SpecStateType, STATE_BINDING_KEY, STATE_FIELDS, toDialectSchema, } from './contract.js';
21
+ export { checkSchemaDocument, DIALECT_KEYWORDS, DIALECT_TYPES, DIALECT_URI, type DialectHooks, type DialectType, type Schema, type SchemaIssue, validateInstance, } from './dialect.js';
22
+ export type { SpecMigration, SpecMigrationResult } from './migrations/types.js';
23
+ export { checkStateSurface, LIST_TEXT_PATTERN, SPEC_CONTROL_STATE_TYPES, SURFACE_PLAYER_CODES, type SurfaceCode, type SurfaceInputs, type SurfaceIssue, surfaceInputs, } from './surface.js';
24
+ export { type SpecDocuments, type SpecFlowInfo, type SpecStateVariable, type TreeOptions, validateBlueprint, validateTree, type WorkflowGraphValidator, } from './validate.js';
17
25
  export { SPEC_VERSION } from './version.js';
package/dist/index.js CHANGED
@@ -1,13 +1,19 @@
1
1
  /**
2
2
  * `@texuli/spec` — the schema-first blueprint contract (spec/Compose design
3
3
  * B1), runtime half: the generated types and vocabulary, the dialect
4
- * validator, the target-neutral blueprint validator and deterministic
5
- * hashing. Build-time generation and the conformance harness live in
6
- * `@texuli/spec/codegen`. Framework-free: no DOM, no Svelte and no Node APIs.
4
+ * validator, the target-neutral blueprint validator, the 0.3.0 interaction
5
+ * contract (bindings, closed actions, events) and deterministic hashing.
6
+ * Opt-in subpaths keep the root small: `@texuli/spec/workflow` (the workflow
7
+ * graph validator, passed in `SpecDocuments.validateWorkflowGraph`) and
8
+ * `@texuli/spec/migrate` (envelope migrations). Build-time generation and the
9
+ * conformance harness live in `@texuli/spec/codegen`. Framework-free: no DOM,
10
+ * no Svelte and no Node APIs.
7
11
  */
8
12
  export { SPEC_CATALOG_HASH, SPEC_COMPONENT_IDS, } from "./generated/typescript/vocabulary.js";
9
13
  export { canonicalJson, sha256 } from "./canonical.js";
10
14
  export { CAPABILITIES, WEB_ONLY_KINDS, WEB_ONLY_PROP_NAMES, } from "./catalog.js";
15
+ export { ACTION_FIELDS, contractRoot, DATA_BINDING_KEY, SPEC_ACTION_OPS, SPEC_EVENT_NAMES, SPEC_LIMITS, SPEC_PATTERNS, SPEC_PROP_REFS, SPEC_STATE_TYPES, STATE_BINDING_KEY, STATE_FIELDS, toDialectSchema, } from "./contract.js";
11
16
  export { checkSchemaDocument, DIALECT_KEYWORDS, DIALECT_TYPES, DIALECT_URI, validateInstance, } from "./dialect.js";
17
+ export { checkStateSurface, LIST_TEXT_PATTERN, SPEC_CONTROL_STATE_TYPES, SURFACE_PLAYER_CODES, surfaceInputs, } from "./surface.js";
12
18
  export { validateBlueprint, validateTree, } from "./validate.js";
13
19
  export { SPEC_VERSION } from "./version.js";
@@ -0,0 +1,7 @@
1
+ import type { SpecMigration } from './types.js';
2
+ /**
3
+ * 0.2.0 → 0.3.0 is additive (ADR-008): every 0.2.0 envelope is a valid
4
+ * 0.3.0 envelope, so the step only stamps `spec`. Object spread keeps a
5
+ * parsed `__proto__` key as an own property, so validation still refuses it.
6
+ */
7
+ export declare const migration020to030: SpecMigration;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 0.2.0 → 0.3.0 is additive (ADR-008): every 0.2.0 envelope is a valid
3
+ * 0.3.0 envelope, so the step only stamps `spec`. Object spread keeps a
4
+ * parsed `__proto__` key as an own property, so validation still refuses it.
5
+ */
6
+ export const migration020to030 = Object.freeze({
7
+ from: '0.2.0',
8
+ to: '0.3.0',
9
+ migrate: (envelope) => ({ ...envelope, spec: '0.3.0' }),
10
+ });
@@ -0,0 +1,9 @@
1
+ import type { SpecMigration } from './types.js';
2
+ /**
3
+ * 0.3.0 → 0.4.0 is additive (PLAN_008 T-catalog-player / ADR-009 deck encoding):
4
+ * layout-deck and deck-slide gain optional model-v2 props (aspect 9:16,
5
+ * transitions slide/zoom/morph, motion, navigation, outline, layout, background,
6
+ * steps, component). Every 0.3.0 envelope is a valid 0.4.0 envelope, so the
7
+ * step only stamps `spec`.
8
+ */
9
+ export declare const migration030to040: SpecMigration;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 0.3.0 → 0.4.0 is additive (PLAN_008 T-catalog-player / ADR-009 deck encoding):
3
+ * layout-deck and deck-slide gain optional model-v2 props (aspect 9:16,
4
+ * transitions slide/zoom/morph, motion, navigation, outline, layout, background,
5
+ * steps, component). Every 0.3.0 envelope is a valid 0.4.0 envelope, so the
6
+ * step only stamps `spec`.
7
+ */
8
+ export const migration030to040 = Object.freeze({
9
+ from: '0.3.0',
10
+ to: '0.4.0',
11
+ migrate: (envelope) => ({ ...envelope, spec: '0.4.0' }),
12
+ });
@@ -0,0 +1,15 @@
1
+ import type { SpecMigration, SpecMigrationResult } from './types.js';
2
+ export type { SpecMigration, SpecMigrationResult };
3
+ /** The version an envelope without `spec` was written for. */
4
+ export declare const UNDECLARED_SPEC_VERSION = "0.2.0";
5
+ /** Every step, in order; each `to` is the next step's `from`. */
6
+ export declare const SPEC_MIGRATIONS: readonly SpecMigration[];
7
+ /**
8
+ * Bring a blueprint envelope up to `target` (the current spec by default)
9
+ * before validation. Never throws and never mutates its input: a value that
10
+ * is not an envelope, or one declaring a version no chain starts from, passes
11
+ * through with no step applied (validation then refuses an unknown `spec`).
12
+ * Only the envelope's `spec` field changes, so the tree, status, provenance
13
+ * and activation digest stay as they were. Idempotent.
14
+ */
15
+ export declare function migrateBlueprint(input: unknown, target?: string): SpecMigrationResult;
@@ -0,0 +1,53 @@
1
+ import { isRecord } from "../dialect.js";
2
+ import { SPEC_VERSION } from "../version.js";
3
+ import { migration020to030 } from "./0.2.0-0.3.0.js";
4
+ import { migration030to040 } from "./0.3.0-0.4.0.js";
5
+ /** The version an envelope without `spec` was written for. */
6
+ export const UNDECLARED_SPEC_VERSION = '0.2.0';
7
+ /** Every step, in order; each `to` is the next step's `from`. */
8
+ export const SPEC_MIGRATIONS = Object.freeze([
9
+ migration020to030,
10
+ migration030to040,
11
+ ]);
12
+ /**
13
+ * Bring a blueprint envelope up to `target` (the current spec by default)
14
+ * before validation. Never throws and never mutates its input: a value that
15
+ * is not an envelope, or one declaring a version no chain starts from, passes
16
+ * through with no step applied (validation then refuses an unknown `spec`).
17
+ * Only the envelope's `spec` field changes, so the tree, status, provenance
18
+ * and activation digest stay as they were. Idempotent.
19
+ */
20
+ export function migrateBlueprint(input, target = SPEC_VERSION) {
21
+ if (!isRecord(input)) {
22
+ return {
23
+ blueprint: input,
24
+ from: UNDECLARED_SPEC_VERSION,
25
+ to: UNDECLARED_SPEC_VERSION,
26
+ applied: [],
27
+ };
28
+ }
29
+ const declared = Object.hasOwn(input, 'spec') ? input.spec : UNDECLARED_SPEC_VERSION;
30
+ if (typeof declared !== 'string') {
31
+ return {
32
+ blueprint: input,
33
+ from: UNDECLARED_SPEC_VERSION,
34
+ to: UNDECLARED_SPEC_VERSION,
35
+ applied: [],
36
+ };
37
+ }
38
+ let blueprint = input;
39
+ let current = declared;
40
+ const applied = [];
41
+ for (let step = 0; step < SPEC_MIGRATIONS.length && current !== target; step += 1) {
42
+ const migration = SPEC_MIGRATIONS.find((m) => m.from === current);
43
+ if (!migration)
44
+ break;
45
+ blueprint = migration.migrate(blueprint);
46
+ applied.push(`${migration.from}->${migration.to}`);
47
+ current = migration.to;
48
+ }
49
+ if (current !== target) {
50
+ return { blueprint: input, from: declared, to: declared, applied: [] };
51
+ }
52
+ return { blueprint, from: declared, to: current, applied };
53
+ }
@@ -0,0 +1,14 @@
1
+ /** One pure step between two adjacent spec versions. */
2
+ export interface SpecMigration {
3
+ readonly from: string;
4
+ readonly to: string;
5
+ /** Pure: never mutates its input; unchanged subtrees may be shared. */
6
+ migrate(envelope: Readonly<Record<string, unknown>>): Record<string, unknown>;
7
+ }
8
+ /** What {@link migrateBlueprint} did: the result and the steps applied (`"0.2.0->0.3.0"`). */
9
+ export interface SpecMigrationResult {
10
+ blueprint: unknown;
11
+ from: string;
12
+ to: string;
13
+ applied: readonly string[];
14
+ }
@@ -0,0 +1 @@
1
+ export {};