@neta-art/cohub 8.10.2 → 8.12.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 (45) hide show
  1. package/dist/board/animation.js +14 -2
  2. package/dist/board/core/file-preview.d.ts +20 -141
  3. package/dist/board/core/file-preview.js +25 -202
  4. package/dist/board/core/file-snapshot.d.ts +106 -0
  5. package/dist/board/core/file-snapshot.js +503 -0
  6. package/dist/board/index.d.ts +4 -2
  7. package/dist/board/index.js +4 -2
  8. package/dist/board/mutation.js +2 -1
  9. package/dist/board/render/board-background.d.ts +16 -0
  10. package/dist/board/render/{themes/clean-theme.js → board-background.js} +28 -35
  11. package/dist/board/render/index.d.ts +3 -3
  12. package/dist/board/render/index.js +2 -2
  13. package/dist/board/render/renderers/file-card-renderer.js +62 -17
  14. package/dist/board/replay.d.ts +52 -0
  15. package/dist/board/replay.js +261 -0
  16. package/dist/board/semantic-document.d.ts +9 -2
  17. package/dist/board/semantic-document.js +1 -3
  18. package/dist/chunks/environment.d.ts +272 -7
  19. package/dist/chunks/environment.js +1 -0
  20. package/dist/chunks/http.d.ts +109 -7
  21. package/dist/chunks/http.js +47 -10
  22. package/dist/chunks/websocket.d.ts +1 -1
  23. package/dist/http.d.ts +3 -3
  24. package/dist/index.d.ts +65 -4
  25. package/dist/index.js +514 -64
  26. package/dist/protocol/dist/board-animation.d.ts +1 -0
  27. package/dist/protocol/dist/board-animation.js +34 -0
  28. package/dist/protocol/dist/board-authoring.d.ts +2 -1
  29. package/dist/protocol/dist/board-capability-registry.js +53 -3
  30. package/dist/protocol/dist/board-codec.js +149 -2
  31. package/dist/protocol/dist/board-constants.js +29 -7
  32. package/dist/protocol/dist/board-document.d.ts +30 -16
  33. package/dist/protocol/dist/board-document.js +15 -12
  34. package/dist/protocol/dist/board-effect.d.ts +4 -2
  35. package/dist/protocol/dist/board-effect.js +3 -2
  36. package/dist/protocol/dist/board.d.ts +148 -3
  37. package/dist/protocol/dist/board.js +7 -0
  38. package/dist/protocol/dist/index.d.ts +4 -2
  39. package/dist/protocol/dist/provenance.d.ts +21 -0
  40. package/dist/types.d.ts +1 -1
  41. package/docs/app-runtime-guide.md +28 -3
  42. package/package.json +1 -1
  43. package/dist/board/render/themes/board-theme-registry.d.ts +0 -22
  44. package/dist/board/render/themes/board-theme-registry.js +0 -13
  45. package/dist/board/render/themes/clean-theme.d.ts +0 -5
package/dist/index.js CHANGED
@@ -8,8 +8,8 @@ import { z } from "zod";
8
8
  const BOARD_DOCUMENT_KIND = "cohub.board";
9
9
  const BOARD_MANIFEST_KIND = "cohub.board.manifest";
10
10
  const idSchema = z.string().min(1).max(160);
