@assistant-ui/react-generative-ui 0.0.23 → 0.1.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 (338) hide show
  1. package/README.md +2 -0
  2. package/dist/a2ui.d.ts +1 -4
  3. package/dist/a2ui.d.ts.map +1 -1
  4. package/dist/a2ui.js +1 -4
  5. package/dist/index.d.ts +1 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -10
  8. package/dist/index.server.d.ts +1 -2
  9. package/dist/index.server.d.ts.map +1 -1
  10. package/dist/index.server.js +1 -10
  11. package/dist/ir.d.ts +1 -111
  12. package/dist/ir.d.ts.map +1 -1
  13. package/dist/ir.js +1 -175
  14. package/dist/slack.d.ts +1 -4
  15. package/dist/slack.d.ts.map +1 -1
  16. package/dist/slack.js +1 -4
  17. package/dist/teams.d.ts +1 -4
  18. package/dist/teams.d.ts.map +1 -1
  19. package/dist/teams.js +1 -4
  20. package/package.json +5 -5
  21. package/src/a2ui.ts +1 -22
  22. package/src/index.server.ts +1 -2
  23. package/src/index.test.ts +75 -0
  24. package/src/index.ts +1 -2
  25. package/src/ir.ts +1 -279
  26. package/src/slack.ts +1 -39
  27. package/src/teams.ts +1 -35
  28. package/dist/JSONGenerativeUI.client.d.ts +0 -28
  29. package/dist/JSONGenerativeUI.client.d.ts.map +0 -1
  30. package/dist/JSONGenerativeUI.client.js +0 -101
  31. package/dist/JSONGenerativeUI.client.js.map +0 -1
  32. package/dist/JSONGenerativeUI.server.d.ts +0 -21
  33. package/dist/JSONGenerativeUI.server.d.ts.map +0 -1
  34. package/dist/JSONGenerativeUI.server.js +0 -32
  35. package/dist/JSONGenerativeUI.server.js.map +0 -1
  36. package/dist/JSONGenerativeUI.shared.d.ts +0 -63
  37. package/dist/JSONGenerativeUI.shared.d.ts.map +0 -1
  38. package/dist/JSONGenerativeUI.shared.js +0 -31
  39. package/dist/JSONGenerativeUI.shared.js.map +0 -1
  40. package/dist/RadioGroupScope.d.ts +0 -6
  41. package/dist/RadioGroupScope.d.ts.map +0 -1
  42. package/dist/RadioGroupScope.js +0 -25
  43. package/dist/RadioGroupScope.js.map +0 -1
  44. package/dist/a2ui/BindingContext.d.ts +0 -11
  45. package/dist/a2ui/BindingContext.d.ts.map +0 -1
  46. package/dist/a2ui/BindingContext.js +0 -12
  47. package/dist/a2ui/BindingContext.js.map +0 -1
  48. package/dist/a2ui/PresentRenderer.d.ts +0 -11
  49. package/dist/a2ui/PresentRenderer.d.ts.map +0 -1
  50. package/dist/a2ui/PresentRenderer.js +0 -39
  51. package/dist/a2ui/PresentRenderer.js.map +0 -1
  52. package/dist/a2ui/convert.d.ts +0 -15
  53. package/dist/a2ui/convert.d.ts.map +0 -1
  54. package/dist/a2ui/convert.js +0 -728
  55. package/dist/a2ui/convert.js.map +0 -1
  56. package/dist/a2ui/dataModel.d.ts +0 -9
  57. package/dist/a2ui/dataModel.d.ts.map +0 -1
  58. package/dist/a2ui/dataModel.js +0 -44
  59. package/dist/a2ui/dataModel.js.map +0 -1
  60. package/dist/a2ui/reducer.d.ts +0 -8
  61. package/dist/a2ui/reducer.d.ts.map +0 -1
  62. package/dist/a2ui/reducer.js +0 -242
  63. package/dist/a2ui/reducer.js.map +0 -1
  64. package/dist/a2ui/snapshot.d.ts +0 -3
  65. package/dist/a2ui/snapshot.d.ts.map +0 -1
  66. package/dist/a2ui/snapshot.js +0 -33
  67. package/dist/a2ui/snapshot.js.map +0 -1
  68. package/dist/a2ui/types.d.ts +0 -88
  69. package/dist/a2ui/types.d.ts.map +0 -1
  70. package/dist/a2ui/types.js +0 -6
  71. package/dist/a2ui/types.js.map +0 -1
  72. package/dist/a2ui/valueFunctions.d.ts +0 -16
  73. package/dist/a2ui/valueFunctions.d.ts.map +0 -1
  74. package/dist/a2ui/valueFunctions.js +0 -332
  75. package/dist/a2ui/valueFunctions.js.map +0 -1
  76. package/dist/actionRegistry.d.ts +0 -29
  77. package/dist/actionRegistry.d.ts.map +0 -1
  78. package/dist/actionRegistry.js +0 -41
  79. package/dist/actionRegistry.js.map +0 -1
  80. package/dist/answeredValues.d.ts +0 -16
  81. package/dist/answeredValues.d.ts.map +0 -1
  82. package/dist/answeredValues.js +0 -37
  83. package/dist/answeredValues.js.map +0 -1
  84. package/dist/buildPresentParameters.d.ts +0 -21
  85. package/dist/buildPresentParameters.d.ts.map +0 -1
  86. package/dist/buildPresentParameters.js +0 -95
  87. package/dist/buildPresentParameters.js.map +0 -1
  88. package/dist/constants.d.ts +0 -15
  89. package/dist/constants.d.ts.map +0 -1
  90. package/dist/constants.js +0 -19
  91. package/dist/constants.js.map +0 -1
  92. package/dist/convert/boundSpec.d.ts +0 -48
  93. package/dist/convert/boundSpec.d.ts.map +0 -1
  94. package/dist/convert/boundSpec.js +0 -108
  95. package/dist/convert/boundSpec.js.map +0 -1
  96. package/dist/convert/copyBounded.d.ts +0 -25
  97. package/dist/convert/copyBounded.d.ts.map +0 -1
  98. package/dist/convert/copyBounded.js +0 -38
  99. package/dist/convert/copyBounded.js.map +0 -1
  100. package/dist/convert/isElement.d.ts +0 -3
  101. package/dist/convert/isElement.d.ts.map +0 -1
  102. package/dist/convert/isElement.js +0 -6
  103. package/dist/convert/isElement.js.map +0 -1
  104. package/dist/convert/takeRun.d.ts +0 -6
  105. package/dist/convert/takeRun.d.ts.map +0 -1
  106. package/dist/convert/takeRun.js +0 -20
  107. package/dist/convert/takeRun.js.map +0 -1
  108. package/dist/defineGenerativeComponents.d.ts +0 -29
  109. package/dist/defineGenerativeComponents.d.ts.map +0 -1
  110. package/dist/defineGenerativeComponents.js +0 -34
  111. package/dist/defineGenerativeComponents.js.map +0 -1
  112. package/dist/fieldReferences.d.ts +0 -9
  113. package/dist/fieldReferences.d.ts.map +0 -1
  114. package/dist/fieldReferences.js +0 -53
  115. package/dist/fieldReferences.js.map +0 -1
  116. package/dist/generativeUIToJSX.d.ts +0 -18
  117. package/dist/generativeUIToJSX.d.ts.map +0 -1
  118. package/dist/generativeUIToJSX.js +0 -76
  119. package/dist/generativeUIToJSX.js.map +0 -1
  120. package/dist/index.shared.d.ts +0 -15
  121. package/dist/index.shared.d.ts.map +0 -1
  122. package/dist/index.shared.js +0 -9
  123. package/dist/ir.js.map +0 -1
  124. package/dist/renderGenerativeUI.d.ts +0 -14
  125. package/dist/renderGenerativeUI.d.ts.map +0 -1
  126. package/dist/renderGenerativeUI.js +0 -83
  127. package/dist/renderGenerativeUI.js.map +0 -1
  128. package/dist/scopeSchema.d.ts +0 -6
  129. package/dist/scopeSchema.d.ts.map +0 -1
  130. package/dist/scopeSchema.js +0 -56
  131. package/dist/scopeSchema.js.map +0 -1
  132. package/dist/slack/constants.d.ts +0 -93
  133. package/dist/slack/constants.d.ts.map +0 -1
  134. package/dist/slack/constants.js +0 -146
  135. package/dist/slack/constants.js.map +0 -1
  136. package/dist/slack/decodeBlockAction.d.ts +0 -10
  137. package/dist/slack/decodeBlockAction.d.ts.map +0 -1
  138. package/dist/slack/decodeBlockAction.js +0 -129
  139. package/dist/slack/decodeBlockAction.js.map +0 -1
  140. package/dist/slack/fromSlackBlocks.d.ts +0 -27
  141. package/dist/slack/fromSlackBlocks.d.ts.map +0 -1
  142. package/dist/slack/fromSlackBlocks.js +0 -483
  143. package/dist/slack/fromSlackBlocks.js.map +0 -1
  144. package/dist/slack/toSlackBlocks.d.ts +0 -4
  145. package/dist/slack/toSlackBlocks.d.ts.map +0 -1
  146. package/dist/slack/toSlackBlocks.js +0 -901
  147. package/dist/slack/toSlackBlocks.js.map +0 -1
  148. package/dist/slack/types.d.ts +0 -204
  149. package/dist/slack/types.d.ts.map +0 -1
  150. package/dist/slack/types.js +0 -0
  151. package/dist/teams/constants.d.ts +0 -34
  152. package/dist/teams/constants.d.ts.map +0 -1
  153. package/dist/teams/constants.js +0 -68
  154. package/dist/teams/constants.js.map +0 -1
  155. package/dist/teams/decodeSubmitData.d.ts +0 -26
  156. package/dist/teams/decodeSubmitData.d.ts.map +0 -1
  157. package/dist/teams/decodeSubmitData.js +0 -70
  158. package/dist/teams/decodeSubmitData.js.map +0 -1
  159. package/dist/teams/temporalId.d.ts +0 -5
  160. package/dist/teams/temporalId.d.ts.map +0 -1
  161. package/dist/teams/temporalId.js +0 -28
  162. package/dist/teams/temporalId.js.map +0 -1
  163. package/dist/teams/toAdaptiveCard.d.ts +0 -45
  164. package/dist/teams/toAdaptiveCard.d.ts.map +0 -1
  165. package/dist/teams/toAdaptiveCard.js +0 -642
  166. package/dist/teams/toAdaptiveCard.js.map +0 -1
  167. package/dist/teams/toTeamsAttachments.d.ts +0 -10
  168. package/dist/teams/toTeamsAttachments.d.ts.map +0 -1
  169. package/dist/teams/toTeamsAttachments.js +0 -99
  170. package/dist/teams/toTeamsAttachments.js.map +0 -1
  171. package/dist/teams/types.d.ts +0 -224
  172. package/dist/teams/types.d.ts.map +0 -1
  173. package/dist/teams/types.js +0 -0
  174. package/dist/temporal.d.ts +0 -33
  175. package/dist/temporal.d.ts.map +0 -1
  176. package/dist/temporal.js +0 -152
  177. package/dist/temporal.js.map +0 -1
  178. package/dist/types.d.ts +0 -99
  179. package/dist/types.d.ts.map +0 -1
  180. package/dist/types.js +0 -0
  181. package/dist/vocabulary/alert.d.ts +0 -32
  182. package/dist/vocabulary/alert.d.ts.map +0 -1
  183. package/dist/vocabulary/alert.js +0 -160
  184. package/dist/vocabulary/alert.js.map +0 -1
  185. package/dist/vocabulary/collectFormValues.d.ts +0 -23
  186. package/dist/vocabulary/collectFormValues.d.ts.map +0 -1
  187. package/dist/vocabulary/collectFormValues.js +0 -44
  188. package/dist/vocabulary/collectFormValues.js.map +0 -1
  189. package/dist/vocabulary/data.d.ts +0 -66
  190. package/dist/vocabulary/data.d.ts.map +0 -1
  191. package/dist/vocabulary/data.js +0 -503
  192. package/dist/vocabulary/data.js.map +0 -1
  193. package/dist/vocabulary/dispatch.d.ts +0 -9
  194. package/dist/vocabulary/dispatch.d.ts.map +0 -1
  195. package/dist/vocabulary/dispatch.js +0 -50
  196. package/dist/vocabulary/dispatch.js.map +0 -1
  197. package/dist/vocabulary/fact.d.ts +0 -19
  198. package/dist/vocabulary/fact.d.ts.map +0 -1
  199. package/dist/vocabulary/fact.js +0 -51
  200. package/dist/vocabulary/fact.js.map +0 -1
  201. package/dist/vocabulary/form.d.ts +0 -11
  202. package/dist/vocabulary/form.d.ts.map +0 -1
  203. package/dist/vocabulary/form.js +0 -23
  204. package/dist/vocabulary/form.js.map +0 -1
  205. package/dist/vocabulary/formatValue.d.ts +0 -7
  206. package/dist/vocabulary/formatValue.d.ts.map +0 -1
  207. package/dist/vocabulary/formatValue.js +0 -76
  208. package/dist/vocabulary/formatValue.js.map +0 -1
  209. package/dist/vocabulary/icon.d.ts +0 -41
  210. package/dist/vocabulary/icon.d.ts.map +0 -1
  211. package/dist/vocabulary/icon.js +0 -272
  212. package/dist/vocabulary/icon.js.map +0 -1
  213. package/dist/vocabulary/index.d.ts +0 -12
  214. package/dist/vocabulary/index.d.ts.map +0 -1
  215. package/dist/vocabulary/index.js +0 -36
  216. package/dist/vocabulary/index.js.map +0 -1
  217. package/dist/vocabulary/interactive.d.ts +0 -230
  218. package/dist/vocabulary/interactive.d.ts.map +0 -1
  219. package/dist/vocabulary/interactive.js +0 -530
  220. package/dist/vocabulary/interactive.js.map +0 -1
  221. package/dist/vocabulary/layout.d.ts +0 -79
  222. package/dist/vocabulary/layout.d.ts.map +0 -1
  223. package/dist/vocabulary/layout.js +0 -139
  224. package/dist/vocabulary/layout.js.map +0 -1
  225. package/dist/vocabulary/list.d.ts +0 -14
  226. package/dist/vocabulary/list.d.ts.map +0 -1
  227. package/dist/vocabulary/list.js +0 -50
  228. package/dist/vocabulary/list.js.map +0 -1
  229. package/dist/vocabulary/media.d.ts +0 -25
  230. package/dist/vocabulary/media.d.ts.map +0 -1
  231. package/dist/vocabulary/media.js +0 -42
  232. package/dist/vocabulary/media.js.map +0 -1
  233. package/dist/vocabulary/text.d.ts +0 -57
  234. package/dist/vocabulary/text.d.ts.map +0 -1
  235. package/dist/vocabulary/text.js +0 -49
  236. package/dist/vocabulary/text.js.map +0 -1
  237. package/dist/vocabulary/toTextContent.d.ts +0 -2
  238. package/dist/vocabulary/toTextContent.d.ts.map +0 -1
  239. package/dist/vocabulary/toTextContent.js +0 -6
  240. package/dist/vocabulary/toTextContent.js.map +0 -1
  241. package/src/JSONGenerativeUI.client.tsx +0 -168
  242. package/src/JSONGenerativeUI.server.tsx +0 -39
  243. package/src/JSONGenerativeUI.shared.ts +0 -90
  244. package/src/JSONGenerativeUI.test.tsx +0 -1298
  245. package/src/RadioGroupScope.server.test.tsx +0 -24
  246. package/src/RadioGroupScope.tsx +0 -34
  247. package/src/a2ui/BindingContext.ts +0 -26
  248. package/src/a2ui/PresentRenderer.tsx +0 -83
  249. package/src/a2ui/convert.test.ts +0 -2923
  250. package/src/a2ui/convert.ts +0 -1207
  251. package/src/a2ui/dataModel.ts +0 -69
  252. package/src/a2ui/reducer.test.ts +0 -422
  253. package/src/a2ui/reducer.ts +0 -363
  254. package/src/a2ui/snapshot.test.ts +0 -52
  255. package/src/a2ui/snapshot.ts +0 -52
  256. package/src/a2ui/types.ts +0 -114
  257. package/src/a2ui/valueFunctions.test.ts +0 -271
  258. package/src/a2ui/valueFunctions.ts +0 -523
  259. package/src/actionRegistry.test.ts +0 -90
  260. package/src/actionRegistry.ts +0 -88
  261. package/src/answeredValues.test.ts +0 -33
  262. package/src/answeredValues.tsx +0 -70
  263. package/src/buildPresentParameters.test.ts +0 -246
  264. package/src/buildPresentParameters.ts +0 -130
  265. package/src/constants.ts +0 -17
  266. package/src/convert/boundSpec.test.ts +0 -192
  267. package/src/convert/boundSpec.ts +0 -134
  268. package/src/convert/copyBounded.test.ts +0 -131
  269. package/src/convert/copyBounded.ts +0 -38
  270. package/src/convert/isElement.ts +0 -6
  271. package/src/convert/takeRun.test.ts +0 -64
  272. package/src/convert/takeRun.ts +0 -19
  273. package/src/defineGenerativeComponents.ts +0 -38
  274. package/src/fieldReferences.test.ts +0 -66
  275. package/src/fieldReferences.ts +0 -83
  276. package/src/generativeUIToJSX.test.ts +0 -268
  277. package/src/generativeUIToJSX.ts +0 -152
  278. package/src/index.server.test.ts +0 -106
  279. package/src/index.shared.ts +0 -61
  280. package/src/ir.test.ts +0 -203
  281. package/src/renderGenerativeUI.test.tsx +0 -373
  282. package/src/renderGenerativeUI.tsx +0 -165
  283. package/src/scopeSchema.test.ts +0 -72
  284. package/src/scopeSchema.ts +0 -71
  285. package/src/slack/a2uiSlack.test.ts +0 -198
  286. package/src/slack/constants.ts +0 -194
  287. package/src/slack/datePicker.test.ts +0 -612
  288. package/src/slack/decodeBlockAction.test.ts +0 -233
  289. package/src/slack/decodeBlockAction.ts +0 -232
  290. package/src/slack/fromSlackBlocks.test.ts +0 -1465
  291. package/src/slack/fromSlackBlocks.ts +0 -789
  292. package/src/slack/toSlackBlocks.test.ts +0 -3065
  293. package/src/slack/toSlackBlocks.ts +0 -1818
  294. package/src/slack/types.ts +0 -264
  295. package/src/teams/constants.ts +0 -93
  296. package/src/teams/decodeSubmitData.test.ts +0 -397
  297. package/src/teams/decodeSubmitData.ts +0 -110
  298. package/src/teams/temporal.test.ts +0 -766
  299. package/src/teams/temporalId.ts +0 -56
  300. package/src/teams/toAdaptiveCard.test.ts +0 -1897
  301. package/src/teams/toAdaptiveCard.ts +0 -1057
  302. package/src/teams/toTeamsAttachments.test.ts +0 -74
  303. package/src/teams/toTeamsAttachments.ts +0 -133
  304. package/src/teams/types.ts +0 -266
  305. package/src/temporal.test.ts +0 -319
  306. package/src/temporal.ts +0 -259
  307. package/src/types.ts +0 -119
  308. package/src/vocabulary/alert.test.tsx +0 -427
  309. package/src/vocabulary/alert.tsx +0 -217
  310. package/src/vocabulary/collectFormValues.test.ts +0 -389
  311. package/src/vocabulary/collectFormValues.ts +0 -116
  312. package/src/vocabulary/data.test.tsx +0 -858
  313. package/src/vocabulary/data.tsx +0 -819
  314. package/src/vocabulary/datepicker.dom.test.tsx +0 -1148
  315. package/src/vocabulary/dispatch.ts +0 -83
  316. package/src/vocabulary/fact.test.tsx +0 -94
  317. package/src/vocabulary/fact.tsx +0 -54
  318. package/src/vocabulary/form.test.tsx +0 -113
  319. package/src/vocabulary/form.tsx +0 -39
  320. package/src/vocabulary/formatValue.test.ts +0 -72
  321. package/src/vocabulary/formatValue.ts +0 -127
  322. package/src/vocabulary/icon.test.tsx +0 -64
  323. package/src/vocabulary/icon.tsx +0 -174
  324. package/src/vocabulary/index.test.ts +0 -65
  325. package/src/vocabulary/index.ts +0 -33
  326. package/src/vocabulary/interactive.dispatch.test.tsx +0 -454
  327. package/src/vocabulary/interactive.dom.test.tsx +0 -1747
  328. package/src/vocabulary/interactive.test.tsx +0 -377
  329. package/src/vocabulary/interactive.tsx +0 -1048
  330. package/src/vocabulary/layout.test.tsx +0 -323
  331. package/src/vocabulary/layout.tsx +0 -247
  332. package/src/vocabulary/list.test.tsx +0 -222
  333. package/src/vocabulary/list.tsx +0 -50
  334. package/src/vocabulary/media.test.tsx +0 -85
  335. package/src/vocabulary/media.tsx +0 -56
  336. package/src/vocabulary/text.test.tsx +0 -102
  337. package/src/vocabulary/text.tsx +0 -60
  338. package/src/vocabulary/toTextContent.ts +0 -2
