@clowder-ai/plugin-contract 0.1.0-beta.9 → 0.2.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 (145) hide show
  1. package/dist/codegen/generate-contract.d.ts +6 -0
  2. package/dist/codegen/generate-contract.d.ts.map +1 -1
  3. package/dist/codegen/generate-contract.js +343 -19
  4. package/dist/codegen/generate-contract.js.map +1 -1
  5. package/dist/conformance/fixtures.d.ts +3 -1
  6. package/dist/conformance/fixtures.d.ts.map +1 -1
  7. package/dist/conformance/fixtures.js +2 -1
  8. package/dist/conformance/fixtures.js.map +1 -1
  9. package/dist/conformance/index.d.ts +2 -1
  10. package/dist/conformance/index.d.ts.map +1 -1
  11. package/dist/conformance/index.js +2 -1
  12. package/dist/conformance/index.js.map +1 -1
  13. package/dist/conformance/messaging-behavior-fixture.d.ts +12 -0
  14. package/dist/conformance/messaging-behavior-fixture.d.ts.map +1 -0
  15. package/dist/conformance/messaging-behavior-fixture.js +30 -0
  16. package/dist/conformance/messaging-behavior-fixture.js.map +1 -0
  17. package/dist/conformance/runner.d.ts.map +1 -1
  18. package/dist/conformance/runner.js +3 -1
  19. package/dist/conformance/runner.js.map +1 -1
  20. package/dist/docx-materialization.d.ts +8 -0
  21. package/dist/docx-materialization.d.ts.map +1 -0
  22. package/dist/docx-materialization.js +19 -0
  23. package/dist/docx-materialization.js.map +1 -0
  24. package/dist/generated/contract.generated.d.ts +1647 -52
  25. package/dist/generated/contract.generated.d.ts.map +1 -1
  26. package/dist/generated/contract.generated.js +72 -3
  27. package/dist/generated/contract.generated.js.map +1 -1
  28. package/dist/index.d.ts +1 -1
  29. package/dist/index.js +1 -1
  30. package/dist/validation/catalog.d.ts +21 -0
  31. package/dist/validation/catalog.d.ts.map +1 -0
  32. package/dist/validation/catalog.js +140 -0
  33. package/dist/validation/catalog.js.map +1 -0
  34. package/dist/validation/cloud-conversation-host.d.ts +18 -0
  35. package/dist/validation/cloud-conversation-host.d.ts.map +1 -0
  36. package/dist/validation/cloud-conversation-host.js +83 -0
  37. package/dist/validation/cloud-conversation-host.js.map +1 -0
  38. package/dist/validation/companion-bridge.d.ts +6 -0
  39. package/dist/validation/companion-bridge.d.ts.map +1 -0
  40. package/dist/validation/companion-bridge.js +198 -0
  41. package/dist/validation/companion-bridge.js.map +1 -0
  42. package/dist/validation/docx-materialization.d.ts +6 -0
  43. package/dist/validation/docx-materialization.d.ts.map +1 -0
  44. package/dist/validation/docx-materialization.js +36 -0
  45. package/dist/validation/docx-materialization.js.map +1 -0
  46. package/dist/validation/index.d.ts +9 -1
  47. package/dist/validation/index.d.ts.map +1 -1
  48. package/dist/validation/index.js +9 -1
  49. package/dist/validation/index.js.map +1 -1
  50. package/dist/validation/manifest.d.ts.map +1 -1
  51. package/dist/validation/manifest.js +303 -0
  52. package/dist/validation/manifest.js.map +1 -1
  53. package/dist/validation/members.d.ts +4 -0
  54. package/dist/validation/members.d.ts.map +1 -0
  55. package/dist/validation/members.js +11 -0
  56. package/dist/validation/members.js.map +1 -0
  57. package/dist/validation/messaging-semantic.d.ts.map +1 -1
  58. package/dist/validation/messaging-semantic.js +98 -0
  59. package/dist/validation/messaging-semantic.js.map +1 -1
  60. package/dist/validation/messaging-wire.d.ts +42 -0
  61. package/dist/validation/messaging-wire.d.ts.map +1 -0
  62. package/dist/validation/messaging-wire.js +184 -0
  63. package/dist/validation/messaging-wire.js.map +1 -0
  64. package/dist/validation/operation-rows.d.ts +25 -0
  65. package/dist/validation/operation-rows.d.ts.map +1 -0
  66. package/dist/validation/operation-rows.js +135 -0
  67. package/dist/validation/operation-rows.js.map +1 -0
  68. package/dist/validation/signals.d.ts +1 -10
  69. package/dist/validation/signals.d.ts.map +1 -1
  70. package/dist/validation/signals.js +0 -174
  71. package/dist/validation/signals.js.map +1 -1
  72. package/dist/variant.d.ts +114 -0
  73. package/dist/variant.d.ts.map +1 -0
  74. package/dist/variant.js +305 -0
  75. package/dist/variant.js.map +1 -0
  76. package/dist/wire/constants.d.ts +2 -1
  77. package/dist/wire/constants.d.ts.map +1 -1
  78. package/dist/wire/constants.js +2 -1
  79. package/dist/wire/constants.js.map +1 -1
  80. package/dist/wire/dispatch.d.ts +49 -0
  81. package/dist/wire/dispatch.d.ts.map +1 -0
  82. package/dist/wire/dispatch.js +880 -0
  83. package/dist/wire/dispatch.js.map +1 -0
  84. package/dist/wire/disposition-fixtures.d.ts +9 -1
  85. package/dist/wire/disposition-fixtures.d.ts.map +1 -1
  86. package/dist/wire/disposition-fixtures.js +622 -95
  87. package/dist/wire/disposition-fixtures.js.map +1 -1
  88. package/dist/wire/envelope.d.ts +31 -0
  89. package/dist/wire/envelope.d.ts.map +1 -1
  90. package/dist/wire/envelope.js +48 -1
  91. package/dist/wire/envelope.js.map +1 -1
  92. package/dist/wire/errors.d.ts +31 -1
  93. package/dist/wire/errors.d.ts.map +1 -1
  94. package/dist/wire/errors.js +36 -0
  95. package/dist/wire/errors.js.map +1 -1
  96. package/dist/wire/grants.d.ts +4 -4
  97. package/dist/wire/grants.js +3 -3
  98. package/dist/wire/handshake-byte-bounds.d.ts.map +1 -1
  99. package/dist/wire/handshake-byte-bounds.js +5 -2
  100. package/dist/wire/handshake-byte-bounds.js.map +1 -1
  101. package/dist/wire/handshake.d.ts +6 -0
  102. package/dist/wire/handshake.d.ts.map +1 -1
  103. package/dist/wire/handshake.js +6 -3
  104. package/dist/wire/handshake.js.map +1 -1
  105. package/dist/wire/index.d.ts +13 -9
  106. package/dist/wire/index.d.ts.map +1 -1
  107. package/dist/wire/index.js +29 -6
  108. package/dist/wire/index.js.map +1 -1
  109. package/dist/wire/lifecycle-byte-bounds.d.ts +40 -0
  110. package/dist/wire/lifecycle-byte-bounds.d.ts.map +1 -0
  111. package/dist/wire/lifecycle-byte-bounds.js +149 -0
  112. package/dist/wire/lifecycle-byte-bounds.js.map +1 -0
  113. package/dist/wire/messaging-byte-bounds.d.ts +62 -0
  114. package/dist/wire/messaging-byte-bounds.d.ts.map +1 -0
  115. package/dist/wire/messaging-byte-bounds.js +581 -0
  116. package/dist/wire/messaging-byte-bounds.js.map +1 -0
  117. package/dist/wire/registry.d.ts +58 -86
  118. package/dist/wire/registry.d.ts.map +1 -1
  119. package/dist/wire/registry.js +45 -88
  120. package/dist/wire/registry.js.map +1 -1
  121. package/dist/wire/row-shapes.d.ts +86 -69
  122. package/dist/wire/row-shapes.d.ts.map +1 -1
  123. package/dist/wire/row-shapes.js +30 -3
  124. package/dist/wire/row-shapes.js.map +1 -1
  125. package/fixtures/behavior/messaging/adversarial-invariants.json +92 -2
  126. package/fixtures/manifest/invalid/duplicate-signal-type.json +4 -2
  127. package/fixtures/manifest/invalid/icon-package-escape.json +22 -0
  128. package/fixtures/manifest/valid/localized-product-metadata.json +27 -0
  129. package/fixtures/messaging/valid/subscription-delivery.json +1 -1
  130. package/package.json +16 -3
  131. package/src/schemas/behavior-fixture.schema.json +903 -116
  132. package/src/schemas/catalog.schema.json +91 -0
  133. package/src/schemas/companion-bridge.schema.json +2256 -0
  134. package/src/schemas/docx-materialization.schema.json +302 -0
  135. package/src/schemas/manifest.schema.json +2273 -88
  136. package/src/schemas/messaging.schema.json +692 -41
  137. package/src/schemas/plugin-metadata.schema.json +62 -0
  138. package/src/schemas/signal.schema.json +68 -78
  139. package/dist/wire/signal-byte-bounds.d.ts +0 -97
  140. package/dist/wire/signal-byte-bounds.d.ts.map +0 -1
  141. package/dist/wire/signal-byte-bounds.js +0 -229
  142. package/dist/wire/signal-byte-bounds.js.map +0 -1
  143. package/fixtures/signals/invalid/destination-injection.json +0 -15
  144. package/fixtures/signals/invalid/non-utc-occurred-at.json +0 -12
  145. package/fixtures/signals/valid/feishu-meeting-artifact.json +0 -18
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Browser-safe configuration-variant resolution (configurationVariants,
3
+ * contractVersion 0.2.0).
4
+ *
5
+ * This module is intentionally free of any `node:` or ajv import so the same
6
+ * code runs in the browser (settings form) and on the server (save/readiness/
7
+ * runtime projection). Value matching is strict `===` against `const`/`enum`
8
+ * declared in each branch's constrained `when` fragment.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ import type { ConfigurationField, PluginManifest } from './generated/contract.generated.js';
13
+ export type VariantResolution = {
14
+ readonly status: 'selected';
15
+ readonly branchId: string;
16
+ } | {
17
+ readonly status: 'unselected';
18
+ } | {
19
+ readonly status: 'invalid';
20
+ readonly value: unknown;
21
+ };
22
+ export interface EffectiveConfiguration {
23
+ readonly resolution: VariantResolution;
24
+ readonly effectiveValues: Record<string, unknown>;
25
+ }
26
+ type StoredValues = Readonly<Record<string, unknown>>;
27
+ /**
28
+ * The single string→type coercion boundary (round-three review P1).
29
+ *
30
+ * Host storage and web drafts transport every scalar as a string, while the
31
+ * contract's requiredness (`===` against declared `const`/`enum`), branch
32
+ * matching, and validation schema (`type: 'boolean'` / `type: 'number'`)
33
+ * are strictly typed. Consumers feed raw stored/drafted strings through this
34
+ * function before calling any other entry point in this module, so both sides
35
+ * evaluate identical values without stringifying the contract's predicates.
36
+ *
37
+ * Rules, per declared non-operation field:
38
+ * - `boolean`: `'true'`/`'false'` become the real booleans; any other string
39
+ * stays a string, so downstream validation fails closed instead of
40
+ * silently coercing garbage.
41
+ * - `number`: a string that trims non-empty and parses to a finite number
42
+ * becomes that number; anything else stays a string (same fail-closed).
43
+ * - every other kind (and every non-string input, which passes through
44
+ * untouched) keeps its value as-is.
45
+ *
46
+ * Keys that no declared field owns are passed through unchanged.
47
+ */
48
+ export declare function coerceStoredValues(manifest: PluginManifest, values: StoredValues): Record<string, unknown>;
49
+ /**
50
+ * Three-state variant resolution for a stored (or drafted) configuration.
51
+ *
52
+ * - `unselected`: no discriminator value present — neither stored nor declared
53
+ * as the discriminator field's `default` (or the manifest declares no
54
+ * variants, preserving pre-0.2.0 behavior).
55
+ * - `invalid`: a discriminator value is present (stored, or a declared default)
56
+ * but no branch `when` matches.
57
+ * - `selected`: exactly one branch matches; the first match wins if a
58
+ * non-conformant manifest makes branches overlap.
59
+ */
60
+ export declare function resolveConfigurationVariant(manifest: PluginManifest, values: StoredValues): VariantResolution;
61
+ /**
62
+ * Computes the effective configuration: common fields (not claimed by any
63
+ * branch) plus, when a branch is selected, that branch's fields. Missing
64
+ * stored values fall back to the declared field default — consumers never
65
+ * depend on save-time materialization. On `unselected`/`invalid` only common
66
+ * fields are returned; an invalid discriminator value is kept as stored (no
67
+ * silent fallback to the declared default).
68
+ */
69
+ export declare function computeEffectiveConfiguration(manifest: PluginManifest, storedValues: StoredValues): EffectiveConfiguration;
70
+ /**
71
+ * The single source of truth for whether a field is required, given an
72
+ * effective (or drafted) configuration object.
73
+ *
74
+ * When `requiredWhen` is present it fully replaces the `required` flag: the
75
+ * field is required iff the referenced field's current value strictly
76
+ * (`===`, no stringification) equals one of the declared conditions. When
77
+ * `requiredWhen` is absent, the plain `required` flag decides. Branch
78
+ * membership never influences requiredness — it only decides whether a field
79
+ * is active at all.
80
+ *
81
+ * `values` must already be typed: pass the product of
82
+ * {@link computeEffectiveConfiguration} or run raw string storage/drafts
83
+ * through {@link coerceStoredValues} first. This function does not coerce —
84
+ * a string `"true"` against a declared `true` condition is *not* a match.
85
+ */
86
+ export declare function evaluateFieldRequiredness(field: ConfigurationField, values: StoredValues): boolean;
87
+ /**
88
+ * Compiles the manifest into a standard JSON Schema for validating the
89
+ * *effective* configuration object (see {@link computeEffectiveConfiguration}),
90
+ * not the raw stored object. Consumers must enable standard URI format validation
91
+ * (for Ajv, register ajv-formats before compiling).
92
+ * Operation controls have no scalar value and are omitted; their target-based
93
+ * configured state remains the responsibility of the operation consumer.
94
+ *
95
+ * - Common fields (not claimed by any branch) are constrained at the top
96
+ * level: unconditionally required fields land in `required` and get a kind
97
+ * constraint (e.g. `{type:'string', minLength:1}` for string-likes, so a
98
+ * present `null` or empty string does not count as configured);
99
+ * `requiredWhen` fields become top-level `if/then` clauses keyed on the
100
+ * referenced field's runtime value.
101
+ * - Each branch compiles to one `oneOf` member containing the cloned `when`
102
+ * fragment, the discriminator in `required`, and its active fields handled
103
+ * the same way (static `required` for plain `required: true`, `if/then` for
104
+ * `requiredWhen`). A field that is `requiredWhen`-gated against the
105
+ * discriminator therefore stays optional in a member whose discriminator
106
+ * values do not satisfy the condition — enum branches covering several
107
+ * options keep working without merging values.
108
+ *
109
+ * Requiredness semantics are exactly {@link evaluateFieldRequiredness}; this
110
+ * schema is the ajv-executable form of that function plus kind constraints.
111
+ */
112
+ export declare function buildVariantValidationSchema(manifest: PluginManifest): Record<string, unknown>;
113
+ export {};
114
+ //# sourceMappingURL=variant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variant.d.ts","sourceRoot":"","sources":["../src/variant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAE5F,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GACjC;IAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5D,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,UAAU,EAAE,iBAAiB,CAAC;IACvC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnD;AAID,KAAK,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AA8BtD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,YAAY,GACnB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,YAAY,GACnB,iBAAiB,CAsBnB;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,YAAY,GACzB,sBAAsB,CAsCxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,kBAAkB,EACzB,MAAM,EAAE,YAAY,GACnB,OAAO,CAQT;AAyCD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,cAAc,GACvB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4DzB"}
@@ -0,0 +1,305 @@
1
+ /**
2
+ * Browser-safe configuration-variant resolution (configurationVariants,
3
+ * contractVersion 0.2.0).
4
+ *
5
+ * This module is intentionally free of any `node:` or ajv import so the same
6
+ * code runs in the browser (settings form) and on the server (save/readiness/
7
+ * runtime projection). Value matching is strict `===` against `const`/`enum`
8
+ * declared in each branch's constrained `when` fragment.
9
+ *
10
+ * @packageDocumentation
11
+ */
12
+ function matchesConstraint(constraint, value) {
13
+ if (typeof constraint !== 'object' || constraint === null)
14
+ return false;
15
+ const candidate = constraint;
16
+ if ('const' in candidate)
17
+ return value === candidate['const'];
18
+ if ('enum' in candidate && Array.isArray(candidate['enum'])) {
19
+ return candidate['enum'].some((option) => option === value);
20
+ }
21
+ return false;
22
+ }
23
+ function branchMatches(branch, discriminator, value) {
24
+ const properties = branch.when['properties'];
25
+ if (typeof properties !== 'object' || properties === null)
26
+ return false;
27
+ return matchesConstraint(properties[discriminator], value);
28
+ }
29
+ function fieldDefault(field) {
30
+ return 'default' in field ? field.default : undefined;
31
+ }
32
+ function effectiveFieldValue(field, storedValues) {
33
+ const stored = Object.hasOwn(storedValues, field.key) ? storedValues[field.key] : undefined;
34
+ return stored === undefined ? fieldDefault(field) : stored;
35
+ }
36
+ /**
37
+ * The single string→type coercion boundary (round-three review P1).
38
+ *
39
+ * Host storage and web drafts transport every scalar as a string, while the
40
+ * contract's requiredness (`===` against declared `const`/`enum`), branch
41
+ * matching, and validation schema (`type: 'boolean'` / `type: 'number'`)
42
+ * are strictly typed. Consumers feed raw stored/drafted strings through this
43
+ * function before calling any other entry point in this module, so both sides
44
+ * evaluate identical values without stringifying the contract's predicates.
45
+ *
46
+ * Rules, per declared non-operation field:
47
+ * - `boolean`: `'true'`/`'false'` become the real booleans; any other string
48
+ * stays a string, so downstream validation fails closed instead of
49
+ * silently coercing garbage.
50
+ * - `number`: a string that trims non-empty and parses to a finite number
51
+ * becomes that number; anything else stays a string (same fail-closed).
52
+ * - every other kind (and every non-string input, which passes through
53
+ * untouched) keeps its value as-is.
54
+ *
55
+ * Keys that no declared field owns are passed through unchanged.
56
+ */
57
+ export function coerceStoredValues(manifest, values) {
58
+ const kinds = new Map();
59
+ for (const field of manifest.configuration ?? []) {
60
+ if (field.kind !== 'operation')
61
+ kinds.set(field.key, field.kind);
62
+ }
63
+ const coerced = {};
64
+ for (const [key, value] of Object.entries(values)) {
65
+ const kind = kinds.get(key);
66
+ if (typeof value !== 'string' || kind === undefined) {
67
+ coerced[key] = value;
68
+ continue;
69
+ }
70
+ if (kind === 'boolean') {
71
+ coerced[key] = value === 'true' ? true : value === 'false' ? false : value;
72
+ continue;
73
+ }
74
+ if (kind === 'number') {
75
+ const trimmed = value.trim();
76
+ coerced[key] = trimmed.length > 0 && Number.isFinite(Number(trimmed)) ? Number(trimmed) : value;
77
+ continue;
78
+ }
79
+ coerced[key] = value;
80
+ }
81
+ return coerced;
82
+ }
83
+ /**
84
+ * Three-state variant resolution for a stored (or drafted) configuration.
85
+ *
86
+ * - `unselected`: no discriminator value present — neither stored nor declared
87
+ * as the discriminator field's `default` (or the manifest declares no
88
+ * variants, preserving pre-0.2.0 behavior).
89
+ * - `invalid`: a discriminator value is present (stored, or a declared default)
90
+ * but no branch `when` matches.
91
+ * - `selected`: exactly one branch matches; the first match wins if a
92
+ * non-conformant manifest makes branches overlap.
93
+ */
94
+ export function resolveConfigurationVariant(manifest, values) {
95
+ const variants = manifest.configurationVariants;
96
+ if (variants === undefined)
97
+ return { status: 'unselected' };
98
+ const stored = coerceStoredValues(manifest, values);
99
+ let value = Object.hasOwn(stored, variants.discriminator)
100
+ ? stored[variants.discriminator]
101
+ : undefined;
102
+ if (value === undefined) {
103
+ const discriminatorField = (manifest.configuration ?? []).find((field) => field.key === variants.discriminator);
104
+ value = discriminatorField === undefined ? undefined : fieldDefault(discriminatorField);
105
+ }
106
+ if (value === undefined)
107
+ return { status: 'unselected' };
108
+ for (const branch of variants.branches) {
109
+ if (branchMatches(branch, variants.discriminator, value)) {
110
+ return { status: 'selected', branchId: branch.id };
111
+ }
112
+ }
113
+ return { status: 'invalid', value };
114
+ }
115
+ /**
116
+ * Computes the effective configuration: common fields (not claimed by any
117
+ * branch) plus, when a branch is selected, that branch's fields. Missing
118
+ * stored values fall back to the declared field default — consumers never
119
+ * depend on save-time materialization. On `unselected`/`invalid` only common
120
+ * fields are returned; an invalid discriminator value is kept as stored (no
121
+ * silent fallback to the declared default).
122
+ */
123
+ export function computeEffectiveConfiguration(manifest, storedValues) {
124
+ const configuration = manifest.configuration ?? [];
125
+ const variants = manifest.configurationVariants;
126
+ const stored = coerceStoredValues(manifest, storedValues);
127
+ const resolution = resolveConfigurationVariant(manifest, stored);
128
+ const branchFieldKeys = new Set();
129
+ if (variants !== undefined) {
130
+ for (const branch of variants.branches) {
131
+ for (const key of branch.fields)
132
+ branchFieldKeys.add(key);
133
+ }
134
+ }
135
+ const activeBranch = resolution.status === 'selected' && variants !== undefined
136
+ ? variants.branches.find((branch) => branch.id === resolution.branchId)
137
+ : undefined;
138
+ const activeKeys = new Set(activeBranch?.fields ?? []);
139
+ const effectiveValues = {};
140
+ for (const field of configuration) {
141
+ if (field.kind === 'operation')
142
+ continue;
143
+ const isBranchField = branchFieldKeys.has(field.key);
144
+ const isActive = activeKeys.has(field.key);
145
+ if (isBranchField && !isActive)
146
+ continue;
147
+ if (resolution.status === 'invalid' &&
148
+ variants !== undefined &&
149
+ field.key === variants.discriminator) {
150
+ effectiveValues[field.key] = stored[field.key];
151
+ continue;
152
+ }
153
+ effectiveValues[field.key] = effectiveFieldValue(field, stored);
154
+ }
155
+ return { resolution, effectiveValues };
156
+ }
157
+ /**
158
+ * The single source of truth for whether a field is required, given an
159
+ * effective (or drafted) configuration object.
160
+ *
161
+ * When `requiredWhen` is present it fully replaces the `required` flag: the
162
+ * field is required iff the referenced field's current value strictly
163
+ * (`===`, no stringification) equals one of the declared conditions. When
164
+ * `requiredWhen` is absent, the plain `required` flag decides. Branch
165
+ * membership never influences requiredness — it only decides whether a field
166
+ * is active at all.
167
+ *
168
+ * `values` must already be typed: pass the product of
169
+ * {@link computeEffectiveConfiguration} or run raw string storage/drafts
170
+ * through {@link coerceStoredValues} first. This function does not coerce —
171
+ * a string `"true"` against a declared `true` condition is *not* a match.
172
+ */
173
+ export function evaluateFieldRequiredness(field, values) {
174
+ const requiredWhen = field.requiredWhen;
175
+ if (requiredWhen === undefined)
176
+ return field.required === true;
177
+ const conditions = Array.isArray(requiredWhen.value)
178
+ ? requiredWhen.value
179
+ : [requiredWhen.value];
180
+ const actual = Object.hasOwn(values, requiredWhen.key) ? values[requiredWhen.key] : undefined;
181
+ return conditions.some((condition) => condition === actual);
182
+ }
183
+ function fieldValueConstraint(field) {
184
+ switch (field.kind) {
185
+ case 'string':
186
+ case 'secret':
187
+ return { type: 'string', minLength: 1, pattern: '\\S' };
188
+ case 'url':
189
+ return { type: 'string', minLength: 1, format: 'uri' };
190
+ case 'select':
191
+ return { type: 'string', enum: (field.options ?? []).map((option) => option.value) };
192
+ case 'number':
193
+ return { type: 'number' };
194
+ case 'boolean':
195
+ return { type: 'boolean' };
196
+ default:
197
+ return {};
198
+ }
199
+ }
200
+ function conditionalRequirement(field) {
201
+ const requiredWhen = field.requiredWhen;
202
+ if (requiredWhen === undefined)
203
+ return undefined;
204
+ const conditions = Array.isArray(requiredWhen.value)
205
+ ? requiredWhen.value
206
+ : [requiredWhen.value];
207
+ const constraint = fieldValueConstraint(field);
208
+ return {
209
+ if: {
210
+ properties: { [requiredWhen.key]: { enum: [...new Set(conditions)] } },
211
+ required: [requiredWhen.key],
212
+ },
213
+ then: {
214
+ required: [field.key],
215
+ ...(Object.keys(constraint).length > 0 ? { properties: { [field.key]: constraint } } : {}),
216
+ },
217
+ };
218
+ }
219
+ /**
220
+ * Compiles the manifest into a standard JSON Schema for validating the
221
+ * *effective* configuration object (see {@link computeEffectiveConfiguration}),
222
+ * not the raw stored object. Consumers must enable standard URI format validation
223
+ * (for Ajv, register ajv-formats before compiling).
224
+ * Operation controls have no scalar value and are omitted; their target-based
225
+ * configured state remains the responsibility of the operation consumer.
226
+ *
227
+ * - Common fields (not claimed by any branch) are constrained at the top
228
+ * level: unconditionally required fields land in `required` and get a kind
229
+ * constraint (e.g. `{type:'string', minLength:1}` for string-likes, so a
230
+ * present `null` or empty string does not count as configured);
231
+ * `requiredWhen` fields become top-level `if/then` clauses keyed on the
232
+ * referenced field's runtime value.
233
+ * - Each branch compiles to one `oneOf` member containing the cloned `when`
234
+ * fragment, the discriminator in `required`, and its active fields handled
235
+ * the same way (static `required` for plain `required: true`, `if/then` for
236
+ * `requiredWhen`). A field that is `requiredWhen`-gated against the
237
+ * discriminator therefore stays optional in a member whose discriminator
238
+ * values do not satisfy the condition — enum branches covering several
239
+ * options keep working without merging values.
240
+ *
241
+ * Requiredness semantics are exactly {@link evaluateFieldRequiredness}; this
242
+ * schema is the ajv-executable form of that function plus kind constraints.
243
+ */
244
+ export function buildVariantValidationSchema(manifest) {
245
+ const variants = manifest.configurationVariants;
246
+ const configuration = manifest.configuration ?? [];
247
+ const configByKey = new Map();
248
+ for (const field of configuration)
249
+ configByKey.set(field.key, field);
250
+ const branchFieldKeys = new Set();
251
+ for (const branch of variants?.branches ?? []) {
252
+ for (const key of branch.fields)
253
+ branchFieldKeys.add(key);
254
+ }
255
+ const properties = {};
256
+ const required = [];
257
+ const commonConditionals = [];
258
+ for (const field of configuration) {
259
+ if (field.kind === 'operation' || branchFieldKeys.has(field.key))
260
+ continue;
261
+ const constraint = fieldValueConstraint(field);
262
+ if (Object.keys(constraint).length > 0)
263
+ properties[field.key] = constraint;
264
+ const conditional = conditionalRequirement(field);
265
+ if (conditional !== undefined) {
266
+ commonConditionals.push(conditional);
267
+ }
268
+ else if (field.required === true) {
269
+ required.push(field.key);
270
+ }
271
+ }
272
+ const oneOf = (variants?.branches ?? []).map((branch) => {
273
+ const memberProperties = structuredClone((branch.when['properties'] ?? {}));
274
+ const memberRequired = [variants.discriminator];
275
+ const memberConditionals = [];
276
+ for (const key of branch.fields) {
277
+ const field = configByKey.get(key);
278
+ if (field === undefined || field.kind === 'operation')
279
+ continue;
280
+ const constraint = fieldValueConstraint(field);
281
+ if (Object.keys(constraint).length > 0)
282
+ memberProperties[key] = constraint;
283
+ const conditional = conditionalRequirement(field);
284
+ if (conditional !== undefined) {
285
+ memberConditionals.push(conditional);
286
+ }
287
+ else if (field.required === true) {
288
+ memberRequired.push(key);
289
+ }
290
+ }
291
+ return {
292
+ properties: memberProperties,
293
+ required: memberRequired,
294
+ ...(memberConditionals.length > 0 ? { allOf: memberConditionals } : {}),
295
+ };
296
+ });
297
+ return {
298
+ type: 'object',
299
+ properties,
300
+ ...(required.length > 0 ? { required } : {}),
301
+ ...(commonConditionals.length > 0 ? { allOf: commonConditionals } : {}),
302
+ ...(oneOf.length > 0 ? { oneOf } : {}),
303
+ };
304
+ }
305
+ //# sourceMappingURL=variant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"variant.js","sourceRoot":"","sources":["../src/variant.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkBH,SAAS,iBAAiB,CAAC,UAAmB,EAAE,KAAc;IAC5D,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACxE,MAAM,SAAS,GAAG,UAAqC,CAAC;IACxD,IAAI,OAAO,IAAI,SAAS;QAAE,OAAO,KAAK,KAAK,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,MAAM,IAAI,SAAS,IAAI,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC5D,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC;IAC9D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,MAAqB,EAAE,aAAqB,EAAE,KAAc;IACjF,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAI,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IACxE,OAAO,iBAAiB,CAAE,UAAsC,CAAC,aAAa,CAAC,EAAE,KAAK,CAAC,CAAC;AAC1F,CAAC;AAED,SAAS,YAAY,CAAC,KAAyB;IAC7C,OAAO,SAAS,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAED,SAAS,mBAAmB,CAC1B,KAAyB,EACzB,YAA0B;IAE1B,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,OAAO,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC7D,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAwB,EACxB,MAAoB;IAEpB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsC,CAAC;IAC5D,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,aAAa,IAAI,EAAE,EAAE,CAAC;QACjD,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC;IACD,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACrB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;YAC3E,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YAC7B,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YAChG,SAAS;QACX,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAAwB,EACxB,MAAoB;IAEpB,MAAM,QAAQ,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAChD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAE5D,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACpD,IAAI,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,aAAa,CAAC;QACvD,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC;QAChC,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,kBAAkB,GAAG,CAAC,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC,IAAI,CAC5D,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,aAAa,CAChD,CAAC;QACF,KAAK,GAAG,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,kBAAkB,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;IAEzD,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC;YACzD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACtC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAC3C,QAAwB,EACxB,YAA0B;IAE1B,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC;IACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAChD,MAAM,MAAM,GAAG,kBAAkB,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,2BAA2B,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAEjE,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;YACvC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM;gBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAChB,UAAU,CAAC,MAAM,KAAK,UAAU,IAAI,QAAQ,KAAK,SAAS;QACxD,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,KAAK,UAAU,CAAC,QAAQ,CAAC;QACvE,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC;IAEvD,MAAM,eAAe,GAA4B,EAAE,CAAC;IACpD,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;YAAE,SAAS;QACzC,MAAM,aAAa,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,aAAa,IAAI,CAAC,QAAQ;YAAE,SAAS;QAEzC,IACE,UAAU,CAAC,MAAM,KAAK,SAAS;YAC/B,QAAQ,KAAK,SAAS;YACtB,KAAK,CAAC,GAAG,KAAK,QAAQ,CAAC,aAAa,EACpC,CAAC;YACD,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC/C,SAAS;QACX,CAAC;QACD,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,yBAAyB,CACvC,KAAyB,EACzB,MAAoB;IAEpB,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IACxC,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC;IAC/D,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC;QAClD,CAAC,CAAC,YAAY,CAAC,KAAK;QACpB,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9F,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAyB;IACrD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,QAAQ,CAAC;QACd,KAAK,QAAQ;YACX,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC1D,KAAK,KAAK;YACR,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;QACzD,KAAK,QAAQ;YACX,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACvF,KAAK,QAAQ;YACX,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5B,KAAK,SAAS;YACZ,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC7B;YACE,OAAO,EAAE,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,sBAAsB,CAC7B,KAAyB;IAEzB,MAAM,YAAY,GAAG,KAAK,CAAC,YAAY,CAAC;IACxC,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACjD,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC;QAClD,CAAC,CAAC,YAAY,CAAC,KAAK;QACpB,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACzB,MAAM,UAAU,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO;QACL,EAAE,EAAE;YACF,UAAU,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE;YACtE,QAAQ,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC;SAC7B;QACD,IAAI,EAAE;YACJ,QAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3F;KACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,4BAA4B,CAC1C,QAAwB;IAExB,MAAM,QAAQ,GAAG,QAAQ,CAAC,qBAAqB,CAAC;IAChD,MAAM,aAAa,GAAG,QAAQ,CAAC,aAAa,IAAI,EAAE,CAAC;IACnD,MAAM,WAAW,GAAG,IAAI,GAAG,EAA8B,CAAC;IAC1D,KAAK,MAAM,KAAK,IAAI,aAAa;QAAE,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAErE,MAAM,eAAe,GAAG,IAAI,GAAG,EAAU,CAAC;IAC1C,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;QAC9C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM;YAAE,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5D,CAAC;IAED,MAAM,UAAU,GAA4B,EAAE,CAAC;IAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,kBAAkB,GAA8B,EAAE,CAAC;IACzD,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;YAAE,SAAS;QAC3E,MAAM,UAAU,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC;YAAE,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;QAC3E,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YAC9B,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QACtD,MAAM,gBAAgB,GAA4B,eAAe,CAC/D,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAA4B,CAC7D,CAAC;QACF,MAAM,cAAc,GAAa,CAAC,QAAS,CAAC,aAAa,CAAC,CAAC;QAC3D,MAAM,kBAAkB,GAA8B,EAAE,CAAC;QAEzD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAChC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YACnC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW;gBAAE,SAAS;YAChE,MAAM,UAAU,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;YAC/C,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC;gBAAE,gBAAgB,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC;YAC3E,MAAM,WAAW,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;YAClD,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;gBAC9B,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YACvC,CAAC;iBAAM,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACnC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACH,CAAC;QAED,OAAO;YACL,UAAU,EAAE,gBAAgB;YAC5B,QAAQ,EAAE,cAAc;YACxB,GAAG,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACxE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,UAAU;QACV,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvE,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC;AACJ,CAAC"}
@@ -14,7 +14,8 @@ export declare const JSONRPC_VERSION: "2.0";
14
14
  /**
15
15
  * Maximum payload bytes per element payload (frozen x-clowder-bounds).
16
16
  * Open-membered payloads (MediaRefElementPayload, RichBlockElementPayload)
17
- * are bounded by this ceiling alone — no structural narrowing.
17
+ * use their contract schemas for structural narrowing. Unknown extension payloads remain
18
+ * open and are bounded by this ceiling.
18
19
  */
