@neta-art/cohub 4.8.0 → 4.9.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/README.md +39 -0
- package/dist/chunks/http.d.ts +1 -1
- package/dist/chunks/http.js +1 -1
- package/dist/chunks/transport.js +7 -2
- package/dist/chunks/websocket.d.ts +166 -4
- package/dist/chunks/websocket.js +56 -4
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +134 -2
- package/dist/index.js +843 -223
- package/docs/work-runtime-guide.md +92 -0
- package/package.json +1 -1
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";
|
|
@@ -81,6 +81,779 @@ var ExploreApi = class {
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
//#endregion
|
|
84
|
+
//#region ../protocol/dist/board-constants.js
|
|
85
|
+
const DEFAULT_BOARD_RENDER_LIMITS = {
|
|
86
|
+
particles: 2e4,
|
|
87
|
+
vertices: 5e5,
|
|
88
|
+
dynamicVertices: 15e4,
|
|
89
|
+
drawCalls: 400,
|
|
90
|
+
filterPasses: 24,
|
|
91
|
+
renderTexturePixels: 16777216,
|
|
92
|
+
textureBytes: 512 * 1024 * 1024,
|
|
93
|
+
bufferBytes: 256 * 1024 * 1024,
|
|
94
|
+
simulationSteps: 1e5
|
|
95
|
+
};
|
|
96
|
+
const BOARD_BUILTIN_CLIP_KINDS = [
|
|
97
|
+
"motion.keyframes",
|
|
98
|
+
"motion.path",
|
|
99
|
+
"draw.reveal",
|
|
100
|
+
"draw.handwrite",
|
|
101
|
+
"text.reveal",
|
|
102
|
+
"effects.particles",
|
|
103
|
+
"effects.trail",
|
|
104
|
+
"effects.impact",
|
|
105
|
+
"effects.flash",
|
|
106
|
+
"effects.color",
|
|
107
|
+
"camera.pan",
|
|
108
|
+
"camera.zoom",
|
|
109
|
+
"camera.shake"
|
|
110
|
+
];
|
|
111
|
+
const BOARD_BUILTIN_EFFECT_KINDS = ["effects.pulse", "effects.float"];
|
|
112
|
+
const BOARD_ARROW_STROKE_SIZE = 2.5;
|
|
113
|
+
const BOARD_BUILTIN_CAPABILITIES = [...BOARD_BUILTIN_CLIP_KINDS.map((id) => ({
|
|
114
|
+
kind: "clip",
|
|
115
|
+
id,
|
|
116
|
+
version: 1,
|
|
117
|
+
renderers: ["webgpu", "webgl"]
|
|
118
|
+
})), ...BOARD_BUILTIN_EFFECT_KINDS.map((id) => ({
|
|
119
|
+
kind: "effect",
|
|
120
|
+
id,
|
|
121
|
+
version: 1,
|
|
122
|
+
renderers: ["webgpu", "webgl"]
|
|
123
|
+
}))];
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region ../protocol/dist/realtime/board-awareness.js
|
|
126
|
+
const idSchema$1 = z.string().min(1).max(160);
|
|
127
|
+
const finiteSchema$1 = z.number().finite();
|
|
128
|
+
const BoardAwarenessPointSchema = z.object({
|
|
129
|
+
x: finiteSchema$1,
|
|
130
|
+
y: finiteSchema$1
|
|
131
|
+
});
|
|
132
|
+
const BoardAwarenessDrawPointSchema = BoardAwarenessPointSchema.extend({ p: finiteSchema$1.min(0).max(1) });
|
|
133
|
+
const BoardAwarenessFrameSchema = z.object({
|
|
134
|
+
x: finiteSchema$1,
|
|
135
|
+
y: finiteSchema$1,
|
|
136
|
+
width: finiteSchema$1.positive(),
|
|
137
|
+
height: finiteSchema$1.positive(),
|
|
138
|
+
rotation: finiteSchema$1
|
|
139
|
+
});
|
|
140
|
+
const arrowEndpointSchema = z.union([z.object({
|
|
141
|
+
kind: z.literal("point"),
|
|
142
|
+
x: finiteSchema$1,
|
|
143
|
+
y: finiteSchema$1
|
|
144
|
+
}), z.object({
|
|
145
|
+
kind: z.literal("binding"),
|
|
146
|
+
target: idSchema$1,
|
|
147
|
+
nx: finiteSchema$1,
|
|
148
|
+
ny: finiteSchema$1,
|
|
149
|
+
precise: z.boolean()
|
|
150
|
+
})]);
|
|
151
|
+
const BoardAwarenessNodePreviewSchema = z.object({
|
|
152
|
+
nodeId: idSchema$1,
|
|
153
|
+
frame: BoardAwarenessFrameSchema,
|
|
154
|
+
arrow: z.object({
|
|
155
|
+
start: arrowEndpointSchema,
|
|
156
|
+
end: arrowEndpointSchema,
|
|
157
|
+
bend: finiteSchema$1
|
|
158
|
+
}).optional()
|
|
159
|
+
});
|
|
160
|
+
const BoardAwarenessStateUpdateSchema = z.object({
|
|
161
|
+
type: z.literal("state"),
|
|
162
|
+
client: z.object({ formFactor: z.enum(["desktop", "mobile"]) }).optional(),
|
|
163
|
+
cursor: BoardAwarenessPointSchema.extend({ pointerType: z.enum([
|
|
164
|
+
"mouse",
|
|
165
|
+
"pen",
|
|
166
|
+
"touch"
|
|
167
|
+
]) }).nullable(),
|
|
168
|
+
tool: z.string().min(1).max(40),
|
|
169
|
+
selection: z.object({
|
|
170
|
+
ids: z.array(idSchema$1).max(64),
|
|
171
|
+
count: z.number().int().nonnegative().max(5e4),
|
|
172
|
+
bounds: BoardAwarenessFrameSchema.nullable()
|
|
173
|
+
}),
|
|
174
|
+
editingId: idSchema$1.nullable()
|
|
175
|
+
});
|
|
176
|
+
const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
|
|
177
|
+
z.object({
|
|
178
|
+
kind: z.literal("draw"),
|
|
179
|
+
id: idSchema$1,
|
|
180
|
+
nodeId: idSchema$1,
|
|
181
|
+
color: z.string().min(1).max(64),
|
|
182
|
+
size: finiteSchema$1.positive().max(256),
|
|
183
|
+
from: z.number().int().nonnegative().max(1e5),
|
|
184
|
+
points: z.array(BoardAwarenessDrawPointSchema).min(1).max(64)
|
|
185
|
+
}),
|
|
186
|
+
z.object({
|
|
187
|
+
kind: z.literal("arrow"),
|
|
188
|
+
id: idSchema$1,
|
|
189
|
+
nodeId: idSchema$1,
|
|
190
|
+
start: BoardAwarenessPointSchema,
|
|
191
|
+
current: BoardAwarenessPointSchema,
|
|
192
|
+
color: z.string().min(1).max(64),
|
|
193
|
+
size: finiteSchema$1.positive().max(256).default(BOARD_ARROW_STROKE_SIZE)
|
|
194
|
+
}),
|
|
195
|
+
z.object({
|
|
196
|
+
kind: z.literal("box"),
|
|
197
|
+
id: idSchema$1,
|
|
198
|
+
nodeId: idSchema$1,
|
|
199
|
+
shape: z.enum(["geo", "frame"]),
|
|
200
|
+
start: BoardAwarenessPointSchema,
|
|
201
|
+
current: BoardAwarenessPointSchema,
|
|
202
|
+
color: z.string().min(1).max(64),
|
|
203
|
+
geo: z.string().min(1).max(40)
|
|
204
|
+
}),
|
|
205
|
+
z.object({
|
|
206
|
+
kind: z.literal("transform"),
|
|
207
|
+
id: idSchema$1,
|
|
208
|
+
mode: z.enum([
|
|
209
|
+
"translate",
|
|
210
|
+
"resize",
|
|
211
|
+
"rotate",
|
|
212
|
+
"arrow"
|
|
213
|
+
]),
|
|
214
|
+
nodes: z.array(BoardAwarenessNodePreviewSchema).max(64),
|
|
215
|
+
bounds: BoardAwarenessFrameSchema.nullable()
|
|
216
|
+
})
|
|
217
|
+
]);
|
|
218
|
+
const BoardAwarenessUpdateSchema = z.discriminatedUnion("type", [
|
|
219
|
+
BoardAwarenessStateUpdateSchema,
|
|
220
|
+
z.object({
|
|
221
|
+
type: z.literal("gesture"),
|
|
222
|
+
gesture: BoardAwarenessGestureSchema
|
|
223
|
+
}),
|
|
224
|
+
z.object({
|
|
225
|
+
type: z.literal("gesture.end"),
|
|
226
|
+
gestureId: idSchema$1,
|
|
227
|
+
resultingNodeIds: z.array(idSchema$1).max(64)
|
|
228
|
+
}),
|
|
229
|
+
z.object({
|
|
230
|
+
type: z.literal("gesture.cancel"),
|
|
231
|
+
gestureId: idSchema$1
|
|
232
|
+
})
|
|
233
|
+
]);
|
|
234
|
+
const BoardAwarenessClientPayloadSchema = z.object({
|
|
235
|
+
spaceId: z.string().uuid(),
|
|
236
|
+
boardId: z.string().uuid(),
|
|
237
|
+
seq: z.number().int().nonnegative(),
|
|
238
|
+
update: BoardAwarenessUpdateSchema
|
|
239
|
+
});
|
|
240
|
+
//#endregion
|
|
241
|
+
//#region ../protocol/dist/realtime/schema.js
|
|
242
|
+
const contentBlockMetaSchema = z.record(z.string(), z.unknown());
|
|
243
|
+
const realtimeRoomSchema = z.string().regex(/^(space|user|board|room):[^:]+$/);
|
|
244
|
+
const contentBlockSchema = z.discriminatedUnion("type", [
|
|
245
|
+
z.object({
|
|
246
|
+
type: z.literal("text"),
|
|
247
|
+
text: z.string(),
|
|
248
|
+
_meta: contentBlockMetaSchema.optional()
|
|
249
|
+
}),
|
|
250
|
+
z.object({
|
|
251
|
+
type: z.literal("thinking"),
|
|
252
|
+
thinking: z.string(),
|
|
253
|
+
signature: z.string().optional(),
|
|
254
|
+
_meta: contentBlockMetaSchema.optional()
|
|
255
|
+
}),
|
|
256
|
+
z.object({
|
|
257
|
+
type: z.literal("image"),
|
|
258
|
+
source: z.union([z.object({
|
|
259
|
+
type: z.literal("url"),
|
|
260
|
+
url: z.string().url()
|
|
261
|
+
}), z.object({
|
|
262
|
+
type: z.literal("base64"),
|
|
263
|
+
media_type: z.string(),
|
|
264
|
+
data: z.string()
|
|
265
|
+
})]),
|
|
266
|
+
_meta: contentBlockMetaSchema.optional()
|
|
267
|
+
}),
|
|
268
|
+
z.object({
|
|
269
|
+
type: z.literal("shell_command"),
|
|
270
|
+
command: z.string(),
|
|
271
|
+
rawText: z.string(),
|
|
272
|
+
_meta: contentBlockMetaSchema.optional()
|
|
273
|
+
}),
|
|
274
|
+
z.object({
|
|
275
|
+
type: z.literal("tool_use"),
|
|
276
|
+
id: z.string(),
|
|
277
|
+
name: z.string(),
|
|
278
|
+
input: z.record(z.string(), z.unknown()),
|
|
279
|
+
_meta: contentBlockMetaSchema.optional()
|
|
280
|
+
}),
|
|
281
|
+
z.object({
|
|
282
|
+
type: z.literal("tool_result"),
|
|
283
|
+
tool_use_id: z.string(),
|
|
284
|
+
content: z.union([z.string(), z.array(z.unknown())]),
|
|
285
|
+
is_error: z.boolean().optional(),
|
|
286
|
+
_meta: contentBlockMetaSchema.optional()
|
|
287
|
+
}),
|
|
288
|
+
z.object({
|
|
289
|
+
type: z.literal("system_note"),
|
|
290
|
+
note_type: z.enum([
|
|
291
|
+
"session_created",
|
|
292
|
+
"forked",
|
|
293
|
+
"compacted",
|
|
294
|
+
"info"
|
|
295
|
+
]),
|
|
296
|
+
text: z.string(),
|
|
297
|
+
_meta: contentBlockMetaSchema.optional()
|
|
298
|
+
})
|
|
299
|
+
]);
|
|
300
|
+
z.discriminatedUnion("type", [
|
|
301
|
+
z.object({
|
|
302
|
+
type: z.literal("auth"),
|
|
303
|
+
requestId: z.string().optional(),
|
|
304
|
+
payload: z.object({
|
|
305
|
+
token: z.string().min(1),
|
|
306
|
+
capabilities: z.array(z.string().min(1)).optional()
|
|
307
|
+
})
|
|
308
|
+
}),
|
|
309
|
+
z.object({
|
|
310
|
+
type: z.literal("subscribe"),
|
|
311
|
+
requestId: z.string().optional(),
|
|
312
|
+
payload: z.object({ rooms: z.array(realtimeRoomSchema).min(1) })
|
|
313
|
+
}),
|
|
314
|
+
z.object({
|
|
315
|
+
type: z.literal("unsubscribe"),
|
|
316
|
+
requestId: z.string().optional(),
|
|
317
|
+
payload: z.object({ rooms: z.array(realtimeRoomSchema).min(1) })
|
|
318
|
+
}),
|
|
319
|
+
z.object({
|
|
320
|
+
type: z.literal("session.message.create"),
|
|
321
|
+
requestId: z.string().optional(),
|
|
322
|
+
payload: z.object({
|
|
323
|
+
spaceId: z.string().uuid(),
|
|
324
|
+
sessionId: z.string().uuid(),
|
|
325
|
+
clientMessageId: z.string().optional(),
|
|
326
|
+
content: z.array(contentBlockSchema).min(1),
|
|
327
|
+
model: z.string().optional(),
|
|
328
|
+
provider: z.string().optional(),
|
|
329
|
+
thinkingLevel: z.enum([
|
|
330
|
+
"off",
|
|
331
|
+
"minimal",
|
|
332
|
+
"low",
|
|
333
|
+
"medium",
|
|
334
|
+
"high",
|
|
335
|
+
"xhigh",
|
|
336
|
+
"max"
|
|
337
|
+
]).optional()
|
|
338
|
+
})
|
|
339
|
+
}),
|
|
340
|
+
z.object({
|
|
341
|
+
type: z.literal("presence.update"),
|
|
342
|
+
requestId: z.string().optional(),
|
|
343
|
+
payload: z.object({
|
|
344
|
+
spaceId: z.string().uuid(),
|
|
345
|
+
meta: z.record(z.string(), z.unknown()).nullable().optional()
|
|
346
|
+
})
|
|
347
|
+
}),
|
|
348
|
+
z.object({
|
|
349
|
+
type: z.literal("board.awareness.update"),
|
|
350
|
+
requestId: z.string().optional(),
|
|
351
|
+
payload: BoardAwarenessClientPayloadSchema
|
|
352
|
+
}),
|
|
353
|
+
z.object({
|
|
354
|
+
type: z.literal("realtime.room.join"),
|
|
355
|
+
requestId: z.string().optional(),
|
|
356
|
+
payload: z.object({
|
|
357
|
+
roomId: z.string().uuid(),
|
|
358
|
+
ticket: z.string().min(1)
|
|
359
|
+
})
|
|
360
|
+
}),
|
|
361
|
+
z.object({
|
|
362
|
+
type: z.literal("realtime.room.publish"),
|
|
363
|
+
requestId: z.string().optional(),
|
|
364
|
+
payload: z.object({
|
|
365
|
+
roomId: z.string().uuid(),
|
|
366
|
+
event: z.string().regex(REALTIME_ROOM_EVENT_NAME_PATTERN),
|
|
367
|
+
data: z.unknown(),
|
|
368
|
+
clientEventId: z.string().max(128).optional()
|
|
369
|
+
})
|
|
370
|
+
}),
|
|
371
|
+
z.object({
|
|
372
|
+
type: z.literal("realtime.room.leave"),
|
|
373
|
+
requestId: z.string().optional(),
|
|
374
|
+
payload: z.object({ roomId: z.string().uuid() })
|
|
375
|
+
}),
|
|
376
|
+
z.object({
|
|
377
|
+
type: z.literal("realtime.room.presence.update"),
|
|
378
|
+
requestId: z.string().optional(),
|
|
379
|
+
payload: z.object({
|
|
380
|
+
roomId: z.string().uuid(),
|
|
381
|
+
presence: z.record(z.string(), z.unknown()).nullable()
|
|
382
|
+
})
|
|
383
|
+
}),
|
|
384
|
+
z.object({
|
|
385
|
+
type: z.literal("ping"),
|
|
386
|
+
requestId: z.string().optional(),
|
|
387
|
+
payload: z.record(z.string(), z.unknown()).optional()
|
|
388
|
+
}),
|
|
389
|
+
z.object({
|
|
390
|
+
type: z.literal("ack"),
|
|
391
|
+
requestId: z.string().optional(),
|
|
392
|
+
payload: z.object({ eventId: z.string().optional() }).optional()
|
|
393
|
+
})
|
|
394
|
+
]);
|
|
395
|
+
z.object({
|
|
396
|
+
id: z.string(),
|
|
397
|
+
timestamp: z.number(),
|
|
398
|
+
domain: z.enum([
|
|
399
|
+
"system",
|
|
400
|
+
"session",
|
|
401
|
+
"space",
|
|
402
|
+
"label",
|
|
403
|
+
"room"
|
|
404
|
+
]),
|
|
405
|
+
type: z.string(),
|
|
406
|
+
requestId: z.string().nullable().optional(),
|
|
407
|
+
spaceId: z.string().nullable().optional(),
|
|
408
|
+
sessionId: z.string().nullable().optional(),
|
|
409
|
+
rooms: z.array(realtimeRoomSchema).optional(),
|
|
410
|
+
payload: z.record(z.string(), z.unknown())
|
|
411
|
+
});
|
|
412
|
+
z.discriminatedUnion("t", [z.object({
|
|
413
|
+
t: z.literal("d"),
|
|
414
|
+
sid: z.string().min(1),
|
|
415
|
+
s: z.number().int().nonnegative(),
|
|
416
|
+
b: z.number().int().nonnegative(),
|
|
417
|
+
v: z.unknown()
|
|
418
|
+
}), z.object({
|
|
419
|
+
t: z.literal("p"),
|
|
420
|
+
sid: z.string().min(1),
|
|
421
|
+
s: z.number().int().nonnegative(),
|
|
422
|
+
b: z.number().int().nonnegative(),
|
|
423
|
+
o: z.enum([
|
|
424
|
+
"append",
|
|
425
|
+
"replace",
|
|
426
|
+
"add",
|
|
427
|
+
"merge",
|
|
428
|
+
"remove"
|
|
429
|
+
]),
|
|
430
|
+
p: z.string().min(1),
|
|
431
|
+
v: z.unknown().optional()
|
|
432
|
+
})]);
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region src/apis/work-realtime.ts
|
|
435
|
+
const randomId = () => globalThis.crypto?.randomUUID?.() ?? `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
436
|
+
const textEncoder = new TextEncoder();
|
|
437
|
+
const byteLength = (text) => textEncoder.encode(text).byteLength;
|
|
438
|
+
/**
|
|
439
|
+
* Ceiling on deltas held during a join, so a stalled handshake cannot buffer without
|
|
440
|
+
* limit. Dropping the tail needs no extra signal: the gap detection below reports it.
|
|
441
|
+
*/
|
|
442
|
+
const WORK_ROOM_MAX_JOIN_BUFFER = 512;
|
|
443
|
+
/** Room events that mutate state, so they must not be applied before the join snapshot. */
|
|
444
|
+
const WORK_ROOM_DELTA_EVENTS = /* @__PURE__ */ new Set([
|
|
445
|
+
"realtime.room.event",
|
|
446
|
+
"realtime.room.member.joined",
|
|
447
|
+
"realtime.room.member.left",
|
|
448
|
+
"realtime.room.presence.updated"
|
|
449
|
+
]);
|
|
450
|
+
const requestError = (event) => {
|
|
451
|
+
const payload = event.payload;
|
|
452
|
+
return new Error(typeof payload.message === "string" ? payload.message : typeof payload.code === "string" ? payload.code : "room request failed");
|
|
453
|
+
};
|
|
454
|
+
const isRoomEvent = (event, roomId) => {
|
|
455
|
+
if (event.domain !== "room") return false;
|
|
456
|
+
return event.payload.roomId === roomId || event.rooms?.includes(`room:${roomId}`);
|
|
457
|
+
};
|
|
458
|
+
var WorkRoom = class {
|
|
459
|
+
websocket;
|
|
460
|
+
admission;
|
|
461
|
+
id;
|
|
462
|
+
code;
|
|
463
|
+
createdAt;
|
|
464
|
+
expiresAt;
|
|
465
|
+
maxParticipants;
|
|
466
|
+
seatPerUser;
|
|
467
|
+
/** Opaque, stable identity of this viewer inside the room. */
|
|
468
|
+
userKey;
|
|
469
|
+
_participantId;
|
|
470
|
+
_state = "connecting";
|
|
471
|
+
_members = [];
|
|
472
|
+
joinBuffer = null;
|
|
473
|
+
lastSequence = 0;
|
|
474
|
+
hasJoined = false;
|
|
475
|
+
explicitLeave = false;
|
|
476
|
+
expiryTimer = null;
|
|
477
|
+
pending = /* @__PURE__ */ new Map();
|
|
478
|
+
handlers = /* @__PURE__ */ new Map();
|
|
479
|
+
allHandlers = /* @__PURE__ */ new Set();
|
|
480
|
+
stateHandlers = /* @__PURE__ */ new Set();
|
|
481
|
+
membersHandlers = /* @__PURE__ */ new Set();
|
|
482
|
+
outOfSyncHandlers = /* @__PURE__ */ new Set();
|
|
483
|
+
sendErrorHandlers = /* @__PURE__ */ new Set();
|
|
484
|
+
offEvent;
|
|
485
|
+
offOpen;
|
|
486
|
+
offClose;
|
|
487
|
+
offReconnecting;
|
|
488
|
+
constructor(websocket, admission) {
|
|
489
|
+
this.websocket = websocket;
|
|
490
|
+
this.admission = admission;
|
|
491
|
+
this.id = admission.room.id;
|
|
492
|
+
this.code = admission.room.code;
|
|
493
|
+
this.createdAt = admission.room.createdAt;
|
|
494
|
+
this.expiresAt = admission.room.expiresAt;
|
|
495
|
+
this.maxParticipants = admission.room.maxParticipants;
|
|
496
|
+
this.seatPerUser = admission.room.seatPerUser === true;
|
|
497
|
+
this.userKey = admission.userKey;
|
|
498
|
+
this._participantId = admission.participantId;
|
|
499
|
+
this.offEvent = websocket.on("event", (event) => this.handleEvent(event));
|
|
500
|
+
this.offOpen = websocket.on("open", () => {
|
|
501
|
+
if (!this.hasJoined || this.explicitLeave || this._state === "expired" || this._state === "closed") return;
|
|
502
|
+
this.rejoin();
|
|
503
|
+
});
|
|
504
|
+
this.offReconnecting = websocket.on("reconnecting", () => {
|
|
505
|
+
if (this.hasJoined && !this.explicitLeave) this.setState("reconnecting");
|
|
506
|
+
});
|
|
507
|
+
this.offClose = websocket.on("close", ({ willReconnect }) => {
|
|
508
|
+
this.rejectPending(/* @__PURE__ */ new Error("room connection closed"));
|
|
509
|
+
if (this.explicitLeave || !willReconnect) {
|
|
510
|
+
if (this._state !== "expired") this.setState("closed");
|
|
511
|
+
this.hasJoined = false;
|
|
512
|
+
this.dispose();
|
|
513
|
+
} else if (this.hasJoined) this.setState("reconnecting");
|
|
514
|
+
});
|
|
515
|
+
const delay = Math.max(0, Date.parse(this.expiresAt) - Date.now());
|
|
516
|
+
this.expiryTimer = setTimeout(() => this.expire(), Math.min(delay, 2147e6));
|
|
517
|
+
}
|
|
518
|
+
get state() {
|
|
519
|
+
return this._state;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Identity of this connection inside the room. A `seatPerUser` join can take over a
|
|
523
|
+
* seat the viewer already holds, so this may differ from the id issued at admission.
|
|
524
|
+
*/
|
|
525
|
+
get participantId() {
|
|
526
|
+
return this._participantId;
|
|
527
|
+
}
|
|
528
|
+
get members() {
|
|
529
|
+
return this._members.slice();
|
|
530
|
+
}
|
|
531
|
+
async connect() {
|
|
532
|
+
await this.joinOverWebsocket(false);
|
|
533
|
+
return this;
|
|
534
|
+
}
|
|
535
|
+
subscribe(type, handler) {
|
|
536
|
+
const handlers = this.handlers.get(type) ?? /* @__PURE__ */ new Set();
|
|
537
|
+
handlers.add(handler);
|
|
538
|
+
this.handlers.set(type, handlers);
|
|
539
|
+
return () => handlers.delete(handler);
|
|
540
|
+
}
|
|
541
|
+
subscribeAll(handler) {
|
|
542
|
+
this.allHandlers.add(handler);
|
|
543
|
+
return () => this.allHandlers.delete(handler);
|
|
544
|
+
}
|
|
545
|
+
onStateChange(handler) {
|
|
546
|
+
this.stateHandlers.add(handler);
|
|
547
|
+
return () => this.stateHandlers.delete(handler);
|
|
548
|
+
}
|
|
549
|
+
onMembersChanged(handler) {
|
|
550
|
+
this.membersHandlers.add(handler);
|
|
551
|
+
return () => this.membersHandlers.delete(handler);
|
|
552
|
+
}
|
|
553
|
+
onOutOfSync(handler) {
|
|
554
|
+
this.outOfSyncHandlers.add(handler);
|
|
555
|
+
return () => this.outOfSyncHandlers.delete(handler);
|
|
556
|
+
}
|
|
557
|
+
/** Reports failures of {@link send}, which has no ack to reject. */
|
|
558
|
+
onSendError(handler) {
|
|
559
|
+
this.sendErrorHandlers.add(handler);
|
|
560
|
+
return () => this.sendErrorHandlers.delete(handler);
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Publishes without waiting for the server ack, for high-frequency traffic such as
|
|
564
|
+
* input frames. Awaiting {@link publish} instead caps a loop at `1000 / rtt` events
|
|
565
|
+
* per second. Ordering still holds, but failures surface through
|
|
566
|
+
* {@link onSendError} rather than a rejected promise, and calls are ignored while
|
|
567
|
+
* the room is not joined; watch {@link onStateChange} to know when it resumes.
|
|
568
|
+
*/
|
|
569
|
+
send(type, data) {
|
|
570
|
+
if (this._state !== "joined" || !this.hasJoined) return;
|
|
571
|
+
const failure = this.validateSend(type, data);
|
|
572
|
+
if (failure) {
|
|
573
|
+
for (const handler of this.sendErrorHandlers) handler(failure);
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
this.websocket.publishRealtimeRoom({
|
|
577
|
+
roomId: this.id,
|
|
578
|
+
event: type,
|
|
579
|
+
data
|
|
580
|
+
}).catch((error) => {
|
|
581
|
+
const reason = error instanceof Error ? error : new Error(String(error));
|
|
582
|
+
for (const handler of this.sendErrorHandlers) handler(reason);
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
validateSend(type, data) {
|
|
586
|
+
if (!REALTIME_ROOM_EVENT_NAME_PATTERN.test(type)) return /* @__PURE__ */ new Error(`invalid room event name: ${type}`);
|
|
587
|
+
let encoded;
|
|
588
|
+
try {
|
|
589
|
+
encoded = JSON.stringify(data);
|
|
590
|
+
} catch {
|
|
591
|
+
return /* @__PURE__ */ new Error("room event data is not serializable");
|
|
592
|
+
}
|
|
593
|
+
if (encoded === void 0) return /* @__PURE__ */ new Error("room event data is not serializable");
|
|
594
|
+
if (byteLength(encoded) > 16384) return /* @__PURE__ */ new Error("room event payload is too large");
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
async publish(type, data, options) {
|
|
598
|
+
this.assertJoined();
|
|
599
|
+
const failure = this.validateSend(type, data);
|
|
600
|
+
if (failure) throw failure;
|
|
601
|
+
const requestId = randomId();
|
|
602
|
+
const response = await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.request.ok"]), () => this.websocket.publishRealtimeRoom({
|
|
603
|
+
roomId: this.id,
|
|
604
|
+
event: type,
|
|
605
|
+
data,
|
|
606
|
+
clientEventId: options?.clientEventId,
|
|
607
|
+
requestId
|
|
608
|
+
}));
|
|
609
|
+
const payload = response.payload;
|
|
610
|
+
return {
|
|
611
|
+
eventId: typeof payload.eventId === "string" ? payload.eventId : response.id,
|
|
612
|
+
sequence: typeof payload.sequence === "number" ? payload.sequence : 0,
|
|
613
|
+
clientEventId: typeof payload.clientEventId === "string" ? payload.clientEventId : null
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
async setPresence(presence) {
|
|
617
|
+
this.assertJoined();
|
|
618
|
+
const requestId = randomId();
|
|
619
|
+
await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.request.ok"]), () => this.websocket.updateRealtimeRoomPresence({
|
|
620
|
+
roomId: this.id,
|
|
621
|
+
presence,
|
|
622
|
+
requestId
|
|
623
|
+
}));
|
|
624
|
+
}
|
|
625
|
+
async leave() {
|
|
626
|
+
if (this.explicitLeave || this._state === "closed" || this._state === "expired") return;
|
|
627
|
+
this.explicitLeave = true;
|
|
628
|
+
try {
|
|
629
|
+
if (this.hasJoined && this.websocket.state === "open") {
|
|
630
|
+
const requestId = randomId();
|
|
631
|
+
await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.request.ok"]), () => this.websocket.leaveRealtimeRoom({
|
|
632
|
+
roomId: this.id,
|
|
633
|
+
requestId
|
|
634
|
+
}));
|
|
635
|
+
}
|
|
636
|
+
} finally {
|
|
637
|
+
this.hasJoined = false;
|
|
638
|
+
this.setState("closed");
|
|
639
|
+
this.dispose();
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async rejoin() {
|
|
643
|
+
if (this.explicitLeave || this._state === "expired" || this._state === "closed") return;
|
|
644
|
+
try {
|
|
645
|
+
await this.joinOverWebsocket(true);
|
|
646
|
+
} catch (error) {
|
|
647
|
+
if (this.state === "expired") return;
|
|
648
|
+
this.setState("closed");
|
|
649
|
+
this.dispose();
|
|
650
|
+
console.warn("[Cohub WorkRoom] failed to rejoin room", error);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
async joinOverWebsocket(isReconnect) {
|
|
654
|
+
if (!this.websocket.supportsCapability("realtime.room.v1") && this.websocket.state === "open") throw new Error("Realtime rooms are not supported by the Gateway");
|
|
655
|
+
this.setState(isReconnect ? "reconnecting" : "connecting");
|
|
656
|
+
const requestId = randomId();
|
|
657
|
+
this.joinBuffer = [];
|
|
658
|
+
try {
|
|
659
|
+
const payload = (await this.request(requestId, /* @__PURE__ */ new Set(["realtime.room.joined"]), () => this.websocket.joinRealtimeRoom({
|
|
660
|
+
roomId: this.id,
|
|
661
|
+
ticket: this.admission.ticket,
|
|
662
|
+
requestId
|
|
663
|
+
}))).payload;
|
|
664
|
+
if (typeof payload.participantId !== "string" || !Array.isArray(payload.members)) throw new Error("invalid room join response");
|
|
665
|
+
this._participantId = payload.participantId;
|
|
666
|
+
this._members = payload.members;
|
|
667
|
+
this.lastSequence = typeof payload.sequence === "number" ? payload.sequence : 0;
|
|
668
|
+
} catch (error) {
|
|
669
|
+
this.joinBuffer = null;
|
|
670
|
+
throw error;
|
|
671
|
+
}
|
|
672
|
+
this.hasJoined = true;
|
|
673
|
+
this.setState("joined");
|
|
674
|
+
this.notifyMembers();
|
|
675
|
+
const buffered = this.joinBuffer ?? [];
|
|
676
|
+
this.joinBuffer = null;
|
|
677
|
+
for (const item of buffered) {
|
|
678
|
+
const sequence = item.payload.sequence;
|
|
679
|
+
if (typeof sequence === "number" && sequence <= this.lastSequence) continue;
|
|
680
|
+
this.handleEvent(item);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
request(requestId, expected, send) {
|
|
684
|
+
return new Promise((resolve, reject) => {
|
|
685
|
+
const timer = setTimeout(() => {
|
|
686
|
+
this.pending.delete(requestId);
|
|
687
|
+
reject(/* @__PURE__ */ new Error("room request timed out"));
|
|
688
|
+
}, 2e4);
|
|
689
|
+
this.pending.set(requestId, {
|
|
690
|
+
expected,
|
|
691
|
+
resolve,
|
|
692
|
+
reject,
|
|
693
|
+
timer
|
|
694
|
+
});
|
|
695
|
+
send().catch((error) => {
|
|
696
|
+
this.pending.delete(requestId);
|
|
697
|
+
clearTimeout(timer);
|
|
698
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
699
|
+
});
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
/** Detaches the entry awaiting this requestId, so the caller can settle it. */
|
|
703
|
+
takePending(requestId) {
|
|
704
|
+
const pending = requestId ? this.pending.get(requestId) : void 0;
|
|
705
|
+
if (!pending || !requestId) return null;
|
|
706
|
+
this.pending.delete(requestId);
|
|
707
|
+
clearTimeout(pending.timer);
|
|
708
|
+
return pending;
|
|
709
|
+
}
|
|
710
|
+
handleEvent(event) {
|
|
711
|
+
if (!isRoomEvent(event, this.id)) {
|
|
712
|
+
if (event.type === "system.request.error") this.takePending(event.requestId)?.reject(requestError(event));
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
if (event.type === "realtime.room.request.error") {
|
|
716
|
+
const failure = requestError(event);
|
|
717
|
+
if (event.requestId) {
|
|
718
|
+
this.takePending(event.requestId)?.reject(failure);
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
for (const handler of this.sendErrorHandlers) handler(failure);
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
const awaiting = event.requestId ? this.pending.get(event.requestId) : void 0;
|
|
725
|
+
if (awaiting?.expected.has(event.type)) {
|
|
726
|
+
this.takePending(event.requestId);
|
|
727
|
+
awaiting.resolve(event);
|
|
728
|
+
}
|
|
729
|
+
if (this.joinBuffer && WORK_ROOM_DELTA_EVENTS.has(event.type)) {
|
|
730
|
+
if (this.joinBuffer.length < WORK_ROOM_MAX_JOIN_BUFFER) this.joinBuffer.push(event);
|
|
731
|
+
return;
|
|
732
|
+
}
|
|
733
|
+
const payload = event.payload;
|
|
734
|
+
const sequence = typeof payload.sequence === "number" ? payload.sequence : null;
|
|
735
|
+
if (sequence !== null) this.observeSequence(sequence);
|
|
736
|
+
if (event.type === "realtime.room.member.joined" || event.type === "realtime.room.member.left" || event.type === "realtime.room.presence.updated") {
|
|
737
|
+
const member = payload.member;
|
|
738
|
+
if (member?.participantId) {
|
|
739
|
+
const members = new Map(this._members.map((item) => [item.participantId, item]));
|
|
740
|
+
if (event.type === "realtime.room.member.left") members.delete(member.participantId);
|
|
741
|
+
else members.set(member.participantId, member);
|
|
742
|
+
this._members = [...members.values()];
|
|
743
|
+
this.notifyMembers();
|
|
744
|
+
}
|
|
745
|
+
return;
|
|
746
|
+
}
|
|
747
|
+
if (event.type === "realtime.room.closed") {
|
|
748
|
+
this.hasJoined = false;
|
|
749
|
+
if (payload.reason === "expired") this.setState("expired");
|
|
750
|
+
else this.setState("closed");
|
|
751
|
+
this.rejectPending(/* @__PURE__ */ new Error(`room closed: ${typeof payload.reason === "string" ? payload.reason : "unknown"}`));
|
|
752
|
+
this.dispose();
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (event.type !== "realtime.room.event") return;
|
|
756
|
+
const roomEvent = event;
|
|
757
|
+
const roomPayload = roomEvent.payload;
|
|
758
|
+
const item = {
|
|
759
|
+
id: roomEvent.id,
|
|
760
|
+
timestamp: roomEvent.timestamp,
|
|
761
|
+
roomId: roomPayload.roomId,
|
|
762
|
+
sequence: roomPayload.sequence,
|
|
763
|
+
type: roomPayload.event,
|
|
764
|
+
data: roomPayload.data,
|
|
765
|
+
clientEventId: roomPayload.clientEventId,
|
|
766
|
+
sender: roomPayload.sender,
|
|
767
|
+
self: roomPayload.sender.participantId === this.participantId
|
|
768
|
+
};
|
|
769
|
+
this.handlers.get(item.type)?.forEach((handler) => {
|
|
770
|
+
handler(item);
|
|
771
|
+
});
|
|
772
|
+
this.allHandlers.forEach((handler) => {
|
|
773
|
+
handler(item);
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
observeSequence(sequence) {
|
|
777
|
+
if (this.lastSequence > 0 && sequence > this.lastSequence + 1) for (const handler of this.outOfSyncHandlers) handler(this.lastSequence + 1, sequence);
|
|
778
|
+
if (sequence > this.lastSequence) this.lastSequence = sequence;
|
|
779
|
+
}
|
|
780
|
+
assertJoined() {
|
|
781
|
+
if (this._state !== "joined" || !this.hasJoined) throw new Error("room is not joined");
|
|
782
|
+
}
|
|
783
|
+
setState(state) {
|
|
784
|
+
if (this._state === state) return;
|
|
785
|
+
this._state = state;
|
|
786
|
+
for (const handler of this.stateHandlers) handler(state);
|
|
787
|
+
}
|
|
788
|
+
notifyMembers() {
|
|
789
|
+
const members = this.members;
|
|
790
|
+
for (const handler of this.membersHandlers) handler(members);
|
|
791
|
+
}
|
|
792
|
+
rejectPending(error) {
|
|
793
|
+
for (const [requestId, pending] of this.pending) {
|
|
794
|
+
this.pending.delete(requestId);
|
|
795
|
+
clearTimeout(pending.timer);
|
|
796
|
+
pending.reject(error);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
expire() {
|
|
800
|
+
if (this.explicitLeave || this._state === "closed" || this._state === "expired") return;
|
|
801
|
+
this.hasJoined = false;
|
|
802
|
+
this.setState("expired");
|
|
803
|
+
this.rejectPending(/* @__PURE__ */ new Error("room expired"));
|
|
804
|
+
this.dispose();
|
|
805
|
+
}
|
|
806
|
+
dispose() {
|
|
807
|
+
this.offEvent();
|
|
808
|
+
this.offOpen();
|
|
809
|
+
this.offClose();
|
|
810
|
+
this.offReconnecting();
|
|
811
|
+
if (this.expiryTimer) clearTimeout(this.expiryTimer);
|
|
812
|
+
this.expiryTimer = null;
|
|
813
|
+
}
|
|
814
|
+
};
|
|
815
|
+
var WorkRealtimeApi = class {
|
|
816
|
+
transport;
|
|
817
|
+
websocket;
|
|
818
|
+
getContext;
|
|
819
|
+
constructor(transport, websocket, getContext) {
|
|
820
|
+
this.transport = transport;
|
|
821
|
+
this.websocket = websocket;
|
|
822
|
+
this.getContext = getContext;
|
|
823
|
+
}
|
|
824
|
+
async createRoom(input = {}) {
|
|
825
|
+
const admission = await this.transport.request(`/api/works/${encodeURIComponent(await this.requireWorkId())}/realtime/rooms`, {
|
|
826
|
+
method: "POST",
|
|
827
|
+
headers: { "Content-Type": "application/json" },
|
|
828
|
+
body: JSON.stringify(input)
|
|
829
|
+
});
|
|
830
|
+
return this.openRoom(admission);
|
|
831
|
+
}
|
|
832
|
+
async joinRoom(input) {
|
|
833
|
+
const admission = await this.transport.request(`/api/works/${encodeURIComponent(await this.requireWorkId())}/realtime/rooms/join`, {
|
|
834
|
+
method: "POST",
|
|
835
|
+
headers: { "Content-Type": "application/json" },
|
|
836
|
+
body: JSON.stringify(input)
|
|
837
|
+
});
|
|
838
|
+
return this.openRoom(admission);
|
|
839
|
+
}
|
|
840
|
+
async requireWorkId() {
|
|
841
|
+
const context = await this.getContext();
|
|
842
|
+
if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
|
|
843
|
+
return context.work.id;
|
|
844
|
+
}
|
|
845
|
+
async openRoom(admission) {
|
|
846
|
+
const room = new WorkRoom(this.websocket, admission);
|
|
847
|
+
try {
|
|
848
|
+
await room.connect();
|
|
849
|
+
return room;
|
|
850
|
+
} catch (error) {
|
|
851
|
+
await room.leave().catch(() => void 0);
|
|
852
|
+
throw error;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
//#endregion
|
|
84
857
|
//#region src/work-runtime.ts
|
|
85
858
|
const isBrowser$1 = () => typeof window !== "undefined" && typeof window.parent !== "undefined";
|
|
86
859
|
const hasParent = () => isBrowser$1() && window.parent !== window;
|
|
@@ -540,41 +1313,45 @@ var CohubClient = class {
|
|
|
540
1313
|
this.referrals = new ReferralsApi(this.transport);
|
|
541
1314
|
this.works = new WorksApi(this.transport);
|
|
542
1315
|
this.workCommerce = new WorkCommerceApi(this.transport);
|
|
1316
|
+
this.work.realtime = new WorkRealtimeApi(this.transport, this.websocketClient, () => this.workRuntime.context());
|
|
543
1317
|
}
|
|
544
1318
|
context() {
|
|
545
1319
|
return this.workRuntime.context();
|
|
546
1320
|
}
|
|
547
1321
|
auth = { request: (input) => this.workRuntime.requestAuthorization(input) };
|
|
548
|
-
work = {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
1322
|
+
work = {
|
|
1323
|
+
realtime: null,
|
|
1324
|
+
commerce: {
|
|
1325
|
+
resolveProducts: async (input) => {
|
|
1326
|
+
const context = await this.workRuntime.context();
|
|
1327
|
+
if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
|
|
1328
|
+
return this.workCommerce.resolveProducts(context.work.id, input);
|
|
1329
|
+
},
|
|
1330
|
+
getEntitlements: async () => {
|
|
1331
|
+
const context = await this.workRuntime.context();
|
|
1332
|
+
if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
|
|
1333
|
+
return this.workCommerce.getEntitlements(context.work.id);
|
|
1334
|
+
},
|
|
1335
|
+
consumeCredits: async (input) => {
|
|
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.consumeCredits(context.work.id, input);
|
|
1339
|
+
},
|
|
1340
|
+
purchase: async (input) => this.workRuntime.purchase(input),
|
|
1341
|
+
getCheckoutState: async () => {
|
|
1342
|
+
const result = await this.workRuntime.checkoutState();
|
|
1343
|
+
return {
|
|
1344
|
+
status: result?.status ?? null,
|
|
1345
|
+
orderId: result?.orderId ?? null
|
|
1346
|
+
};
|
|
1347
|
+
},
|
|
1348
|
+
getOrder: async (orderId) => {
|
|
1349
|
+
const context = await this.workRuntime.context();
|
|
1350
|
+
if (!context?.work?.id) throw new Error("Work context is unavailable — not running inside a published Work runtime.");
|
|
1351
|
+
return this.workCommerce.getOrder(context.work.id, orderId);
|
|
1352
|
+
}
|
|
576
1353
|
}
|
|
577
|
-
}
|
|
1354
|
+
};
|
|
578
1355
|
space(spaceId) {
|
|
579
1356
|
return new SpaceClient(spaceId, this.transport, this.websocketClient);
|
|
580
1357
|
}
|
|
@@ -1290,53 +2067,12 @@ function filterGenerationDeclarationsByPolicy(declarations, policy) {
|
|
|
1290
2067
|
});
|
|
1291
2068
|
}
|
|
1292
2069
|
//#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
2070
|
//#region ../protocol/dist/board.js
|
|
1335
2071
|
const BOARD_MANIFEST_KIND = "cohub.board.manifest";
|
|
1336
|
-
const idSchema
|
|
2072
|
+
const idSchema = z.string().min(1).max(160);
|
|
1337
2073
|
const extensionIdSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
|
|
1338
2074
|
const jsonObjectSchema = z.record(z.string(), z.unknown());
|
|
1339
|
-
const finiteSchema
|
|
2075
|
+
const finiteSchema = z.number().finite();
|
|
1340
2076
|
z.object({
|
|
1341
2077
|
kind: z.literal(BOARD_MANIFEST_KIND),
|
|
1342
2078
|
version: z.literal(1),
|
|
@@ -1346,11 +2082,11 @@ z.object({
|
|
|
1346
2082
|
const BoardTargetSchema = z.discriminatedUnion("type", [
|
|
1347
2083
|
z.object({
|
|
1348
2084
|
type: z.literal("node"),
|
|
1349
|
-
nodeId: idSchema
|
|
2085
|
+
nodeId: idSchema
|
|
1350
2086
|
}),
|
|
1351
2087
|
z.object({
|
|
1352
2088
|
type: z.literal("effect"),
|
|
1353
|
-
effectId: idSchema
|
|
2089
|
+
effectId: idSchema
|
|
1354
2090
|
}),
|
|
1355
2091
|
z.object({ type: z.literal("board") }),
|
|
1356
2092
|
z.object({ type: z.literal("camera") })
|
|
@@ -1361,18 +2097,18 @@ const BoardAssetRefSchema = z.object({
|
|
|
1361
2097
|
digest: z.string().min(16).max(160).optional()
|
|
1362
2098
|
});
|
|
1363
2099
|
const BoardKeyframeSchema = z.object({
|
|
1364
|
-
at: finiteSchema
|
|
2100
|
+
at: finiteSchema.nonnegative(),
|
|
1365
2101
|
value: z.unknown(),
|
|
1366
2102
|
easing: z.string().min(1).max(80).optional()
|
|
1367
2103
|
});
|
|
1368
2104
|
const BoardClipSchema = z.object({
|
|
1369
|
-
id: idSchema
|
|
1370
|
-
sequenceId: idSchema
|
|
2105
|
+
id: idSchema,
|
|
2106
|
+
sequenceId: idSchema,
|
|
1371
2107
|
kind: extensionIdSchema,
|
|
1372
2108
|
kindVersion: z.number().int().positive(),
|
|
1373
2109
|
target: BoardTargetSchema,
|
|
1374
|
-
start: finiteSchema
|
|
1375
|
-
duration: finiteSchema
|
|
2110
|
+
start: finiteSchema.nonnegative(),
|
|
2111
|
+
duration: finiteSchema.positive(),
|
|
1376
2112
|
layer: z.enum([
|
|
1377
2113
|
"behind",
|
|
1378
2114
|
"content",
|
|
@@ -1393,11 +2129,11 @@ const BoardClipSchema = z.object({
|
|
|
1393
2129
|
metadata: jsonObjectSchema.default({})
|
|
1394
2130
|
});
|
|
1395
2131
|
const BoardEffectSchema = z.object({
|
|
1396
|
-
id: idSchema
|
|
2132
|
+
id: idSchema,
|
|
1397
2133
|
boardId: z.string().uuid(),
|
|
1398
2134
|
target: z.discriminatedUnion("type", [z.object({
|
|
1399
2135
|
type: z.literal("node"),
|
|
1400
|
-
nodeId: idSchema
|
|
2136
|
+
nodeId: idSchema
|
|
1401
2137
|
}), z.object({ type: z.literal("board") })]),
|
|
1402
2138
|
kind: extensionIdSchema,
|
|
1403
2139
|
kindVersion: z.number().int().positive(),
|
|
@@ -1424,25 +2160,25 @@ const BoardEffectSchema = z.object({
|
|
|
1424
2160
|
revision: z.number().int().nonnegative()
|
|
1425
2161
|
});
|
|
1426
2162
|
const BoardSequenceSchema = z.object({
|
|
1427
|
-
id: idSchema
|
|
2163
|
+
id: idSchema,
|
|
1428
2164
|
boardId: z.string().uuid(),
|
|
1429
2165
|
name: z.string().min(1).max(255),
|
|
1430
|
-
duration: finiteSchema
|
|
2166
|
+
duration: finiteSchema.nonnegative(),
|
|
1431
2167
|
seed: z.string().min(1).max(160),
|
|
1432
2168
|
restPose: jsonObjectSchema.default({}),
|
|
1433
2169
|
metadata: jsonObjectSchema.default({}),
|
|
1434
2170
|
revision: z.number().int().nonnegative()
|
|
1435
2171
|
});
|
|
1436
2172
|
const BoardNodeInputSchema = z.object({
|
|
1437
|
-
nodeId: idSchema
|
|
2173
|
+
nodeId: idSchema,
|
|
1438
2174
|
type: z.string().min(1).max(40),
|
|
1439
|
-
parentId: idSchema
|
|
2175
|
+
parentId: idSchema.nullable(),
|
|
1440
2176
|
orderKey: z.string().max(4096).nullable(),
|
|
1441
|
-
x: finiteSchema
|
|
1442
|
-
y: finiteSchema
|
|
1443
|
-
width: finiteSchema
|
|
1444
|
-
height: finiteSchema
|
|
1445
|
-
rotation: finiteSchema
|
|
2177
|
+
x: finiteSchema,
|
|
2178
|
+
y: finiteSchema,
|
|
2179
|
+
width: finiteSchema.positive(),
|
|
2180
|
+
height: finiteSchema.positive(),
|
|
2181
|
+
rotation: finiteSchema,
|
|
1446
2182
|
refKind: z.string().max(40).nullable(),
|
|
1447
2183
|
refPath: z.string().max(4096).nullable(),
|
|
1448
2184
|
refUrl: z.string().max(4096).nullable(),
|
|
@@ -1478,17 +2214,17 @@ z.object({
|
|
|
1478
2214
|
"playback"
|
|
1479
2215
|
])).optional(),
|
|
1480
2216
|
viewport: z.object({
|
|
1481
|
-
x: finiteSchema
|
|
1482
|
-
y: finiteSchema
|
|
1483
|
-
width: finiteSchema
|
|
1484
|
-
height: finiteSchema
|
|
2217
|
+
x: finiteSchema,
|
|
2218
|
+
y: finiteSchema,
|
|
2219
|
+
width: finiteSchema.positive(),
|
|
2220
|
+
height: finiteSchema.positive()
|
|
1485
2221
|
}).optional()
|
|
1486
2222
|
});
|
|
1487
2223
|
/** Persisted on `boards.metadata.playback`: how a Board plays when opened. */
|
|
1488
2224
|
const BoardPlaybackPolicySchema = z.object({
|
|
1489
|
-
sequenceId: idSchema
|
|
2225
|
+
sequenceId: idSchema,
|
|
1490
2226
|
/** Delay before the first local playback after opening the Board, in milliseconds. */
|
|
1491
|
-
delayMs: finiteSchema
|
|
2227
|
+
delayMs: finiteSchema.nonnegative().default(0),
|
|
1492
2228
|
loop: z.boolean().default(false)
|
|
1493
2229
|
});
|
|
1494
2230
|
function parseBoardPlaybackPolicy(metadata) {
|
|
@@ -1497,148 +2233,32 @@ function parseBoardPlaybackPolicy(metadata) {
|
|
|
1497
2233
|
}
|
|
1498
2234
|
z.discriminatedUnion("type", [
|
|
1499
2235
|
z.object({
|
|
1500
|
-
commandId: idSchema
|
|
2236
|
+
commandId: idSchema,
|
|
1501
2237
|
type: z.literal("play"),
|
|
1502
|
-
sequenceId: idSchema
|
|
1503
|
-
position: finiteSchema
|
|
1504
|
-
timeScale: finiteSchema
|
|
2238
|
+
sequenceId: idSchema,
|
|
2239
|
+
position: finiteSchema.nonnegative().optional(),
|
|
2240
|
+
timeScale: finiteSchema.positive().max(4).optional(),
|
|
1505
2241
|
shared: z.boolean().optional(),
|
|
1506
|
-
seed: idSchema
|
|
2242
|
+
seed: idSchema.optional()
|
|
1507
2243
|
}),
|
|
1508
2244
|
z.object({
|
|
1509
|
-
commandId: idSchema
|
|
2245
|
+
commandId: idSchema,
|
|
1510
2246
|
type: z.literal("pause"),
|
|
1511
2247
|
playbackId: z.string().uuid()
|
|
1512
2248
|
}),
|
|
1513
2249
|
z.object({
|
|
1514
|
-
commandId: idSchema
|
|
2250
|
+
commandId: idSchema,
|
|
1515
2251
|
type: z.literal("seek"),
|
|
1516
2252
|
playbackId: z.string().uuid(),
|
|
1517
|
-
position: finiteSchema
|
|
2253
|
+
position: finiteSchema.nonnegative()
|
|
1518
2254
|
}),
|
|
1519
2255
|
z.object({
|
|
1520
|
-
commandId: idSchema
|
|
2256
|
+
commandId: idSchema,
|
|
1521
2257
|
type: z.literal("stop"),
|
|
1522
2258
|
playbackId: z.string().uuid()
|
|
1523
2259
|
})
|
|
1524
2260
|
]);
|
|
1525
2261
|
//#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
2262
|
//#region ../protocol/dist/public-identifiers.js
|
|
1643
2263
|
/**
|
|
1644
2264
|
* Platform-owned path segments that must not be newly assigned to public
|
|
@@ -2026,4 +2646,4 @@ function createBoardExtensionRegistry(input = {}) {
|
|
|
2026
2646
|
return registry;
|
|
2027
2647
|
}
|
|
2028
2648
|
//#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 };
|
|
2649
|
+
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 };
|