@neta-art/cohub 4.8.0 → 5.0.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.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { A as CronJobsApi, C as ReferencesApi, D as PromptsApi, E as SkillsApi, O as ModelsApi, S as SessionAccessApi, T as PublicAssetsApi, _ as createSessionGenerationStreamClient, a as ReferralsApi, b as createSessionPatchReducer, c as TasksApi, d as SpaceClient, f as SpacesApi, g as SessionGenerationStreamClient, h as buildSpacePath, i as WorksApi, j as ChannelsApi, k as GenerationsApi, l as BoardClient, m as buildSpaceInvitePath, n as createHttpClient, o as UsersApi, p as PublicInviteApi, r as WorkCommerceApi, s as UserApi, t as CohubHttpClient, u as BoardTransactionError, v as parseAssistantMessageCommit, w as SearchApi, x as ensureRealtimeConnected, y as SessionPatchReducer } from "./chunks/http.js";
2
- import { a as COHUB_SOURCE_HEADER, c as hasRequestSourceIdentity, d as mergeRequestSourceIntoMeta, f as normalizeRequestSource, g as resolveRequestSourceChannel, h as requestSourceToHeaders, i as sanitizeAccessToken, l as isRequestSourceEmpty, m as readRequestSourceFromEnv, n as HttpTransport, o as COHUB_SOURCE_HEADER_NAMES, p as parseRequestSourceFromHeaders, r as joinApiUrl, s as REQUEST_SOURCE_VIA_MAX_LENGTH, t as HttpError, u as isRequestSourceUuid } from "./chunks/transport.js";
2
+ import { _ as REALTIME_ROOM_EVENT_NAME_PATTERN, a as COHUB_SOURCE_HEADER, c as hasRequestSourceIdentity, d as mergeRequestSourceIntoMeta, f as normalizeRequestSource, g as resolveRequestSourceChannel, h as requestSourceToHeaders, i as sanitizeAccessToken, l as isRequestSourceEmpty, m as readRequestSourceFromEnv, n as HttpTransport, o as COHUB_SOURCE_HEADER_NAMES, p as parseRequestSourceFromHeaders, r as joinApiUrl, s as REQUEST_SOURCE_VIA_MAX_LENGTH, t as HttpError, u as isRequestSourceUuid } from "./chunks/transport.js";
3
3
  import { a as resolveApiBaseUrl, c as resolveWebsocketUrl, i as normalizeWebsocketUrl, n as normalizeBaseUrl, o as resolveCohubEnvironment, r as normalizeVoiceInputWebsocketUrl, s as resolveVoiceInputWebsocketUrl, t as COHUB_ENVIRONMENTS } from "./chunks/environment.js";
4
4
  import { a as extractBillingPayload, c as isFeatureNotEntitledError, i as FEATURE_NOT_ENTITLED_ERROR_CODE, l as isHttpErrorCode, n as createWebsocketClient, o as isBillingAccessBlockedCode, r as BILLING_ACCESS_BLOCKED_ERROR_CODE, s as isBillingAccessBlockedError, t as WebsocketClient } from "./chunks/websocket.js";
5
5
  import { VoiceApi, VoiceInputClient, createVoiceInputClient } from "./voice-input.js";
@@ -70,14 +70,776 @@ var BillingApi = class {
70
70
  }
71
71
  };
72
72
  //#endregion
