@jini-ai/agentic 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/core/a2ui/json-pointer.js +94 -73
  3. package/dist/core/a2ui/resolve.js +45 -23
  4. package/dist/core/a2ui/tree.js +8 -5
  5. package/dist/core/capability.js +21 -12
  6. package/dist/core/dom/dom-page-driver.js +89 -74
  7. package/dist/core/gen-ui/encoder.js +31 -31
  8. package/dist/core/guards.js +13 -6
  9. package/dist/core/handle.d.ts +13 -0
  10. package/dist/core/handle.js +19 -0
  11. package/dist/core/index.d.ts +2 -1
  12. package/dist/core/index.js +2 -1
  13. package/dist/core/mcp-ui-apps.js +12 -6
  14. package/dist/core/page-executor.js +131 -111
  15. package/dist/core/site-guide/index.d.ts +4 -0
  16. package/dist/core/site-guide/index.js +4 -0
  17. package/dist/core/site-guide/site-guide.d.ts +18 -0
  18. package/dist/core/site-guide/site-guide.js +162 -0
  19. package/dist/core/site-guide/topic-schema.d.ts +16 -0
  20. package/dist/core/site-guide/topic-schema.js +68 -0
  21. package/dist/core/site-guide/types.d.ts +83 -0
  22. package/dist/core/site-guide/types.js +2 -0
  23. package/dist/skills/install/archive.js +42 -30
  24. package/dist/skills/install/github.js +102 -63
  25. package/dist/skills/install/index.d.ts +1 -0
  26. package/dist/skills/install/index.js +1 -0
  27. package/dist/skills/install/install-service.d.ts +20 -1
  28. package/dist/skills/install/install-service.js +23 -11
  29. package/dist/skills/install/layout.d.ts +8 -0
  30. package/dist/skills/install/layout.js +26 -1
  31. package/dist/skills/install/live-registration.js +1 -0
  32. package/dist/skills/install/node-filesystem.js +3 -1
  33. package/dist/skills/install/state.js +18 -7
  34. package/dist/skills/install/validation.d.ts +5 -1
  35. package/dist/skills/install/validation.js +85 -52
  36. package/dist/skills/install/yauzl-archive-reader.d.ts +29 -0
  37. package/dist/skills/install/yauzl-archive-reader.js +31 -0
  38. package/package.json +4 -4
  39. package/dist/a2ui/agent-to-renderer.d.ts +0 -613
  40. package/dist/a2ui/agent-to-renderer.js +0 -191
  41. package/dist/a2ui/catalog.d.ts +0 -73
  42. package/dist/a2ui/catalog.js +0 -304
  43. package/dist/a2ui/common-types.d.ts +0 -401
  44. package/dist/a2ui/common-types.js +0 -130
  45. package/dist/a2ui/index.d.ts +0 -16
  46. package/dist/a2ui/index.js +0 -16
  47. package/dist/a2ui/interpreter.d.ts +0 -71
  48. package/dist/a2ui/interpreter.js +0 -337
  49. package/dist/a2ui/json-pointer.d.ts +0 -48
  50. package/dist/a2ui/json-pointer.js +0 -174
  51. package/dist/a2ui/renderer-to-agent.d.ts +0 -342
  52. package/dist/a2ui/renderer-to-agent.js +0 -111
  53. package/dist/a2ui/resolve.d.ts +0 -28
  54. package/dist/a2ui/resolve.js +0 -144
  55. package/dist/a2ui/tree.d.ts +0 -66
  56. package/dist/a2ui/tree.js +0 -74
  57. package/dist/ag-ui.d.ts +0 -82
  58. package/dist/ag-ui.js +0 -85
  59. package/dist/agui/encoder.d.ts +0 -50
  60. package/dist/agui/encoder.js +0 -97
  61. package/dist/agui/events.d.ts +0 -59
  62. package/dist/agui/events.js +0 -15
  63. package/dist/capability.d.ts +0 -81
  64. package/dist/capability.js +0 -79
  65. package/dist/dom/dom-page-driver.d.ts +0 -36
  66. package/dist/dom/dom-page-driver.js +0 -601
  67. package/dist/dom/index.d.ts +0 -17
  68. package/dist/dom/index.js +0 -17
  69. package/dist/dom/model-context.d.ts +0 -69
  70. package/dist/dom/model-context.js +0 -44
  71. package/dist/element-handles.d.ts +0 -120
  72. package/dist/element-handles.js +0 -39
  73. package/dist/gen-ui/encoder.d.ts +0 -50
  74. package/dist/gen-ui/encoder.js +0 -97
  75. package/dist/gen-ui/events.d.ts +0 -59
  76. package/dist/gen-ui/events.js +0 -15
  77. package/dist/gen-ui/index.d.ts +0 -18
  78. package/dist/gen-ui/index.js +0 -17
  79. package/dist/guards.d.ts +0 -96
  80. package/dist/guards.js +0 -186
  81. package/dist/handle.d.ts +0 -41
  82. package/dist/handle.js +0 -41
  83. package/dist/mcp-ui-apps.d.ts +0 -223
  84. package/dist/mcp-ui-apps.js +0 -252
  85. package/dist/mcp-ui.d.ts +0 -133
  86. package/dist/mcp-ui.js +0 -134
  87. package/dist/page-capabilities.d.ts +0 -14
  88. package/dist/page-capabilities.js +0 -129
  89. package/dist/page-driver.d.ts +0 -120
  90. package/dist/page-driver.js +0 -2
  91. package/dist/page-executor.d.ts +0 -94
  92. package/dist/page-executor.js +0 -320
  93. package/dist/webmcp.d.ts +0 -202
  94. package/dist/webmcp.js +0 -173