11
- const jsonObjectSchema = z.record(z.string(), z.unknown());
12
- const finiteSchema = z.number().finite();
11
+ const jsonObjectSchema$1 = z.record(z.string(), z.unknown());
12
+ const finiteSchema$1 = z.number().finite();
13
13
  z.object({
14
14
  kind: z.literal(BOARD_MANIFEST_KIND),
15
15
  version: z.literal(1),
@@ -17,18 +17,18 @@ z.object({
17
17
  title: z.string().min(1).max(255)
18
18
  });
19
19
  z.object({
20
- centerX: finiteSchema,
21
- centerY: finiteSchema,
22
- zoom: finiteSchema.positive()
20
+ centerX: finiteSchema$1,
21
+ centerY: finiteSchema$1,
22
+ zoom: finiteSchema$1.positive()
23
23
  });
24
24
  const BoardCameraFocusSchema = z.discriminatedUnion("type", [
25
25
  z.object({
26
26
  type: z.literal("rect"),
27
27
  rect: z.object({
28
- x: finiteSchema,
29
- y: finiteSchema,
30
- width: finiteSchema.positive(),
31
- height: finiteSchema.positive()
28
+ x: finiteSchema$1,
29
+ y: finiteSchema$1,
30
+ width: finiteSchema$1.positive(),
31
+ height: finiteSchema$1.positive()
32
32
  })
33
33
  }),
34
34
  z.object({
@@ -47,9 +47,9 @@ const BoardCameraFocusSchema = z.discriminatedUnion("type", [
47
47
  const BoardCameraFocusParamsSchema = z.object({
48
48
  focus: BoardCameraFocusSchema,
49
49
  fit: z.enum(["contain", "cover"]).default("contain"),
50
- padding: finiteSchema.nonnegative().default(32),
51
- minZoom: finiteSchema.positive().optional(),
52
- maxZoom: finiteSchema.positive().optional()
50
+ padding: finiteSchema$1.nonnegative().default(32),
51
+ minZoom: finiteSchema$1.positive().optional(),
52
+ maxZoom: finiteSchema$1.positive().optional()
53
53
  }).superRefine((value, context) => {
54
54
  if (value.minZoom !== void 0 && value.maxZoom !== void 0 && value.minZoom > value.maxZoom) context.addIssue({
55
55
  code: "custom",
@@ -62,17 +62,17 @@ z.object({
62
62
  type: z.string().min(1).max(40),
63
63
  parentId: idSchema.nullable(),
64
64
  orderKey: z.string().max(4096).nullable(),
65
- x: finiteSchema,
66
- y: finiteSchema,
67
- width: finiteSchema.positive(),
68
- height: finiteSchema.positive(),
69
- rotation: finiteSchema,
65
+ x: finiteSchema$1,
66
+ y: finiteSchema$1,
67
+ width: finiteSchema$1.positive(),
68
+ height: finiteSchema$1.positive(),
69
+ rotation: finiteSchema$1,
70
70
  refKind: z.string().max(40).nullable(),
71
71
  refPath: z.string().max(4096).nullable(),
72
72
  refUrl: z.string().max(4096).nullable(),
73
- view: jsonObjectSchema,
74
- style: jsonObjectSchema,
75
- data: jsonObjectSchema
73
+ view: jsonObjectSchema$1,
74
+ style: jsonObjectSchema$1,
75
+ data: jsonObjectSchema$1
76
76
  });
77
77
  const stripBoardServerFields = (value) => {
78
78
  if (!value || typeof value !== "object" || Array.isArray(value)) return value;
@@ -86,7 +86,7 @@ const BoardCreateInputSchema = z.object({
86
86
  /** Reused by clients when board creation is interrupted and retried. */
87
87
  mutationId: z.string().max(128).optional(),
88
88
  title: z.string().min(1).max(255).optional(),
89
- metadata: jsonObjectSchema.optional(),
89
+ metadata: jsonObjectSchema$1.optional(),
90
90
  items: z.array(BoardAuthoringItemSchema).max(5e4).optional(),
91
91
  connections: z.array(BoardConnectionSchema).max(5e4).optional(),
92
92
  effects: z.array(BoardCreateEffectInputSchema).max(5e4).optional(),
@@ -132,17 +132,24 @@ z.object({
132
132
  effectIds: z.array(idSchema).max(5e4).optional(),
133
133
  compositionIds: z.array(idSchema).max(5e4).optional(),
134
134
  viewport: z.object({
135
- x: finiteSchema,
136
- y: finiteSchema,
137
- width: finiteSchema.positive(),
138
- height: finiteSchema.positive()
135
+ x: finiteSchema$1,
136
+ y: finiteSchema$1,
137
+ width: finiteSchema$1.positive(),
138
+ height: finiteSchema$1.positive()
139
139
  }).optional()
140
140
  });
141
+ z.object({
142
+ /** Return transactions with `version < before`. Omit for the newest page. */
143
+ before: z.number().int().positive().optional(),
144
+ limit: z.number().int().min(1).max(500).default(200),
145
+ /** Include the current rows on the newest page (default true). Tail refreshes turn this off. */
146
+ snapshot: z.boolean().default(true)
147
+ });
141
148
  /** Persisted on `boards.metadata.playback`: how a Board plays when opened. */
142
149
  const BoardPlaybackPolicySchema = z.object({
143
150
  compositionId: idSchema,
144
151
  /** Delay before the first local playback after opening the Board, in milliseconds. */
145
- delayMs: finiteSchema.nonnegative().default(0)
152
+ delayMs: finiteSchema$1.nonnegative().default(0)
146
153
  });
147
154
  function parseBoardPlaybackPolicy(metadata) {
148
155
  const parsed = BoardPlaybackPolicySchema.safeParse(metadata.playback);
@@ -153,8 +160,8 @@ z.discriminatedUnion("type", [
153
160
  commandId: idSchema,
154
161
  type: z.literal("play"),
155
162
  compositionId: idSchema,
156
- position: finiteSchema.nonnegative().optional(),
157
- timeScale: finiteSchema.positive().max(4).optional(),
163
+ position: finiteSchema$1.nonnegative().optional(),
164
+ timeScale: finiteSchema$1.positive().max(4).optional(),
158
165
  shared: z.boolean().optional(),
159
166
  seed: idSchema.optional()
160
167
  }),
@@ -167,7 +174,7 @@ z.discriminatedUnion("type", [
167
174
  commandId: idSchema,
168
175
  type: z.literal("seek"),
169
176
  playbackId: z.string().uuid(),
170
- position: finiteSchema.nonnegative()
177
+ position: finiteSchema$1.nonnegative()
171
178
  }),
172
179
  z.object({
173
180
  commandId: idSchema,
@@ -176,9 +183,49 @@ z.discriminatedUnion("type", [
176
183
  })
177
184
  ]);
178
185
  //#endregion
186
+ //#region ../protocol/dist/board-animation.js
187
+ const extensionKindSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
188
+ const jsonObjectSchema = z.record(z.string(), z.unknown());
189
+ const finiteSchema = z.number().finite();
190
+ /** Parameters shared by the built-in deal entrance preset. */
191
+ const BoardDealParamsSchema = z.object({
192
+ lift: finiteSchema.nonnegative().max(2e3).optional(),
193
+ swing: finiteSchema.nonnegative().max(2e3).optional(),
194
+ curve: finiteSchema.nonnegative().max(2e3).optional(),
195
+ tilt: finiteSchema.nonnegative().max(180).optional(),
196
+ scale: finiteSchema.positive().max(2).optional(),
197
+ duration: finiteSchema.positive().max(1e4).optional(),
198
+ landing: finiteSchema.nonnegative().max(1e4).optional()
199
+ }).strict();
200
+ /** A versioned, reusable animation preset reference. */
201
+ const BoardAnimationSpecSchema = z.object({
202
+ kind: extensionKindSchema,
203
+ kindVersion: z.number().int().positive().default(1),
204
+ params: jsonObjectSchema.default({})
205
+ }).strict().superRefine((spec, context) => {
206
+ if (spec.kind !== "effects.deal" || spec.kindVersion !== 1) return;
207
+ const parsed = BoardDealParamsSchema.safeParse(spec.params);
208
+ if (parsed.success) return;
209
+ context.addIssue({
210
+ code: "custom",
211
+ message: parsed.error.issues[0]?.message ?? "invalid effects.deal parameters",
212
+ path: ["params", ...parsed.error.issues[0]?.path ?? []]
213
+ });
214
+ });
215
+ /** Board-wide default motion policies. Omitted policies mean no motion. */
216
+ const BoardMotionSchema = z.object({ enter: BoardAnimationSpecSchema.optional() }).strict();
217
+ //#endregion
179
218
  //#region ../protocol/dist/board-capability-registry.js
180
219
  const CLIPS = new Set(BOARD_BUILTIN_CLIP_KINDS);
181
- new Set(BOARD_BUILTIN_EFFECT_KINDS);
220
+ const EFFECTS = new Set(BOARD_BUILTIN_EFFECT_KINDS);
221
+ const BUILTIN_VERSIONS = new Set(BOARD_BUILTIN_CAPABILITIES.map((c) => `${c.kind}:${c.id}@${c.version}`));
222
+ /**
223
+ * True when a built-in renderer exists for exactly this kind@version. A known
224
+ * kind at an unknown version is not built-in: it must not pass as one.
225
+ */
226
+ function isBuiltinBoardCapability(kind, id, version) {
227
+ return BUILTIN_VERSIONS.has(`${kind}:${id}@${version}`);
228
+ }
182
229
  const record = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
183
230
  const finite = (value) => typeof value === "number" && Number.isFinite(value);
184
231
  function validateBuiltinBoardClip(clip, path = "clip") {
@@ -212,6 +259,47 @@ function validateBuiltinBoardClip(clip, path = "clip") {
212
259
  }
213
260
  return errors;
214
261
  }
262
+ function validateBuiltinBoardEffect(effect, path = "effect") {
263
+ const diagnostics = [];
264
+ if (effect.lifecycle === "on-enter") {
265
+ if (effect.target.type !== "item") diagnostics.push({
266
+ severity: "error",
267
+ code: "INVALID_BOARD_EFFECT",
268
+ message: "on-enter effects must target an item",
269
+ path: `${path}.target`
270
+ });
271
+ if (effect.timeOrigin !== "activation") diagnostics.push({
272
+ severity: "error",
273
+ code: "INVALID_BOARD_EFFECT",
274
+ message: "on-enter effects must use activation time",
275
+ path: `${path}.timeOrigin`
276
+ });
277
+ } else if (EFFECTS.has(effect.kind) && effect.target.type !== "item") diagnostics.push({
278
+ severity: "error",
279
+ code: "INVALID_BOARD_EFFECT",
280
+ message: `${effect.kind} must target an item`,
281
+ path: `${path}.target`
282
+ });
283
+ if (effect.kind === "effects.deal" && effect.kindVersion === 1) {
284
+ if (effect.lifecycle !== "on-enter") diagnostics.push({
285
+ severity: "error",
286
+ code: "INVALID_BOARD_EFFECT",
287
+ message: "effects.deal must use the on-enter lifecycle",
288
+ path: `${path}.lifecycle`
289
+ });
290
+ const parsed = BoardDealParamsSchema.safeParse(effect.params);
291
+ if (!parsed.success) diagnostics.push({
292
+ severity: "error",
293
+ code: "INVALID_BOARD_EFFECT",
294
+ message: parsed.error.issues[0]?.message ?? "invalid effects.deal parameters",
295
+ path: `${path}.params`
296
+ });
297
+ }
298
+ return diagnostics;
299
+ }
300
+ function estimateBuiltinBoardEffectCost(effect) {
301
+ return isBuiltinBoardCapability("effect", effect.kind, effect.kindVersion) ? { drawCalls: 1 } : {};
302
+ }
215
303
  function estimateBuiltinBoardClipCost(clip) {
216
304
  switch (clip.kind) {
217
305
  case "effects.particles": {
@@ -352,7 +440,18 @@ const BoardViewportSchema = z.object({
352
440
  zoom: z.number().finite().min(.05).max(8)
353
441
  });
354
442
  const BoardAppearanceSchema = z.object({
355
- theme: z.string().min(1).default("clean"),
443
+ /** Legacy field retained when reading older Board documents; not used for rendering. */
444
+ theme: z.string().min(1).optional(),
445
+ /** Board-wide motion policies. Omitted policies mean no motion. */
446
+ motion: BoardMotionSchema.optional(),
447
+ /** Legacy field retained when reading older Board documents; not used for rendering. */
448
+ mood: z.enum([
449
+ "clean",
450
+ "playful",
451
+ "arcane",
452
+ "cyber",
453
+ "natural"
454
+ ]).optional(),
356
455
  background: z.object({
357
456
  kind: z.enum([
358
457
  "solid",
@@ -386,14 +485,7 @@ const BoardAppearanceSchema = z.object({
386
485
  visible: false,
387
486
  size: 24,
388
487
  opacity: .12
389
- }),
390
- mood: z.enum([
391
- "clean",
392
- "playful",
393
- "arcane",
394
- "cyber",
395
- "natural"
396
- ]).default("clean")
488
+ })
397
489
  });
398
490
  /** Optional visual chrome still carried by a few older shapes. */
399
491
  const BoardItemStyleSchema = z.object({
@@ -695,14 +787,12 @@ z.object({
695
787
  kind: z.literal(BOARD_DOCUMENT_KIND),
696
788
  version: z.literal(1),
697
789
  appearance: BoardAppearanceSchema.default({
698
- theme: "clean",
699
790
  background: { kind: "solid" },
700
791
  grid: {
701
792
  visible: false,
702
793
  size: 24,
703
794
  opacity: .12
704
- },
705
- mood: "clean"
795
+ }
706
796
  }),
707
797
  viewport: BoardViewportSchema,
708
798
  items: z.array(BoardItemSchema),
@@ -891,14 +981,14 @@ var GenerationPolicyError = class extends Error {
891
981
  this.name = "GenerationPolicyError";
892
982
  }
893
983
  };
894
- function isRecord$2(value) {
984
+ function isRecord$4(value) {
895
985
  return !!value && typeof value === "object" && !Array.isArray(value);
896
986
  }
897
987
  function isPrimitiveEnumValue(value) {
898
988
  return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
899
989
  }
900
990
  function normalizeConstraint(value) {
901
- if (!isRecord$2(value) || typeof value.kind !== "string") return null;
991
+ if (!isRecord$4(value) || typeof value.kind !== "string") return null;
902
992
  if (value.kind === "enum") {
903
993
  if (!Array.isArray(value.values) || value.values.length === 0 || !value.values.every(isPrimitiveEnumValue)) return null;
904
994
  return {
@@ -928,7 +1018,7 @@ function normalizeConstraint(value) {
928
1018
  return null;
929
1019
  }
930
1020
  function normalizeGenerationPolicy(value) {
931
- if (!isRecord$2(value) || value.version !== 1) return null;
1021
+ if (!isRecord$4(value) || value.version !== 1) return null;
932
1022
  if (value.mode === "auto") return {
933
1023
  version: 1,
934
1024
  mode: "auto"
@@ -936,10 +1026,10 @@ function normalizeGenerationPolicy(value) {
936
1026
  if (value.mode !== "limited" || !Array.isArray(value.models) || value.models.length === 0) return null;
937
1027
  const models = [];
938
1028
  for (const item of value.models) {
939
- if (!isRecord$2(item) || typeof item.model !== "string" || !item.model.trim()) return null;
1029
+ if (!isRecord$4(item) || typeof item.model !== "string" || !item.model.trim()) return null;
940
1030
  const modelPolicy = { model: item.model.trim() };
941
1031
  if (item.parameters !== void 0) {
942
- if (!isRecord$2(item.parameters)) return null;
1032
+ if (!isRecord$4(item.parameters)) return null;
943
1033
  const parameters = {};
944
1034
  for (const [key, rawConstraint] of Object.entries(item.parameters)) {
945
1035
  if (!key.trim()) return null;
@@ -1172,8 +1262,8 @@ const APP_SURFACE_REQUEST_TIMEOUT_MS = 15e3;
1172
1262
  const APP_COMPOSER_CHIP_KEY_MAX_LENGTH = 80;
1173
1263
  const APP_COMPOSER_CHIP_LABEL_MAX_LENGTH = 120;
1174
1264
  const APP_COMPOSER_CHIP_CONTENT_MAX_BYTES = 32768;
1175
- const isRecord$1 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
1176
- const isSurfaceEnvelope = (value) => isRecord$1(value) && value.protocol === "cohub.app.surface" && value.version === 1;
1265
+ const isRecord$3 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
1266
+ const isSurfaceEnvelope = (value) => isRecord$3(value) && value.protocol === "cohub.app.surface" && value.version === 1;
1177
1267
  const parseAppSurfaceReady = (value) => {
1178
1268
  if (!isSurfaceEnvelope(value) || value.type !== "ready") return null;
1179
1269
  const methods = Array.isArray(value.methods) ? value.methods.filter((method) => typeof method === "string" && Boolean(method)) : [];
@@ -1187,7 +1277,7 @@ const parseAppSurfaceReady = (value) => {
1187
1277
  const parseAppSurfaceResponse = (value) => {
1188
1278
  if (!isSurfaceEnvelope(value) || value.type !== "response") return null;
1189
1279
  if (typeof value.requestId !== "string" || !value.requestId) return null;
1190
- const error = isRecord$1(value.error) ? {
1280
+ const error = isRecord$3(value.error) ? {
1191
1281
  code: typeof value.error.code === "string" && value.error.code ? value.error.code : "surface_error",
1192
1282
  message: typeof value.error.message === "string" ? value.error.message : "App surface call failed"
1193
1283
  } : void 0;
@@ -1207,7 +1297,7 @@ const parseComposerChipKey = (value) => {
1207
1297
  return key;
1208
1298
  };
1209
1299
  const parseAppComposerChipSet = (value) => {
1210
- if (!isSurfaceEnvelope(value) || value.type !== "composer.chip.set" || !isRecord$1(value.chip)) return null;
1300
+ if (!isSurfaceEnvelope(value) || value.type !== "composer.chip.set" || !isRecord$3(value.chip)) return null;
1211
1301
  const key = parseComposerChipKey(value.chip.key);
1212
1302
  if (!key || typeof value.chip.label !== "string" || typeof value.chip.content !== "string") return null;
1213
1303
  const label = value.chip.label.trim();
@@ -1289,12 +1379,23 @@ const buildAppRuntimeReady = () => ({
1289
1379
  version: 1,
1290
1380
  type: "ready"
1291
1381
  });
1382
+ const buildAppRuntimeCloseRequest = () => ({
1383
+ protocol: APP_RUNTIME_PROTOCOL,
1384
+ version: 1,
1385
+ type: "close.request"
1386
+ });
1387
+ const buildAppRuntimeConfigureRequest = (input) => ({
1388
+ protocol: APP_RUNTIME_PROTOCOL,
1389
+ version: 1,
1390
+ type: "configure.request",
1391
+ ...input
1392
+ });
1292
1393
  //#endregion
1293
1394
  //#region ../protocol/dist/app-navigation.js
1294
1395
  const APP_NAVIGATION_PROTOCOL = "cohub.app.navigation";
1295
1396
  const APP_NAVIGATION_MAX_ERROR_CODE_LENGTH = 64;
1296
1397
  const APP_NAVIGATION_MAX_ERROR_MESSAGE_LENGTH = NAVIGATION_ERROR_MESSAGE_MAX_LENGTH;
1297
- const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
1398
+ const isRecord$2 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
1298
1399
  const text = (value, max) => typeof value === "string" && value.trim() && value.length <= max ? value : null;
1299
1400
  const buildAppNavigationOpenMessage = (input) => ({
1300
1401
  protocol: APP_NAVIGATION_PROTOCOL,
@@ -1310,7 +1411,7 @@ const NAVIGATION_REASONS = /* @__PURE__ */ new Set([
1310
1411
  ]);
1311
1412
  function parseNavigationCall(value) {
1312
1413
  if (value === void 0) return void 0;
1313
- if (!isRecord(value) || typeof value.ok !== "boolean") return null;
1414
+ if (!isRecord$2(value) || typeof value.ok !== "boolean") return null;
1314
1415
  if (value.ok) return {
1315
1416
  ok: true,
1316
1417
  ...value.result === void 0 ? {} : { result: value.result }
@@ -1325,7 +1426,7 @@ function parseNavigationCall(value) {
1325
1426
  };
1326
1427
  }
1327
1428
  const parseAppNavigationOpenResponse = (value) => {
1328
- if (!isRecord(value)) return null;
1429
+ if (!isRecord$2(value)) return null;
1329
1430
  if (value.protocol !== "cohub.app.navigation" || value.version !== 1 || value.type !== "open.result" || !text(value.requestId, 128) || typeof value.handled !== "boolean" || value.reason !== void 0 && !NAVIGATION_REASONS.has(value.reason)) return null;
1330
1431
  const call = parseNavigationCall(value.call);
1331
1432
  if (call === null) return null;
@@ -1339,6 +1440,39 @@ const parseAppNavigationOpenResponse = (value) => {
1339
1440
  ...call === void 0 ? {} : { call }
1340
1441
  };
1341
1442
  };
1443
+ const envelope = {
1444
+ protocol: "cohub.app.embed",
1445
+ version: 1
1446
+ };
1447
+ const isRecord$1 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
1448
+ const isEnvelope = (value) => isRecord$1(value) && value.protocol === "cohub.app.embed" && value.version === 1;
1449
+ const parseEmbedId = (value) => typeof value === "string" && value.trim() && value.length <= 128 ? value : null;
1450
+ function parseAppEmbedAttachRequest(value) {
1451
+ if (!isEnvelope(value) || value.type !== "attach.request") return null;
1452
+ return {
1453
+ ...envelope,
1454
+ type: "attach.request"
1455
+ };
1456
+ }
1457
+ function parseAppEmbedCloseRequest(value) {
1458
+ if (!isEnvelope(value) || value.type !== "close.request") return null;
1459
+ const embedId = parseEmbedId(value.embedId);
1460
+ return embedId ? {
1461
+ ...envelope,
1462
+ type: "close.request",
1463
+ embedId
1464
+ } : null;
1465
+ }
1466
+ const buildAppEmbedAttach = (input) => ({
1467
+ ...envelope,
1468
+ type: "attach",
1469
+ ...input
1470
+ });
1471
+ const buildAppEmbedShellChanged = (input) => ({
1472
+ ...envelope,
1473
+ type: "shell.changed",
1474
+ ...input
1475
+ });
1342
1476
  //#endregion
1343
1477
  //#region src/apis/billing.ts
1344
1478
  var BillingApi = class {
@@ -1988,6 +2122,61 @@ var AppSurfaceApi = class {
1988
2122
  /** @deprecated Use `AppSurfaceApi`. */
1989
2123
  var WorkSurfaceApi = class extends AppSurfaceApi {};
1990
2124
  //#endregion
2125
+ //#region src/app-embed.ts
2126
+ const generateEmbedId = () => globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
2127
+ const frameOrigin = (frame) => {
2128
+ try {
2129
+ return new URL(frame.src, window.location.href).origin;
2130
+ } catch {
2131
+ return null;
2132
+ }
2133
+ };
2134
+ /**
2135
+ * Attaches to an iframe that renders a Cohub public App page. The page keeps
2136
+ * owning the embedded App's runtime; this only forwards navigation hints and
2137
+ * relays the App's close intent back to the embedder. Either side may come up
2138
+ * first: the page asks to be attached, and the embedder also announces itself
2139
+ * on attach and on every frame load.
2140
+ */
2141
+ function attachAppEmbed(frame, options) {
2142
+ const embedId = generateEmbedId();
2143
+ let shell = options.shell ?? null;
2144
+ const post = (message) => {
2145
+ const origin = frameOrigin(frame);
2146
+ if (!origin) return;
2147
+ try {
2148
+ frame.contentWindow?.postMessage(message, origin);
2149
+ } catch {}
2150
+ };
2151
+ const attach = () => post(buildAppEmbedAttach({
2152
+ embedId,
2153
+ embedder: { appId: options.appId },
2154
+ shell
2155
+ }));
2156
+ const onMessage = (event) => {
2157
+ if (event.source !== frame.contentWindow || event.origin !== frameOrigin(frame)) return;
2158
+ if (parseAppEmbedAttachRequest(event.data)) return attach();
2159
+ if (parseAppEmbedCloseRequest(event.data)?.embedId === embedId) options.onCloseRequest?.();
2160
+ };
2161
+ window.addEventListener("message", onMessage);
2162
+ frame.addEventListener("load", attach);
2163
+ attach();
2164
+ return {
2165
+ embedId,
2166
+ setShell(next) {
2167
+ shell = next;
2168
+ post(buildAppEmbedShellChanged({
2169
+ embedId,
2170
+ shell
2171
+ }));
2172
+ },
2173
+ dispose() {
2174
+ window.removeEventListener("message", onMessage);
2175
+ frame.removeEventListener("load", attach);
2176
+ }
2177
+ };
2178
+ }
2179
+ //#endregion
1991
2180
  //#region src/app-runtime.ts
1992
2181
  const isBrowser$1 = () => typeof window !== "undefined" && typeof window.parent !== "undefined";
1993
2182
  const hasParent = () => isBrowser$1() && window.parent !== window;
@@ -2038,6 +2227,12 @@ var ParentBridgeTransport = class {
2038
2227
  }
2039
2228
  };
2040
2229
  }
2230
+ notify(message) {
2231
+ if (!hasParent()) return;
2232
+ try {
2233
+ window.parent.postMessage(message, this.trustedParentOrigin ?? getParentOrigin() ?? "*");
2234
+ } catch {}
2235
+ }
2041
2236
  request(message, options) {
2042
2237
  const timeoutMs = options?.timeoutMs ?? 1200;
2043
2238
  const retryIntervalMs = options?.retryIntervalMs;
@@ -2345,6 +2540,22 @@ var AppRuntimeApi = class {
2345
2540
  reason: response === null ? "timeout" : "unsupported"
2346
2541
  };
2347
2542
  }
2543
+ /**
2544
+ * Asks the host to close this App: a workspace tab closes, an embedded page
2545
+ * forwards the request to its embedder, a standalone page closes the tab.
2546
+ * No-op in broker mode, where the App owns its own window.
2547
+ */
2548
+ requestClose() {
2549
+ this.transport.notify?.(buildAppRuntimeCloseRequest());
2550
+ }
2551
+ /**
2552
+ * Requests the host to update the overlay's geometry or pointer hit regions.
2553
+ * Only meaningful when the App was opened as an `overlay` surface; the host
2554
+ * is free to clamp or ignore values that violate its layout policy.
2555
+ */
2556
+ requestConfigure(input) {
2557
+ this.transport.notify?.(buildAppRuntimeConfigureRequest(input));
2558
+ }
2348
2559
  async getAccessToken(options) {
2349
2560
  await this.ensureStorageKeys();
2350
2561
  if (this.token && !options?.forceRefresh) return this.token;
@@ -2442,6 +2653,41 @@ var AppRuntimeApi = class {
2442
2653
  } : null
2443
2654
  };
2444
2655
  }
2656
+ /**
2657
+ * One consent: create a viewer-owned Space (full `CreateSpaceInput`, same
2658
+ * as `spaces.create`) and grant the scopes on it. Never silent — each
2659
+ * confirm mints a new Space. The host creates with the viewer's account
2660
+ * token.
2661
+ * `{ granted: false, space }` means the Space was created but not provisioned;
2662
+ * no grant was issued. A viewer deny is `{ granted: false, space: null }`.
2663
+ */
2664
+ async requestCreateSpaceAuthorization(input) {
2665
+ await this.ensureStorageKeys();
2666
+ const response = await this.transport.request({
2667
+ type: "cohub.app.authorize",
2668
+ scopes: input.scopes,
2669
+ reason: input.reason,
2670
+ createSpace: input.space
2671
+ }, { timeoutMs: 12e4 });
2672
+ const token = response?.token ?? null;
2673
+ const spaceId = typeof response?.space?.id === "string" ? response.space.id : null;
2674
+ const spaceName = typeof response?.space?.name === "string" ? response.space.name : null;
2675
+ if (token) {
2676
+ this.token = token;
2677
+ this.writeStoredToken(token);
2678
+ }
2679
+ if (token && spaceId) {
2680
+ this.authorizedGrants = recordConsent(this.authorizedGrants, spaceId, input.scopes);
2681
+ this.writeStoredGrants(this.authorizedGrants);
2682
+ }
2683
+ return {
2684
+ granted: Boolean(token),
2685
+ space: spaceId ? {
2686
+ id: spaceId,
2687
+ name: spaceName
2688
+ } : null
2689
+ };
2690
+ }
2445
2691
  async purchase(input) {
2446
2692
  const purchaseAttemptId = input.purchaseAttemptId?.trim() || generateRequestId();
2447
2693
  return (await this.transport.request({
@@ -2613,13 +2859,25 @@ var CohubClient = class {
2613
2859
  /** Ensure the app holds these scopes. Silent when a grant already covers them; `alwaysAsk` forces the dialog. */
2614
2860
  request: (input) => this.appRuntime.requestAuthorization(input),
2615
2861
  /** One consent: the viewer picks a Space and grants the scopes on it. `alwaysAsk` re-opens the picker. */
2616
- requestSpace: (input) => this.appRuntime.requestSpaceAuthorization(input)
2862
+ requestSpace: (input) => this.appRuntime.requestSpaceAuthorization(input),
2863
+ /** One consent: create a viewer-owned Space and grant the scopes on it. `space` is `CreateSpaceInput`. */
2864
+ requestCreateSpace: (input) => this.appRuntime.requestCreateSpaceAuthorization(input)
2617
2865
  };
2618
2866
  app = {
2619
2867
  realtime: null,
2620
2868
  /** Expose callable methods from inside a published app. */
2621
2869
  surface: new AppSurfaceApi(),
2622
2870
  onContextChanged: (listener) => this.appRuntime.onContextChanged(listener),
2871
+ /** Ask the host to close this App's surface. */
2872
+ requestClose: () => this.appRuntime.requestClose(),
2873
+ /**
2874
+ * Request that the host update this overlay's geometry or pointer hit
2875
+ * regions. Only meaningful for `overlay` surfaces; ignored otherwise.
2876
+ */
2877
+ requestConfigure: (input) => this.appRuntime.requestConfigure(input),
2878
+ embed: {
2879
+ /** Host another App's public page in an iframe and forward the shell location to it. */
2880
+ attach: attachAppEmbed },
2623
2881
  composer: {
2624
2882
  /** Attach or update context from this app in the Cohub composer. */
2625
2883
  setChip: (chip) => this.app.surface.setComposerChip(chip),
@@ -2987,6 +3245,88 @@ function sanitizeReason(value) {
2987
3245
  if (!trimmed) return void 0;
2988
3246
  return trimmed.length > MAX_REASON_LENGTH ? trimmed.slice(0, MAX_REASON_LENGTH) : trimmed;
2989
3247
  }
3248
+ function isRecord(value) {
3249
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
3250
+ }
3251
+ function sanitizeBootstrapSource(value) {
3252
+ if (!isRecord(value) || typeof value.type !== "string") return null;
3253
+ if (value.type === "blank") return { type: "blank" };
3254
+ if (value.type === "checkpoint") {
3255
+ const checkpointId = typeof value.checkpointId === "string" ? value.checkpointId.trim() : "";
3256
+ return checkpointId ? {
3257
+ type: "checkpoint",
3258
+ checkpointId
3259
+ } : null;
3260
+ }
3261
+ if (value.type === "git_repo") {
3262
+ const repoUrl = typeof value.repoUrl === "string" ? value.repoUrl.trim() : "";
3263
+ if (!repoUrl) return null;
3264
+ const ref = typeof value.ref === "string" ? value.ref.trim() || null : value.ref === null ? null : void 0;
3265
+ return ref === void 0 ? {
3266
+ type: "git_repo",
3267
+ repoUrl
3268
+ } : {
3269
+ type: "git_repo",
3270
+ repoUrl,
3271
+ ref
3272
+ };
3273
+ }
3274
+ return null;
3275
+ }
3276
+ /**
3277
+ * Untrusted postMessage payload → `CreateSpaceInput`. Unknown keys are
3278
+ * dropped; the create API still validates the rest.
3279
+ */
3280
+ function sanitizeCreateSpaceInput(value) {
3281
+ if (!isRecord(value)) return null;
3282
+ const name = typeof value.name === "string" ? value.name.trim() : "";
3283
+ if (!name) return null;
3284
+ const input = { name };
3285
+ if (value.slug !== void 0) {
3286
+ if (value.slug !== null && typeof value.slug !== "string") return null;
3287
+ input.slug = value.slug;
3288
+ }
3289
+ if (value.description !== void 0) {
3290
+ if (value.description !== null && typeof value.description !== "string") return null;
3291
+ input.description = value.description;
3292
+ }
3293
+ if (value.source !== void 0) {
3294
+ if (typeof value.source !== "string") return null;
3295
+ input.source = value.source;
3296
+ }
3297
+ if (value.bootstrapSource !== void 0) {
3298
+ const bootstrap = sanitizeBootstrapSource(value.bootstrapSource);
3299
+ if (!bootstrap) return null;
3300
+ input.bootstrapSource = bootstrap;
3301
+ }
3302
+ if (value.extraEnv !== void 0) {
3303
+ if (!Array.isArray(value.extraEnv)) return null;
3304
+ input.extraEnv = value.extraEnv;
3305
+ }
3306
+ if (value.channelBindings !== void 0) {
3307
+ if (!Array.isArray(value.channelBindings)) return null;
3308
+ input.channelBindings = value.channelBindings;
3309
+ }
3310
+ if (value.mods !== void 0) {
3311
+ if (!Array.isArray(value.mods)) return null;
3312
+ input.mods = value.mods;
3313
+ }
3314
+ if (value.config !== void 0) {
3315
+ if (!isRecord(value.config)) return null;
3316
+ input.config = value.config;
3317
+ }
3318
+ return input;
3319
+ }
3320
+ function readCreatedSpace(payload) {
3321
+ if (!isRecord(payload) || !isRecord(payload.space)) return null;
3322
+ const id = payload.space.id;
3323
+ if (typeof id !== "string" || !id) return null;
3324
+ const name = payload.space.name;
3325
+ return {
3326
+ id,
3327
+ name: typeof name === "string" && name ? name : null
3328
+ };
3329
+ }
2990
3330
  function normalizePermissionScopes(scopes) {
2991
3331
  return Array.from(new Set(clonePermissionScopes(scopes)));
2992
3332
  }
@@ -3108,6 +3448,8 @@ function createAppBridgeCore(config) {
3108
3448
  const pendingPurchaseStorageKey = `cohub-app-purchase:${app.id}`;
3109
3449
  const purchaseInFlight = /* @__PURE__ */ new Map();
3110
3450
  let activePurchase = null;
3451
+ /** Space minted during the current create-space consent; retries skip create. */
3452
+ let mintedSpace = null;
3111
3453
  async function isCurrentViewerAppOwner() {
3112
3454
  const viewerUuid = await getViewerUuid();
3113
3455
  return Boolean(viewerUuid && viewerUuid === app.userUuid);
@@ -3119,7 +3461,7 @@ function createAppBridgeCore(config) {
3119
3461
  return Array.from(bySpace.values());
3120
3462
  }
3121
3463
  function allowsOwnerAutoAuthorization() {
3122
- return authorizationContext.surface === "background" || authorizationContext.surface === "app";
3464
+ return authorizationContext.surface === "background" || authorizationContext.surface === "app" || authorizationContext.surface === "overlay";
3123
3465
  }
3124
3466
  async function ensureBaseToken(forceRefresh = false) {
3125
3467
  if (appToken && !forceRefresh) return appToken;
@@ -3225,6 +3567,45 @@ function createAppBridgeCore(config) {
3225
3567
  } catch {}
3226
3568
  }
3227
3569
  /**
3570
+ * Creates the Space with the viewer's own token — the same `POST /api/spaces`
3571
+ * path as the web New Space flow and the CLI. The app never holds this token.
3572
+ */
3573
+ async function createViewerSpace(input) {
3574
+ const request = async (forceRefresh = false) => {
3575
+ const userToken = await getAccessToken({ forceRefresh });
3576
+ if (!userToken) {
3577
+ await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
3578
+ throw new Error("Sign in is required to create a Space.");
3579
+ }
3580
+ return fetch(`${apiOrigin}/api/spaces`, {
3581
+ method: "POST",
3582
+ headers: {
3583
+ Authorization: `Bearer ${userToken}`,
3584
+ "Content-Type": "application/json"
3585
+ },
3586
+ body: JSON.stringify(input)
3587
+ });
3588
+ };
3589
+ let response = await request();
3590
+ if (response.status === 401) response = await request(true);
3591
+ const payload = await response.json().catch(() => null);
3592
+ const space = readCreatedSpace(payload);
3593
+ if (response.ok) {
3594
+ if (!space) throw new Error("Invalid space create response.");
3595
+ return {
3596
+ ...space,
3597
+ provisioned: true
3598
+ };
3599
+ }
3600
+ const message = isRecord(payload) && typeof payload.message === "string" ? payload.message : "Failed to create Space.";
3601
+ if (space) return {
3602
+ ...space,
3603
+ provisioned: false,
3604
+ error: message
3605
+ };
3606
+ throw new Error(message);
3607
+ }
3608
+ /**
3228
3609
  * Resolves the target space's name for the consent dialog. The host — not
3229
3610
  * the app — resolves it, so the dialog cannot be tricked into labeling a
3230
3611
  * grant with the wrong space.
@@ -3380,6 +3761,7 @@ function createAppBridgeCore(config) {
3380
3761
  const scopes = sanitizeRequestedScopes(data.scopes);
3381
3762
  const spaceId = typeof data.spaceId === "string" && data.spaceId ? data.spaceId : void 0;
3382
3763
  const selectSpace = data.selectSpace === true && !spaceId;
3764
+ const createSpace = data.createSpace === void 0 ? void 0 : sanitizeCreateSpaceInput(data.createSpace);
3383
3765
  const alwaysAsk = data.alwaysAsk === true;
3384
3766
  if (scopes.length === 0) {
3385
3767
  replyForRequest(data.requestId, {
@@ -3388,6 +3770,43 @@ function createAppBridgeCore(config) {
3388
3770
  }, true);
3389
3771
  return;
3390
3772
  }
3773
+ if (data.createSpace !== void 0 && !createSpace) {
3774
+ const named = isRecord(data.createSpace) && typeof data.createSpace.name === "string" && Boolean(data.createSpace.name.trim());
3775
+ replyForRequest(data.requestId, {
3776
+ type: "cohub.app.error",
3777
+ message: named ? "Invalid space create input." : "Space name is required."
3778
+ }, true);
3779
+ return;
3780
+ }
3781
+ if (createSpace && (selectSpace || spaceId)) {
3782
+ replyForRequest(data.requestId, {
3783
+ type: "cohub.app.error",
3784
+ message: "createSpace cannot be combined with spaceId or selectSpace."
3785
+ }, true);
3786
+ return;
3787
+ }
3788
+ if (state.authSaving) {
3789
+ replyForRequest(data.requestId, {
3790
+ type: "cohub.app.error",
3791
+ message: "Another authorization is already in progress."
3792
+ }, true);
3793
+ return;
3794
+ }
3795
+ if (state.pendingAuth) dismissPendingAuth();
3796
+ if (createSpace) {
3797
+ mintedSpace = null;
3798
+ state.pendingAuth = {
3799
+ requestId: data.requestId,
3800
+ scopes,
3801
+ reason: sanitizeReason(data.reason),
3802
+ homeSpaceName: app.spaceName ?? null,
3803
+ createSpace
3804
+ };
3805
+ state.authError = null;
3806
+ state.authOpen = true;
3807
+ notify();
3808
+ return;
3809
+ }
3391
3810
  if (!selectSpace && !alwaysAsk && allowsOwnerAutoAuthorization() && await isCurrentViewerAppOwner()) try {
3392
3811
  const result = await authorize(scopes, spaceId, { silent: true });
3393
3812
  replyForRequest(data.requestId, authorizeResult(result.token, result.spaceId, result.spaceId === app.spaceId ? app.spaceName ?? null : null), true);
@@ -3443,16 +3862,22 @@ function createAppBridgeCore(config) {
3443
3862
  }, true);
3444
3863
  }
3445
3864
  }
3446
- function cancelAuth() {
3447
- if (state.authSaving) return;
3865
+ function dismissPendingAuth() {
3448
3866
  if (!state.pendingAuth) return;
3449
3867
  replyForRequest(state.pendingAuth.requestId, {
3450
3868
  type: "cohub.app.authorize.result",
3451
3869
  token: null
3452
3870
  }, true);
3453
- state.authOpen = false;
3454
3871
  state.pendingAuth = null;
3872
+ state.authOpen = false;
3455
3873
  state.authError = null;
3874
+ mintedSpace = null;
3875
+ notify();
3876
+ }
3877
+ function cancelAuth() {
3878
+ if (state.authSaving) return;
3879
+ if (!state.pendingAuth) return;
3880
+ dismissPendingAuth();
3456
3881
  state.authSaving = false;
3457
3882
  notify();
3458
3883
  }
@@ -3501,14 +3926,27 @@ function createAppBridgeCore(config) {
3501
3926
  state.authSaving = true;
3502
3927
  notify();
3503
3928
  try {
3504
- const requestedSpaceId = pending.selectSpace ? pickedSpaceId : pending.spaceId;
3929
+ let requestedSpaceId = pending.selectSpace ? pickedSpaceId : pending.spaceId;
3930
+ let spaceName = pending.selectSpace ? pending.spaces?.find((space) => space.id === requestedSpaceId)?.name ?? null : pending.spaceName ?? app.spaceName ?? null;
3931
+ if (pending.createSpace) {
3932
+ mintedSpace ??= await createViewerSpace(pending.createSpace);
3933
+ if (!mintedSpace.provisioned) {
3934
+ replyForRequest(pending.requestId, authorizeResult(null, mintedSpace.id, mintedSpace.name ?? pending.createSpace.name), true);
3935
+ state.authOpen = false;
3936
+ state.pendingAuth = null;
3937
+ mintedSpace = null;
3938
+ return;
3939
+ }
3940
+ requestedSpaceId = mintedSpace.id;
3941
+ spaceName = mintedSpace.name ?? pending.createSpace.name;
3942
+ }
3505
3943
  const result = await authorize(pending.scopes, requestedSpaceId);
3506
3944
  setGrantedAppScopes(await getViewerUuid(), app.id, result.scopes, result.spaceId);
3507
- if (pending.selectSpace) writeLastPickedSpace(result.spaceId);
3508
- const spaceName = pending.selectSpace ? pending.spaces?.find((space) => space.id === result.spaceId)?.name ?? null : pending.spaceName ?? app.spaceName ?? null;
3945
+ if (pending.selectSpace || pending.createSpace) writeLastPickedSpace(result.spaceId);
3509
3946
  replyForRequest(pending.requestId, authorizeResult(result.token, result.spaceId, spaceName), true);
3510
3947
  state.authOpen = false;
3511
3948
  state.pendingAuth = null;
3949
+ mintedSpace = null;
3512
3950
  } catch (error) {
3513
3951
  state.authError = error instanceof Error ? error.message : "Authorization failed.";
3514
3952
  } finally {
@@ -3704,6 +4142,15 @@ var BoardExtensionRegistry = class {
3704
4142
  const diagnostics = [];
3705
4143
  const composition = parsed.data;
3706
4144
  const cost = { ...ZERO_COST };
4145
+ for (const effect of input.effects ?? []) {
4146
+ diagnostics.push(...validateBuiltinBoardEffect(effect, `effects.${effect.id}`));
4147
+ if (!this.#extensions.has(`effect:${effect.kind}@${effect.kindVersion}`)) diagnostics.push({
4148
+ severity: "warning",
4149
+ code: "UNKNOWN_EFFECT",
4150
+ message: `No renderer is registered for ${effect.kind}@${effect.kindVersion}`,
4151
+ path: `effects.${effect.id}`
4152
+ });
4153
+ }
3707
4154
  const events = [];
3708
4155
  for (const clip of composition.timeline.clips) {
3709
4156
  const definition = this.#extensions.get(`clip:${clip.kind}@${clip.kindVersion}`);
@@ -3737,7 +4184,10 @@ var BoardExtensionRegistry = class {
3737
4184
  active[key] += event.cost[key] * event.direction;
3738
4185
  cost[key] = Math.max(cost[key], active[key]);
3739
4186
  }
3740
- for (const effect of input.effects ?? []) if (effect.kind === "effects.pulse" || effect.kind === "effects.float") cost.drawCalls += 1;
4187
+ for (const effect of input.effects ?? []) {
4188
+ const estimate = estimateBuiltinBoardEffectCost(effect);
4189
+ for (const key of Object.keys(cost)) cost[key] += estimate[key] ?? 0;
4190
+ }
3741
4191
  const limits = input.limits ?? DEFAULT_BOARD_LIMITS;
3742
4192
  for (const key of Object.keys(cost)) if (cost[key] > limits[key]) diagnostics.push({
3743
4193
  severity: "warning",
@@ -3758,4 +4208,4 @@ function createBoardExtensionRegistry() {
3758
4208
  }
3759
4209
  const BOARD_CHANNELS = BOARD_ANIMATION_CHANNELS;
3760
4210
  //#endregion
3761
- export { APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppSurfaceApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BillingApi, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardEffectInputSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, BoardPlaybackPolicySchema, BoardSemanticCommandSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, DESKTOP_COMMAND_PENDING_TTL_SECONDS, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, DESKTOP_COMMAND_VERSION, DesktopCommandsApi, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, SpacePublicFilesApi, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, assertGenerationRequestAllowedByPolicy, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileComposition, composition, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, formatAppRef, formatWorkRef, getAllowedGenerationModelIds, getCohubContext, hasGrantedAppScopes, hasRequestSourceIdentity, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardEffectInput, parseBoardPlaybackPolicy, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseWorkRef, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, scopeListHasPermission, setGrantedAppScopes, track };
4211
+ export { APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppSurfaceApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BillingApi, BoardAnimationSpecSchema, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardDealParamsSchema, BoardEffectInputSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, BoardPlaybackPolicySchema, BoardSemanticCommandSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, DESKTOP_COMMAND_PENDING_TTL_SECONDS, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, DESKTOP_COMMAND_VERSION, DesktopCommandsApi, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, SpacePublicFilesApi, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, assertGenerationRequestAllowedByPolicy, attachAppEmbed, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileComposition, composition, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, formatAppRef, formatWorkRef, getAllowedGenerationModelIds, getCohubContext, hasGrantedAppScopes, hasRequestSourceIdentity, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardEffectInput, parseBoardPlaybackPolicy, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseWorkRef, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, scopeListHasPermission, setGrantedAppScopes, track };