73
- //#region src/apis/explore.ts
74
- var ExploreApi = class {
73
+ //#region ../protocol/dist/board-constants.js
74
+ const DEFAULT_BOARD_RENDER_LIMITS = {
75
+ particles: 2e4,
76
+ vertices: 5e5,
77
+ dynamicVertices: 15e4,
78
+ drawCalls: 400,
79
+ filterPasses: 24,
80
+ renderTexturePixels: 16777216,
81
+ textureBytes: 512 * 1024 * 1024,
82
+ bufferBytes: 256 * 1024 * 1024,
83
+ simulationSteps: 1e5
84
+ };
85
+ const BOARD_BUILTIN_CLIP_KINDS = [
86
+ "motion.keyframes",
87
+ "motion.path",
88
+ "draw.reveal",
89
+ "draw.handwrite",
90
+ "text.reveal",
91
+ "effects.particles",
92
+ "effects.trail",
93
+ "effects.impact",
94
+ "effects.flash",
95
+ "effects.color",
96
+ "camera.pan",
97
+ "camera.zoom",
98
+ "camera.shake"
99
+ ];
100
+ const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
101
+ const BOARD_ARROW_STROKE_SIZE = 2.5;
102
+ const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
103
+ kind: "clip",
104
+ id,
105
+ version: 1,
106
+ renderers: ["webgpu", "webgl"]
107
+ })), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
108
+ kind: "effect",
109
+ id,
110
+ version: 1,
111
+ renderers: ["webgpu", "webgl"]
112
+ }))];
113
+ //#endregion
114
+ //#region ../protocol/dist/realtime/board-awareness.js
115
+ const idSchema$1 = z.string().min(1).max(160);
116
+ const finiteSchema$1 = z.number().finite();
117
+ const BoardAwarenessPointSchema = z.object({
118
+ x: finiteSchema$1,
119
+ y: finiteSchema$1
120
+ });
121
+ const BoardAwarenessDrawPointSchema = BoardAwarenessPointSchema.extend({ p: finiteSchema$1.min(0).max(1) });
122
+ const BoardAwarenessFrameSchema = z.object({
123
+ x: finiteSchema$1,
124
+ y: finiteSchema$1,
125
+ width: finiteSchema$1.positive(),
126
+ height: finiteSchema$1.positive(),
127
+ rotation: finiteSchema$1
128
+ });
129
+ const arrowEndpointSchema = z.union([z.object({
130
+ kind: z.literal("point"),
131
+ x: finiteSchema$1,
132
+ y: finiteSchema$1
133
+ }), z.object({
134
+ kind: z.literal("binding"),
135
+ target: idSchema$1,
136
+ nx: finiteSchema$1,
137
+ ny: finiteSchema$1,
138
+ precise: z.boolean()
139
+ })]);
140
+ const BoardAwarenessNodePreviewSchema = z.object({
141
+ nodeId: idSchema$1,
142
+ frame: BoardAwarenessFrameSchema,
143
+ arrow: z.object({
144
+ start: arrowEndpointSchema,
145
+ end: arrowEndpointSchema,
146
+ bend: finiteSchema$1
147
+ }).optional()
148
+ });
149
+ const BoardAwarenessStateUpdateSchema = z.object({
150
+ type: z.literal("state"),
151
+ client: z.object({ formFactor: z.enum(["desktop", "mobile"]) }).optional(),
152
+ cursor: BoardAwarenessPointSchema.extend({ pointerType: z.enum([
153
+ "mouse",
154
+ "pen",
155
+ "touch"
156
+ ]) }).nullable(),
157
+ tool: z.string().min(1).max(40),
158
+ selection: z.object({
159
+ ids: z.array(idSchema$1).max(64),
160
+ count: z.number().int().nonnegative().max(5e4),
161
+ bounds: BoardAwarenessFrameSchema.nullable()
162
+ }),
163
+ editingId: idSchema$1.nullable()
164
+ });
165
+ const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
166
+ z.object({
167
+ kind: z.literal("draw"),
168
+ id: idSchema$1,
169
+ nodeId: idSchema$1,
170
+ color: z.string().min(1).max(64),
171
+ size: finiteSchema$1.positive().max(256),
172
+ from: z.number().int().nonnegative().max(1e5),
173
+ points: z.array(BoardAwarenessDrawPointSchema).min(1).max(64)
174
+ }),
175
+ z.object({
176
+ kind: z.literal("arrow"),
177
+ id: idSchema$1,
178
+ nodeId: idSchema$1,
179
+ start: BoardAwarenessPointSchema,
180
+ current: BoardAwarenessPointSchema,
181
+ color: z.string().min(1).max(64),
182
+ size: finiteSchema$1.positive().max(256).default(BOARD_ARROW_STROKE_SIZE)
183
+ }),
184
+ z.object({
185
+ kind: z.literal("box"),
186
+ id: idSchema$1,
187
+ nodeId: idSchema$1,
188
+ shape: z.enum(["geo", "frame"]),
189
+ start: BoardAwarenessPointSchema,
190
+ current: BoardAwarenessPointSchema,
191
+ color: z.string().min(1).max(64),
192
+ geo: z.string().min(1).max(40)
193
+ }),
194
+ z.object({
195
+ kind: z.literal("transform"),
196
+ id: idSchema$1,
197
+ mode: z.enum([
198
+ "translate",
199
+ "resize",
200
+ "rotate",
201
+ "arrow"
202
+ ]),
203
+ nodes: z.array(BoardAwarenessNodePreviewSchema).max(64),
204
+ bounds: BoardAwarenessFrameSchema.nullable()
205
+ })
206
+ ]);
207
+ const BoardAwarenessUpdateSchema = z.discriminatedUnion("type", [
208
+ BoardAwarenessStateUpdateSchema,
209
+ z.object({
210
+ type: z.literal("gesture"),
211
+ gesture: BoardAwarenessGestureSchema
212
+ }),
213
+ z.object({
214
+ type: z.literal("gesture.end"),
215
+ gestureId: idSchema$1,
216
+ resultingNodeIds: z.array(idSchema$1).max(64)
217
+ }),
218
+ z.object({
219
+ type: z.literal("gesture.cancel"),
220
+ gestureId: idSchema$1
221
+ })
222
+ ]);
223
+ const BoardAwarenessClientPayloadSchema = z.object({
224
+ spaceId: z.string().uuid(),
225
+ boardId: z.string().uuid(),
226
+ seq: z.number().int().nonnegative(),
227
+ update: BoardAwarenessUpdateSchema
228
+ });
229
+ //#endregion
230
+ //#region ../protocol/dist/realtime/schema.js
231
+ const contentBlockMetaSchema = z.record(z.string(), z.unknown());
232
+ const realtimeRoomSchema = z.string().regex(/^(space|user|board|room):[^:]+$/);
233
+ const contentBlockSchema = z.discriminatedUnion("type", [
234
+ z.object({
235
+ type: z.literal("text"),
236
+ text: z.string(),
237
+ _meta: contentBlockMetaSchema.optional()
238
+ }),
239
+ z.object({
240
+ type: z.literal("thinking"),
241
+ thinking: z.string(),
242
+ signature: z.string().optional(),
243
+ _meta: contentBlockMetaSchema.optional()
244
+ }),
245
+ z.object({
246
+ type: z.literal("image"),
247
+ source: z.union([z.object({
248
+ type: z.literal("url"),
249
+ url: z.string().url()
250
+ }), z.object({
251
+ type: z.literal("base64"),
252
+ media_type: z.string(),
253
+ data: z.string()
254
+ })]),
255
+ _meta: contentBlockMetaSchema.optional()
256
+ }),
257
+ z.object({
258
+ type: z.literal("shell_command"),
259
+ command: z.string(),
260
+ rawText: z.string(),
261
+ _meta: contentBlockMetaSchema.optional()
262
+ }),
263
+ z.object({
264
+ type: z.literal("tool_use"),
265
+ id: z.string(),
266
+ name: z.string(),
267
+ input: z.record(z.string(), z.unknown()),
268
+ _meta: contentBlockMetaSchema.optional()
269
+ }),
270
+ z.object({
271
+ type: z.literal("tool_result"),
272
+ tool_use_id: z.string(),
273
+ content: z.union([z.string(), z.array(z.unknown())]),
274
+ is_error: z.boolean().optional(),
275
+ _meta: contentBlockMetaSchema.optional()
276
+ }),
277
+ z.object({
278
+ type: z.literal("system_note"),
279
+ note_type: z.enum([
280
+ "session_created",
281
+ "forked",
282
+ "compacted",
283
+ "info"
284
+ ]),
285
+ text: z.string(),
286
+ _meta: contentBlockMetaSchema.optional()
287
+ })
288
+ ]);
289
+ z.discriminatedUnion("type", [
290
+ z.object({
291
+ type: z.literal("auth"),
292
+ requestId: z.string().optional(),
293
+ payload: z.object({
294
+ token: z.string().min(1),
295
+ capabilities: z.array(z.string().min(1)).optional()
296
+ })
297
+ }),
298
+ z.object({
299
+ type: z.literal("subscribe"),
300
+ requestId: z.string().optional(),
301
+ payload: z.object({ rooms: z.array(realtimeRoomSchema).min(1) })
302
+ }),
303
+ z.object({
304
+ type: z.literal("unsubscribe"),
305
+ requestId: z.string().optional(),
306
+ payload: z.object({ rooms: z.array(realtimeRoomSchema).min(1) })
307
+ }),
308
+ z.object({
309
+ type: z.literal("session.message.create"),
310
+ requestId: z.string().optional(),
311
+ payload: z.object({
312
+ spaceId: z.string().uuid(),
313
+ sessionId: z.string().uuid(),
314
+ clientMessageId: z.string().optional(),
315
+ content: z.array(contentBlockSchema).min(1),
316
+ model: z.string().optional(),
317
+ provider: z.string().optional(),
318
+ thinkingLevel: z.enum([
319
+ "off",
320
+ "minimal",
321
+ "low",
322
+ "medium",
323
+ "high",
324
+ "xhigh",
325
+ "max"
326
+ ]).optional()
327
+ })
328
+ }),
329
+ z.object({
330
+ type: z.literal("presence.update"),
331
+ requestId: z.string().optional(),
332
+ payload: z.object({
333
+ spaceId: z.string().uuid(),
334
+ meta: z.record(z.string(), z.unknown()).nullable().optional()
335
+ })
336
+ }),
337
+ z.object({
338
+ type: z.literal("board.awareness.update"),
339
+ requestId: z.string().optional(),
340
+ payload: BoardAwarenessClientPayloadSchema
341
+ }),
342
+ z.object({
343
+ type: z.literal("realtime.room.join"),
344
+ requestId: z.string().optional(),
345
+ payload: z.object({
346
+ roomId: z.string().uuid(),
347
+ ticket: z.string().min(1)
348
+ })
349
+ }),
350
+ z.object({
351
+ type: z.literal("realtime.room.publish"),
352
+ requestId: z.string().optional(),
353
+ payload: z.object({
354
+ roomId: z.string().uuid(),
355
+ event: z.string().regex(REALTIME_ROOM_EVENT_NAME_PATTERN),
356
+ data: z.unknown(),
357
+ clientEventId: z.string().max(128).optional()
358
+ })
359
+ }),
360
+ z.object({
361
+ type: z.literal("realtime.room.leave"),
362
+ requestId: z.string().optional(),
363
+ payload: z.object({ roomId: z.string().uuid() })
364
+ }),
365
+ z.object({
366
+ type: z.literal("realtime.room.presence.update"),
367
+ requestId: z.string().optional(),
368
+ payload: z.object({
369
+ roomId: z.string().uuid(),
370
+ presence: z.record(z.string(), z.unknown()).nullable()
371
+ })
372
+ }),
373
+ z.object({
374
+ type: z.literal("ping"),
375
+ requestId: z.string().optional(),
376
+ payload: z.record(z.string(), z.unknown()).optional()
377
+ }),
378
+ z.object({
379
+ type: z.literal("ack"),
380
+ requestId: z.string().optional(),
381
+ payload: z.object({ eventId: z.string().optional() }).optional()
382
+ })
383
+ ]);
384
+ z.object({
385
+ id: z.string(),
386
+ timestamp: z.number(),
387
+ domain: z.enum([
388
+ "system",
389
+ "session",
390
+ "space",
391
+ "label",
392
+ "room"
393
+ ]),
394
+ type: z.string(),
395
+ requestId: z.string().nullable().optional(),
396
+ spaceId: z.string().nullable().optional(),
397
+ sessionId: z.string().nullable().optional(),
398
+ rooms: z.array(realtimeRoomSchema).optional(),
399
+ payload: z.record(z.string(), z.unknown())
400
+ });
401
+ z.discriminatedUnion("t", [z.object({
402
+ t: z.literal("d"),
403
+ sid: z.string().min(1),
404
+ s: z.number().int().nonnegative(),
405
+ b: z.number().int().nonnegative(),
406
+ v: z.unknown()
407
+ }), z.object({
408
+ t: z.literal("p"),
409
+ sid: z.string().min(1),
410
+ s: z.number().int().nonnegative(),
411
+ b: z.number().int().nonnegative(),
412
+ o: z.enum([
413
+ "append",
414
+ "replace",
415
+ "add",
416
+ "merge",
417
+ "remove"
418
+ ]),
419
+ p: z.string().min(1),
420
+ v: z.unknown().optional()
421
+ })]);
422
+ //#endregion
423
+ //#region src/apis/work-realtime.ts
424
+ const randomId = () => globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
425
+ const textEncoder = new TextEncoder();
426
+ const byteLength = (text) => textEncoder.encode(text).byteLength;
427
+ /**
428
+ * Ceiling on deltas held during a join, so a stalled handshake cannot buffer without
429
+ * limit. Dropping the tail needs no extra signal: the gap detection below reports it.
430
+ */
431
+ const WORK_ROOM_MAX_JOIN_BUFFER = 512;
432
+ /** Room events that mutate state, so they must not be applied before the join snapshot. */
433
+ const WORK_ROOM_DELTA_EVENTS = /* @__PURE__ */ new Set([
434
+ "realtime.room.event",
435
+ "realtime.room.member.joined",
436
+ "realtime.room.member.left",
437
+ "realtime.room.presence.updated"
438
+ ]);
439
+ const requestError = (event) => {
440
+ const payload = event.payload;
441
+ return new Error(typeof payload.message === "string" ? payload.message : typeof payload.code === "string" ? payload.code : "room request failed");
442
+ };
443
+ const isRoomEvent = (event, roomId) => {
444
+ if (event.domain !== "room") return false;
445
+ return event.payload.roomId === roomId || event.rooms?.includes(`room:${roomId}`);
446
+ };
447
+ var WorkRoom = class {
448
+ websocket;
449
+ admission;
450
+ id;
451
+ code;
452
+ createdAt;
453
+ expiresAt;
454
+ maxParticipants;
455
+ seatPerUser;
456
+ /** Opaque, stable identity of this viewer inside the room. */
457
+ userKey;
458
+ _participantId;
459
+ _state = "connecting";
460
+ _members = [];
461
+ joinBuffer = null;
462
+ lastSequence = 0;
463
+ hasJoined = false;
464
+ explicitLeave = false;
465
+ expiryTimer = null;
466
+ pending = /* @__PURE__ */ new Map();
467
+ handlers = /* @__PURE__ */ new Map();
468
+ allHandlers = /* @__PURE__ */ new Set();
469
+ stateHandlers = /* @__PURE__ */ new Set();
470
+ membersHandlers = /* @__PURE__ */ new Set();
471
+ outOfSyncHandlers = /* @__PURE__ */ new Set();
472
+ sendErrorHandlers = /* @__PURE__ */ new Set();
473
+ offEvent;
474
+ offOpen;
475
+ offClose;
476
+ offReconnecting;
477
+ constructor(websocket, admission) {
478
+ this.websocket = websocket;
479
+ this.admission = admission;
480
+ this.id = admission.room.id;
481
+ this.code = admission.room.code;
482
+ this.createdAt = admission.room.createdAt;
483
+ this.expiresAt = admission.room.expiresAt;
484
+ this.maxParticipants = admission.room.maxParticipants;
485
+ this.seatPerUser = admission.room.seatPerUser === true;
486
+ this.userKey = admission.userKey;
487
+ this._participantId = admission.participantId;
488
+ this.offEvent = websocket.on("event", (event) => this.handleEvent(event));
489
+ this.offOpen = websocket.on("open", () => {
490
+ if (!this.hasJoined || this.explicitLeave || this._state === "expired" || this._state === "closed") return;
491
+ this.rejoin();
492
+ });
493
+ this.offReconnecting = websocket.on("reconnecting", () => {
494
+ if (this.hasJoined && !this.explicitLeave) this.setState("reconnecting");
495
+ });
496
+ this.offClose = websocket.on("close", ({ willReconnect }) => {
497
+ this.rejectPending(/* @__PURE__ */ new Error("room connection closed"));
498
+ if (this.explicitLeave || !willReconnect) {
499
+ if (this._state !== "expired") this.setState("closed");
500
+ this.hasJoined = false;
501
+ this.dispose();
502
+ } else if (this.hasJoined) this.setState("reconnecting");
503
+ });
504
+ const delay = Math.max(0, Date.parse(this.expiresAt) - Date.now());
505
+ this.expiryTimer = setTimeout(() => this.expire(), Math.min(delay, 2147e6));
506
+ }
507
+ get state() {
508
+ return this._state;
509
+ }
510
+ /**
511
+ * Identity of this connection inside the room. A `seatPerUser` join can take over a
512
+ * seat the viewer already holds, so this may differ from the id issued at admission.
513
+ */
514
+ get participantId() {
515
+ return this._participantId;
516
+ }
517
+ get members() {
518
+ return this._members.slice();
519
+ }
520
+ async connect() {
521
+ await this.joinOverWebsocket(false);
522
+ return this;
523
+ }
524
+ subscribe(type, handler) {
525
+ const handlers = this.handlers.get(type) ?? /* @__PURE__ */ new Set();
526
+ handlers.add(handler);
527
+ this.handlers.set(type, handlers);
528
+ return () => handlers.delete(handler);
529
+ }
530
+ subscribeAll(handler) {
531
+ this.allHandlers.add(handler);
532
+ return () => this.allHandlers.delete(handler);
533
+ }
534
+ onStateChange(handler) {
535
+ this.stateHandlers.add(handler);
536
+ return () => this.stateHandlers.delete(handler);
537
+ }
538
+ onMembersChanged(handler) {
539
+ this.membersHandlers.add(handler);
540
+ return () => this.membersHandlers.delete(handler);
541
+ }
542
+ onOutOfSync(handler) {
543
+ this.outOfSyncHandlers.add(handler);
544
+ return () => this.outOfSyncHandlers.delete(handler);
545
+ }
546
+ /** Reports failures of {@link send}, which has no ack to reject. */
547
+ onSendError(handler) {
548
+ this.sendErrorHandlers.add(handler);
549
+ return () => this.sendErrorHandlers.delete(handler);
550
+ }
551
+ /**
552
+ * Publishes without waiting for the server ack, for high-frequency traffic such as
553
+ * input frames. Awaiting {@link publish} instead caps a loop at `1000 / rtt` events
554
+ * per second. Ordering still holds, but failures surface through
555
+ * {@link onSendError} rather than a rejected promise, and calls are ignored while
556
+ * the room is not joined; watch {@link onStateChange} to know when it resumes.
557
+ */
558
+ send(type, data) {
559
+ if (this._state !== "joined" || !this.hasJoined) return;
560
+ const failure = this.validateSend(type, data);
561
+ if (failure) {
562
+ for (const handler of this.sendErrorHandlers) handler(failure);
563
+ return;
564
+ }
565
+ this.websocket.publishRealtimeRoom({
566
+ roomId: this.id,
567
+ event: type,
568
+ data
569
+ }).catch((error) => {
570
+ const reason = error instanceof Error ? error : new Error(String(error));
571
+ for (const handler of this.sendErrorHandlers) handler(reason);
572
+ });
573
+ }
574
+ validateSend(type, data) {
575
+ if (!REALTIME_ROOM_EVENT_NAME_PATTERN.test(type)) return /* @__PURE__ */ new Error(`invalid room event name: ${type}`);
576
+ let encoded;
577
+ try {
578
+ encoded = JSON.stringify(data);
579
+ } catch {
580
+ return /* @__PURE__ */ new Error("room event data is not serializable");
581
+ }
582
+ if (encoded === void 0) return /* @__PURE__ */ new Error("room event data is not serializable");
583
+ if (byteLength(encoded) > 16384) return /* @__PURE__ */ new Error("room event payload is too large");
584
+ return null;
585
+ }
586
+ async publish(type, data, options) {
587
+ this.assertJoined();
588
+ const failure = this.validateSend(type, data);
589
+ if (failure) throw failure;
590
+ const requestId = randomId();
591
+ const response = await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.request.ok"]), () => this.websocket.publishRealtimeRoom({
592
+ roomId: this.id,
593
+ event: type,
594
+ data,
595
+ clientEventId: options?.clientEventId,
596
+ requestId
597
+ }));
598
+ const payload = response.payload;
599
+ return {
600
+ eventId: typeof payload.eventId === "string" ? payload.eventId : response.id,
601
+ sequence: typeof payload.sequence === "number" ? payload.sequence : 0,
602
+ clientEventId: typeof payload.clientEventId === "string" ? payload.clientEventId : null
603
+ };
604
+ }
605
+ async setPresence(presence) {
606
+ this.assertJoined();
607
+ const requestId = randomId();
608
+ await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.request.ok"]), () => this.websocket.updateRealtimeRoomPresence({
609
+ roomId: this.id,
610
+ presence,
611
+ requestId
612
+ }));
613
+ }
614
+ async leave() {
615
+ if (this.explicitLeave || this._state === "closed" || this._state === "expired") return;
616
+ this.explicitLeave = true;
617
+ try {
618
+ if (this.hasJoined && this.websocket.state === "open") {
619
+ const requestId = randomId();
620
+ await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.request.ok"]), () => this.websocket.leaveRealtimeRoom({
621
+ roomId: this.id,
622
+ requestId
623
+ }));
624
+ }
625
+ } finally {
626
+ this.hasJoined = false;
627
+ this.setState("closed");
628
+ this.dispose();
629
+ }
630
+ }
631
+ async rejoin() {
632
+ if (this.explicitLeave || this._state === "expired" || this._state === "closed") return;
633
+ try {
634
+ await this.joinOverWebsocket(true);
635
+ } catch (error) {
636
+ if (this.state === "expired") return;
637
+ this.setState("closed");
638
+ this.dispose();
639
+ console.warn("[Cohub WorkRoom] failed to rejoin room", error);
640
+ }
641
+ }
642
+ async joinOverWebsocket(isReconnect) {
643
+ if (!this.websocket.supportsCapability("realtime.room.v1") && this.websocket.state === "open") throw new Error("Realtime rooms are not supported by the Gateway");
644
+ this.setState(isReconnect ? "reconnecting" : "connecting");
645
+ const requestId = randomId();
646
+ this.joinBuffer = [];
647
+ try {
648
+ const payload = (await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.joined"]), () => this.websocket.joinRealtimeRoom({
649
+ roomId: this.id,
650
+ ticket: this.admission.ticket,
651
+ requestId
652
+ }))).payload;
653
+ if (typeof payload.participantId !== "string" || !Array.isArray(payload.members)) throw new Error("invalid room join response");
654
+ this._participantId = payload.participantId;
655
+ this._members = payload.members;
656
+ this.lastSequence = typeof payload.sequence === "number" ? payload.sequence : 0;
657
+ } catch (error) {
658
+ this.joinBuffer = null;
659
+ throw error;
660
+ }
661
+ this.hasJoined = true;
662
+ this.setState("joined");
663
+ this.notifyMembers();
664
+ const buffered = this.joinBuffer ?? [];
665
+ this.joinBuffer = null;
666
+ for (const item of buffered) {
667
+ const sequence = item.payload.sequence;
668
+ if (typeof sequence === "number" && sequence <= this.lastSequence) continue;
669
+ this.handleEvent(item);
670
+ }
671
+ }
672
+ request(requestId, expected, send) {
673
+ return new Promise((resolve, reject) => {
674
+ const timer = setTimeout(() => {
675
+ this.pending.delete(requestId);
676
+ reject(/* @__PURE__ */ new Error("room request timed out"));
677
+ }, 2e4);
678
+ this.pending.set(requestId, {
679
+ expected,
680
+ resolve,
681
+ reject,
682
+ timer
683
+ });
684
+ send().catch((error) => {
685
+ this.pending.delete(requestId);
686
+ clearTimeout(timer);
687
+ reject(error instanceof Error ? error : new Error(String(error)));
688
+ });
689
+ });
690
+ }
691
+ /** Detaches the entry awaiting this requestId, so the caller can settle it. */
692
+ takePending(requestId) {
693
+ const pending = requestId ? this.pending.get(requestId) : void 0;
694
+ if (!pending || !requestId) return null;
695
+ this.pending.delete(requestId);
696
+ clearTimeout(pending.timer);
697
+ return pending;
698
+ }
699
+ handleEvent(event) {
700
+ if (!isRoomEvent(event, this.id)) {
701
+ if (event.type === "system.request.error") this.takePending(event.requestId)?.reject(requestError(event));
702
+ return;
703
+ }
704
+ if (event.type === "realtime.room.request.error") {
705
+ const failure = requestError(event);
706
+ if (event.requestId) {
707
+ this.takePending(event.requestId)?.reject(failure);
708
+ return;
709
+ }
710
+ for (const handler of this.sendErrorHandlers) handler(failure);
711
+ return;
712
+ }
713
+ const awaiting = event.requestId ? this.pending.get(event.requestId) : void 0;
714
+ if (awaiting?.expected.has(event.type)) {
715
+ this.takePending(event.requestId);
716
+ awaiting.resolve(event);
717
+ }
718
+ if (this.joinBuffer && WORK_ROOM_DELTA_EVENTS.has(event.type)) {
719
+ if (this.joinBuffer.length < WORK_ROOM_MAX_JOIN_BUFFER) this.joinBuffer.push(event);
720
+ return;
721
+ }
722
+ const payload = event.payload;
723
+ const sequence = typeof payload.sequence === "number" ? payload.sequence : null;
724
+ if (sequence !== null) this.observeSequence(sequence);
725
+ if (event.type === "realtime.room.member.joined" || event.type === "realtime.room.member.left" || event.type === "realtime.room.presence.updated") {
726
+ const member = payload.member;
727
+ if (member?.participantId) {
728
+ const members = new Map(this._members.map((item) => [item.participantId, item]));
729
+ if (event.type === "realtime.room.member.left") members.delete(member.participantId);
730
+ else members.set(member.participantId, member);
731
+ this._members = [...members.values()];
732
+ this.notifyMembers();
733
+ }
734
+ return;
735
+ }
736
+ if (event.type === "realtime.room.closed") {
737
+ this.hasJoined = false;
738
+ if (payload.reason === "expired") this.setState("expired");
739
+ else this.setState("closed");
740
+ this.rejectPending(/* @__PURE__ */ new Error(`room closed: ${typeof payload.reason === "string" ? payload.reason : "unknown"}`));
741
+ this.dispose();
742
+ return;
743
+ }
744
+ if (event.type !== "realtime.room.event") return;
745
+ const roomEvent = event;
746
+ const roomPayload = roomEvent.payload;
747
+ const item = {
748
+ id: roomEvent.id,
749
+ timestamp: roomEvent.timestamp,
750
+ roomId: roomPayload.roomId,
751
+ sequence: roomPayload.sequence,
752
+ type: roomPayload.event,
753
+ data: roomPayload.data,
754
+ clientEventId: roomPayload.clientEventId,
755
+ sender: roomPayload.sender,
756
+ self: roomPayload.sender.participantId === this.participantId
757
+ };
758
+ this.handlers.get(item.type)?.forEach((handler) => {
759
+ handler(item);
760
+ });
761
+ this.allHandlers.forEach((handler) => {
762
+ handler(item);
763
+ });
764
+ }
765
+ observeSequence(sequence) {
766
+ if (this.lastSequence > 0 && sequence > this.lastSequence + 1) for (const handler of this.outOfSyncHandlers) handler(this.lastSequence + 1, sequence);
767
+ if (sequence > this.lastSequence) this.lastSequence = sequence;
768
+ }
769
+ assertJoined() {
770
+ if (this._state !== "joined" || !this.hasJoined) throw new Error("room is not joined");
771
+ }
772
+ setState(state) {
773
+ if (this._state === state) return;
774
+ this._state = state;
775
+ for (const handler of this.stateHandlers) handler(state);
776
+ }
777
+ notifyMembers() {
778
+ const members = this.members;
779
+ for (const handler of this.membersHandlers) handler(members);
780
+ }
781
+ rejectPending(error) {
782
+ for (const [requestId, pending] of this.pending) {
783
+ this.pending.delete(requestId);
784
+ clearTimeout(pending.timer);
785
+ pending.reject(error);
786
+ }
787
+ }
788
+ expire() {
789
+ if (this.explicitLeave || this._state === "closed" || this._state === "expired") return;
790
+ this.hasJoined = false;
791
+ this.setState("expired");
792
+ this.rejectPending(/* @__PURE__ */ new Error("room expired"));
793
+ this.dispose();
794
+ }
795
+ dispose() {
796
+ this.offEvent();
797
+ this.offOpen();
798
+ this.offClose();
799
+ this.offReconnecting();
800
+ if (this.expiryTimer) clearTimeout(this.expiryTimer);
801
+ this.expiryTimer = null;
802
+ }
803
+ };
804
+ var WorkRealtimeApi = class {
75
805
  transport;
76
- constructor(transport) {
806
+ websocket;
807
+ getContext;
808
+ constructor(transport, websocket, getContext) {
77
809
  this.transport = transport;
810
+ this.websocket = websocket;
811
+ this.getContext = getContext;
812
+ }
813
+ async createRoom(input = {}) {
814
+ const admission = await this.transport.request(`/api/works/${encodeURIComponent(await this.requireWorkId())}/realtime/rooms`, {
815
+ method: "POST",
816
+ headers: { "Content-Type": "application/json" },
817
+ body: JSON.stringify(input)
818
+ });
819
+ return this.openRoom(admission);
820
+ }
821
+ async joinRoom(input) {
822
+ const admission = await this.transport.request(`/api/works/${encodeURIComponent(await this.requireWorkId())}/realtime/rooms/join`, {
823
+ method: "POST",
824
+ headers: { "Content-Type": "application/json" },
825
+ body: JSON.stringify(input)
826
+ });
827
+ return this.openRoom(admission);
78
828
  }
79
- spaces() {
80
- return this.transport.request("/api/explore/spaces");
829
+ async requireWorkId() {
830
+ const context = await this.getContext();
831
+ if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
832
+ return context.work.id;
833
+ }
834
+ async openRoom(admission) {
835
+ const room = new WorkRoom(this.websocket, admission);
836
+ try {
837
+ await room.connect();
838
+ return room;
839
+ } catch (error) {
840
+ await room.leave().catch(() => void 0);
841
+ throw error;
842
+ }
81
843
  }
82
844
  };
83
845
  //#endregion
@@ -478,7 +1240,6 @@ var CohubClient = class {
478
1240
  references;
479
1241
  tasks;
480
1242
  cronJobs;
481
- explore;
482
1243
  invite;
483
1244
  referrals;
484
1245
  voice;
@@ -535,46 +1296,49 @@ var CohubClient = class {
535
1296
  this.references = new ReferencesApi(this.transport);
536
1297
  this.tasks = new TasksApi(this.transport);
537
1298
  this.cronJobs = new CronJobsApi(this.transport);
538
- this.explore = new ExploreApi(this.transport);
539
1299
  this.invite = new PublicInviteApi(this.transport);
540
1300
  this.referrals = new ReferralsApi(this.transport);
541
1301
  this.works = new WorksApi(this.transport);
542
1302
  this.workCommerce = new WorkCommerceApi(this.transport);
1303
+ this.work.realtime = new WorkRealtimeApi(this.transport, this.websocketClient, () => this.workRuntime.context());
543
1304
  }
544
1305
  context() {
545
1306
  return this.workRuntime.context();
546
1307
  }
547
1308
  auth = { request: (input) => this.workRuntime.requestAuthorization(input) };
548
- work = { commerce: {
549
- resolveProducts: async (input) => {
550
- const context = await this.workRuntime.context();
551
- if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
552
- return this.workCommerce.resolveProducts(context.work.id, input);
553
- },
554
- getEntitlements: async () => {
555
- const context = await this.workRuntime.context();
556
- if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
557
- return this.workCommerce.getEntitlements(context.work.id);
558
- },
559
- consumeCredits: async (input) => {
560
- const context = await this.workRuntime.context();
561
- if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
562
- return this.workCommerce.consumeCredits(context.work.id, input);
563
- },
564
- purchase: async (input) => this.workRuntime.purchase(input),
565
- getCheckoutState: async () => {
566
- const result = await this.workRuntime.checkoutState();
567
- return {
568
- status: result?.status ?? null,
569
- orderId: result?.orderId ?? null
570
- };
571
- },
572
- getOrder: async (orderId) => {
573
- const context = await this.workRuntime.context();
574
- if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
575
- return this.workCommerce.getOrder(context.work.id, orderId);
1309
+ work = {
1310
+ realtime: null,
1311
+ commerce: {
1312
+ resolveProducts: async (input) => {
1313
+ const context = await this.workRuntime.context();
1314
+ if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
1315
+ return this.workCommerce.resolveProducts(context.work.id, input);
1316
+ },
1317
+ getEntitlements: async () => {
1318
+ const context = await this.workRuntime.context();
1319
+ if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
1320
+ return this.workCommerce.getEntitlements(context.work.id);
1321
+ },
1322
+ consumeCredits: async (input) => {
1323
+ const context = await this.workRuntime.context();
1324
+ if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
1325
+ return this.workCommerce.consumeCredits(context.work.id, input);
1326
+ },
1327
+ purchase: async (input) => this.workRuntime.purchase(input),
1328
+ getCheckoutState: async () => {
1329
+ const result = await this.workRuntime.checkoutState();
1330
+ return {
1331
+ status: result?.status ?? null,
1332
+ orderId: result?.orderId ?? null
1333
+ };
1334
+ },
1335
+ getOrder: async (orderId) => {
1336
+ const context = await this.workRuntime.context();
1337
+ if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
1338
+ return this.workCommerce.getOrder(context.work.id, orderId);
1339
+ }
576
1340
  }
577
- } };
1341
+ };
578
1342
  space(spaceId) {
579
1343
  return new SpaceClient(spaceId, this.transport, this.websocketClient);
580
1344
  }
@@ -1290,53 +2054,12 @@ function filterGenerationDeclarationsByPolicy(declarations, policy) {
1290
2054
  });
1291
2055
  }
1292
2056
  //#endregion
1293
- //#region ../protocol/dist/board-constants.js
1294
- const DEFAULT_BOARD_RENDER_LIMITS = {
1295
- particles: 2e4,
1296
- vertices: 5e5,
1297
- dynamicVertices: 15e4,
1298
- drawCalls: 400,
1299
- filterPasses: 24,
1300
- renderTexturePixels: 16777216,
1301
- textureBytes: 512 * 1024 * 1024,
1302
- bufferBytes: 256 * 1024 * 1024,
1303
- simulationSteps: 1e5
1304
- };
1305
- const BOARD_BUILTIN_CLIP_KINDS = [
1306
- "motion.keyframes",
1307
- "motion.path",
1308
- "draw.reveal",
1309
- "draw.handwrite",
1310
- "text.reveal",
1311
- "effects.particles",
1312
- "effects.trail",
1313
- "effects.impact",
1314
- "effects.flash",
1315
- "effects.color",
1316
- "camera.pan",
1317
- "camera.zoom",
1318
- "camera.shake"
1319
- ];
1320
- const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
1321
- const BOARD_ARROW_STROKE_SIZE = 2.5;
1322
- const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
1323
- kind: "clip",
1324
- id,
1325
- version: 1,
1326
- renderers: ["webgpu", "webgl"]
1327
- })), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
1328
- kind: "effect",
1329
- id,
1330
- version: 1,
1331
- renderers: ["webgpu", "webgl"]
1332
- }))];
1333
- //#endregion
1334
2057
  //#region ../protocol/dist/board.js