19
20
  export declare const MAX_ELEMENT_PAYLOAD_BYTES: 65536;
20
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/wire/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sEAAsE;AACtE,eAAO,MAAM,eAAe,EAAG,OAAkB,CAAC;AAElD,oCAAoC;AACpC,eAAO,MAAM,YAAY,EAAG,OAAgB,CAAC;AAE7C,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,EAAG,OAAgB,CAAC;AAEjD,gDAAgD;AAChD,eAAO,MAAM,eAAe,EAAG,KAAc,CAAC;AAE9C;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAG,KAAe,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAG,MAAgB,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAG,EAAW,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAG,GAAY,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAG,EAAW,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/wire/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sEAAsE;AACtE,eAAO,MAAM,eAAe,EAAG,OAAkB,CAAC;AAElD,oCAAoC;AACpC,eAAO,MAAM,YAAY,EAAG,OAAgB,CAAC;AAE7C,uDAAuD;AACvD,eAAO,MAAM,gBAAgB,EAAG,OAAgB,CAAC;AAEjD,gDAAgD;AAChD,eAAO,MAAM,eAAe,EAAG,KAAc,CAAC;AAE9C;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,EAAG,KAAe,CAAC;AAEzD;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAG,MAAgB,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAG,EAAW,CAAC;AAEtD;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAG,GAAY,CAAC;AAErD;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAG,EAAW,CAAC"}
@@ -14,7 +14,8 @@ export const JSONRPC_VERSION = '2.0';
14
14
  /**
15
15
  * Maximum payload bytes per element payload (frozen x-clowder-bounds).
16
16
  * Open-membered payloads (MediaRefElementPayload, RichBlockElementPayload)
17
- * are bounded by this ceiling alone — no structural narrowing.
17
+ * use their contract schemas for structural narrowing. Unknown extension payloads remain
18
+ * open and are bounded by this ceiling.
18
19
  */
