@neta-art/cohub 12.2.0 → 12.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +87 -3
  2. package/dist/board/editor/context.d.ts +2 -0
  3. package/dist/board/editor/document.d.ts +3 -1
  4. package/dist/board/editor/document.js +8 -6
  5. package/dist/board/editor/editor.d.ts +7 -3
  6. package/dist/board/editor/editor.js +8 -1
  7. package/dist/board/editor/index.d.ts +3 -3
  8. package/dist/board/editor/index.js +2 -2
  9. package/dist/board/editor/interaction.d.ts +23 -2
  10. package/dist/board/editor/interaction.js +99 -5
  11. package/dist/board/editor/query.d.ts +1 -1
  12. package/dist/board/editor/query.js +3 -7
  13. package/dist/board/editor/selection.js +13 -1
  14. package/dist/board/editor/tool.d.ts +4 -1
  15. package/dist/board/editor/tool.js +6 -1
  16. package/dist/board/model/asset-key.d.ts +9 -1
  17. package/dist/board/model/asset-key.js +27 -7
  18. package/dist/board/model/index.d.ts +5 -5
  19. package/dist/board/model/index.js +4 -4
  20. package/dist/board/model/items/create.js +1 -1
  21. package/dist/board/model/items/definition.d.ts +9 -1
  22. package/dist/board/model/items/index.d.ts +2 -2
  23. package/dist/board/model/items/registry.d.ts +2 -1
  24. package/dist/board/model/items/registry.js +1 -0
  25. package/dist/board/model/text-metrics.d.ts +21 -1
  26. package/dist/board/model/text-metrics.js +24 -1
  27. package/dist/board/model/themes.d.ts +49 -42
  28. package/dist/board/model/themes.js +49 -44
  29. package/dist/board/render/index.d.ts +8 -6
  30. package/dist/board/render/index.js +7 -5
  31. package/dist/board/render/labels.d.ts +15 -0
  32. package/dist/board/render/labels.js +14 -0
  33. package/dist/board/render/lod.d.ts +9 -1
  34. package/dist/board/render/lod.js +7 -1
  35. package/dist/board/render/media-interaction.d.ts +5 -2
  36. package/dist/board/render/media-interaction.js +14 -2
  37. package/dist/board/render/renderers/arrow-card-renderer.js +7 -5
  38. package/dist/board/render/renderers/board-renderer-registry.d.ts +12 -1
  39. package/dist/board/render/renderers/board-renderer-registry.js +9 -4
  40. package/dist/board/render/renderers/far-plate.d.ts +4 -1
  41. package/dist/board/render/renderers/far-plate.js +5 -1
  42. package/dist/board/render/renderers/file-card-renderer.js +44 -24
  43. package/dist/board/render/renderers/frame-card-renderer.js +9 -3
  44. package/dist/board/render/renderers/image-card-renderer.js +2 -2
  45. package/dist/board/render/renderers/model-card-renderer.js +2 -2
  46. package/dist/board/render/renderers/task-card-renderer.js +2 -2
  47. package/dist/board/render/renderers/video-card-renderer.js +2 -2
  48. package/dist/board/render/style.d.ts +1 -0
  49. package/dist/board/render/style.js +3 -1
  50. package/dist/board/render/text-edit.d.ts +32 -0
  51. package/dist/board/render/text-edit.js +134 -0
  52. package/dist/board/render/text-fit.d.ts +1 -3
  53. package/dist/board/render/text-fit.js +4 -43
  54. package/dist/board/render/text-measurement.d.ts +12 -2
  55. package/dist/board/render/text-measurement.js +55 -10
  56. package/dist/board/replica/index.d.ts +4 -2
  57. package/dist/board/replica/index.js +34 -21
  58. package/dist/board/replica/indexeddb.d.ts +16 -0
  59. package/dist/board/replica/indexeddb.js +155 -0
  60. package/dist/board/stage/assets.d.ts +16 -4
  61. package/dist/board/stage/assets.js +155 -30
  62. package/dist/board/stage/bench.d.ts +35 -0
  63. package/dist/board/stage/bench.js +153 -0
  64. package/dist/board/stage/device.d.ts +41 -0
  65. package/dist/board/stage/device.js +62 -0
  66. package/dist/board/stage/frame-budget.d.ts +19 -0
  67. package/dist/board/stage/frame-budget.js +69 -0
  68. package/dist/board/stage/idle.d.ts +4 -0
  69. package/dist/board/stage/idle.js +26 -0
  70. package/dist/board/stage/index.d.ts +9 -5
  71. package/dist/board/stage/index.js +5 -2
  72. package/dist/board/stage/presses.d.ts +21 -0
  73. package/dist/board/stage/presses.js +66 -0
  74. package/dist/board/stage/scene.d.ts +4 -0
  75. package/dist/board/stage/scene.js +45 -13
  76. package/dist/board/stage/stage.d.ts +21 -2
  77. package/dist/board/stage/stage.js +309 -89
  78. package/dist/board/stage/texture-pool.d.ts +6 -4
  79. package/dist/board/stage/texture-pool.js +42 -8
  80. package/dist/board/stage/views.d.ts +1 -1
  81. package/dist/board/stage/views.js +2 -2
  82. package/dist/chunks/environment.d.ts +6 -0
  83. package/dist/chunks/http.d.ts +9 -1
  84. package/dist/chunks/http.js +791 -4
  85. package/dist/index.d.ts +52 -1
  86. package/dist/index.js +65 -733
  87. package/dist/protocol/dist/board-model.d.ts +15 -1
  88. package/dist/protocol/dist/board-model.js +12 -2
  89. package/dist/protocol/dist/board-schema.d.ts +2 -1
  90. package/dist/protocol/dist/board-schema.js +4 -1
  91. package/dist/protocol/dist/core/media.js +4 -0
  92. package/dist/protocol/dist/index.d.ts +2 -2
  93. package/package.json +2 -1
@@ -1,6 +1,768 @@
1
1
  import { S as getRealtimeSpaceRoom, c as HttpError, l as HttpTransport, s as isHttpErrorCode, x as getRealtimeBoardRoom, z as isUuid } from "./http-error.js";
2
2
  import { l as resolveExecutionToken, o as resolveApiBaseUrl } from "./environment.js";
3
3
  import { z } from "zod";