1335
2058
  const BOARD_MANIFEST_KIND = "cohub.board.manifest";
1336
- const idSchema$1 = z.string().min(1).max(160);
2059
+ const idSchema = z.string().min(1).max(160);
1337
2060
  const extensionIdSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
1338
2061
  const jsonObjectSchema = z.record(z.string(), z.unknown());
1339
- const finiteSchema$1 = z.number().finite();
2062
+ const finiteSchema = z.number().finite();
1340
2063
  z.object({
1341
2064
  kind: z.literal(BOARD_MANIFEST_KIND),
1342
2065
  version: z.literal(1),
@@ -1346,11 +2069,11 @@ z.object({
1346
2069
  const BoardTargetSchema = z.discriminatedUnion("type", [
1347
2070
  z.object({
1348
2071
  type: z.literal("node"),
1349
- nodeId: idSchema$1
2072
+ nodeId: idSchema
1350
2073
  }),
1351
2074
  z.object({
1352
2075
  type: z.literal("effect"),
1353
- effectId: idSchema$1
2076
+ effectId: idSchema
1354
2077
  }),
1355
2078
  z.object({ type: z.literal("board") }),
1356
2079
  z.object({ type: z.literal("camera") })
@@ -1361,18 +2084,18 @@ const BoardAssetRefSchema = z.object({
1361
2084
  digest: z.string().min(16).max(160).optional()
1362
2085
  });
1363
2086
  const BoardKeyframeSchema = z.object({
1364
- at: finiteSchema$1.nonnegative(),
2087
+ at: finiteSchema.nonnegative(),
1365
2088
  value: z.unknown(),
1366
2089
  easing: z.string().min(1).max(80).optional()
1367
2090
  });
1368
2091
  const BoardClipSchema = z.object({
1369
- id: idSchema$1,
1370
- sequenceId: idSchema$1,
2092
+ id: idSchema,
2093
+ sequenceId: idSchema,
1371
2094
  kind: extensionIdSchema,
1372
2095
  kindVersion: z.number().int().positive(),
1373
2096
  target: BoardTargetSchema,
1374
- start: finiteSchema$1.nonnegative(),
1375
- duration: finiteSchema$1.positive(),
2097
+ start: finiteSchema.nonnegative(),
2098
+ duration: finiteSchema.positive(),
1376
2099
  layer: z.enum([
1377
2100
  "behind",
1378
2101
  "content",
@@ -1393,11 +2116,11 @@ const BoardClipSchema = z.object({
1393
2116
  metadata: jsonObjectSchema.default({})
1394
2117
  });
1395
2118
  const BoardEffectSchema = z.object({
1396
- id: idSchema$1,
2119
+ id: idSchema,
1397
2120
  boardId: z.string().uuid(),
1398
2121
  target: z.discriminatedUnion("type", [z.object({
1399
2122
  type: z.literal("node"),
1400
- nodeId: idSchema$1
2123
+ nodeId: idSchema
1401
2124
  }), z.object({ type: z.literal("board") })]),
1402
2125
  kind: extensionIdSchema,
1403
2126
  kindVersion: z.number().int().positive(),
@@ -1424,25 +2147,25 @@ const BoardEffectSchema = z.object({
1424
2147
  revision: z.number().int().nonnegative()
1425
2148
  });
1426
2149
  const BoardSequenceSchema = z.object({
1427
- id: idSchema$1,
2150
+ id: idSchema,
1428
2151
  boardId: z.string().uuid(),
1429
2152
  name: z.string().min(1).max(255),
1430
- duration: finiteSchema$1.nonnegative(),
2153
+ duration: finiteSchema.nonnegative(),
1431
2154
  seed: z.string().min(1).max(160),
1432
2155
  restPose: jsonObjectSchema.default({}),
1433
2156
  metadata: jsonObjectSchema.default({}),
1434
2157
  revision: z.number().int().nonnegative()
1435
2158
  });
1436
2159
  const BoardNodeInputSchema = z.object({
1437
- nodeId: idSchema$1,
2160
+ nodeId: idSchema,
1438
2161
  type: z.string().min(1).max(40),
1439
- parentId: idSchema$1.nullable(),
2162
+ parentId: idSchema.nullable(),
1440
2163
  orderKey: z.string().max(4096).nullable(),
1441
- x: finiteSchema$1,
1442
- y: finiteSchema$1,
1443
- width: finiteSchema$1.positive(),
1444
- height: finiteSchema$1.positive(),
1445
- rotation: finiteSchema$1,
2164
+ x: finiteSchema,
2165
+ y: finiteSchema,
2166
+ width: finiteSchema.positive(),
2167
+ height: finiteSchema.positive(),
2168
+ rotation: finiteSchema,
1446
2169
  refKind: z.string().max(40).nullable(),
1447
2170
  refPath: z.string().max(4096).nullable(),
1448
2171
  refUrl: z.string().max(4096).nullable(),
@@ -1478,17 +2201,17 @@ z.object({
1478
2201
  "playback"
1479
2202
  ])).optional(),
1480
2203
  viewport: z.object({
1481
- x: finiteSchema$1,
1482
- y: finiteSchema$1,
1483
- width: finiteSchema$1.positive(),
1484
- height: finiteSchema$1.positive()
2204
+ x: finiteSchema,
2205
+ y: finiteSchema,
2206
+ width: finiteSchema.positive(),
2207
+ height: finiteSchema.positive()
1485
2208
  }).optional()
1486
2209
  });
1487
2210
  /** Persisted on `boards.metadata.playback`: how a Board plays when opened. */
1488
2211
  const BoardPlaybackPolicySchema = z.object({
1489
- sequenceId: idSchema$1,
2212
+ sequenceId: idSchema,
1490
2213
  /** Delay before the first local playback after opening the Board, in milliseconds. */
1491
- delayMs: finiteSchema$1.nonnegative().default(0),
2214
+ delayMs: finiteSchema.nonnegative().default(0),
1492
2215
  loop: z.boolean().default(false)
1493
2216
  });
1494
2217
  function parseBoardPlaybackPolicy(metadata) {
@@ -1497,148 +2220,32 @@ function parseBoardPlaybackPolicy(metadata) {
1497
2220
  }
1498
2221
  z.discriminatedUnion("type", [
1499
2222
  z.object({
1500
- commandId: idSchema$1,
2223
+ commandId: idSchema,
1501
2224
  type: z.literal("play"),
1502
- sequenceId: idSchema$1,
1503
- position: finiteSchema$1.nonnegative().optional(),
1504
- timeScale: finiteSchema$1.positive().max(4).optional(),
2225
+ sequenceId: idSchema,
2226
+ position: finiteSchema.nonnegative().optional(),
2227
+ timeScale: finiteSchema.positive().max(4).optional(),
1505
2228
  shared: z.boolean().optional(),
1506
- seed: idSchema$1.optional()
2229
+ seed: idSchema.optional()
1507
2230
  }),
1508
2231
  z.object({
1509
- commandId: idSchema$1,
2232
+ commandId: idSchema,
1510
2233
  type: z.literal("pause"),
1511
2234
  playbackId: z.string().uuid()
1512
2235
  }),
1513
2236
  z.object({
1514
- commandId: idSchema$1,
2237
+ commandId: idSchema,
1515
2238
  type: z.literal("seek"),
1516
2239
  playbackId: z.string().uuid(),
1517
- position: finiteSchema$1.nonnegative()
2240
+ position: finiteSchema.nonnegative()
1518
2241
  }),
1519
2242
  z.object({
1520
- commandId: idSchema$1,
2243
+ commandId: idSchema,
1521
2244
  type: z.literal("stop"),
1522
2245
  playbackId: z.string().uuid()
1523
2246
  })
1524
2247
  ]);
1525
2248
  //#endregion
1526
- //#region ../protocol/dist/realtime/board-awareness.js
1527
- const idSchema = z.string().min(1).max(160);
1528
- const finiteSchema = z.number().finite();
1529
- const BoardAwarenessPointSchema = z.object({
1530
- x: finiteSchema,
1531
- y: finiteSchema
1532
- });
1533
- const BoardAwarenessDrawPointSchema = BoardAwarenessPointSchema.extend({ p: finiteSchema.min(0).max(1) });
1534
- const BoardAwarenessFrameSchema = z.object({
1535
- x: finiteSchema,
1536
- y: finiteSchema,
1537
- width: finiteSchema.positive(),
1538
- height: finiteSchema.positive(),
1539
- rotation: finiteSchema
1540
- });
1541
- const arrowEndpointSchema = z.union([z.object({
1542
- kind: z.literal("point"),
1543
- x: finiteSchema,
1544
- y: finiteSchema
1545
- }), z.object({
1546
- kind: z.literal("binding"),
1547
- target: idSchema,
1548
- nx: finiteSchema,
1549
- ny: finiteSchema,
1550
- precise: z.boolean()
1551
- })]);
1552
- const BoardAwarenessNodePreviewSchema = z.object({
1553
- nodeId: idSchema,
1554
- frame: BoardAwarenessFrameSchema,
1555
- arrow: z.object({
1556
- start: arrowEndpointSchema,
1557
- end: arrowEndpointSchema,
1558
- bend: finiteSchema
1559
- }).optional()
1560
- });
1561
- const BoardAwarenessStateUpdateSchema = z.object({
1562
- type: z.literal("state"),
1563
- client: z.object({ formFactor: z.enum(["desktop", "mobile"]) }).optional(),
1564
- cursor: BoardAwarenessPointSchema.extend({ pointerType: z.enum([
1565
- "mouse",
1566
- "pen",
1567
- "touch"
1568
- ]) }).nullable(),
1569
- tool: z.string().min(1).max(40),
1570
- selection: z.object({
1571
- ids: z.array(idSchema).max(64),
1572
- count: z.number().int().nonnegative().max(5e4),
1573
- bounds: BoardAwarenessFrameSchema.nullable()
1574
- }),
1575
- editingId: idSchema.nullable()
1576
- });
1577
- const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
1578
- z.object({
1579
- kind: z.literal("draw"),
1580
- id: idSchema,
1581
- nodeId: idSchema,
1582
- color: z.string().min(1).max(64),
1583
- size: finiteSchema.positive().max(256),
1584
- from: z.number().int().nonnegative().max(1e5),
1585
- points: z.array(BoardAwarenessDrawPointSchema).min(1).max(64)
1586
- }),
1587
- z.object({
1588
- kind: z.literal("arrow"),
1589
- id: idSchema,
1590
- nodeId: idSchema,
1591
- start: BoardAwarenessPointSchema,
1592
- current: BoardAwarenessPointSchema,
1593
- color: z.string().min(1).max(64),
1594
- size: finiteSchema.positive().max(256).default(BOARD_ARROW_STROKE_SIZE)
1595
- }),
1596
- z.object({
1597
- kind: z.literal("box"),
1598
- id: idSchema,
1599
- nodeId: idSchema,
1600
- shape: z.enum(["geo", "frame"]),
1601
- start: BoardAwarenessPointSchema,
1602
- current: BoardAwarenessPointSchema,
1603
- color: z.string().min(1).max(64),
1604
- geo: z.string().min(1).max(40)
1605
- }),
1606
- z.object({
1607
- kind: z.literal("transform"),
1608
- id: idSchema,
1609
- mode: z.enum([
1610
- "translate",
1611
- "resize",
1612
- "rotate",
1613
- "arrow"
1614
- ]),
1615
- nodes: z.array(BoardAwarenessNodePreviewSchema).max(64),
1616
- bounds: BoardAwarenessFrameSchema.nullable()
1617
- })
1618
- ]);
1619
- const BoardAwarenessUpdateSchema = z.discriminatedUnion("type", [
1620
- BoardAwarenessStateUpdateSchema,
1621
- z.object({
1622
- type: z.literal("gesture"),
1623
- gesture: BoardAwarenessGestureSchema
1624
- }),
1625
- z.object({
1626
- type: z.literal("gesture.end"),
1627
- gestureId: idSchema,
1628
- resultingNodeIds: z.array(idSchema).max(64)
1629
- }),
1630
- z.object({
1631
- type: z.literal("gesture.cancel"),
1632
- gestureId: idSchema
1633
- })
1634
- ]);
1635
- z.object({
1636
- spaceId: z.string().uuid(),
1637
- boardId: z.string().uuid(),
1638
- seq: z.number().int().nonnegative(),
1639
- update: BoardAwarenessUpdateSchema
1640
- });
1641
- //#endregion
1642
2249
  //#region ../protocol/dist/public-identifiers.js
1643
2250
  /**
1644
2251
  * Platform-owned path segments that must not be newly assigned to public
@@ -2026,4 +2633,4 @@ function createBoardExtensionRegistry(input = {}) {
2026
2633
  return registry;
2027
2634
  }
2028
2635
  //#endregion
2029
- export { BILLING_ACCESS_BLOCKED_ERROR_CODE, BillingApi, BoardClient, BoardExtensionRegistry, BoardPlaybackPolicySchema, BoardTransactionError, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRuntimeApi, WorksApi, assertGenerationRequestAllowedByPolicy, buildSpaceInvitePath, buildSpacePath, clearGrantedWorkScopes, clip, compileSequence, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, hasGrantedWorkScopes, hasRequestSourceIdentity, isBillingAccessBlockedCode, isBillingAccessBlockedError, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceEmpty, isRequestSourceUuid, joinApiUrl, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseBoardPlaybackPolicy, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveCohubEnvironment, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, sanitizeAccessToken, setGrantedWorkScopes, timeline };
2636
+ export { BILLING_ACCESS_BLOCKED_ERROR_CODE, BillingApi, BoardClient, BoardExtensionRegistry, BoardPlaybackPolicySchema, BoardTransactionError, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRoom, WorkRuntimeApi, WorksApi, assertGenerationRequestAllowedByPolicy, buildSpaceInvitePath, buildSpacePath, clearGrantedWorkScopes, clip, compileSequence, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, getAllowedGenerationModelIds, hasGrantedWorkScopes, hasRequestSourceIdentity, isBillingAccessBlockedCode, isBillingAccessBlockedError, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceEmpty, isRequestSourceUuid, joinApiUrl, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseBoardPlaybackPolicy, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveCohubEnvironment, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, sanitizeAccessToken, setGrantedWorkScopes, timeline };