19
20
  export const MAX_ELEMENT_PAYLOAD_BYTES = 65_536;
20
21
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/wire/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG,SAAkB,CAAC;AAElD,oCAAoC;AACpC,MAAM,CAAC,MAAM,YAAY,GAAG,OAAgB,CAAC;AAE7C,uDAAuD;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAgB,CAAC;AAEjD,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAc,CAAC;AAE9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAe,CAAC;AAEzD;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAgB,CAAC;AAExD;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAW,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAY,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAW,CAAC"}
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/wire/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG,SAAkB,CAAC;AAElD,oCAAoC;AACpC,MAAM,CAAC,MAAM,YAAY,GAAG,OAAgB,CAAC;AAE7C,uDAAuD;AACvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAgB,CAAC;AAEjD,gDAAgD;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAc,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAe,CAAC;AAEzD;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,OAAgB,CAAC;AAExD;;GAEG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAW,CAAC;AAEtD;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAY,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAW,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Wire dispatch classifier — pre-dispatch frame classification per the
3
+ * disposition table (T-A through T-M, §3.8-1 plus beta.8 closure).
4
+ *
5
+ * This module classifies decoded NDJSON frames into one of the 13
6
+ * disposition classes. T-A (transport failure) and T-B (JSON parse error)
7
+ * are handled by the NDJSON frame decoder layer — this classifier covers
8
+ * T-C through T-M.
9
+ *
10
+ * A frame that passes all rejection checks returns disposition=null with
11
+ * outcome='accept', indicating a valid request that should be dispatched
12
+ * to a method handler.
13
+ *
14
+ * This module lives in @clowder-ai/plugin-contract (F202 C1: the wire
15
+ * frame classifier was moved here from @clowder-ai/plugin-sdk so the
16
+ * dependency arrow is 插件 → SDK → contract ← Host). It defines nothing
17
+ * new — every classification rule traces to the frozen disposition table
18
+ * in this package, and every key set it uses is co-located with or
19
+ * generated from the contract types it mirrors.
20
+ */
21
+ import type { DecodedNdjsonFrame, JsonObject } from '../conformance/stdio-harness/ndjson-frame.js';
22
+ import type { DispositionClass } from './disposition.js';
23
+ import type { RequestSnapshot } from './disposition-fixtures.js';
24
+ import { type WireMethodName } from './registry.js';
25
+ export type { RequestSnapshot } from './disposition-fixtures.js';
26
+ export interface InFlightEntry {
27
+ readonly method: WireMethodName;
28
+ readonly requestSnapshot?: RequestSnapshot;
29
+ }
30
+ export interface DispatchResult {
31
+ /** T-class from the disposition table, or null for valid requests. */
32
+ readonly disposition: DispositionClass | null;
33
+ /** Required transport action: close, respond (with error), or accept. */
34
+ readonly outcome: 'close' | 'respond' | 'accept';
35
+ /** For 'respond': the error envelope to write back as NDJSON. */
36
+ readonly response?: JsonObject;
37
+ }
38
+ /**
39
+ * Classify a decoded NDJSON frame into a disposition class.
40
+ *
41
+ * Covers T-C through T-M of the disposition table. T-A and T-B
42
+ * are handled by the NDJSON frame decoder layer.
43
+ *
44
+ * @param frame Decoded frame with raw bytes and parsed value.
45
+ * @param inFlight Map of in-flight request IDs to their entry metadata.
46
+ * @returns The disposition result with class, outcome, and optional error response.
47
+ */
48
+ export declare function classifyFrame(frame: DecodedNdjsonFrame, inFlight: ReadonlyMap<string, InFlightEntry>): DispatchResult;
49
+ //# sourceMappingURL=dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/wire/dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAEnG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAwDjE,OAAO,EAIL,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAiBvB,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEjE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,WAAW,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC9C,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC;CAChC;AAwzBD;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,kBAAkB,EACzB,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,cAAc,CAuEhB"}