4
+ //#region ../protocol/dist/board-constants.js
5
+ const BOARD_ARROW_STROKE_SIZE = 2.5;
6
+ const BOARD_DEFAULT_ITEM_SIZE = {
7
+ width: 240,
8
+ height: 160
9
+ };
10
+ const BOARD_DEFAULT_SIZES = {
11
+ frame: {
12
+ width: 480,
13
+ height: 320
14
+ },
15
+ shape: {
16
+ width: 200,
17
+ height: 140
18
+ },
19
+ image: {
20
+ width: 480,
21
+ height: 270
22
+ },
23
+ video: {
24
+ width: 480,
25
+ height: 270
26
+ },
27
+ audio: {
28
+ width: 320,
29
+ height: 112
30
+ },
31
+ file: {
32
+ width: 260,
33
+ height: 132
34
+ },
35
+ task: {
36
+ width: 480,
37
+ height: 270
38
+ },
39
+ effect: {
40
+ width: 240,
41
+ height: 240
42
+ },
43
+ custom: {
44
+ width: 480,
45
+ height: 320
46
+ }
47
+ };
48
+ function boardDefaultSize(type) {
49
+ return { ...Object.hasOwn(BOARD_DEFAULT_SIZES, type) ? BOARD_DEFAULT_SIZES[type] : BOARD_DEFAULT_ITEM_SIZE };
50
+ }
51
+ //#endregion
52
+ //#region ../protocol/dist/board-url.js
53
+ const BOARD_REMOTE_URL_MAX_LENGTH = 4096;
54
+ function parseIpv4(host) {
55
+ const parts = host.split(".").map(Number);
56
+ return parts.length === 4 && parts.every((part) => Number.isInteger(part) && part >= 0 && part <= 255) ? parts : null;
57
+ }
58
+ function isBlockedIpv4(host) {
59
+ const parts = parseIpv4(host);
60
+ if (!parts) return false;
61
+ const [first, second, third] = parts;
62
+ if (first === 0 || first === 10 || first === 127) return true;
63
+ if (first === 100 && second >= 64 && second <= 127) return true;
64
+ if (first === 169 && second === 254) return true;
65
+ if (first === 172 && second >= 16 && second <= 31) return true;
66
+ if (first === 192 && second === 168) return true;
67
+ if (first === 192 && second === 0 && (third === 0 || third === 2)) return true;
68
+ if (first === 192 && second === 88 && third === 99) return true;
69
+ if (first === 198 && (second === 18 || second === 19)) return true;
70
+ if (first === 198 && second === 51 && third === 100) return true;
71
+ if (first === 203 && second === 0 && third === 113) return true;
72
+ return first >= 224;
73
+ }
74
+ function expandIpv6(host) {
75
+ const [head, tail, extra] = host.toLowerCase().split("::");
76
+ if (extra !== void 0) return null;
77
+ const headParts = head ? head.split(":").filter(Boolean) : [];
78
+ const tailParts = tail ? tail.split(":").filter(Boolean) : [];
79
+ const missing = 8 - headParts.length - tailParts.length;
80
+ if (missing < 0 || tail === void 0 && missing !== 0) return null;
81
+ const parts = [
82
+ ...headParts,
83
+ ...Array.from({ length: missing }, () => "0"),
84
+ ...tailParts
85
+ ];
86
+ if (parts.length !== 8 || parts.some((part) => !/^[0-9a-f]{1,4}$/.test(part))) return null;
87
+ return parts.map((part) => part.padStart(4, "0"));
88
+ }
89
+ function isBlockedIpv6(host) {
90
+ const parts = expandIpv6(host);
91
+ if (!parts) return true;
92
+ if (parts.every((part) => part === "0000")) return true;
93
+ if (parts.slice(0, 7).every((part) => part === "0000") && parts[7] === "0001") return true;
94
+ if (parts.slice(0, 5).every((part) => part === "0000") && parts[5] === "ffff") {
95
+ const high = Number.parseInt(parts[6] ?? "0", 16);
96
+ const low = Number.parseInt(parts[7] ?? "0", 16);
97
+ return isBlockedIpv4(`${high >> 8}.${high & 255}.${low >> 8}.${low & 255}`);
98
+ }
99
+ if (parts.slice(0, 6).every((part) => part === "0000")) return true;
100
+ const first = Number.parseInt(parts[0] ?? "0", 16);
101
+ if ((first & 65024) === 64512) return true;
102
+ if ((first & 65472) === 65152 || (first & 65472) === 65216) return true;
103
+ if ((first & 65280) === 65280) return true;
104
+ return parts[0] === "2001" && parts[1] === "0db8";
105
+ }
106
+ function isPublicBoardRemoteAddress(value) {
107
+ const address = value.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
108
+ if (parseIpv4(address)) return !isBlockedIpv4(address);
109
+ return address.includes(":") && !isBlockedIpv6(address);
110
+ }
111
+ function isBlockedHost(hostname) {
112
+ const host = hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
113
+ if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host.endsWith(".internal")) return true;
114
+ if (parseIpv4(host) || host.includes(":")) return !isPublicBoardRemoteAddress(host);
115
+ return false;
116
+ }
117
+ /**
118
+ * Normalize a browser-loadable public HTTP(S) URL. This blocks explicit local
119
+ * addresses; any future server-side fetcher must additionally validate DNS
120
+ * resolution to defend against rebinding.
121
+ */
122
+ function normalizeBoardRemoteUrl(value) {
123
+ if (typeof value !== "string") return void 0;
124
+ const input = value.trim();
125
+ if (!input || input.length > 4096) return void 0;
126
+ try {
127
+ const url = new URL(input);
128
+ if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
129
+ if (url.username || url.password || isBlockedHost(url.hostname)) return;
130
+ const normalized = url.toString();
131
+ return normalized.length <= 4096 ? normalized : void 0;
132
+ } catch {
133
+ return;
134
+ }
135
+ }
136
+ z.string().max(BOARD_REMOTE_URL_MAX_LENGTH).refine((value) => normalizeBoardRemoteUrl(value) !== void 0, { message: "URL must be a public HTTP(S) URL without credentials" });
137
+ const BOARD_CAMERA_TARGET = "camera";
138
+ const BoardKeySchema = z.string().min(1).max(160).regex(/^[^\s/]+$/, "ids must not contain whitespace or '/'");
139
+ const BoardIdSchema = BoardKeySchema.refine((value) => value !== BOARD_CAMERA_TARGET, "\"camera\" is reserved");
140
+ const finite = z.number().finite();
141
+ const nonNegative = finite.nonnegative();
142
+ const ratio = finite.min(0).max(1);
143
+ const BoardVec2Schema = z.object({
144
+ x: finite,
145
+ y: finite
146
+ }).strict();
147
+ const BoardSizeSchema = z.object({
148
+ width: finite.positive(),
149
+ height: finite.positive()
150
+ }).strict();
151
+ const BOARD_COLOR_TOKENS = [
152
+ "brand",
153
+ "neutral",
154
+ "black",
155
+ "white",
156
+ "blue",
157
+ "green",
158
+ "amber",
159
+ "violet",
160
+ "rose"
161
+ ];
162
+ const CSS_NAMED_COLORS = new Set("transparent aliceblue antiquewhite aqua aquamarine azure beige bisque blanchedalmond blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray grey greenyellow honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat whitesmoke yellow yellowgreen".split(" "));
163
+ function isBoardColorString(value) {
164
+ const color = value.trim().toLowerCase();
165
+ return BOARD_COLOR_TOKENS.includes(color) || CSS_NAMED_COLORS.has(color) || /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(color) || /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\([^()]*\)$/.test(color);
166
+ }
167
+ const colorString = z.string().max(120).refine(isBoardColorString, "expected a palette token or a CSS color");
168
+ const BoardColorSchema = z.union([colorString, z.object({
169
+ light: colorString,
170
+ dark: colorString
171
+ }).strict()]).describe("Palette token (follows the theme), CSS color, or { light, dark }.");
172
+ const BoardStyleSchema = z.object({
173
+ fill: BoardColorSchema.optional(),
174
+ fillOpacity: ratio.optional().describe("Fill opacity, independent of the item's opacity."),
175
+ stroke: BoardColorSchema.optional(),
176
+ strokeWidth: finite.min(0).max(64).optional(),
177
+ dash: z.enum([
178
+ "solid",
179
+ "dashed",
180
+ "dotted"
181
+ ]).optional(),
182
+ radius: nonNegative.optional().describe("Corner radius in board units."),
183
+ trim: ratio.optional().describe("Fraction of the outline drawn; animate 0 → 1 to draw it in.")
184
+ }).strict();
185
+ function isSafeBoardSourcePath(value) {
186
+ return value.length > 0 && value.length <= 4096 && !value.startsWith("/") && !/^[a-z][a-z\d+.-]*:/i.test(value.trimStart()) && !value.includes("\\") && value.split("/").every((part) => part.length > 0 && part !== "." && part !== "..");
187
+ }
188
+ const srcSchema = z.string().refine(isSafeBoardSourcePath, "src must be a relative Space file path");
189
+ function parseBoardMediaSource(src) {
190
+ if (isSafeBoardSourcePath(src)) return {
191
+ kind: "file",
192
+ value: src
193
+ };
194
+ return normalizeBoardRemoteUrl(src) ? {
195
+ kind: "url",
196
+ value: src
197
+ } : null;
198
+ }
199
+ const BoardMediaSourceSchema = z.string().max(4096).refine((src) => parseBoardMediaSource(src) !== null, "src must be a public HTTP(S) URL or relative Space file path").describe("Prefer a public HTTP(S) URL; a Space path relative to the workspace root also works.");
200
+ const BoardScriptSchema = z.object({
201
+ src: srcSchema.refine((path) => /\.m?js$/.test(path), "script src must be a .js or .mjs module").describe("A .js or .mjs Space file."),
202
+ params: z.record(z.string(), z.json()).default({}).describe("Values the module reads as params."),
203
+ targets: z.record(z.string().min(1).max(80), BoardIdSchema).default({}).describe("Named items the module can reach, as ctx.targets."),
204
+ seed: z.string().min(1).max(160).optional().describe("Seed for ctx.random(); defaults to the item id."),
205
+ enabled: z.boolean().default(true)
206
+ }).strict().describe("A JavaScript module attached to the item; `cohub boards schema script` lists its API.");
207
+ const itemEnvelope = {
208
+ script: BoardScriptSchema.optional(),
209
+ parent: BoardIdSchema.optional().describe("A frame id; position becomes relative to the frame, and the item moves with it."),
210
+ z: finite.optional().describe("Order among siblings; new items go on top."),
211
+ position: BoardVec2Schema.default({
212
+ x: 0,
213
+ y: 0
214
+ }),
215
+ rotation: finite.default(0),
216
+ scale: z.union([finite, BoardVec2Schema]).default(1),
217
+ origin: BoardVec2Schema.default({
218
+ x: .5,
219
+ y: .5
220
+ }).describe("Rotation and scale origin as fractions of the size."),
221
+ opacity: ratio.default(1),
222
+ style: BoardStyleSchema.default({}),
223
+ locked: z.boolean().optional(),
224
+ metadata: z.record(z.string(), z.unknown()).optional()
225
+ };
226
+ const boxed = (size) => ({
227
+ ...itemEnvelope,
228
+ size: BoardSizeSchema.default({ ...size })
229
+ });
230
+ const unsized = { ...itemEnvelope };
231
+ const fontSize = finite.min(2).max(512);
232
+ const BOARD_TEXT_ALIGNS = [
233
+ "left",
234
+ "center",
235
+ "right"
236
+ ];
237
+ const BOARD_SHAPE_GEOMETRIES = [
238
+ "rectangle",
239
+ "rounded",
240
+ "ellipse",
241
+ "diamond",
242
+ "triangle",
243
+ "path"
244
+ ];
245
+ const BoardFrameItemSchema = z.object({
246
+ ...boxed(BOARD_DEFAULT_SIZES.frame),
247
+ type: z.literal("frame"),
248
+ props: z.object({
249
+ label: z.string().max(280).default(""),
250
+ decoration: z.enum(["frame", "none"]).optional().describe("none hides the title, border and background: an invisible group whose tracks move every child."),
251
+ clip: z.boolean().default(true).describe("Hide children outside the frame.")
252
+ }).strict().prefault({})
253
+ }).strict();
254
+ const BoardTextItemSchema = z.object({
255
+ ...unsized,
256
+ type: z.literal("text"),
257
+ props: z.object({
258
+ text: z.string().default(""),
259
+ fontSize: fontSize.default(24),
260
+ fontWeight: finite.min(100).max(900).default(500),
261
+ font: z.string().min(1).max(120).default("sans").describe("sans, serif, mono, or a font family name."),
262
+ align: z.enum(BOARD_TEXT_ALIGNS).default("left"),
263
+ lineHeight: finite.min(.5).max(4).default(4 / 3),
264
+ width: finite.positive().optional().describe("Wrap width; the height follows the text."),
265
+ reveal: ratio.default(1).describe("Fraction of the text shown; animate 0 → 1 to type it."),
266
+ caret: z.boolean().default(false).describe("Blink a caret while the text is being revealed.")
267
+ }).strict().prefault({})
268
+ }).strict();
269
+ const BoardShapeItemSchema = z.object({
270
+ ...boxed(BOARD_DEFAULT_SIZES.shape),
271
+ type: z.literal("shape"),
272
+ props: z.object({
273
+ geometry: z.enum(BOARD_SHAPE_GEOMETRIES).default("rectangle"),
274
+ path: z.string().min(1).max(2e5).optional().describe("SVG path data for path geometry, fitted to the item size."),
275
+ text: z.string().default(""),
276
+ fontSize: fontSize.default(20),
277
+ align: z.enum(BOARD_TEXT_ALIGNS).default("center")
278
+ }).strict().refine((props) => props.geometry !== "path" || Boolean(props.path), {
279
+ message: "path geometry requires props.path",
280
+ path: ["path"]
281
+ }).prefault({})
282
+ }).strict();
283
+ const BoardDrawPointSchema = z.object({
284
+ x: finite,
285
+ y: finite,
286
+ p: ratio.default(.5).describe("Pen pressure.")
287
+ }).strict();
288
+ const BoardDrawItemSchema = z.object({
289
+ ...unsized,
290
+ type: z.literal("draw"),
291
+ props: z.object({ points: z.array(BoardDrawPointSchema).min(1).max(1e5).describe("Stroke points relative to position; the size follows them.") }).strict()
292
+ }).strict();
293
+ const BoardArrowAnchorSchema = z.union([
294
+ z.literal("auto"),
295
+ z.object({
296
+ side: z.enum([
297
+ "top",
298
+ "right",
299
+ "bottom",
300
+ "left"
301
+ ]),
302
+ offset: ratio.default(.5)
303
+ }).strict(),
304
+ z.object({
305
+ x: ratio,
306
+ y: ratio
307
+ }).strict()
308
+ ]);
309
+ const BoardArrowBindingSchema = z.object({
310
+ item: BoardIdSchema,
311
+ anchor: BoardArrowAnchorSchema.default("auto").describe("auto uses the side facing the other end; or a side with an offset, or a point as fractions of the item."),
312
+ port: z.string().min(1).max(120).optional()
313
+ }).strict();
314
+ const BoardArrowEndSchema = z.union([BoardVec2Schema, BoardArrowBindingSchema]).describe("A point relative to position, or { item } to follow that item.");
315
+ const BOARD_ARROW_ROUTES = [
316
+ "straight",
317
+ "curve",
318
+ "orthogonal"
319
+ ];
320
+ const BoardArrowItemSchema = z.object({
321
+ ...unsized,
322
+ type: z.literal("arrow"),
323
+ props: z.object({
324
+ start: BoardArrowEndSchema,
325
+ end: BoardArrowEndSchema,
326
+ route: z.enum(BOARD_ARROW_ROUTES).default("straight"),
327
+ bend: finite.min(-.85).max(.85).default(0).describe("Sideways curve as a fraction of the length; the sign picks the side."),
328
+ waypoints: z.array(BoardVec2Schema).max(64).default([]).describe("Points the route passes through."),
329
+ arrowStart: z.boolean().default(false),
330
+ arrowEnd: z.boolean().default(true),
331
+ label: z.string().max(280).default(""),
332
+ fontSize: fontSize.default(14),
333
+ relation: z.string().max(64).regex(/^[a-z0-9]+(?:[.-][a-z0-9]+)*$/, "relation must be a lowercase slug").optional().describe("What the arrow means, as a slug such as triggers or depends-on.")
334
+ }).strict()
335
+ }).strict();
336
+ const fileProps = {
337
+ src: BoardMediaSourceSchema,
338
+ snapshot: z.object({
339
+ title: z.string().optional(),
340
+ mimeType: z.string().optional(),
341
+ size: nonNegative.optional(),
342
+ mtimeMs: nonNegative.optional(),
343
+ naturalWidth: finite.positive().optional(),
344
+ naturalHeight: finite.positive().optional(),
345
+ durationMs: nonNegative.optional(),
346
+ excerpt: z.string().optional(),
347
+ coverPath: z.string().optional(),
348
+ coverUrl: z.string().optional()
349
+ }).strict().describe("Cached facts for an instant preview; filled in when the media loads.").optional()
350
+ };
351
+ const BoardMediaOriginSchema = z.object({
352
+ taskRunId: z.string().min(1).max(160),
353
+ artifactId: z.string().min(1).max(240)
354
+ }).strict().describe("The generation run and result this media came from.");
355
+ const mediaProps = {
356
+ ...fileProps,
357
+ origin: BoardMediaOriginSchema.optional()
358
+ };
359
+ const timedFileProps = {
360
+ ...mediaProps,
361
+ time: nonNegative.optional().describe("Playback position in milliseconds; animate props.time to play it on a timeline.")
362
+ };
363
+ const BoardCropSchema = z.object({
364
+ x: ratio,
365
+ y: ratio,
366
+ w: ratio,
367
+ h: ratio
368
+ }).strict().describe("Region shown, as fractions of the image. Without it the whole image fits inside size.");
369
+ const BoardImageItemSchema = z.object({
370
+ ...boxed(BOARD_DEFAULT_SIZES.image),
371
+ type: z.literal("image"),
372
+ props: z.object({
373
+ ...mediaProps,
374
+ crop: BoardCropSchema.optional()
375
+ }).strict()
376
+ }).strict();
377
+ const BoardVideoItemSchema = z.object({
378
+ ...boxed(BOARD_DEFAULT_SIZES.video),
379
+ type: z.literal("video"),
380
+ props: z.object(timedFileProps).strict()
381
+ }).strict();
382
+ const BoardAudioItemSchema = z.object({
383
+ ...boxed(BOARD_DEFAULT_SIZES.audio),
384
+ type: z.literal("audio"),
385
+ props: z.object(timedFileProps).strict()
386
+ }).strict();
387
+ const BoardFileItemSchema = z.object({
388
+ ...boxed(BOARD_DEFAULT_SIZES.file),
389
+ type: z.literal("file"),
390
+ props: z.object(fileProps).strict()
391
+ }).strict();
392
+ const httpsUrl = z.string().max(4096).url();
393
+ const artifactBase = {
394
+ id: z.string().min(1).max(240),
395
+ title: z.string().max(240).optional(),
396
+ url: httpsUrl,
397
+ mimeType: z.string().max(160).optional()
398
+ };
399
+ const BoardTaskArtifactSchema = z.discriminatedUnion("type", [
400
+ z.object({
401
+ ...artifactBase,
402
+ type: z.literal("image"),
403
+ naturalWidth: finite.positive().optional(),
404
+ naturalHeight: finite.positive().optional()
405
+ }).strict(),
406
+ z.object({
407
+ ...artifactBase,
408
+ type: z.literal("video"),
409
+ previewUrl: httpsUrl.optional(),
410
+ durationMs: z.number().int().positive().optional(),
411
+ naturalWidth: finite.positive().optional(),
412
+ naturalHeight: finite.positive().optional()
413
+ }).strict(),
414
+ z.object({
415
+ ...artifactBase,
416
+ type: z.literal("audio"),
417
+ previewUrl: httpsUrl.optional(),
418
+ durationMs: z.number().int().positive().optional()
419
+ }).strict(),
420
+ z.object({
421
+ id: z.string().min(1).max(240),
422
+ type: z.literal("text"),
423
+ title: z.string().max(240).optional(),
424
+ textExcerpt: z.string().min(1).max(480)
425
+ }).strict()
426
+ ]);
427
+ const BoardTaskSnapshotSchema = z.object({
428
+ taskType: z.string().min(1).max(120),
429
+ status: z.enum([
430
+ "pending",
431
+ "running",
432
+ "completed",
433
+ "failed"
434
+ ]),
435
+ title: z.string().min(1).max(240),
436
+ model: z.string().max(160).optional(),
437
+ promptExcerpt: z.string().max(480).optional(),
438
+ errorExcerpt: z.string().max(240).optional(),
439
+ artifactCount: z.number().int().nonnegative(),
440
+ artifacts: z.array(BoardTaskArtifactSchema).max(6).default([]),
441
+ startedAt: z.string().max(64).optional(),
442
+ updatedAt: z.string().optional()
443
+ }).strict();
444
+ const BoardTaskItemSchema = z.object({
445
+ ...boxed(BOARD_DEFAULT_SIZES.task),
446
+ type: z.literal("task"),
447
+ props: z.object({
448
+ taskRunId: z.string().min(1).max(160).describe("The generation run shown; the server keeps the card's status and results up to date."),
449
+ snapshot: BoardTaskSnapshotSchema.describe("Maintained by the server; omit it.")
450
+ }).strict()
451
+ }).strict();
452
+ const BOARD_EFFECT_KINDS = [
453
+ "particles",
454
+ "trail",
455
+ "impact",
456
+ "flash",
457
+ "glow"
458
+ ];
459
+ const BoardEffectItemSchema = z.object({
460
+ ...boxed(BOARD_DEFAULT_SIZES.effect),
461
+ type: z.literal("effect"),
462
+ props: z.object({
463
+ kind: z.enum(BOARD_EFFECT_KINDS),
464
+ rate: nonNegative.max(2e4).default(40),
465
+ life: finite.positive().max(6e4).default(1200),
466
+ particleSize: finite.positive().max(512).default(6),
467
+ speed: nonNegative.max(1e4).default(120),
468
+ direction: finite.default(-90),
469
+ spread: finite.min(0).max(360).default(360),
470
+ gravity: finite.default(0),
471
+ intensity: nonNegative.max(10).default(1),
472
+ follow: BoardIdSchema.optional().describe("trail: the item to follow."),
473
+ seed: z.string().min(1).max(160).optional().describe("Makes procedural motion repeatable.")
474
+ }).strict()
475
+ }).strict();
476
+ const BoardCustomItemSchema = z.object({
477
+ ...boxed(BOARD_DEFAULT_SIZES.custom),
478
+ type: z.literal("custom"),
479
+ script: BoardScriptSchema,
480
+ props: z.object({}).strict().default({})
481
+ }).strict();
482
+ const BOARD_EXTENSION_TYPE_PATTERN = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
483
+ const BoardItemPreviewSchema = z.object({
484
+ title: z.string().max(500).optional(),
485
+ excerpt: z.string().max(2e3).optional(),
486
+ cover: BoardMediaSourceSchema.optional().describe("An image for the card."),
487
+ src: BoardMediaSourceSchema.optional().describe("The file or page the card stands for.")
488
+ }).strict().describe("How a client without this type's renderer shows the card, and what it refers to. The type's own client keeps it current.");
489
+ const BoardExtensionItemSchema = z.object({
490
+ ...boxed(BOARD_DEFAULT_ITEM_SIZE),
491
+ type: z.string().regex(BOARD_EXTENSION_TYPE_PATTERN),
492
+ props: z.record(z.string(), z.unknown()).default({}),
493
+ preview: BoardItemPreviewSchema.optional()
494
+ }).strict();
495
+ const BOARD_ITEM_SCHEMAS = {
496
+ frame: BoardFrameItemSchema,
497
+ text: BoardTextItemSchema,
498
+ shape: BoardShapeItemSchema,
499
+ draw: BoardDrawItemSchema,
500
+ arrow: BoardArrowItemSchema,
501
+ image: BoardImageItemSchema,
502
+ video: BoardVideoItemSchema,
503
+ audio: BoardAudioItemSchema,
504
+ file: BoardFileItemSchema,
505
+ task: BoardTaskItemSchema,
506
+ effect: BoardEffectItemSchema,
507
+ custom: BoardCustomItemSchema
508
+ };
509
+ const BOARD_ITEM_TYPES = Object.keys(BOARD_ITEM_SCHEMAS);
510
+ function isBuiltinItemType(type) {
511
+ return Object.hasOwn(BOARD_ITEM_SCHEMAS, type);
512
+ }
513
+ function boardItemSchema(type) {
514
+ if (isBuiltinItemType(type)) return BOARD_ITEM_SCHEMAS[type];
515
+ return BOARD_EXTENSION_TYPE_PATTERN.test(type) ? BoardExtensionItemSchema : null;
516
+ }
517
+ function issuesToDiagnostics(error, path) {
518
+ return error.issues.map((issue) => {
519
+ return {
520
+ severity: "error",
521
+ code: "INVALID_ITEM",
522
+ path: [path, ...issue.path.map(String)].filter(Boolean).join("."),
523
+ message: issue.code === "unrecognized_keys" ? `unknown ${issue.keys.length === 1 ? "property" : "properties"} ${issue.keys.join(", ")}` : issue.message
524
+ };
525
+ });
526
+ }
527
+ function parseBoardItem(value, path = "item") {
528
+ const type = value && typeof value === "object" && !Array.isArray(value) ? value.type : void 0;
529
+ if (typeof type !== "string") return {
530
+ ok: false,
531
+ diagnostics: [{
532
+ severity: "error",
533
+ code: "INVALID_ITEM",
534
+ path: `${path}.type`,
535
+ message: "type is required"
536
+ }]
537
+ };
538
+ const schema = boardItemSchema(type);
539
+ if (!schema) return {
540
+ ok: false,
541
+ diagnostics: [{
542
+ severity: "error",
543
+ code: "INVALID_ITEM",
544
+ path: `${path}.type`,
545
+ message: `unknown type ${type}; expected ${BOARD_ITEM_TYPES.join(", ")} or a namespaced extension type`
546
+ }]
547
+ };
548
+ const parsed = schema.safeParse(value);
549
+ return parsed.success ? {
550
+ ok: true,
551
+ item: parsed.data
552
+ } : {
553
+ ok: false,
554
+ diagnostics: issuesToDiagnostics(parsed.error, path)
555
+ };
556
+ }
557
+ const CSS_EASE_KEYWORDS = /* @__PURE__ */ new Set([
558
+ "linear",
559
+ "ease",
560
+ "ease-in",
561
+ "ease-out",
562
+ "ease-in-out",
563
+ "step-start",
564
+ "step-end"
565
+ ]);
566
+ function isBoardEase(value) {
567
+ const ease = value.trim();
568
+ if (CSS_EASE_KEYWORDS.has(ease)) return true;
569
+ const bezier = /^cubic-bezier\(\s*([^,()]+),\s*([^,()]+),\s*([^,()]+),\s*([^,()]+)\)$/.exec(ease);
570
+ if (bezier) {
571
+ const [x1, , x2] = bezier.slice(1).map(Number);
572
+ return bezier.slice(1).every((part) => Number.isFinite(Number(part))) && x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1;
573
+ }
574
+ return /^steps\(\s*[1-9]\d*\s*(?:,\s*(?:start|end|jump-start|jump-end|jump-none|jump-both)\s*)?\)$/.test(ease);
575
+ }
576
+ const BoardEaseSchema = z.string().max(120).refine(isBoardEase, "expected a CSS easing: linear, ease-in-out, cubic-bezier(…) or steps(…)");
577
+ const BoardKeyframeSchema = z.object({
578
+ at: nonNegative.describe("Time in milliseconds."),
579
+ value: z.unknown(),
580
+ ease: BoardEaseSchema.optional().describe("Easing into this keyframe: a CSS keyword, cubic-bezier() or steps(); defaults to linear.")
581
+ }).strict();
582
+ const BoardTrackSchema = z.object({
583
+ target: z.string().min(1).max(160).describe("An item id, camera, or another animation id (its time property nests that timeline)."),
584
+ property: z.string().min(1).max(200).describe("JSON path in the target, e.g. position, opacity, style.fill, props.text."),
585
+ keyframes: z.array(BoardKeyframeSchema).min(1).max(1e5).describe("Ordered by at. The value holds before the first and after the last keyframe."),
586
+ composite: z.enum(["replace", "add"]).default("replace").describe("replace: the latest-started track wins. add: positions and rotations add; scale and opacity multiply."),
587
+ interpolation: z.enum([
588
+ "auto",
589
+ "step",
590
+ "spline"
591
+ ]).default("auto").describe("auto blends numbers, vectors and colors and steps other values; spline smooths position paths."),
592
+ orient: z.boolean().optional().describe("Rotate the item along its path.")
593
+ }).strict().superRefine((track, context) => {
594
+ for (let index = 1; index < track.keyframes.length; index += 1) if ((track.keyframes[index]?.at ?? 0) < (track.keyframes[index - 1]?.at ?? 0)) context.addIssue({
595
+ code: "custom",
596
+ message: "keyframes must be ordered by at",
597
+ path: [
598
+ "keyframes",
599
+ index,
600
+ "at"
601
+ ]
602
+ });
603
+ });
604
+ const BoardMarkerSchema = z.object({
605
+ at: nonNegative,
606
+ label: z.string().max(280).optional(),
607
+ pause: z.boolean().optional().describe("Hold shared playback here until next.")
608
+ }).strict();
609
+ const BoardAnimationHeaderSchema = z.object({
610
+ name: z.string().max(280).optional(),
611
+ duration: finite.positive().max(864e5).describe("Milliseconds; a new animation without it ends at its last keyframe."),
612
+ play: z.enum([
613
+ "manual",
614
+ "auto",
615
+ "always"
616
+ ]).default("manual").describe("manual: only shared playback starts it. auto: plays when the Board opens. always: loops continuously."),
617
+ delay: nonNegative.default(0),
618
+ loop: z.boolean().default(false),
619
+ end: z.enum(["hold", "reset"]).default("hold").describe("hold keeps the last frame; reset returns to the start."),
620
+ markers: z.array(BoardMarkerSchema).max(1e4).default([]).describe("Labeled points on this timeline; a nested animation's markers do not carry over.")
621
+ }).strict();
622
+ const BoardAnimationSchema = BoardAnimationHeaderSchema.extend({ tracks: z.record(BoardKeySchema, BoardTrackSchema).default({}) }).strict();
623
+ const BOARD_ENTER_PRESETS = [
624
+ "fade-in",
625
+ "rise",
626
+ "drop",
627
+ "pop",
628
+ "deal"
629
+ ];
630
+ const BoardBackgroundSchema = z.object({
631
+ kind: z.enum([
632
+ "solid",
633
+ "dots",
634
+ "grid",
635
+ "image"
636
+ ]).default("dots"),
637
+ color: BoardColorSchema.optional(),
638
+ imageUrl: z.string().url().max(4096).optional().describe("Background image for kind image."),
639
+ fit: z.enum([
640
+ "cover",
641
+ "contain",
642
+ "repeat"
643
+ ]).optional(),
644
+ opacity: ratio.optional()
645
+ }).strict();
646
+ const BoardSettingsSchema = z.object({
647
+ title: z.string().min(1).max(255).optional(),
648
+ background: BoardBackgroundSchema.default({ kind: "dots" }),
649
+ grid: z.object({
650
+ visible: z.boolean().default(false).describe("Show the grid overlay."),
651
+ size: finite.min(4).max(512).default(24)
652
+ }).strict().optional(),
653
+ enter: z.object({
654
+ preset: z.enum(BOARD_ENTER_PRESETS),
655
+ duration: finite.positive().max(1e4).optional()
656
+ }).strict().optional().describe("Motion for items as they are added.")
657
+ }).strict();
658
+ const patchObject = z.record(z.string(), z.unknown());
659
+ const BoardPatchSchema = z.object({
660
+ board: patchObject.nullable().optional(),
661
+ items: z.record(BoardIdSchema, patchObject.nullable()).optional(),
662
+ animations: z.record(BoardIdSchema, patchObject.and(z.object({ tracks: z.record(BoardKeySchema, patchObject.nullable()).optional() })).nullable()).optional()
663
+ }).strict();
664
+ //#endregion
665
+ //#region ../protocol/dist/board.js
666
+ const BOARD_EXTENSION = ".board";
667
+ const BOARD_MIME_TYPE = "application/json";
668
+ const BoardManifestSchema = z.object({
669
+ kind: z.literal("cohub.board.manifest"),
670
+ version: z.literal(1),
671
+ boardId: z.string().uuid(),
672
+ title: z.string().min(1).max(255)
673
+ });
674
+ var InvalidBoardFileError = class extends Error {
675
+ code = "INVALID_BOARD_FILE";
676
+ constructor(message = "Board file is invalid") {
677
+ super(message);
678
+ this.name = "InvalidBoardFileError";
679
+ }
680
+ };
681
+ function parseBoardManifest(input) {
682
+ let value = input;
683
+ if (typeof input === "string") try {
684
+ value = JSON.parse(input);
685
+ } catch {
686
+ throw new InvalidBoardFileError("Board file must contain valid JSON");
687
+ }
688
+ const parsed = BoardManifestSchema.safeParse(value);
689
+ if (!parsed.success) throw new InvalidBoardFileError("Board file must contain a valid boardId");
690
+ return parsed.data;
691
+ }
692
+ function isBoardPath(path) {
693
+ return path.toLowerCase().endsWith(BOARD_EXTENSION);
694
+ }
695
+ const BOARD_READ_SECTIONS = ["items", "animations"];
696
+ const rectSchema = z.object({
697
+ x: z.number().finite(),
698
+ y: z.number().finite(),
699
+ width: z.number().finite().positive(),
700
+ height: z.number().finite().positive()
701
+ }).strict();
702
+ z.object({
703
+ only: z.array(z.enum(BOARD_READ_SECTIONS)).optional(),
704
+ rect: rectSchema.optional(),
705
+ within: BoardIdSchema.optional(),
706
+ items: z.array(z.string().min(1)).max(5e4).optional(),
707
+ animations: z.array(z.string().min(1)).max(1e4).optional(),
708
+ limit: z.number().int().min(1).max(5e4).optional(),
709
+ cursor: z.string().min(1).optional()
710
+ }).strict().refine((read) => !(read.cursor && (read.rect || read.within)), {
711
+ path: ["cursor"],
712
+ message: "cursor pages by id, so it cannot be combined with rect or within"
713
+ });
714
+ z.object({
715
+ patch: BoardPatchSchema,
716
+ replace: z.boolean().default(false),
717
+ cascade: z.boolean().default(false),
718
+ dryRun: z.boolean().default(false),
719
+ baseVersion: z.number().int().nonnegative().optional(),
720
+ mutationId: z.string().min(1).max(160).optional(),
721
+ clientId: z.string().min(1).max(160).optional()
722
+ }).strict();
723
+ z.object({
724
+ path: z.string().min(1),
725
+ title: z.string().min(1).max(255).optional(),
726
+ document: BoardPatchSchema.optional(),
727
+ mutationId: z.string().max(160).optional()
728
+ }).strict();
729
+ z.object({
730
+ before: z.number().int().positive().optional(),
731
+ limit: z.number().int().min(1).max(500).default(200)
732
+ }).strict();
733
+ const commandId = z.string().min(1).max(160);
734
+ z.discriminatedUnion("type", [
735
+ z.object({
736
+ commandId,
737
+ type: z.literal("play"),
738
+ animationId: z.string().min(1),
739
+ position: z.number().finite().nonnegative().optional(),
740
+ timeScale: z.number().finite().positive().max(4).optional(),
741
+ seed: z.string().min(1).max(160).optional()
742
+ }).strict(),
743
+ z.object({
744
+ commandId,
745
+ type: z.literal("pause")
746
+ }).strict(),
747
+ z.object({
748
+ commandId,
749
+ type: z.literal("resume")
750
+ }).strict(),
751
+ z.object({
752
+ commandId,
753
+ type: z.literal("seek"),
754
+ position: z.number().finite().nonnegative()
755
+ }).strict(),
756
+ z.object({
757
+ commandId,
758
+ type: z.literal("next")
759
+ }).strict(),
760
+ z.object({
761
+ commandId,
762
+ type: z.literal("stop")
763
+ }).strict()
764
+ ]);
765
+ //#endregion
4
766
  //#region ../protocol/dist/model/metrics.js