@@ -1,191 +0,0 @@
1
- /**
2
- * @module agent-to-renderer
3
- *
4
- * A2UI v1.0 agent→renderer envelope — mirrors `specification/v1_0/json/agent_to_renderer.json`
5
- * (fetched from https://github.com/a2ui-project/a2ui, `main` branch, this session). Every
6
- * required/optional field and every `additionalProperties: false` closure below was copied
7
- * directly from that JSON Schema, not guessed. See `common-types.ts`'s module doc for the overall
8
- * scope note (wire shape only; catalog membership is a separate runtime concern).
9
- *
10
- * The six message kinds, each keyed by version + exactly one message-type key
11
- * (`createSurface` | `updateComponents` | `updateDataModel` | `deleteSurface` | `callFunction` +
12
- * `functionCallId` | `actionResponse` + `actionId`):
13
- * `CreateSurfaceMessage`, `UpdateComponentsMessage`, `UpdateDataModelMessage`,
14
- * `DeleteSurfaceMessage`, `CallFunctionMessage`, `ActionResponseMessage`.
15
- *
16
- * `parseAgentToRendererMessage` is a hand-written dispatcher, not a plain `z.union(...)`: zod's
17
- * union error for a 6-branch, all-`.strict()` union is an unreadable dump of all 6 branches'
18
- * failures at once. Real renderers need to tell an agent *specifically* "you sent no version",
19
- * "you sent two message-type keys", or "`updateComponents` is missing `surfaceId`" — so this
20
- * dispatcher inspects the envelope's own shape first (which key is present) and only then
21
- * validates against the one matching schema, matching what `renderer_to_agent.json`'s own error
22
- * schema anticipates (`VALIDATION_FAILED` with a JSON-Pointer `path` into the offending field).
23
- */
24
- import { z } from 'zod';
25
- import { ComponentIdSchema, FunctionCallSchema, CallIdSchema } from './common-types.js';
26
- const PROTOCOL_VERSION = 'v1.0';
27
- /**
28
- * A component's wire shape is only closed by its *catalog's* own per-type schema (e.g. `Text`
29
- * requires `text`, forbids unknown extra keys via that type's own `unevaluatedProperties: false`)
30
- * — a shape this module cannot know statically, since a renderer may be configured with any
31
- * catalog. This schema validates only what every component, in every catalog, always carries:
32
- * an `id` and a `component` type-name string. `catalog.ts`/`interpreter.ts` layer the closed,
33
- * per-type check on top at runtime (component-type whitelisting against the active catalog).
34
- */
35
- export const WireComponentSchema = z
36
- .object({
37
- id: ComponentIdSchema,
38
- component: z.string().min(1),
39
- })
40
- .passthrough();
41
- /** `agent_to_renderer.json#/$defs/ComponentsList` — "A list containing UI components for the surface." `minItems: 1`. */
42
- export const ComponentsListSchema = z.array(WireComponentSchema).min(1);
43
- export const CreateSurfaceMessageSchema = z
44
- .object({
45
- version: z.literal(PROTOCOL_VERSION),
46
- createSurface: z
47
- .object({
48
- surfaceId: z.string(),
49
- catalogId: z.string(),
50
- surfaceProperties: z.record(z.string(), z.unknown()).optional(),
51
- sendDataModel: z.boolean().optional(),
52
- components: ComponentsListSchema.optional(),
53
- dataModel: z.record(z.string(), z.unknown()).optional(),
54
- })
55
- .strict(),
56
- })
57
- .strict();
58
- export const UpdateComponentsMessageSchema = z
59
- .object({
60
- version: z.literal(PROTOCOL_VERSION),
61
- updateComponents: z
62
- .object({
63
- surfaceId: z.string(),
64
- components: ComponentsListSchema,
65
- })
66
- .strict(),
67
- })
68
- .strict();
69
- /**
70
- * `value` is required by the real schema (`"required": ["surfaceId", "value"]`, re-fetched and
71
- * checked 2026-07-29) — but declaring it `z.unknown()` did not make it so. In Zod 3 a key whose
72
- * schema accepts `undefined` is satisfied by the key being absent entirely, and `undefined`
73
- * inhabits `unknown`; `z.unknown().isOptional()` is literally `true`. So `{updateDataModel:
74
- * {surfaceId: "s1"}}` parsed clean, and `interpreter.ts` then wrote that missing value at the
75
- * default `'/'` pointer — replacing the surface's whole data model with `undefined`, silently,
76
- * with no error message and no way for the agent to learn it had happened.
77
- *
78
- * Presence is therefore asserted on the object rather than on the field: there is no Zod 3 schema
79
- * for "any value, but it has to be there," because optionality is decided by the field's *type*.
80
- * `'value' in body` rather than a `!== undefined` check, so every legal JSON value — `null`
81
- * (the spec's own delete verb), `false`, `0`, `""` — is still accepted as content.
82
- *
83
- * The same limitation leaves `value` typed `value?: unknown` on the inferred type. That is
84
- * unavoidable in Zod 3 for an `unknown`-typed key (`undefined extends unknown`), and is why this
85
- * is enforced at runtime rather than trusted to the type.
86
- */
87
- export const UpdateDataModelMessageSchema = z
88
- .object({
89
- version: z.literal(PROTOCOL_VERSION),
90
- updateDataModel: z
91
- .object({
92
- surfaceId: z.string(),
93
- path: z.string().optional(),
94
- value: z.unknown(),
95
- })
96
- .strict()
97
- .refine((body) => 'value' in body, {
98
- message: 'updateDataModel requires an explicit "value" (use null to delete the key at "path")',
99
- path: ['value'],
100
- }),
101
- })
102
- .strict();
103
- export const DeleteSurfaceMessageSchema = z
104
- .object({
105
- version: z.literal(PROTOCOL_VERSION),
106
- deleteSurface: z.object({ surfaceId: z.string() }).strict(),
107
- })
108
- .strict();
109
- export const CallFunctionMessageSchema = z
110
- .object({
111
- version: z.literal(PROTOCOL_VERSION),
112
- functionCallId: CallIdSchema,
113
- wantResponse: z.boolean().optional(),
114
- callFunction: FunctionCallSchema,
115
- })
116
- .strict();
117
- export const ActionResponseMessageSchema = z
118
- .object({
119
- version: z.literal(PROTOCOL_VERSION),
120
- actionId: z.string(),
121
- actionResponse: z
122
- .union([
123
- z.object({ value: z.unknown() }).strict(),
124
- z.object({ error: z.object({ code: z.string(), message: z.string() }).strict() }).strict(),
125
- ])
126
- .refine((v) => ('value' in v) !== ('error' in v), 'exactly one of value/error is required'),
127
- })
128
- .strict();
129
- const MESSAGE_KEY_SCHEMAS = {
130
- createSurface: CreateSurfaceMessageSchema,
131
- updateComponents: UpdateComponentsMessageSchema,
132
- updateDataModel: UpdateDataModelMessageSchema,
133
- deleteSurface: DeleteSurfaceMessageSchema,
134
- callFunction: CallFunctionMessageSchema,
135
- actionResponse: ActionResponseMessageSchema,
136
- };
137
- /** Exported so `interpreter.ts` can look up "which of the *known* message-type keys is present" the same way this module's own dispatcher does, instead of guessing from raw object-key order (which could pick up an unrelated extra top-level key first). */
138
- export const AGENT_TO_RENDERER_MESSAGE_KEYS = Object.keys(MESSAGE_KEY_SCHEMAS);
139
- const MESSAGE_KEYS = AGENT_TO_RENDERER_MESSAGE_KEYS;
140
- /**
141
- * Validates a raw (untrusted, possibly-malformed) value as one A2UI agent→renderer envelope.
142
- * Never throws — every failure mode (missing `version`, an unrecognized/absent message-type key,
143
- * two message-type keys at once, or a structurally invalid message body) returns a tagged
144
- * `ParseFailure` instead, mirroring how a real renderer must degrade on the wire: reject the one
145
- * bad message with a specific reason, not crash the whole connection.
146
- */
147
- export function parseAgentToRendererMessage(raw) {
148
- if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
149
- return { ok: false, code: 'VALIDATION_FAILED', message: 'envelope must be a JSON object' };
150
- }
151
- const obj = raw;
152
- if (!('version' in obj)) {
153
- return { ok: false, code: 'MISSING_VERSION', message: 'envelope is missing the required "version" field' };
154
- }
155
- if (obj.version !== PROTOCOL_VERSION) {
156
- return {
157
- ok: false,
158
- code: 'UNSUPPORTED_VERSION',
159
- message: `envelope declares version ${JSON.stringify(obj.version)}, this renderer only supports "${PROTOCOL_VERSION}"`,
160
- };
161
- }
162
- const presentKeys = MESSAGE_KEYS.filter((key) => key in obj);
163
- if (presentKeys.length === 0) {
164
- return {
165
- ok: false,
166
- code: 'NO_MESSAGE_KEY',
167
- message: `envelope has "version" but none of the known message-type keys (${MESSAGE_KEYS.join(', ')})`,
168
- };
169
- }
170
- if (presentKeys.length > 1) {
171
- return {
172
- ok: false,
173
- code: 'AMBIGUOUS_MESSAGE',
174
- message: `envelope has more than one message-type key at once: ${presentKeys.join(', ')}`,
175
- };
176
- }
177
- const key = presentKeys[0];
178
- const schema = MESSAGE_KEY_SCHEMAS[key];
179
- const result = schema.safeParse(obj);
180
- if (!result.success) {
181
- // zod only ever returns `success: false` with a non-empty `error.issues` — there is no zod
182
- // code path that produces a failed `SafeParseReturnType` with zero issues. Asserted directly
183
- // (not defensively branched-and-left-untested) per this package's own testing discipline: a
184
- // branch that cannot occur given an upstream guarantee gets removed, not fake-covered.
185
- const firstIssue = result.error.issues[0];
186
- const path = `/${firstIssue.path.join('/')}`;
187
- return { ok: false, code: 'VALIDATION_FAILED', message: `${key}: ${firstIssue.message} at ${path}`, path };
188
- }
189
- return { ok: true, message: result.data };
190
- }
191
- //# sourceMappingURL=agent-to-renderer.js.map
@@ -1,73 +0,0 @@
1
- /**
2
- * @module catalog
3
- *
4
- * A2UI's catalog is the spec's own named security boundary: "a JSON Schema that whitelists which
5
- * component types and functions may be used" (`specification/v1_0/json/catalog_definition.json`,
6
- * fetched from https://github.com/a2ui-project/a2ui this session). A component type or function
7
- * name absent from the active catalog — or a function invoked across a `callableFrom` boundary it
8
- * isn't permitted to cross — must be refused, not silently rendered or executed. This module is
9
- * that whitelist plus the closed per-component-type property shape for the small subset this port
10
- * actually renders; `interpreter.ts` is the code path that enforces it at message-processing time.
11
- *
12
- * **Scope**: `createLabCatalog()` below implements **all 18** of the real basic catalog's
13
- * components (`specification/v1_0/catalogs/basic/catalog.json`, 53KB, fetched from the spec repo
14
- * and read directly — every property name, type, enum member, default value, required-ness and
15
- * mixin below was copied field-for-field from it, not inferred from the component's name). It
16
- * implements 3 of that catalog's 14 **functions** (`and`/`or`/`not`, the only ones with
17
- * unambiguous, fully-specified semantics reachable from the fetched schema text alone — the
18
- * others, e.g. `formatString`/`formatDate`, depend on locale/formatting semantics not pinned down
19
- * by the schema text, and are deliberately not guessed at). The remaining 11 functions are **not
20
- * implemented** — see `../source-map.md` for the full gap list. `createLabCatalog()` also adds
21
- * three lab-only demo functions (`greetUser`/`logServerEvent`/`adminReset`, clearly not part of
22
- * the real basic catalog) purely to exercise all three `callableFrom` values end-to-end — the real
23
- * basic catalog's own 14 functions are all `rendererOnly`, which alone can't test the `agentOnly` /
24
- * `rendererOrAgent` boundary this spec explicitly calls out as security-relevant.
25
- *
26
- * Note that "implemented" here means **the protocol/validation layer**: a component type in this
27
- * catalog is accepted, closed-schema-validated and held in interpreter state. Whether any given
28
- * host renderer draws it is a separate concern this package has no opinion on.
29
- */
30
- import { z } from 'zod';
31
- export type CallableFrom = 'rendererOnly' | 'agentOnly' | 'rendererOrAgent';
32
- /** `catalog_definition.json#/$defs/FunctionDefinition` — the metadata half (not the JSON-Schema-validation half, which this port doesn't implement generically — see module doc). */
33
- export interface FunctionSpec {
34
- readonly returnType: 'string' | 'number' | 'boolean' | 'array' | 'object' | 'any' | 'void';
35
- /** Defaults to `'rendererOnly'` per the real schema's own `default`, matched here explicitly rather than left implicit — every lookup site in this package treats an absent entry (function not registered at all) and an explicit `rendererOnly` entry identically, per the spec's "or if the function is not registered at all, the renderer MUST immediately reject" wording. */
36
- readonly callableFrom: CallableFrom;
37
- /** Pure implementation, only present for functions this port can actually evaluate. A function present in `functions` but with no `impl` is registered (so `callableFrom` checks against it are meaningful and testable) but cannot be evaluated — `resolve.ts` reports that as a distinct, non-crashing "not implemented" resolution failure rather than pretending it doesn't exist. */
38
- readonly impl?: (args: Record<string, unknown>) => unknown;
39
- }
40
- /**
41
- * A coarse rendering hint, not a spec concept — the real catalog has no notion of "kind". It
42
- * groups the 18 component types by the shape a host renderer would draw them with, so a renderer
43
- * can fall back to something sane for a type it has no bespoke case for.
44
- */
45
- export type ComponentKind = 'text' | 'container' | 'button' | 'image' | 'icon' | 'video' | 'audio' | 'card' | 'tabs' | 'modal' | 'divider' | 'input';
46
- export interface ComponentSpec {
47
- readonly kind: ComponentKind;
48
- /**
49
- * Validates everything on the wire component object except `id`/`component` (already checked
50
- * generically by `WireComponentSchema`). Typed as `z.ZodTypeAny` rather than
51
- * `z.ZodType<Record<string, unknown>>` deliberately — each concrete schema's *input* type is
52
- * narrower than a bare record (known keys, some required), and zod's `parse`/`safeParse` are
53
- * effectively contravariant in that position; callers (`interpreter.ts`) treat `.safeParse(...)`'s
54
- * `data` as `Record<string, unknown>` via an explicit cast instead of fighting that variance here.
55
- */
56
- readonly propsSchema: z.ZodTypeAny;
57
- }
58
- export interface Catalog {
59
- readonly catalogId: string;
60
- readonly components: ReadonlyMap<string, ComponentSpec>;
61
- readonly functions: ReadonlyMap<string, FunctionSpec>;
62
- }
63
- export declare function isComponentAllowed(catalog: Catalog, componentType: string): boolean;
64
- /** Mirrors the spec's own default: absent registration behaves exactly like an explicit `rendererOnly` entry. */
65
- export declare function callableFromOf(catalog: Catalog, functionName: string): CallableFrom;
66
- export declare function isFunctionRegistered(catalog: Catalog, functionName: string): boolean;
67
- /**
68
- * Builds the demo catalog this port's interpreter/fixture is validated against. A fresh object
69
- * each call (not a shared singleton) so tests can register their own `impl`s / mutate a copy
70
- * without cross-test leakage.
71
- */
72
- export declare function createLabCatalog(): Catalog;
73
- //# sourceMappingURL=catalog.d.ts.map
@@ -1,304 +0,0 @@
1
- /**
2
- * @module catalog
3
- *
4
- * A2UI's catalog is the spec's own named security boundary: "a JSON Schema that whitelists which
5
- * component types and functions may be used" (`specification/v1_0/json/catalog_definition.json`,
6
- * fetched from https://github.com/a2ui-project/a2ui this session). A component type or function
7
- * name absent from the active catalog — or a function invoked across a `callableFrom` boundary it
8
- * isn't permitted to cross — must be refused, not silently rendered or executed. This module is
9
- * that whitelist plus the closed per-component-type property shape for the small subset this port
10
- * actually renders; `interpreter.ts` is the code path that enforces it at message-processing time.
11
- *
12
- * **Scope**: `createLabCatalog()` below implements **all 18** of the real basic catalog's
13
- * components (`specification/v1_0/catalogs/basic/catalog.json`, 53KB, fetched from the spec repo
14
- * and read directly — every property name, type, enum member, default value, required-ness and
15
- * mixin below was copied field-for-field from it, not inferred from the component's name). It
16
- * implements 3 of that catalog's 14 **functions** (`and`/`or`/`not`, the only ones with
17
- * unambiguous, fully-specified semantics reachable from the fetched schema text alone — the
18
- * others, e.g. `formatString`/`formatDate`, depend on locale/formatting semantics not pinned down
19
- * by the schema text, and are deliberately not guessed at). The remaining 11 functions are **not
20
- * implemented** — see `../source-map.md` for the full gap list. `createLabCatalog()` also adds
21
- * three lab-only demo functions (`greetUser`/`logServerEvent`/`adminReset`, clearly not part of
22
- * the real basic catalog) purely to exercise all three `callableFrom` values end-to-end — the real
23
- * basic catalog's own 14 functions are all `rendererOnly`, which alone can't test the `agentOnly` /
24
- * `rendererOrAgent` boundary this spec explicitly calls out as security-relevant.
25
- *
26
- * Note that "implemented" here means **the protocol/validation layer**: a component type in this
27
- * catalog is accepted, closed-schema-validated and held in interpreter state. Whether any given
28
- * host renderer draws it is a separate concern this package has no opinion on.
29
- */
30
- import { z } from 'zod';
31
- import { AccessibilityAttributesSchema, ActionSchema, CheckRuleSchema, ChildListSchema, ChildSchema, DataBindingSchema, DynamicBooleanSchema, DynamicNumberSchema, DynamicStringListSchema, DynamicStringSchema, } from './common-types.js';
32
- export function isComponentAllowed(catalog, componentType) {
33
- return catalog.components.has(componentType);
34
- }
35
- /** Mirrors the spec's own default: absent registration behaves exactly like an explicit `rendererOnly` entry. */
36
- export function callableFromOf(catalog, functionName) {
37
- return catalog.functions.get(functionName)?.callableFrom ?? 'rendererOnly';
38
- }
39
- export function isFunctionRegistered(catalog, functionName) {
40
- return catalog.functions.has(functionName);
41
- }
42
- // ---------------------------------------------------------------------------------------------
43
- // Component property schemas — ported field-for-field from the real basic catalog's own
44
- // component definitions (`specification/v1_0/catalogs/basic/catalog.json`).
45
- //
46
- // Every one of the real catalog's 18 components is composed the same way:
47
- // `allOf: [ComponentCommon, (Checkable,) {its own properties}]` + `unevaluatedProperties: false`.
48
- // The two builders below reproduce that composition literally — `.strict()` is Zod's equivalent of
49
- // the `unevaluatedProperties: false` closure, and the shared halves are spread in rather than
50
- // copy-pasted 18 times.
51
- // ---------------------------------------------------------------------------------------------
52
- /**
53
- * `common_types.json#/$defs/ComponentCommon` minus `id` — the interpreter strips `id`/`component`
54
- * off the wire object before per-type validation, so `accessibility` is the only part of
55
- * ComponentCommon that ever reaches a props schema. All 18 components `allOf` ComponentCommon, so
56
- * `accessibility` is legal on every one of them.
57
- *
58
- * This was a real bug before the full-catalog pass: no props schema listed `accessibility`, and
59
- * every schema is `.strict()`, so a spec-valid component carrying it was refused with
60
- * `VALIDATION_FAILED` ("Unrecognized key(s) in object: 'accessibility'"). `AccessibilityAttributes`
61
- * existed as a tested wire type in `common-types.ts` but nothing actually accepted it on a
62
- * component.
63
- */
64
- const COMMON_PROPS = { accessibility: AccessibilityAttributesSchema.optional() };
65
- /**
66
- * `weight` is **not** part of ComponentCommon — each of the 18 components re-declares it
67
- * individually, with an identical type and description ("The relative weight of this component
68
- * within a Row or Column..."). Verified identical across all 18 before hoisting it here.
69
- */
70
- const WEIGHT_PROP = { weight: z.number().optional() };
71
- /**
72
- * `common_types.json#/$defs/Checkable` — mixed in by exactly 6 of the 18 (`Button`, `TextField`,
73
- * `CheckBox`, `ChoicePicker`, `Slider`, `DateTimeInput`), verified against each component's own
74
- * `allOf` list rather than assumed from which ones "look like" form inputs. `checks` is a real
75
- * `CheckRule[]`, not an unvalidated array — `specification/v1_0/test/cases/button_checks.json` and
76
- * `checkable_components.json` both exercise nested `and`/`or`/`not`/`required` check compositions
77
- * these schemas must actually accept.
78
- */
79
- const CHECKABLE_PROPS = { checks: z.array(CheckRuleSchema).optional() };
80
- function componentProps(own) {
81
- return z.object({ ...COMMON_PROPS, ...WEIGHT_PROP, ...own }).strict();
82
- }
83
- function checkableComponentProps(own) {
84
- return z.object({ ...COMMON_PROPS, ...WEIGHT_PROP, ...CHECKABLE_PROPS, ...own }).strict();
85
- }
86
- const TextPropsSchema = componentProps({
87
- text: DynamicStringSchema,
88
- variant: z.enum(['caption', 'body']).default('body'),
89
- });
90
- const JUSTIFY_VALUES = ['start', 'center', 'end', 'spaceBetween', 'spaceAround', 'spaceEvenly', 'stretch'];
91
- const ALIGN_VALUES = ['center', 'end', 'start', 'stretch'];
92
- const ContainerPropsSchema = componentProps({
93
- children: ChildListSchema,
94
- justify: z.enum(JUSTIFY_VALUES).default('start'),
95
- align: z.enum(ALIGN_VALUES).default('stretch'),
96
- });
97
- const ButtonPropsSchema = checkableComponentProps({
98
- child: ChildSchema,
99
- variant: z.enum(['default', 'primary', 'borderless']).default('default'),
100
- action: ActionSchema,
101
- });
102
- const ImagePropsSchema = componentProps({
103
- url: DynamicStringSchema,
104
- description: DynamicStringSchema.optional(),
105
- fit: z.enum(['contain', 'cover', 'fill', 'none', 'scaleDown']).default('fill'),
106
- variant: z.enum(['icon', 'avatar', 'smallFeature', 'mediumFeature', 'largeFeature', 'header']).default('mediumFeature'),
107
- });
108
- /**
109
- * The real `Icon.name` enum, all 59 members, generated directly from the fetched catalog JSON
110
- * rather than typed out by hand. Note it is **not** a `DynamicString`: the spec's `oneOf` admits a
111
- * literal enum member, a `{svgPath}` object, or a bare `DataBinding` — but *not* a `FunctionCall`.
112
- */
113
- const ICON_NAMES = [
114
- 'accountCircle', 'add', 'arrowBack', 'arrowForward', 'attachFile', 'calendarToday', 'call', 'camera',
115
- 'check', 'close', 'delete', 'download', 'edit', 'event', 'error', 'fastForward', 'favorite',
116
- 'favoriteOff', 'folder', 'help', 'home', 'info', 'locationOn', 'lock', 'lockOpen', 'mail', 'menu',
117
- 'moreVert', 'moreHoriz', 'notificationsOff', 'notifications', 'pause', 'payment', 'person', 'phone',
118
- 'photo', 'play', 'print', 'refresh', 'rewind', 'search', 'send', 'settings', 'share', 'shoppingCart',
119
- 'skipNext', 'skipPrevious', 'star', 'starHalf', 'starOff', 'stop', 'upload', 'visibility',
120
- 'visibilityOff', 'volumeDown', 'volumeMute', 'volumeOff', 'volumeUp', 'warning',
121
- ];
122
- const IconPropsSchema = componentProps({
123
- name: z.union([
124
- z.enum(ICON_NAMES),
125
- z.object({ svgPath: DynamicStringSchema }).strict(),
126
- DataBindingSchema,
127
- ]),
128
- });
129
- const VideoPropsSchema = componentProps({
130
- url: DynamicStringSchema,
131
- posterUrl: DynamicStringSchema.optional(),
132
- });
133
- const AudioPlayerPropsSchema = componentProps({
134
- url: DynamicStringSchema,
135
- description: DynamicStringSchema.optional(),
136
- });
137
- /** `List` is layout-shaped like Row/Column but has its own distinct property set: `direction` (not `justify`). */
138
- const ListPropsSchema = componentProps({
139
- children: ChildListSchema,
140
- direction: z.enum(['vertical', 'horizontal']).default('vertical'),
141
- align: z.enum(['start', 'center', 'end', 'stretch']).default('stretch'),
142
- });
143
- const CardPropsSchema = componentProps({
144
- child: ChildSchema,
145
- });
146
- const TabsPropsSchema = componentProps({
147
- tabs: z
148
- .array(z.object({ title: DynamicStringSchema, child: ChildSchema }).strict())
149
- .min(1),
150
- });
151
- const ModalPropsSchema = componentProps({
152
- trigger: ChildSchema,
153
- content: ChildSchema,
154
- });
155
- const DividerPropsSchema = componentProps({
156
- axis: z.enum(['horizontal', 'vertical']).default('horizontal'),
157
- });
158
- const TextFieldPropsSchema = checkableComponentProps({
159
- label: DynamicStringSchema,
160
- value: DynamicStringSchema.optional(),
161
- placeholder: DynamicStringSchema.optional(),
162
- variant: z.enum(['longText', 'number', 'shortText', 'obscured']).default('shortText'),
163
- });
164
- const CheckBoxPropsSchema = checkableComponentProps({
165
- label: DynamicStringSchema,
166
- value: DynamicBooleanSchema,
167
- });
168
- const ChoicePickerPropsSchema = checkableComponentProps({
169
- label: DynamicStringSchema.optional(),
170
- variant: z.enum(['multipleSelection', 'mutuallyExclusive']).default('mutuallyExclusive'),
171
- // `options.items.value` is a plain `string`, deliberately NOT a DynamicString — the real schema
172
- // calls it "the stable value associated with this option", and the array has no `minItems`, so an
173
- // empty `options` array is spec-legal.
174
- options: z.array(z.object({ label: DynamicStringSchema, value: z.string() }).strict()),
175
- value: DynamicStringListSchema,
176
- displayStyle: z.enum(['checkbox', 'chips']).default('checkbox'),
177
- filterable: z.boolean().default(false),
178
- });
179
- const SliderPropsSchema = checkableComponentProps({
180
- label: DynamicStringSchema.optional(),
181
- // `min`/`max` are plain numbers here (only `value` is dynamic), and `max` is required while
182
- // `min` has a default of 0 — an asymmetry copied from the real schema, not a transcription slip.
183
- min: z.number().default(0),
184
- max: z.number(),
185
- value: DynamicNumberSchema,
186
- steps: z.number().int().min(1).optional(),
187
- });
188
- /**
189
- * `DateTimeInput.min`/`max` — the one place in the 18 where the real schema is genuinely ambiguous,
190
- * so this is a **documented judgment call** rather than a literal port.
191
- *
192
- * The real definition is `allOf: [DynamicString, {if: {type: string}, then: {oneOf: [{format: date},
193
- * {format: time}, {format: date-time}]}}]`. Two readings collide:
194
- *
195
- * - JSON Schema's `format` is an *annotation* by default — a validator only asserts it if it opts
196
- * in (ajv, which the spec's own conformance runner uses, needs `ajv-formats` for this). Under
197
- * that reading the constraint is advisory and any string passes.
198
- * - But the author explicitly wrapped it in an `if`/`then`/`oneOf`, which is only meaningful as an
199
- * *assertion*. A structural wrapper around three annotations would be dead weight otherwise.
200
- *
201
- * Decision: assert it, because a validating renderer catching a malformed agent-sent bound is the
202
- * entire point of this layer — but assert **ISO 8601** (what the property's own description says,
203
- * "in ISO 8601 format") rather than RFC 3339, which is what JSON Schema's `format: time`/`date-time`
204
- * formally mean. RFC 3339 *requires* a UTC offset, so a literal `"09:00"` would be refused under it
205
- * while being perfectly good ISO 8601 and an obvious thing for an agent to send. Rejecting that
206
- * seemed clearly worse than accepting a value RFC 3339 purists would call under-specified.
207
- *
208
- * So: literal strings must parse as an ISO 8601 date, time, or date-time (offset optional);
209
- * `DataBinding`/`FunctionCall` forms are passed through unchecked, since their value isn't known
210
- * until resolution time. `oneOf` is implemented as "matches at least one" — the three grammars are
211
- * mutually exclusive in practice, so exactly-one and at-least-one coincide.
212
- */
213
- const ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
214
- const ISO_TIME = /^\d{2}:\d{2}(:\d{2}(\.\d+)?)?([Zz]|[+-]\d{2}:\d{2})?$/;
215
- const ISO_DATE_TIME = /^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}(:\d{2}(\.\d+)?)?([Zz]|[+-]\d{2}:\d{2})?$/;
216
- const IsoDateTimeBoundSchema = DynamicStringSchema.superRefine((value, ctx) => {
217
- if (typeof value !== 'string')
218
- return;
219
- if (ISO_DATE.test(value) || ISO_TIME.test(value) || ISO_DATE_TIME.test(value))
220
- return;
221
- ctx.addIssue({
222
- code: z.ZodIssueCode.custom,
223
- message: `literal date/time bound ${JSON.stringify(value)} is not an ISO 8601 date, time, or date-time`,
224
- });
225
- });
226
- const DateTimeInputPropsSchema = checkableComponentProps({
227
- value: DynamicStringSchema,
228
- enableDate: z.boolean().default(false),
229
- enableTime: z.boolean().default(false),
230
- min: IsoDateTimeBoundSchema.optional(),
231
- max: IsoDateTimeBoundSchema.optional(),
232
- label: DynamicStringSchema.optional(),
233
- });
234
- /**
235
- * Real basic-catalog functions this port can actually evaluate (boolean combinators — unambiguous
236
- * from the fetched schema alone, no formatting/locale semantics to guess at). Arg shapes copied
237
- * field-for-field from `specification/v1_0/catalogs/basic/catalog.json`'s own function
238
- * definitions, cross-checked against the spec repo's own conformance fixtures
239
- * (`specification/v1_0/test/cases/button_checks.json`, fetched and inspected this session) — an
240
- * earlier version of this port had `and`/`or` reading an arbitrary flat map of args instead of the
241
- * real `{values: DynamicBoolean[]}` shape (a plural, array-typed, `minItems: 2` property), caught
242
- * by cross-referencing that real fixture rather than trusting this file's own first read of
243
- * `common_types.json` alone (which only shows the generic `FunctionCall` envelope, not any one
244
- * function's own specific `args` shape).
245
- */
246
- function and(args) {
247
- const values = Array.isArray(args.values) ? args.values : [];
248
- return values.length > 0 && values.every((v) => v === true);
249
- }
250
- function or(args) {
251
- const values = Array.isArray(args.values) ? args.values : [];
252
- return values.some((v) => v === true);
253
- }
254
- /** `not`'s arg shape (singular `value`, not `values`) was already correct — real basic catalog: `args: {value: DynamicBoolean}`. */
255
- function not(args) {
256
- return args.value !== true;
257
- }
258
- /**
259
- * Builds the demo catalog this port's interpreter/fixture is validated against. A fresh object
260
- * each call (not a shared singleton) so tests can register their own `impl`s / mutate a copy
261
- * without cross-test leakage.
262
- */
263
- export function createLabCatalog() {
264
- // All 18 components of the real basic catalog, in that catalog's own declaration order.
265
- const components = new Map([
266
- ['Text', { kind: 'text', propsSchema: TextPropsSchema }],
267
- ['Image', { kind: 'image', propsSchema: ImagePropsSchema }],
268
- ['Icon', { kind: 'icon', propsSchema: IconPropsSchema }],
269
- ['Video', { kind: 'video', propsSchema: VideoPropsSchema }],
270
- ['AudioPlayer', { kind: 'audio', propsSchema: AudioPlayerPropsSchema }],
271
- ['Row', { kind: 'container', propsSchema: ContainerPropsSchema }],
272
- ['Column', { kind: 'container', propsSchema: ContainerPropsSchema }],
273
- ['List', { kind: 'container', propsSchema: ListPropsSchema }],
274
- ['Card', { kind: 'card', propsSchema: CardPropsSchema }],
275
- ['Tabs', { kind: 'tabs', propsSchema: TabsPropsSchema }],
276
- ['Modal', { kind: 'modal', propsSchema: ModalPropsSchema }],
277
- ['Divider', { kind: 'divider', propsSchema: DividerPropsSchema }],
278
- ['Button', { kind: 'button', propsSchema: ButtonPropsSchema }],
279
- ['TextField', { kind: 'input', propsSchema: TextFieldPropsSchema }],
280
- ['CheckBox', { kind: 'input', propsSchema: CheckBoxPropsSchema }],
281
- ['ChoicePicker', { kind: 'input', propsSchema: ChoicePickerPropsSchema }],
282
- ['Slider', { kind: 'input', propsSchema: SliderPropsSchema }],
283
- ['DateTimeInput', { kind: 'input', propsSchema: DateTimeInputPropsSchema }],
284
- ]);
285
- const functions = new Map([
286
- ['and', { returnType: 'boolean', callableFrom: 'rendererOnly', impl: and }],
287
- ['or', { returnType: 'boolean', callableFrom: 'rendererOnly', impl: or }],
288
- ['not', { returnType: 'boolean', callableFrom: 'rendererOnly', impl: not }],
289
- // Lab-only demo functions (not part of the real basic catalog) — exist purely to exercise
290
- // all three callableFrom values, see module doc.
291
- [
292
- 'greetUser',
293
- {
294
- returnType: 'string',
295
- callableFrom: 'rendererOrAgent',
296
- impl: (args) => `Hello, ${typeof args.name === 'string' ? args.name : 'there'}!`,
297
- },
298
- ],
299
- ['logServerEvent', { returnType: 'void', callableFrom: 'agentOnly', impl: () => undefined }],
300
- ['adminReset', { returnType: 'void', callableFrom: 'rendererOnly', impl: () => undefined }],
301
- ]);
302
- return { catalogId: 'https://a2ui.org/specification/v1_0/catalogs/basic/catalog.json#lab-subset', components, functions };
303
- }
304
- //# sourceMappingURL=catalog.js.map