@@ -1,363 +0,0 @@
1
- import {
2
- A2UI_SURFACE_ID,
3
- type A2uiOperationResult,
4
- type A2uiState,
5
- type A2uiSurfaceState,
6
- type A2uiVersion,
7
- } from "./types";
8
-
9
- const OPERATION_KEYS = new Set([
10
- "createSurface",
11
- "updateComponents",
12
- "updateDataModel",
13
- "deleteSurface",
14
- ]);
15
- // This defensive ceiling is well above the renderer's displayed-item limit.
16
- export const MAX_AUTO_VIVIFY_ARRAY_INDEX = 10_000;
17
- const INVALID_POINTER = Symbol("invalidPointer");
18
-
19
- const isRecord = (value: unknown): value is Record<string, unknown> =>
20
- typeof value === "object" && value !== null && !Array.isArray(value);
21
-
22
- const isVersion = (value: unknown): value is A2uiVersion =>
23
- value === "v0.9" || value === "v0.9.1" || value === "v1.0";
24
-
25
- const surfaceIdOf = (payload: Record<string, unknown>): string | undefined => {
26
- const surfaceId = payload["surfaceId"];
27
- return typeof surfaceId === "string" && surfaceId.length > 0
28
- ? surfaceId
29
- : undefined;
30
- };
31
-
32
- const catalogIdOf = (payload: Record<string, unknown>): string | undefined => {
33
- if (typeof payload["catalogId"] === "string") {
34
- return payload["catalogId"];
35
- }
36
- const surfaceProperties = payload["surfaceProperties"];
37
- return isRecord(surfaceProperties) &&
38
- typeof surfaceProperties["catalogId"] === "string"
39
- ? surfaceProperties["catalogId"]
40
- : undefined;
41
- };
42
-
43
- const withSurfaceId = (
44
- surface: A2uiSurfaceState,
45
- surfaceId: string,
46
- ): A2uiSurfaceState => {
47
- Object.defineProperty(surface, A2UI_SURFACE_ID, {
48
- value: surfaceId,
49
- enumerable: false,
50
- });
51
- return surface;
52
- };
53
-
54
- const getSurfaceId = (surface: A2uiSurfaceState): string | undefined =>
55
- (surface as A2uiSurfaceState & { [A2UI_SURFACE_ID]?: string })[
56
- A2UI_SURFACE_ID
57
- ];
58
-
59
- const cloneSurface = (
60
- surface: A2uiSurfaceState,
61
- surfaceId: string,
62
- ): A2uiSurfaceState =>
63
- withSurfaceId(
64
- {
65
- ...(surface.catalogId !== undefined
66
- ? { catalogId: surface.catalogId }
67
- : {}),
68
- components: new Map(surface.components),
69
- dataModel: surface.dataModel,
70
- },
71
- getSurfaceId(surface) ?? surfaceId,
72
- );
73
-
74
- const upsertComponents = (
75
- surface: A2uiSurfaceState,
76
- components: unknown,
77
- warnings: string[],
78
- operationIndex: number,
79
- ): void => {
80
- if (!Array.isArray(components)) {
81
- warnings.push(
82
- `Operation at index ${operationIndex} has malformed components.`,
83
- );
84
- return;
85
- }
86
-
87
- for (
88
- let componentIndex = 0;
89
- componentIndex < components.length;
90
- componentIndex++
91
- ) {
92
- const component = components[componentIndex];
93
- if (
94
- !isRecord(component) ||
95
- typeof component["id"] !== "string" ||
96
- component["id"].length === 0 ||
97
- typeof component["component"] !== "string" ||
98
- component["component"].length === 0
99
- ) {
100
- warnings.push(
101
- `Component at index ${componentIndex} in operation ${operationIndex} is malformed.`,
102
- );
103
- continue;
104
- }
105
- surface.components.set(component["id"], { ...component });
106
- }
107
- };
108
-
109
- const decodePointer = (path: string): string[] | undefined => {
110
- if (path === "" || path === "/") return [];
111
- if (!path.startsWith("/")) return undefined;
112
- return path
113
- .slice(1)
114
- .split("/")
115
- .map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"));
116
- };
117
-
118
- const isArrayIndex = (segment: string): boolean =>
119
- segment === "0" || /^[1-9]\d*$/.test(segment);
120
-
121
- export const setAtPointer = (
122
- model: unknown,
123
- path: string,
124
- value: unknown,
125
- nullDeletes: boolean,
126
- ): { readonly ok: boolean; readonly value: unknown } => {
127
- const segments = decodePointer(path);
128
- if (!segments) return { ok: false, value: model };
129
- if (segments.length === 0) return { ok: true, value };
130
-
131
- const remove = (current: unknown, index: number): unknown => {
132
- const segment = segments[index]!;
133
- const isLast = index === segments.length - 1;
134
-
135
- if (Array.isArray(current)) {
136
- if (segment !== "-" && !isArrayIndex(segment)) return current;
137
- const targetIndex = segment === "-" ? current.length : Number(segment);
138
- if (isLast) {
139
- if (
140
- segment === "-" ||
141
- !Object.prototype.hasOwnProperty.call(current, targetIndex)
142
- ) {
143
- return current;
144
- }
145
- const clone = current.slice();
146
- // Preserve indices referenced by other JSON Pointers.
147
- delete clone[targetIndex];
148
- return clone;
149
- }
150
- const child = current[targetIndex];
151
- if (!Array.isArray(child) && !isRecord(child)) return current;
152
- const next = remove(child, index + 1);
153
- if (next === child) return current;
154
- const clone = current.slice();
155
- clone[targetIndex] = next;
156
- return clone;
157
- }
158
-
159
- if (!isRecord(current)) return current;
160
- if (!Object.prototype.hasOwnProperty.call(current, segment)) return current;
161
- if (isLast) {
162
- const clone = { ...current };
163
- delete clone[segment];
164
- return clone;
165
- }
166
- const child = current[segment];
167
- if (!Array.isArray(child) && !isRecord(child)) return current;
168
- const next = remove(child, index + 1);
169
- if (next === child) return current;
170
- return { ...current, [segment]: next };
171
- };
172
-
173
- if (nullDeletes && value === null) {
174
- return { ok: true, value: remove(model, 0) };
175
- }
176
-
177
- const update = (current: unknown, index: number): unknown => {
178
- const segment = segments[index]!;
179
- const isLast = index === segments.length - 1;
180
-
181
- if (Array.isArray(current)) {
182
- if (segment !== "-" && !isArrayIndex(segment)) return current;
183
- const targetIndex = segment === "-" ? current.length : Number(segment);
184
- if (
185
- segment !== "-" &&
186
- targetIndex >= current.length &&
187
- targetIndex > MAX_AUTO_VIVIFY_ARRAY_INDEX
188
- ) {
189
- return INVALID_POINTER;
190
- }
191
- const next = isLast ? value : update(current[targetIndex], index + 1);
192
- if (next === INVALID_POINTER) return INVALID_POINTER;
193
- const clone = current.slice();
194
- clone[targetIndex] = next;
195
- return clone;
196
- }
197
-
198
- const record: Record<string, unknown> = isRecord(current) ? current : {};
199
- const child = Object.hasOwn(record, segment) ? record[segment] : undefined;
200
- const next = isLast
201
- ? value
202
- : update(
203
- child ??
204
- (isArrayIndex(segments[index + 1] ?? "") ||
205
- segments[index + 1] === "-"
206
- ? []
207
- : {}),
208
- index + 1,
209
- );
210
- if (next === INVALID_POINTER) return INVALID_POINTER;
211
- return { ...record, [segment]: next };
212
- };
213
-
214
- const result = update(model, 0);
215
- return result === INVALID_POINTER
216
- ? { ok: false, value: model }
217
- : { ok: true, value: result };
218
- };
219
-
220
- const dataModelValue = (
221
- payload: Record<string, unknown>,
222
- ): { readonly found: boolean; readonly value: unknown } => {
223
- for (const key of ["contents", "value", "data"] as const) {
224
- if (payload[key] !== undefined) {
225
- return { found: true, value: payload[key] };
226
- }
227
- }
228
- return { found: false, value: undefined };
229
- };
230
-
231
- export function applyA2uiOperations(
232
- state: A2uiState,
233
- operations: unknown,
234
- ): A2uiOperationResult {
235
- const nextState = new Map(state);
236
- const warnings: string[] = [];
237
-
238
- if (!Array.isArray(operations)) {
239
- return {
240
- state: nextState,
241
- warnings: ["A2UI operations must be an array."],
242
- };
243
- }
244
-
245
- for (let index = 0; index < operations.length; index++) {
246
- try {
247
- const entry = operations[index];
248
- if (!isRecord(entry)) {
249
- warnings.push(`Operation at index ${index} is malformed.`);
250
- continue;
251
- }
252
-
253
- const version = entry["version"];
254
- if (!isVersion(version)) {
255
- warnings.push(
256
- `Operation at index ${index} has an unsupported version.`,
257
- );
258
- continue;
259
- }
260
-
261
- const operationKeys = Object.keys(entry).filter(
262
- (key) => key !== "version",
263
- );
264
- if (operationKeys.length !== 1) {
265
- warnings.push(
266
- `Operation at index ${index} must contain exactly one operation key.`,
267
- );
268
- continue;
269
- }
270
-
271
- const operationKey = operationKeys[0]!;
272
- if (!OPERATION_KEYS.has(operationKey)) {
273
- warnings.push(
274
- `Unknown A2UI operation "${operationKey}" at index ${index}.`,
275
- );
276
- continue;
277
- }
278
-
279
- const payload = entry[operationKey];
280
- if (!isRecord(payload)) {
281
- warnings.push(`Operation at index ${index} has a malformed payload.`);
282
- continue;
283
- }
284
-
285
- const surfaceId = surfaceIdOf(payload);
286
- if (!surfaceId) {
287
- warnings.push(`Operation at index ${index} has no valid surfaceId.`);
288
- continue;
289
- }
290
-
291
- if (operationKey === "createSurface") {
292
- const catalogId = catalogIdOf(payload);
293
- const surface = withSurfaceId(
294
- {
295
- ...(catalogId !== undefined ? { catalogId } : {}),
296
- components: new Map(),
297
- dataModel:
298
- version === "v1.0" && payload["dataModel"] !== undefined
299
- ? payload["dataModel"]
300
- : undefined,
301
- },
302
- surfaceId,
303
- );
304
- if (version === "v1.0" && payload["components"] !== undefined) {
305
- upsertComponents(surface, payload["components"], warnings, index);
306
- }
307
- nextState.set(surfaceId, surface);
308
- continue;
309
- }
310
-
311
- if (operationKey === "deleteSurface") {
312
- nextState.delete(surfaceId);
313
- continue;
314
- }
315
-
316
- const currentSurface = nextState.get(surfaceId);
317
- if (!currentSurface) {
318
- warnings.push(
319
- `Operation at index ${index} references missing surface "${surfaceId}".`,
320
- );
321
- continue;
322
- }
323
- const surface = cloneSurface(currentSurface, surfaceId);
324
-
325
- if (operationKey === "updateComponents") {
326
- upsertComponents(surface, payload["components"], warnings, index);
327
- nextState.set(surfaceId, surface);
328
- continue;
329
- }
330
-
331
- const update = dataModelValue(payload);
332
- if (!update.found) {
333
- warnings.push(`Operation at index ${index} has no data model value.`);
334
- continue;
335
- }
336
- const path = payload["path"] ?? "/";
337
- if (typeof path !== "string") {
338
- warnings.push(
339
- `Operation at index ${index} has a malformed data model path.`,
340
- );
341
- continue;
342
- }
343
- const result = setAtPointer(
344
- surface.dataModel,
345
- path,
346
- update.value,
347
- version === "v1.0",
348
- );
349
- if (!result.ok) {
350
- warnings.push(
351
- `Operation at index ${index} has an invalid JSON Pointer path.`,
352
- );
353
- continue;
354
- }
355
- surface.dataModel = result.value;
356
- nextState.set(surfaceId, surface);
357
- } catch {
358
- warnings.push(`Operation at index ${index} is malformed.`);
359
- }
360
- }
361
-
362
- return { state: nextState, warnings };
363
- }
@@ -1,52 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { surfaceToOperations } from "./snapshot";
3
- import { A2UI_SURFACE_ID, type A2uiSurfaceState } from "./types";
4
-
5
- const surface = (dataModel: unknown): A2uiSurfaceState => ({
6
- components: new Map([["root", { id: "root", component: "Text" }]]),
7
- dataModel,
8
- });
9
-
10
- describe("surfaceToOperations", () => {
11
- it("uses an explicit surface id and omits an undefined data model", () => {
12
- const value = Object.defineProperty(surface(undefined), A2UI_SURFACE_ID, {
13
- value: "stored",
14
- });
15
-
16
- expect(surfaceToOperations(value, "provided")).toEqual([
17
- {
18
- version: "v0.9",
19
- createSurface: { surfaceId: "provided" },
20
- },
21
- {
22
- version: "v0.9",
23
- updateComponents: {
24
- surfaceId: "provided",
25
- components: [{ id: "root", component: "Text" }],
26
- },
27
- },
28
- ]);
29
- });
30
-
31
- it("uses the reducer surface id when no explicit id is supplied", () => {
32
- const value = Object.defineProperty(surface(null), A2UI_SURFACE_ID, {
33
- value: "stored",
34
- });
35
-
36
- expect(surfaceToOperations(value)).toMatchObject([
37
- { createSurface: { surfaceId: "stored" } },
38
- { updateComponents: { surfaceId: "stored" } },
39
- { updateDataModel: { surfaceId: "stored", contents: null } },
40
- ]);
41
- });
42
-
43
- it("requires either an explicit or reducer surface id", () => {
44
- expect(() => surfaceToOperations(surface({}))).toThrow(
45
- "A2UI surfaces must have a surface id to be replayed.",
46
- );
47
- });
48
- it("rejects an empty surface id", () => {
49
- const value = { components: new Map(), dataModel: undefined };
50
- expect(() => surfaceToOperations(value, "")).toThrow();
51
- });
52
- });
@@ -1,52 +0,0 @@
1
- import {
2
- A2UI_SURFACE_ID,
3
- type A2uiSurfaceState,
4
- type A2uiSurfaceSnapshotOperation,
5
- type ComponentNode,
6
- } from "./types";
7
-
8
- const surfaceIdOf = (surface: A2uiSurfaceState): string | undefined =>
9
- (surface as A2uiSurfaceState & { [A2UI_SURFACE_ID]?: string })[
10
- A2UI_SURFACE_ID
11
- ];
12
-
13
- export function surfaceToOperations(
14
- surface: A2uiSurfaceState,
15
- surfaceId?: string,
16
- ): readonly A2uiSurfaceSnapshotOperation[] {
17
- const resolvedSurfaceId = surfaceId ?? surfaceIdOf(surface);
18
- if (!resolvedSurfaceId) {
19
- throw new Error("A2UI surfaces must have a surface id to be replayed.");
20
- }
21
- const operations: A2uiSurfaceSnapshotOperation[] = [
22
- {
23
- version: "v0.9",
24
- createSurface: {
25
- surfaceId: resolvedSurfaceId,
26
- ...(surface.catalogId !== undefined
27
- ? { catalogId: surface.catalogId }
28
- : {}),
29
- },
30
- },
31
- {
32
- version: "v0.9",
33
- updateComponents: {
34
- surfaceId: resolvedSurfaceId,
35
- components: [...surface.components.values()].map((component) => ({
36
- ...component,
37
- })) as ComponentNode[],
38
- },
39
- },
40
- ];
41
- if (surface.dataModel !== undefined) {
42
- operations.push({
43
- version: "v0.9",
44
- updateDataModel: {
45
- surfaceId: resolvedSurfaceId,
46
- path: "/",
47
- contents: surface.dataModel,
48
- },
49
- });
50
- }
51
- return operations;
52
- }
package/src/a2ui/types.ts DELETED
@@ -1,114 +0,0 @@
1
- export const A2UI_SURFACE_ID = Symbol("a2uiSurfaceId");
2
-
3
- export type A2uiVersion = "v0.9" | "v0.9.1" | "v1.0";
4
-
5
- export interface A2uiTemplateChildren {
6
- readonly template: {
7
- readonly componentId: string;
8
- readonly path: string;
9
- };
10
- }
11
-
12
- export interface ComponentNode extends Record<string, unknown> {
13
- readonly id: string;
14
- readonly component: string;
15
- readonly children?:
16
- | readonly string[]
17
- | { readonly componentId: string; readonly path: string }
18
- | A2uiTemplateChildren;
19
- }
20
-
21
- export interface A2uiCreateSurfaceV09Payload {
22
- readonly surfaceId: string;
23
- readonly catalogId?: string;
24
- readonly theme?: unknown;
25
- readonly attachDataModel?: unknown;
26
- }
27
-
28
- export interface A2uiCreateSurfaceV10Payload {
29
- readonly surfaceId: string;
30
- readonly catalogId?: string;
31
- readonly surfaceProperties?: unknown;
32
- readonly sendDataModel?: unknown;
33
- readonly components?: readonly ComponentNode[];
34
- readonly dataModel?: unknown;
35
- }
36
-
37
- export interface A2uiUpdateComponentsPayload {
38
- readonly surfaceId: string;
39
- readonly components: readonly ComponentNode[];
40
- }
41
-
42
- export interface A2uiUpdateDataModelPayload {
43
- readonly surfaceId: string;
44
- readonly path?: string;
45
- readonly contents?: unknown;
46
- readonly value?: unknown;
47
- readonly data?: unknown;
48
- }
49
-
50
- export interface A2uiDeleteSurfacePayload {
51
- readonly surfaceId: string;
52
- }
53
-
54
- export type A2uiCreateSurfaceOperation =
55
- | {
56
- readonly version: "v0.9";
57
- readonly createSurface: A2uiCreateSurfaceV09Payload;
58
- }
59
- | {
60
- readonly version: "v0.9.1";
61
- readonly createSurface: A2uiCreateSurfaceV09Payload;
62
- }
63
- | {
64
- readonly version: "v1.0";
65
- readonly createSurface: A2uiCreateSurfaceV10Payload;
66
- };
67
-
68
- export interface A2uiUpdateComponentsOperation {
69
- readonly version: A2uiVersion;
70
- readonly updateComponents: A2uiUpdateComponentsPayload;
71
- }
72
-
73
- export interface A2uiUpdateDataModelOperation {
74
- readonly version: A2uiVersion;
75
- readonly updateDataModel: A2uiUpdateDataModelPayload;
76
- }
77
-
78
- export interface A2uiDeleteSurfaceOperation {
79
- readonly version: A2uiVersion;
80
- readonly deleteSurface: A2uiDeleteSurfacePayload;
81
- }
82
-
83
- export type A2uiOperation =
84
- | A2uiCreateSurfaceOperation
85
- | A2uiUpdateComponentsOperation
86
- | A2uiUpdateDataModelOperation
87
- | A2uiDeleteSurfaceOperation;
88
-
89
- export type A2uiSurfaceSnapshotOperation =
90
- | {
91
- readonly version: "v0.9";
92
- readonly createSurface: A2uiCreateSurfaceV09Payload;
93
- }
94
- | {
95
- readonly version: "v0.9";
96
- readonly updateComponents: A2uiUpdateComponentsPayload;
97
- }
98
- | {
99
- readonly version: "v0.9";
100
- readonly updateDataModel: A2uiUpdateDataModelPayload;
101
- };
102
-
103
- export type A2uiSurfaceState = {
104
- catalogId?: string;
105
- components: Map<string, Record<string, unknown>>;
106
- dataModel: unknown;
107
- };
108
-
109
- export type A2uiState = ReadonlyMap<string, A2uiSurfaceState>;
110
-
111
- export interface A2uiOperationResult {
112
- readonly state: A2uiState;
113
- readonly warnings: string[];
114
- }