@ggui-ai/preview-a2ui 0.1.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +87 -0
- package/dist/catalog.d.ts +51 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +57 -0
- package/dist/components.d.ts +143 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +177 -0
- package/dist/emitters/deterministic.d.ts +94 -0
- package/dist/emitters/deterministic.d.ts.map +1 -0
- package/dist/emitters/deterministic.js +184 -0
- package/dist/emitters/index.d.ts +15 -0
- package/dist/emitters/index.d.ts.map +1 -0
- package/dist/emitters/index.js +14 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/messages.d.ts +308 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +117 -0
- package/package.json +62 -0
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2UI server → client message shapes for the V1 provisional subset.
|
|
3
|
+
*
|
|
4
|
+
* V1 accepts only the write-path messages needed to render a
|
|
5
|
+
* server-assembled provisional surface:
|
|
6
|
+
*
|
|
7
|
+
* - `createSurface` — open a surface with a named catalog.
|
|
8
|
+
* - `updateComponents` — add/replace components by id.
|
|
9
|
+
* - `deleteSurface` — tear down the surface (cancellation, handoff).
|
|
10
|
+
*
|
|
11
|
+
* Intentionally deferred (see `@ggui-ai/preview-a2ui` scope lock):
|
|
12
|
+
*
|
|
13
|
+
* - `updateDataModel` — interactive data-binding surface. Not used
|
|
14
|
+
* while the provisional UI is non-interactive in V1.
|
|
15
|
+
* - Client → server `action` / `error` messages. Preview accepts no
|
|
16
|
+
* user interactions in V1; these would reject cleanly here if a
|
|
17
|
+
* client ever tried to forward them into this parser.
|
|
18
|
+
*
|
|
19
|
+
* Message shape note: A2UI wraps each envelope under a discriminator
|
|
20
|
+
* key (not a `type` field). `{version, createSurface: {...}}` vs
|
|
21
|
+
* `{version, updateComponents: {...}}`. We honor that shape; the Zod
|
|
22
|
+
* union keys on presence of the payload key rather than on a
|
|
23
|
+
* dedicated discriminator string.
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
/** A2UI protocol version our V1 subset targets. */
|
|
27
|
+
export declare const A2UI_MESSAGE_VERSION = "v0.9";
|
|
28
|
+
/**
|
|
29
|
+
* `createSurface` — opens a named surface tied to a catalog id. In
|
|
30
|
+
* ggui's wiring, `surfaceId` equals the stack item id; `catalogId`
|
|
31
|
+
* points at a ggui preview catalog manifest (see `./catalog`).
|
|
32
|
+
*
|
|
33
|
+
* Theming / data-model bootstrapping fields from the upstream spec
|
|
34
|
+
* are deferred — they're not on the V1 path and would invite scope
|
|
35
|
+
* creep to accept here.
|
|
36
|
+
*/
|
|
37
|
+
export declare const CreateSurfaceMessageSchema: z.ZodObject<{
|
|
38
|
+
version: z.ZodLiteral<"v0.9">;
|
|
39
|
+
createSurface: z.ZodObject<{
|
|
40
|
+
surfaceId: z.ZodString;
|
|
41
|
+
catalogId: z.ZodString;
|
|
42
|
+
}, z.core.$strip>;
|
|
43
|
+
}, z.core.$strip>;
|
|
44
|
+
export type CreateSurfaceMessage = z.infer<typeof CreateSurfaceMessageSchema>;
|
|
45
|
+
/**
|
|
46
|
+
* `updateComponents` — ships a batch of components for the surface.
|
|
47
|
+
* Each component's id is the replace key; the client accumulates
|
|
48
|
+
* them into a flat adjacency-list tree.
|
|
49
|
+
*
|
|
50
|
+
* Empty component arrays are legal (no-op). This matters because the
|
|
51
|
+
* preamble may emit an initial `updateComponents` with just the root
|
|
52
|
+
* placeholder and fill children in later frames.
|
|
53
|
+
*/
|
|
54
|
+
export declare const UpdateComponentsMessageSchema: z.ZodObject<{
|
|
55
|
+
version: z.ZodLiteral<"v0.9">;
|
|
56
|
+
updateComponents: z.ZodObject<{
|
|
57
|
+
surfaceId: z.ZodString;
|
|
58
|
+
components: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
59
|
+
id: z.ZodString;
|
|
60
|
+
component: z.ZodLiteral<"Row">;
|
|
61
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
62
|
+
gap: z.ZodOptional<z.ZodString>;
|
|
63
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
64
|
+
start: "start";
|
|
65
|
+
center: "center";
|
|
66
|
+
end: "end";
|
|
67
|
+
stretch: "stretch";
|
|
68
|
+
}>>;
|
|
69
|
+
justify: z.ZodOptional<z.ZodEnum<{
|
|
70
|
+
start: "start";
|
|
71
|
+
center: "center";
|
|
72
|
+
end: "end";
|
|
73
|
+
between: "between";
|
|
74
|
+
around: "around";
|
|
75
|
+
evenly: "evenly";
|
|
76
|
+
}>>;
|
|
77
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
78
|
+
id: z.ZodString;
|
|
79
|
+
component: z.ZodLiteral<"Column">;
|
|
80
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
81
|
+
gap: z.ZodOptional<z.ZodString>;
|
|
82
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
83
|
+
start: "start";
|
|
84
|
+
center: "center";
|
|
85
|
+
end: "end";
|
|
86
|
+
stretch: "stretch";
|
|
87
|
+
}>>;
|
|
88
|
+
justify: z.ZodOptional<z.ZodEnum<{
|
|
89
|
+
start: "start";
|
|
90
|
+
center: "center";
|
|
91
|
+
end: "end";
|
|
92
|
+
between: "between";
|
|
93
|
+
around: "around";
|
|
94
|
+
evenly: "evenly";
|
|
95
|
+
}>>;
|
|
96
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
97
|
+
id: z.ZodString;
|
|
98
|
+
component: z.ZodLiteral<"Card">;
|
|
99
|
+
child: z.ZodOptional<z.ZodString>;
|
|
100
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
101
|
+
id: z.ZodString;
|
|
102
|
+
component: z.ZodLiteral<"List">;
|
|
103
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
104
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
105
|
+
id: z.ZodString;
|
|
106
|
+
component: z.ZodLiteral<"Divider">;
|
|
107
|
+
orientation: z.ZodOptional<z.ZodEnum<{
|
|
108
|
+
horizontal: "horizontal";
|
|
109
|
+
vertical: "vertical";
|
|
110
|
+
}>>;
|
|
111
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
112
|
+
id: z.ZodString;
|
|
113
|
+
component: z.ZodLiteral<"Text">;
|
|
114
|
+
text: z.ZodString;
|
|
115
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
116
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
117
|
+
id: z.ZodString;
|
|
118
|
+
component: z.ZodLiteral<"Image">;
|
|
119
|
+
src: z.ZodString;
|
|
120
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
121
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
122
|
+
id: z.ZodString;
|
|
123
|
+
component: z.ZodLiteral<"Icon">;
|
|
124
|
+
name: z.ZodString;
|
|
125
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
126
|
+
id: z.ZodString;
|
|
127
|
+
component: z.ZodLiteral<"Button">;
|
|
128
|
+
label: z.ZodString;
|
|
129
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
130
|
+
id: z.ZodString;
|
|
131
|
+
component: z.ZodLiteral<"TextField">;
|
|
132
|
+
label: z.ZodOptional<z.ZodString>;
|
|
133
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
134
|
+
value: z.ZodOptional<z.ZodString>;
|
|
135
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
136
|
+
id: z.ZodString;
|
|
137
|
+
component: z.ZodLiteral<"CheckBox">;
|
|
138
|
+
label: z.ZodOptional<z.ZodString>;
|
|
139
|
+
checked: z.ZodOptional<z.ZodBoolean>;
|
|
140
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
141
|
+
id: z.ZodString;
|
|
142
|
+
component: z.ZodLiteral<"ChoicePicker">;
|
|
143
|
+
label: z.ZodOptional<z.ZodString>;
|
|
144
|
+
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
145
|
+
label: z.ZodString;
|
|
146
|
+
value: z.ZodString;
|
|
147
|
+
}, z.core.$strip>>>;
|
|
148
|
+
value: z.ZodOptional<z.ZodString>;
|
|
149
|
+
}, z.core.$strip>], "component">>;
|
|
150
|
+
}, z.core.$strip>;
|
|
151
|
+
}, z.core.$strip>;
|
|
152
|
+
export type UpdateComponentsMessage = z.infer<typeof UpdateComponentsMessageSchema>;
|
|
153
|
+
/**
|
|
154
|
+
* `deleteSurface` — closes the surface. Emitted on preamble
|
|
155
|
+
* cancellation (fast-path hit arrived) or on handoff (final
|
|
156
|
+
* component code committed and the crossfade is complete).
|
|
157
|
+
*/
|
|
158
|
+
export declare const DeleteSurfaceMessageSchema: z.ZodObject<{
|
|
159
|
+
version: z.ZodLiteral<"v0.9">;
|
|
160
|
+
deleteSurface: z.ZodObject<{
|
|
161
|
+
surfaceId: z.ZodString;
|
|
162
|
+
}, z.core.$strip>;
|
|
163
|
+
}, z.core.$strip>;
|
|
164
|
+
export type DeleteSurfaceMessage = z.infer<typeof DeleteSurfaceMessageSchema>;
|
|
165
|
+
/**
|
|
166
|
+
* Server → client message — the V1 write-path union.
|
|
167
|
+
*
|
|
168
|
+
* A2UI keys its envelopes on the payload key rather than a dedicated
|
|
169
|
+
* discriminator. Using `z.union` (not `z.discriminatedUnion`) is
|
|
170
|
+
* deliberate: the envelope keys are distinct object keys, not values
|
|
171
|
+
* of a single discriminator field, so Zod can't narrow by discriminator.
|
|
172
|
+
*/
|
|
173
|
+
export declare const ServerMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
174
|
+
version: z.ZodLiteral<"v0.9">;
|
|
175
|
+
createSurface: z.ZodObject<{
|
|
176
|
+
surfaceId: z.ZodString;
|
|
177
|
+
catalogId: z.ZodString;
|
|
178
|
+
}, z.core.$strip>;
|
|
179
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
180
|
+
version: z.ZodLiteral<"v0.9">;
|
|
181
|
+
updateComponents: z.ZodObject<{
|
|
182
|
+
surfaceId: z.ZodString;
|
|
183
|
+
components: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
184
|
+
id: z.ZodString;
|
|
185
|
+
component: z.ZodLiteral<"Row">;
|
|
186
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
187
|
+
gap: z.ZodOptional<z.ZodString>;
|
|
188
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
189
|
+
start: "start";
|
|
190
|
+
center: "center";
|
|
191
|
+
end: "end";
|
|
192
|
+
stretch: "stretch";
|
|
193
|
+
}>>;
|
|
194
|
+
justify: z.ZodOptional<z.ZodEnum<{
|
|
195
|
+
start: "start";
|
|
196
|
+
center: "center";
|
|
197
|
+
end: "end";
|
|
198
|
+
between: "between";
|
|
199
|
+
around: "around";
|
|
200
|
+
evenly: "evenly";
|
|
201
|
+
}>>;
|
|
202
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
203
|
+
id: z.ZodString;
|
|
204
|
+
component: z.ZodLiteral<"Column">;
|
|
205
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
206
|
+
gap: z.ZodOptional<z.ZodString>;
|
|
207
|
+
align: z.ZodOptional<z.ZodEnum<{
|
|
208
|
+
start: "start";
|
|
209
|
+
center: "center";
|
|
210
|
+
end: "end";
|
|
211
|
+
stretch: "stretch";
|
|
212
|
+
}>>;
|
|
213
|
+
justify: z.ZodOptional<z.ZodEnum<{
|
|
214
|
+
start: "start";
|
|
215
|
+
center: "center";
|
|
216
|
+
end: "end";
|
|
217
|
+
between: "between";
|
|
218
|
+
around: "around";
|
|
219
|
+
evenly: "evenly";
|
|
220
|
+
}>>;
|
|
221
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
222
|
+
id: z.ZodString;
|
|
223
|
+
component: z.ZodLiteral<"Card">;
|
|
224
|
+
child: z.ZodOptional<z.ZodString>;
|
|
225
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
226
|
+
id: z.ZodString;
|
|
227
|
+
component: z.ZodLiteral<"List">;
|
|
228
|
+
children: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
229
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
230
|
+
id: z.ZodString;
|
|
231
|
+
component: z.ZodLiteral<"Divider">;
|
|
232
|
+
orientation: z.ZodOptional<z.ZodEnum<{
|
|
233
|
+
horizontal: "horizontal";
|
|
234
|
+
vertical: "vertical";
|
|
235
|
+
}>>;
|
|
236
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
237
|
+
id: z.ZodString;
|
|
238
|
+
component: z.ZodLiteral<"Text">;
|
|
239
|
+
text: z.ZodString;
|
|
240
|
+
variant: z.ZodOptional<z.ZodString>;
|
|
241
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
242
|
+
id: z.ZodString;
|
|
243
|
+
component: z.ZodLiteral<"Image">;
|
|
244
|
+
src: z.ZodString;
|
|
245
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
246
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
247
|
+
id: z.ZodString;
|
|
248
|
+
component: z.ZodLiteral<"Icon">;
|
|
249
|
+
name: z.ZodString;
|
|
250
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
251
|
+
id: z.ZodString;
|
|
252
|
+
component: z.ZodLiteral<"Button">;
|
|
253
|
+
label: z.ZodString;
|
|
254
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
255
|
+
id: z.ZodString;
|
|
256
|
+
component: z.ZodLiteral<"TextField">;
|
|
257
|
+
label: z.ZodOptional<z.ZodString>;
|
|
258
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
259
|
+
value: z.ZodOptional<z.ZodString>;
|
|
260
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
261
|
+
id: z.ZodString;
|
|
262
|
+
component: z.ZodLiteral<"CheckBox">;
|
|
263
|
+
label: z.ZodOptional<z.ZodString>;
|
|
264
|
+
checked: z.ZodOptional<z.ZodBoolean>;
|
|
265
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
266
|
+
id: z.ZodString;
|
|
267
|
+
component: z.ZodLiteral<"ChoicePicker">;
|
|
268
|
+
label: z.ZodOptional<z.ZodString>;
|
|
269
|
+
options: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
270
|
+
label: z.ZodString;
|
|
271
|
+
value: z.ZodString;
|
|
272
|
+
}, z.core.$strip>>>;
|
|
273
|
+
value: z.ZodOptional<z.ZodString>;
|
|
274
|
+
}, z.core.$strip>], "component">>;
|
|
275
|
+
}, z.core.$strip>;
|
|
276
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
277
|
+
version: z.ZodLiteral<"v0.9">;
|
|
278
|
+
deleteSurface: z.ZodObject<{
|
|
279
|
+
surfaceId: z.ZodString;
|
|
280
|
+
}, z.core.$strip>;
|
|
281
|
+
}, z.core.$strip>]>;
|
|
282
|
+
export type ServerMessage = CreateSurfaceMessage | UpdateComponentsMessage | DeleteSurfaceMessage;
|
|
283
|
+
/** Narrow parse result — mirror of the component parse result shape. */
|
|
284
|
+
export type ServerMessageParseResult = {
|
|
285
|
+
readonly ok: true;
|
|
286
|
+
readonly value: ServerMessage;
|
|
287
|
+
} | {
|
|
288
|
+
readonly ok: false;
|
|
289
|
+
readonly issues: ReadonlyArray<{
|
|
290
|
+
path: ReadonlyArray<PropertyKey>;
|
|
291
|
+
message: string;
|
|
292
|
+
}>;
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* Safe-parse one server → client A2UI message. Returns a narrow
|
|
296
|
+
* discriminated result without leaking Zod internals; callers handle
|
|
297
|
+
* rejection by surfacing the `issues` list or by logging + dropping.
|
|
298
|
+
*/
|
|
299
|
+
export declare function parseServerMessage(input: unknown): ServerMessageParseResult;
|
|
300
|
+
/**
|
|
301
|
+
* Narrow type guards for the discriminated consumer code. Reading
|
|
302
|
+
* the payload key is the canonical shape — avoids consumers having
|
|
303
|
+
* to introspect Zod-parsed objects by presence of unrelated fields.
|
|
304
|
+
*/
|
|
305
|
+
export declare function isCreateSurfaceMessage(msg: ServerMessage): msg is CreateSurfaceMessage;
|
|
306
|
+
export declare function isUpdateComponentsMessage(msg: ServerMessage): msg is UpdateComponentsMessage;
|
|
307
|
+
export declare function isDeleteSurfaceMessage(msg: ServerMessage): msg is DeleteSurfaceMessage;
|
|
308
|
+
//# sourceMappingURL=messages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,mDAAmD;AACnD,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAK3C;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B;;;;;;iBAMrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMxC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAC3C,OAAO,6BAA6B,CACrC,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;;iBAKrC,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAE9E;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAI9B,CAAC;AAEH,MAAM,MAAM,aAAa,GACrB,oBAAoB,GACpB,uBAAuB,GACvB,oBAAoB,CAAC;AAEzB,wEAAwE;AACxE,MAAM,MAAM,wBAAwB,GAChC;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GACpD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvF,CAAC;AAEN;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CAU3E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,aAAa,GACjB,GAAG,IAAI,oBAAoB,CAE7B;AAED,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,aAAa,GACjB,GAAG,IAAI,uBAAuB,CAEhC;AAED,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,aAAa,GACjB,GAAG,IAAI,oBAAoB,CAE7B"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A2UI server → client message shapes for the V1 provisional subset.
|
|
3
|
+
*
|
|
4
|
+
* V1 accepts only the write-path messages needed to render a
|
|
5
|
+
* server-assembled provisional surface:
|
|
6
|
+
*
|
|
7
|
+
* - `createSurface` — open a surface with a named catalog.
|
|
8
|
+
* - `updateComponents` — add/replace components by id.
|
|
9
|
+
* - `deleteSurface` — tear down the surface (cancellation, handoff).
|
|
10
|
+
*
|
|
11
|
+
* Intentionally deferred (see `@ggui-ai/preview-a2ui` scope lock):
|
|
12
|
+
*
|
|
13
|
+
* - `updateDataModel` — interactive data-binding surface. Not used
|
|
14
|
+
* while the provisional UI is non-interactive in V1.
|
|
15
|
+
* - Client → server `action` / `error` messages. Preview accepts no
|
|
16
|
+
* user interactions in V1; these would reject cleanly here if a
|
|
17
|
+
* client ever tried to forward them into this parser.
|
|
18
|
+
*
|
|
19
|
+
* Message shape note: A2UI wraps each envelope under a discriminator
|
|
20
|
+
* key (not a `type` field). `{version, createSurface: {...}}` vs
|
|
21
|
+
* `{version, updateComponents: {...}}`. We honor that shape; the Zod
|
|
22
|
+
* union keys on presence of the payload key rather than on a
|
|
23
|
+
* dedicated discriminator string.
|
|
24
|
+
*/
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { ComponentSchema } from './components.js';
|
|
27
|
+
/** A2UI protocol version our V1 subset targets. */
|
|
28
|
+
export const A2UI_MESSAGE_VERSION = 'v0.9';
|
|
29
|
+
const VersionLiteral = z.literal(A2UI_MESSAGE_VERSION);
|
|
30
|
+
const SurfaceId = z.string().min(1);
|
|
31
|
+
/**
|
|
32
|
+
* `createSurface` — opens a named surface tied to a catalog id. In
|
|
33
|
+
* ggui's wiring, `surfaceId` equals the stack item id; `catalogId`
|
|
34
|
+
* points at a ggui preview catalog manifest (see `./catalog`).
|
|
35
|
+
*
|
|
36
|
+
* Theming / data-model bootstrapping fields from the upstream spec
|
|
37
|
+
* are deferred — they're not on the V1 path and would invite scope
|
|
38
|
+
* creep to accept here.
|
|
39
|
+
*/
|
|
40
|
+
export const CreateSurfaceMessageSchema = z.object({
|
|
41
|
+
version: VersionLiteral,
|
|
42
|
+
createSurface: z.object({
|
|
43
|
+
surfaceId: SurfaceId,
|
|
44
|
+
catalogId: z.string().min(1),
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
/**
|
|
48
|
+
* `updateComponents` — ships a batch of components for the surface.
|
|
49
|
+
* Each component's id is the replace key; the client accumulates
|
|
50
|
+
* them into a flat adjacency-list tree.
|
|
51
|
+
*
|
|
52
|
+
* Empty component arrays are legal (no-op). This matters because the
|
|
53
|
+
* preamble may emit an initial `updateComponents` with just the root
|
|
54
|
+
* placeholder and fill children in later frames.
|
|
55
|
+
*/
|
|
56
|
+
export const UpdateComponentsMessageSchema = z.object({
|
|
57
|
+
version: VersionLiteral,
|
|
58
|
+
updateComponents: z.object({
|
|
59
|
+
surfaceId: SurfaceId,
|
|
60
|
+
components: z.array(ComponentSchema),
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
/**
|
|
64
|
+
* `deleteSurface` — closes the surface. Emitted on preamble
|
|
65
|
+
* cancellation (fast-path hit arrived) or on handoff (final
|
|
66
|
+
* component code committed and the crossfade is complete).
|
|
67
|
+
*/
|
|
68
|
+
export const DeleteSurfaceMessageSchema = z.object({
|
|
69
|
+
version: VersionLiteral,
|
|
70
|
+
deleteSurface: z.object({
|
|
71
|
+
surfaceId: SurfaceId,
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
/**
|
|
75
|
+
* Server → client message — the V1 write-path union.
|
|
76
|
+
*
|
|
77
|
+
* A2UI keys its envelopes on the payload key rather than a dedicated
|
|
78
|
+
* discriminator. Using `z.union` (not `z.discriminatedUnion`) is
|
|
79
|
+
* deliberate: the envelope keys are distinct object keys, not values
|
|
80
|
+
* of a single discriminator field, so Zod can't narrow by discriminator.
|
|
81
|
+
*/
|
|
82
|
+
export const ServerMessageSchema = z.union([
|
|
83
|
+
CreateSurfaceMessageSchema,
|
|
84
|
+
UpdateComponentsMessageSchema,
|
|
85
|
+
DeleteSurfaceMessageSchema,
|
|
86
|
+
]);
|
|
87
|
+
/**
|
|
88
|
+
* Safe-parse one server → client A2UI message. Returns a narrow
|
|
89
|
+
* discriminated result without leaking Zod internals; callers handle
|
|
90
|
+
* rejection by surfacing the `issues` list or by logging + dropping.
|
|
91
|
+
*/
|
|
92
|
+
export function parseServerMessage(input) {
|
|
93
|
+
const result = ServerMessageSchema.safeParse(input);
|
|
94
|
+
if (result.success)
|
|
95
|
+
return { ok: true, value: result.data };
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
issues: result.error.issues.map((issue) => ({
|
|
99
|
+
path: issue.path,
|
|
100
|
+
message: issue.message,
|
|
101
|
+
})),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Narrow type guards for the discriminated consumer code. Reading
|
|
106
|
+
* the payload key is the canonical shape — avoids consumers having
|
|
107
|
+
* to introspect Zod-parsed objects by presence of unrelated fields.
|
|
108
|
+
*/
|
|
109
|
+
export function isCreateSurfaceMessage(msg) {
|
|
110
|
+
return 'createSurface' in msg;
|
|
111
|
+
}
|
|
112
|
+
export function isUpdateComponentsMessage(msg) {
|
|
113
|
+
return 'updateComponents' in msg;
|
|
114
|
+
}
|
|
115
|
+
export function isDeleteSurfaceMessage(msg) {
|
|
116
|
+
return 'deleteSurface' in msg;
|
|
117
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ggui-ai/preview-a2ui",
|
|
3
|
+
"version": "0.1.0-rc.1",
|
|
4
|
+
"description": "Narrow A2UI boundary for ggui's provisional UI assembly channel. Framework-neutral types and validators for the server-write subset (createSurface / updateComponents / deleteSurface) used to paint shimmering placeholder UI before the final generated interface arrives.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ggui",
|
|
7
|
+
"a2ui",
|
|
8
|
+
"ui",
|
|
9
|
+
"preview",
|
|
10
|
+
"validation"
|
|
11
|
+
],
|
|
12
|
+
"license": "Apache-2.0",
|
|
13
|
+
"homepage": "https://github.com/ggui-ai/ggui/tree/main/packages/preview-a2ui",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/ggui-ai/ggui.git",
|
|
17
|
+
"directory": "packages/preview-a2ui"
|
|
18
|
+
},
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/ggui-ai/ggui/issues"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "dist/index.js",
|
|
27
|
+
"types": "dist/index.d.ts",
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./emitters": {
|
|
39
|
+
"types": "./dist/emitters/index.d.ts",
|
|
40
|
+
"import": "./dist/emitters/index.js",
|
|
41
|
+
"default": "./dist/emitters/index.js"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"zod": "^4.3.6"
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"typescript": "^5.0.0",
|
|
49
|
+
"vitest": "^3.0.0"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=20.0.0"
|
|
53
|
+
},
|
|
54
|
+
"author": "ggui contributors <hello@ggui.ai>",
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsc && node ../scripts/fix-esm-imports.mjs dist",
|
|
57
|
+
"dev": "tsc --watch",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
59
|
+
"test": "vitest run",
|
|
60
|
+
"test:watch": "vitest"
|
|
61
|
+
}
|
|
62
|
+
}
|