5
767
  const count = z.number().finite().nonnegative();
6
768
  const usageSchema = z.object({
@@ -1132,7 +1894,8 @@ var BoardRealtimeClient = class {
1132
1894
  subscribe(handlers) {
1133
1895
  if (!this.websocketClient) throw new Error("realtime transport is not configured for this client");
1134
1896
  ensureRealtimeConnected(this.websocketClient);
1135
- const releaseRoom = this.websocketClient.retainRooms([getRealtimeSpaceRoom(this.spaceId), getRealtimeBoardRoom(this.boardId)]);
1897
+ const room = getRealtimeBoardRoom(this.boardId);
1898
+ const releaseRoom = this.websocketClient.retainRooms([getRealtimeSpaceRoom(this.spaceId), room]);
1136
1899
  const unsubscribe = this.websocketClient.on("event", (event) => {
1137
1900
  if (event.spaceId !== this.spaceId) return;
1138
1901
  if (event.type === "board.changed" && event.payload.boardId === this.boardId) {
@@ -1153,8 +1916,13 @@ var BoardRealtimeClient = class {
1153
1916
  handlers.playback?.(playbackEvent);
1154
1917
  }
1155
1918
  });
1919
+ const resync = handlers.resync;
1920
+ const stopResync = resync ? this.websocketClient.on("subscribed", ({ rooms }) => {
1921
+ if (rooms.includes(room)) resync();
1922
+ }) : null;
1156
1923
  return () => {
1157
1924
  unsubscribe();
1925
+ stopResync?.();
1158
1926
  releaseRoom();
1159
1927
  };
1160
1928
  }
@@ -1292,14 +2060,25 @@ var BoardClient = class {
1292
2060
  return this.realtime.on("playback", handler);
1293
2061
  }
1294
2062
  };
2063
+ async function fileText(file, customFetch = fetch) {
2064
+ if (!file.content && file.delivery === "url" && file.url) {
2065
+ const response = await customFetch(file.url);
2066
+ if (!response.ok) throw new Error(`${file.path} could not be read (${response.status})`);
2067
+ return response.text();
2068
+ }
2069
+ if (file.encoding !== "base64") return file.content;
2070
+ return new TextDecoder().decode(Uint8Array.from(atob(file.content), (char) => char.charCodeAt(0)));
2071
+ }
1295
2072
  var SpaceBoardsApi = class {
1296
2073
  http;
1297
2074
  spaceId;
1298
2075
  websocket;
1299
- constructor(http, spaceId, websocket) {
2076
+ files;
2077
+ constructor(http, spaceId, websocket, files) {
1300
2078
  this.http = http;
1301
2079
  this.spaceId = spaceId;
1302
2080
  this.websocket = websocket;
2081
+ this.files = files;
1303
2082
  }
1304
2083
  byId(boardId) {
1305
2084
  return new BoardClient({
@@ -1309,6 +2088,14 @@ var SpaceBoardsApi = class {
1309
2088
  boardId
1310
2089
  });
1311
2090
  }
2091
+ async open(target, customFetch) {
2092
+ return this.byId(isBoardPath(target) ? await this.resolveId(target, customFetch) : target);
2093
+ }
2094
+ async resolveId(path, customFetch) {
2095
+ const file = await this.files.read(path, customFetch);
2096
+ if (!("content" in file)) throw new Error(`${path} is being prepared; try again shortly.`);
2097
+ return parseBoardManifest(await fileText(file, customFetch)).boardId;
2098
+ }
1312
2099
  /** Create a `.board` file and its Board, optionally with an initial document. */
1313
2100
  create(input) {
1314
2101
  return this.http.request(`/api/spaces/${this.spaceId}/boards`, {
@@ -4075,7 +4862,7 @@ var SpaceClient = class {
4075
4862
  this.displays = new SpaceDisplaysApi(transport, id);
4076
4863
  this.invitations = new SpaceInvitationsApi(transport, id);
4077
4864
  this.labels = new SpaceLabelsApi(transport, id);
4078
- this.boards = new SpaceBoardsApi(transport, id, websocketClient);
4865
+ this.boards = new SpaceBoardsApi(transport, id, websocketClient, this.files);
4079
4866
  this.wallet = new SpaceWalletApi(transport, id);
4080
4867
  this.commerce = new SpaceCommerceApi(transport, id);
4081
4868
  }
@@ -5036,4 +5823,4 @@ var CohubHttpClient = class {
5036
5823
  };
5037
5824
  const createHttpClient = (options) => new CohubHttpClient(options);
5038
5825
  //#endregion
5039
- export { isTerminalDesktopCommandStatus as $, BoardClient as A, CronJobsApi as B, SessionPatchReducer as C, connectDisplay as D, DisplayConnection as E, PublicAssetsApi as F, DESKTOP_COMMAND_OPEN_TIMEOUT_MS as G, DESKTOP_COMMAND_ACCEPT_TIMEOUT_MS as H, SkillsApi as I, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS as J, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES as K, PromptsApi as L, SessionAccessApi as M, ReferencesApi as N, readRtcTransportStats as O, SearchApi as P, isDesktopCallMethod as Q, ModelsApi as R, parseAssistantMessageCommit as S, SpaceDisplaysApi as T, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS as U, ChannelsApi as V, DESKTOP_COMMAND_MAX_TIMEOUT_MS as W, DESKTOP_COMMAND_VERSION as X, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS as Y, defaultDesktopCommandTimeoutMs as Z, PublicInviteApi as _, WorkCommerceApi as a, DISPLAY_INPUT_MAX_SCHEDULE_MS as at, SessionGenerationStreamClient as b, AppsApi as c, normalizeDisplayPoint as ct, UserApi as d, parseDesktopCommand as et, TasksApi as f, SpacesApi as g, SpaceWebhooksApi as h, AppCommerceApi as i, DISPLAY_ELEMENT_REF_PATTERN as it, ensureRealtimeConnected as j, waitForIceGathering as k, ReferralsApi as l, splitDisplayText as lt, SpacePublicFilesApi as m, createHttpClient as n, resolveOpenSurface as nt, DesktopCommandsApi as o, DISPLAY_INPUT_MAX_TEXT as ot, SpaceClient as p, DESKTOP_COMMAND_PENDING_TTL_SECONDS as q, RoomsApi as r, NAVIGATION_ERROR_MESSAGE_MAX_LENGTH as rt, UiCommandsApi as s, DISPLAY_SYSTEM_ACTIONS as st, CohubHttpClient as t, parseDesktopCommandId as tt, UsersApi as u, buildSpaceInvitePath as v, createSessionPatchReducer as w, createSessionGenerationStreamClient as x, buildSpacePath as y, GenerationsApi as z };
5826
+ export { isTerminalDesktopCommandStatus as $, BoardClient as A, CronJobsApi as B, SessionPatchReducer as C, isBuiltinItemType as Ct, connectDisplay as D, boardDefaultSize as Dt, DisplayConnection as E, BOARD_ARROW_STROKE_SIZE as Et, PublicAssetsApi as F, DESKTOP_COMMAND_OPEN_TIMEOUT_MS as G, DESKTOP_COMMAND_ACCEPT_TIMEOUT_MS as H, SkillsApi as I, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS as J, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES as K, PromptsApi as L, SessionAccessApi as M, ReferencesApi as N, readRtcTransportStats as O, SearchApi as P, isDesktopCallMethod as Q, ModelsApi as R, parseAssistantMessageCommit as S, boardItemSchema as St, SpaceDisplaysApi as T, normalizeBoardRemoteUrl as Tt, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS as U, ChannelsApi as V, DESKTOP_COMMAND_MAX_TIMEOUT_MS as W, DESKTOP_COMMAND_VERSION as X, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS as Y, defaultDesktopCommandTimeoutMs as Z, PublicInviteApi as _, BoardColorSchema as _t, WorkCommerceApi as a, DISPLAY_INPUT_MAX_SCHEDULE_MS as at, SessionGenerationStreamClient as b, BoardTrackSchema as bt, AppsApi as c, normalizeDisplayPoint as ct, UserApi as d, BOARD_MIME_TYPE as dt, parseDesktopCommand as et, TasksApi as f, BOARD_CAMERA_TARGET as ft, SpacesApi as g, BoardAnimationSchema as gt, SpaceWebhooksApi as h, BoardAnimationHeaderSchema as ht, AppCommerceApi as i, DISPLAY_ELEMENT_REF_PATTERN as it, ensureRealtimeConnected as j, waitForIceGathering as k, ReferralsApi as l, splitDisplayText as lt, SpacePublicFilesApi as m, BOARD_ITEM_TYPES as mt, createHttpClient as n, resolveOpenSurface as nt, DesktopCommandsApi as o, DISPLAY_INPUT_MAX_TEXT as ot, SpaceClient as p, BOARD_COLOR_TOKENS as pt, DESKTOP_COMMAND_PENDING_TTL_SECONDS as q, RoomsApi as r, NAVIGATION_ERROR_MESSAGE_MAX_LENGTH as rt, UiCommandsApi as s, DISPLAY_SYSTEM_ACTIONS as st, CohubHttpClient as t, parseDesktopCommandId as tt, UsersApi as u, BOARD_EXTENSION as ut, buildSpaceInvitePath as v, BoardPatchSchema as vt, createSessionPatchReducer as w, parseBoardItem as wt, createSessionGenerationStreamClient as x, BoardVec2Schema as xt, buildSpacePath as y, BoardSettingsSchema as yt, GenerationsApi as z };