@neta-art/cohub 8.17.0 → 8.18.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,10 +1,55 @@
1
- import { $ as BoardConnectionSchema, A as DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, B as BoardItemPatchSchema, C as SessionPatchReducer, D as DESKTOP_COMMAND_MAX_TIMEOUT_MS, E as DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, F as parseDesktopCommand, G as parseBoardEffectInput, H as BoardSemanticMutationSchema, I as parseDesktopCommandId, J as BoardCompositionInputSchema, K as BOARD_ANIMATION_CHANNELS, L as resolveOpenSurface, M as DESKTOP_COMMAND_VERSION, N as isDesktopCallMethod, O as DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, P as isTerminalDesktopCommandStatus, Q as parseBoardCompositionInput, R as NAVIGATION_ERROR_MESSAGE_MAX_LENGTH, S as parseAssistantMessageCommit, T as ensureRealtimeConnected, U as BoardEffectInputSchema, V as BoardSemanticCommandSchema, W as BoardEffectSchema, X as BoardProceduralClipSchema, Y as BoardCompositionSchema, Z as BoardTrackSchema, _ as PublicInviteApi, a as DesktopCommandsApi, at as SessionAccessApi, b as SessionGenerationStreamClient, c as ReferralsApi, ct as PublicAssetsApi, d as TasksApi, dt as ModelsApi, et as BOARD_ARROW_STROKE_SIZE, f as BoardClient, ft as GenerationsApi, g as SpacesApi, h as SpaceWebhooksApi, i as WorkCommerceApi, it as DEFAULT_BOARD_RENDER_LIMITS, j as DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, k as DESKTOP_COMMAND_PENDING_TTL_SECONDS, l as UsersApi, lt as SkillsApi, m as SpacePublicFilesApi, mt as ChannelsApi, n as createHttpClient, nt as BOARD_BUILTIN_CLIP_KINDS, o as UiCommandsApi, ot as ReferencesApi, p as SpaceClient, pt as CronJobsApi, q as BOARD_ANIMATION_CHANNEL_CAPABILITIES, r as AppCommerceApi, rt as BOARD_BUILTIN_EFFECT_KINDS, s as AppsApi, st as SearchApi, t as CohubHttpClient, tt as BOARD_BUILTIN_CAPABILITIES, u as UserApi, ut as PromptsApi, v as buildSpaceInvitePath, w as createSessionPatchReducer, x as createSessionGenerationStreamClient, y as buildSpacePath, z as BoardAuthoringItemSchema } from "./chunks/http.js";
1
+ import { $ as BoardEffectInputSchema, A as SkillsApi, B as DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, C as SessionPatchReducer, D as ReferencesApi, E as SessionAccessApi, F as ChannelsApi, G as parseDesktopCommand, H as DESKTOP_COMMAND_VERSION, I as DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, J as NAVIGATION_ERROR_MESSAGE_MAX_LENGTH, K as parseDesktopCommandId, L as DESKTOP_COMMAND_MAX_TIMEOUT_MS, M as ModelsApi, N as GenerationsApi, O as SearchApi, P as CronJobsApi, Q as BoardSemanticMutationSchema, R as DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, S as parseAssistantMessageCommit, T as ensureRealtimeConnected, U as isDesktopCallMethod, V as DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, W as isTerminalDesktopCommandStatus, X as BoardItemPatchSchema, Y as BoardAuthoringItemSchema, Z as BoardSemanticCommandSchema, _ as PublicInviteApi, a as DesktopCommandsApi, at as BoardCompositionSchema, b as SessionGenerationStreamClient, c as ReferralsApi, ct as parseBoardCompositionInput, d as TasksApi, dt as BOARD_BUILTIN_CAPABILITIES, et as BoardEffectSchema, f as BoardClient, ft as BOARD_BUILTIN_CLIP_KINDS, g as SpacesApi, h as SpaceWebhooksApi, i as WorkCommerceApi, it as BoardCompositionInputSchema, j as PromptsApi, k as PublicAssetsApi, l as UsersApi, lt as BoardConnectionSchema, m as SpacePublicFilesApi, mt as DEFAULT_BOARD_RENDER_LIMITS, n as createHttpClient, nt as BOARD_ANIMATION_CHANNELS, o as UiCommandsApi, ot as BoardProceduralClipSchema, p as SpaceClient, pt as BOARD_BUILTIN_EFFECT_KINDS, q as resolveOpenSurface, r as AppCommerceApi, rt as BOARD_ANIMATION_CHANNEL_CAPABILITIES, s as AppsApi, st as BoardTrackSchema, t as CohubHttpClient, tt as parseBoardEffectInput, u as UserApi, ut as BOARD_ARROW_STROKE_SIZE, v as buildSpaceInvitePath, w as createSessionPatchReducer, x as createSessionGenerationStreamClient, y as buildSpacePath, z as DESKTOP_COMMAND_PENDING_TTL_SECONDS } from "./chunks/http.js";
2
2
  import { _ as requestSourceToHeaders, a as sanitizeAccessToken, b as REALTIME_ROOM_EVENT_NAME_PATTERN, c as REQUEST_SOURCE_VIA_MAX_LENGTH, d as isRequestSourceEmpty, f as isRequestSourceUuid, g as readRequestSourceFromEnv, h as parseRequestSourceFromHeaders, i as matchesUnauthorizedErrorToken, l as hasRequestSourceIdentity, m as normalizeRequestSource, n as HttpTransport, o as COHUB_SOURCE_HEADER, p as mergeRequestSourceIntoMeta, r as joinApiUrl, s as COHUB_SOURCE_HEADER_NAMES, t as HttpError, u as isRequestSourceClientId, v as resolveRequestSourceChannel, y as isUuid } from "./chunks/transport.js";
3
3
  import { a as normalizeWebsocketUrl, c as resolveExecutionAppId, d as resolveWebsocketUrl, f as PERMISSIONS, h as scopeListHasPermission, i as normalizeVoiceInputWebsocketUrl, l as resolveExecutionToken, m as isUserLevelPermission, n as getCohubContext, o as resolveApiBaseUrl, p as USER_LEVEL_PERMISSIONS, r as normalizeBaseUrl, s as resolveCohubEnvironment, t as COHUB_ENVIRONMENTS, u as resolveVoiceInputWebsocketUrl } 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";
6
6
  import { filterSpacePickerItems, normalizeSpacePickerQuery, orderSpacePickerItems, selectSpacePickerItems } from "./space-picker.js";
7
7
  import { z } from "zod";
8
+ //#region ../protocol/dist/app-authorization.js
9
+ const appAuthorizationTargetSchema = z.discriminatedUnion("kind", [
10
+ z.object({ kind: z.literal("account") }),
11
+ z.object({
12
+ kind: z.literal("space"),
13
+ spaceId: z.string().min(1)
14
+ }),
15
+ z.object({ kind: z.literal("pick-space") })
16
+ ]);
17
+ const appAuthorizationRequestSchema = z.object({
18
+ target: appAuthorizationTargetSchema,
19
+ scopes: z.array(z.string().min(1)).min(1).max(128),
20
+ reason: z.string().max(280).optional(),
21
+ alwaysAsk: z.boolean().optional(),
22
+ fallback: z.enum(["allow", "none"]).default("allow")
23
+ });
24
+ const appAuthorizationGrantSchema = z.object({
25
+ id: z.string().min(1),
26
+ spaceId: z.string().min(1),
27
+ scopes: z.array(z.string()),
28
+ expiresAt: z.string().nullable()
29
+ });
30
+ const appAuthorizationResultSchema = z.discriminatedUnion("status", [
31
+ z.object({
32
+ status: z.literal("granted"),
33
+ requestedTarget: appAuthorizationTargetSchema,
34
+ target: z.discriminatedUnion("kind", [z.object({ kind: z.literal("account") }), z.object({
35
+ kind: z.literal("space"),
36
+ spaceId: z.string().min(1),
37
+ name: z.string().nullable()
38
+ })]),
39
+ resolution: z.enum([
40
+ "requested",
41
+ "selected",
42
+ "fallback"
43
+ ]),
44
+ grant: appAuthorizationGrantSchema
45
+ }),
46
+ z.object({ status: z.literal("cancelled") }),
47
+ z.object({
48
+ status: z.literal("denied"),
49
+ code: z.string()
50
+ })
51
+ ]);
52
+ //#endregion
8
53
  //#region ../protocol/dist/board.js
9
54
  const BOARD_DOCUMENT_KIND = "cohub.board";
10
55
  const BOARD_MANIFEST_KIND = "cohub.board.manifest";
@@ -1205,6 +1250,440 @@ function filterGenerationDeclarationsByPolicy(declarations, policy) {
1205
1250
  });
1206
1251
  }
1207
1252
  //#endregion
1253
+ //#region ../protocol/dist/core/content-schema.js
1254
+ const meta = z.record(z.string(), z.unknown());
1255
+ const contentBlockSchema = z.lazy(() => z.discriminatedUnion("type", [
1256
+ z.object({
1257
+ type: z.literal("text"),
1258
+ text: z.string(),
1259
+ _meta: meta.optional()
1260
+ }),
1261
+ z.object({
1262
+ type: z.literal("thinking"),
1263
+ thinking: z.string(),
1264
+ signature: z.string().optional(),
1265
+ _meta: meta.optional()
1266
+ }),
1267
+ z.object({
1268
+ type: z.literal("image"),
1269
+ source: z.union([z.object({
1270
+ type: z.literal("url"),
1271
+ url: z.string().url()
1272
+ }), z.object({
1273
+ type: z.literal("base64"),
1274
+ media_type: z.string(),
1275
+ data: z.string()
1276
+ })]),
1277
+ _meta: meta.optional()
1278
+ }),
1279
+ z.object({
1280
+ type: z.literal("shell_command"),
1281
+ command: z.string(),
1282
+ rawText: z.string(),
1283
+ _meta: meta.optional()
1284
+ }),
1285
+ z.object({
1286
+ type: z.literal("tool_use"),
1287
+ id: z.string().min(1),
1288
+ name: z.string().min(1),
1289
+ input: z.record(z.string(), z.unknown()),
1290
+ _meta: meta.optional()
1291
+ }),
1292
+ z.object({
1293
+ type: z.literal("tool_result"),
1294
+ tool_use_id: z.string().min(1),
1295
+ content: z.union([z.string(), z.array(contentBlockSchema)]),
1296
+ is_error: z.boolean().optional(),
1297
+ _meta: meta.optional()
1298
+ }),
1299
+ z.object({
1300
+ type: z.literal("system_note"),
1301
+ note_type: z.enum([
1302
+ "session_created",
1303
+ "forked",
1304
+ "compacted",
1305
+ "info"
1306
+ ]),
1307
+ text: z.string(),
1308
+ _meta: meta.optional()
1309
+ })
1310
+ ]));
1311
+ //#endregion
1312
+ //#region ../protocol/dist/runtime/archive.js
1313
+ const RUNTIME_ARCHIVE_SEGMENT_BYTES = 4194304;
1314
+ const digest = z.string().regex(/^[a-f0-9]{64}$/);
1315
+ const runtimeArchiveSegmentSchema = z.object({
1316
+ offset: z.number().int().safe().nonnegative(),
1317
+ sizeBytes: z.number().int().min(1).max(RUNTIME_ARCHIVE_SEGMENT_BYTES),
1318
+ sha256: digest,
1319
+ md5: z.string().regex(/^[a-f0-9]{32}$/)
1320
+ }).strict();
1321
+ const harnessArchiveSchema = z.object({
1322
+ sessionId: z.string().uuid(),
1323
+ turnId: z.string().uuid(),
1324
+ harness: z.enum(["pi", "codex"])
1325
+ }).strict();
1326
+ const harnessArchiveIndexSchema = harnessArchiveSchema.extend({
1327
+ version: z.literal(1),
1328
+ nativeFormat: z.enum(["pi.jsonl", "codex.rollout"]),
1329
+ nativeSessionId: z.string().min(1).max(255),
1330
+ parentTurnId: z.string().uuid().nullable(),
1331
+ sizeBytes: z.number().int().safe().positive(),
1332
+ sha256: digest,
1333
+ segments: z.array(runtimeArchiveSegmentSchema).max(256)
1334
+ }).strict().refine((value) => value.nativeFormat === (value.harness === "pi" ? "pi.jsonl" : "codex.rollout"), "Native format mismatch");
1335
+ function validateArchiveBoundary(index, parent) {
1336
+ if (index.parentTurnId !== (parent?.turnId ?? null)) throw new Error("Archive parent mismatch");
1337
+ if (parent && (parent.sessionId !== index.sessionId || parent.harness !== index.harness || parent.nativeSessionId !== index.nativeSessionId)) throw new Error("Archive identity mismatch");
1338
+ let offset = parent?.sizeBytes ?? 0;
1339
+ for (const segment of index.segments) {
1340
+ if (segment.offset !== offset) throw new Error("Archive segments are not contiguous");
1341
+ offset += segment.sizeBytes;
1342
+ }
1343
+ if (offset !== index.sizeBytes || !parent && !index.segments.length) throw new Error("Archive is incomplete");
1344
+ if (!index.segments.length && parent?.sha256 !== index.sha256) throw new Error("Unchanged archive checksum mismatch");
1345
+ }
1346
+ //#endregion
1347
+ //#region ../protocol/dist/runtime/context.js
1348
+ const createEmptyUsage = () => ({
1349
+ input: 0,
1350
+ output: 0,
1351
+ cacheRead: 0,
1352
+ cacheWrite: 0,
1353
+ totalTokens: 0,
1354
+ cost: {
1355
+ input: 0,
1356
+ output: 0,
1357
+ cacheRead: 0,
1358
+ cacheWrite: 0,
1359
+ total: 0
1360
+ }
1361
+ });
1362
+ /**
1363
+ * Project one block as itself, or drop it. Nothing is ever rewritten into prompt text.
1364
+ * URL images, system notes and unknown blocks have no native representation here; the
1365
+ * durable copy stays in the database and is not faked into the model's input.
1366
+ */
1367
+ function projectBlock(block) {
1368
+ if (block.type === "text") return {
1369
+ type: "text",
1370
+ text: block.text
1371
+ };
1372
+ if (block.type === "image") return block.source.type === "base64" ? {
1373
+ type: "image",
1374
+ data: block.source.data,
1375
+ mimeType: block.source.media_type
1376
+ } : null;
1377
+ if (block.type === "thinking") return {
1378
+ type: "thinking",
1379
+ thinking: block.thinking,
1380
+ ...block.signature ? { thinkingSignature: block.signature } : {}
1381
+ };
1382
+ return null;
1383
+ }
1384
+ const projectContent = (content) => content.map(projectBlock).filter((block) => block !== null);
1385
+ const isCompaction = (message) => message.role === "system" && message.content.some((block) => block.type === "system_note" && block.note_type === "compacted");
1386
+ /** A generation placeholder must never be projected as if it were a finished result. */
1387
+ const isPendingGenerationResult = (message) => message.role === "assistant" && message.meta?.messageKind === "generation_result" && message.meta?.generationStatus !== "completed" && message.meta?.generationStatus !== "failed";
1388
+ function selectRuntimeContextMessages(messages) {
1389
+ let boundary = -1;
1390
+ let latest = -1;
1391
+ messages.forEach((message, index) => {
1392
+ if (!isCompaction(message)) return;
1393
+ const compaction = message.meta?.compaction;
1394
+ const timestamp = Date.parse(compaction?.compactedAt ?? String(message.meta?.createdAt ?? ""));
1395
+ const order = Number.isFinite(timestamp) ? timestamp : index;
1396
+ if (order >= latest) {
1397
+ latest = order;
1398
+ boundary = index;
1399
+ }
1400
+ });
1401
+ const compaction = messages[boundary];
1402
+ if (!compaction) return messages;
1403
+ return [compaction, ...messages.slice(boundary + 1).filter((message) => !isCompaction(message))];
1404
+ }
1405
+ /**
1406
+ * Compile durable, normalized messages into Pi-compatible context without replaying tools.
1407
+ * Representable blocks and tool pairing are preserved verbatim; anything without a native
1408
+ * representation is dropped rather than described in prompt text.
1409
+ */
1410
+ function contextToPiMessages(messages, options = {}) {
1411
+ const result = [];
1412
+ for (const message of selectRuntimeContextMessages(messages)) {
1413
+ if (isPendingGenerationResult(message)) continue;
1414
+ const meta = {
1415
+ ...message.meta,
1416
+ messageId: message.id,
1417
+ turnId: message.turnId
1418
+ };
1419
+ const recordedAt = Date.parse(String(message.meta?.createdAt ?? ""));
1420
+ const timestamp = Number.isFinite(recordedAt) ? recordedAt : 0;
1421
+ if (message.role === "system") continue;
1422
+ if (message.role !== "assistant") {
1423
+ const projected = projectContent(message.content);
1424
+ if (projected.length) result.push({
1425
+ role: "user",
1426
+ content: projected,
1427
+ timestamp,
1428
+ meta
1429
+ });
1430
+ continue;
1431
+ }
1432
+ const calls = new Map(message.content.flatMap((block) => block.type === "tool_use" ? [[block.id, block.name]] : []));
1433
+ const content = message.content.flatMap((block) => {
1434
+ if (block.type === "tool_result") return [];
1435
+ if (block.type === "tool_use") return [{
1436
+ type: "toolCall",
1437
+ id: block.id,
1438
+ name: block.name,
1439
+ arguments: block.input
1440
+ }];
1441
+ const projected = projectBlock(block);
1442
+ return projected ? [projected] : [];
1443
+ });
1444
+ if (content.length) result.push({
1445
+ role: "assistant",
1446
+ content,
1447
+ api: typeof message.meta?.nativeApi === "string" ? message.meta.nativeApi : options.resolveApi?.({
1448
+ provider: message.provider ?? null,
1449
+ model: message.model ?? null
1450
+ }) ?? "history",
1451
+ provider: message.provider ?? options.fallbackProvider ?? "history",
1452
+ model: message.model ?? "history",
1453
+ usage: {
1454
+ ...createEmptyUsage(),
1455
+ ...message.usage
1456
+ },
1457
+ stopReason: message.stopReason === "tool_use" ? "toolUse" : message.stopReason ?? (calls.size ? "toolUse" : "stop"),
1458
+ ...message.errorMessage ? { errorMessage: message.errorMessage } : {},
1459
+ timestamp,
1460
+ meta
1461
+ });
1462
+ for (const block of message.content) {
1463
+ if (block.type !== "tool_result") continue;
1464
+ if (!calls.has(block.tool_use_id)) continue;
1465
+ result.push({
1466
+ role: "toolResult",
1467
+ toolCallId: block.tool_use_id,
1468
+ toolName: calls.get(block.tool_use_id) ?? "tool",
1469
+ content: typeof block.content === "string" ? [{
1470
+ type: "text",
1471
+ text: block.content
1472
+ }] : projectContent(block.content),
1473
+ isError: block.is_error ?? false,
1474
+ timestamp,
1475
+ meta
1476
+ });
1477
+ calls.delete(block.tool_use_id);
1478
+ }
1479
+ }
1480
+ return result;
1481
+ }
1482
+ //#endregion
1483
+ //#region ../protocol/dist/runtime/index.js
1484
+ const RUNTIME_PROTOCOL_VERSION = 1;
1485
+ const RUNTIME_MAX_FRAME_BYTES = 33554432;
1486
+ z.enum([
1487
+ "cohub",
1488
+ "pi",
1489
+ "codex"
1490
+ ]);
1491
+ const isLocalHarness = (value) => value === "pi" || value === "codex";
1492
+ const resolveHarness = (meta) => {
1493
+ const value = meta && typeof meta === "object" ? meta.harness : null;
1494
+ return isLocalHarness(value) ? value : "cohub";
1495
+ };
1496
+ const runtimeCapabilitiesSchema = z.object({
1497
+ harnesses: z.array(z.enum(["pi", "codex"])).min(1).max(2),
1498
+ models: z.array(z.object({
1499
+ harness: z.enum(["pi", "codex"]),
1500
+ provider: z.string().max(100),
1501
+ id: z.string().min(1).max(255),
1502
+ name: z.string().max(255)
1503
+ })).max(2e3)
1504
+ });
1505
+ z.object({
1506
+ connectionId: z.string().uuid(),
1507
+ endpoint: z.url({ protocol: /^wss?$/ }),
1508
+ ownerUserId: z.string().min(1),
1509
+ capabilities: runtimeCapabilitiesSchema
1510
+ });
1511
+ const runtimeReadySchema = z.object({
1512
+ type: z.literal("runtime.ready"),
1513
+ connectionId: z.string().uuid()
1514
+ });
1515
+ z.object({
1516
+ revision: z.string().min(1),
1517
+ confirmed: z.literal(true)
1518
+ }).strict();
1519
+ const id = z.string().uuid();
1520
+ const ordinal = z.number().int().min(0).max(1e5);
1521
+ const content = z.array(contentBlockSchema).max(1e5);
1522
+ const count = z.number().finite().nonnegative().optional();
1523
+ const usageSchema = z.object({
1524
+ input: count,
1525
+ output: count,
1526
+ cacheRead: count,
1527
+ cacheWrite: count,
1528
+ totalTokens: count,
1529
+ cost: z.object({
1530
+ input: count,
1531
+ output: count,
1532
+ cacheRead: count,
1533
+ cacheWrite: count,
1534
+ total: count
1535
+ }).nullable().optional()
1536
+ });
1537
+ const runtimeMessageSchema = z.object({
1538
+ ordinal,
1539
+ content,
1540
+ provider: z.string().nullable().optional(),
1541
+ model: z.string().nullable().optional(),
1542
+ usage: usageSchema.nullable().optional(),
1543
+ stopReason: z.string().max(64).nullable().optional(),
1544
+ errorMessage: z.string().max(16384).nullable().optional()
1545
+ });
1546
+ const runtimeEventSchema = z.discriminatedUnion("type", [
1547
+ z.object({
1548
+ type: z.literal("message.start"),
1549
+ ordinal
1550
+ }),
1551
+ z.object({
1552
+ type: z.literal("text.delta"),
1553
+ ordinal,
1554
+ index: ordinal,
1555
+ kind: z.enum(["text", "thinking"]),
1556
+ delta: z.string()
1557
+ }),
1558
+ z.object({
1559
+ type: z.literal("content.replace"),
1560
+ ordinal,
1561
+ content
1562
+ }),
1563
+ z.object({
1564
+ type: z.literal("message.commit"),
1565
+ message: runtimeMessageSchema
1566
+ }),
1567
+ z.object({
1568
+ type: z.literal("turn.end"),
1569
+ message: runtimeMessageSchema,
1570
+ archive: harnessArchiveSchema.nullable().optional(),
1571
+ resume: z.enum([
1572
+ "native",
1573
+ "restored",
1574
+ "handoff",
1575
+ "new"
1576
+ ])
1577
+ }),
1578
+ z.object({
1579
+ type: z.literal("context.required"),
1580
+ pendingTurnIds: z.array(id).max(2).optional(),
1581
+ historyOnly: z.boolean().optional()
1582
+ }),
1583
+ z.object({ type: z.literal("turn.acknowledged") }),
1584
+ z.object({
1585
+ type: z.literal("turn.error"),
1586
+ message: z.string().max(16384),
1587
+ uncertain: z.boolean().optional()
1588
+ })
1589
+ ]);
1590
+ z.discriminatedUnion("type", [
1591
+ z.object({
1592
+ type: z.literal("runtime.hello"),
1593
+ version: z.literal(1),
1594
+ spaceId: id,
1595
+ token: z.string().min(1).max(16384),
1596
+ capabilities: runtimeCapabilitiesSchema
1597
+ }),
1598
+ z.object({ type: z.literal("runtime.heartbeat") }),
1599
+ z.object({
1600
+ type: z.literal("runtime.auth"),
1601
+ token: z.string().min(1).max(16384)
1602
+ }),
1603
+ z.object({
1604
+ type: z.literal("runtime.event"),
1605
+ requestId: id,
1606
+ event: runtimeEventSchema
1607
+ })
1608
+ ]);
1609
+ const runtimeContextSchema = z.object({
1610
+ complete: z.boolean().optional(),
1611
+ revision: z.string(),
1612
+ throughTurnId: id.nullable(),
1613
+ messages: z.array(z.object({
1614
+ id: z.string(),
1615
+ turnId: id,
1616
+ role: z.enum([
1617
+ "user",
1618
+ "assistant",
1619
+ "system"
1620
+ ]),
1621
+ content,
1622
+ provider: z.string().nullable().optional(),
1623
+ model: z.string().nullable().optional(),
1624
+ usage: usageSchema.nullable().optional(),
1625
+ stopReason: z.string().nullable().optional(),
1626
+ errorMessage: z.string().nullable().optional(),
1627
+ meta: z.record(z.string(), z.unknown()).nullable().optional()
1628
+ })),
1629
+ archive: harnessArchiveSchema.nullable().optional(),
1630
+ resolvedTurnIds: z.array(id).max(2).optional(),
1631
+ settledTurnIds: z.array(id).max(2).optional()
1632
+ });
1633
+ const runtimeCommandSchema = z.discriminatedUnion("type", [
1634
+ z.object({
1635
+ type: z.literal("turn.recover"),
1636
+ requestId: id,
1637
+ execution: z.object({
1638
+ spaceId: id,
1639
+ sessionId: id,
1640
+ turnId: id,
1641
+ harness: z.enum(["pi", "codex"])
1642
+ })
1643
+ }),
1644
+ z.object({
1645
+ type: z.literal("turn.start"),
1646
+ requestId: id,
1647
+ resumeOnly: z.boolean().optional(),
1648
+ input: z.object({
1649
+ spaceId: id,
1650
+ sessionId: id,
1651
+ turnId: id,
1652
+ userMessageId: id,
1653
+ harness: z.enum(["pi", "codex"]),
1654
+ messages: z.array(z.object({
1655
+ turnId: id,
1656
+ userMessageId: id,
1657
+ userId: z.string().nullable(),
1658
+ content
1659
+ })).min(1).max(64),
1660
+ context: runtimeContextSchema,
1661
+ provider: z.string().nullable().optional(),
1662
+ model: z.string().nullable().optional(),
1663
+ thinkingLevel: z.string().nullable().optional(),
1664
+ accessMode: z.enum(["read_only", "full_access"])
1665
+ }).refine((input) => {
1666
+ const owner = input.messages.at(-1);
1667
+ return owner?.turnId === input.turnId && owner.userMessageId === input.userMessageId && new Set(input.messages.map((message) => message.turnId)).size === input.messages.length && new Set(input.messages.map((message) => message.userMessageId)).size === input.messages.length;
1668
+ }, "Runtime batch owner or message identity mismatch")
1669
+ }),
1670
+ z.object({
1671
+ type: z.literal("session.context"),
1672
+ requestId: id,
1673
+ context: runtimeContextSchema
1674
+ }),
1675
+ z.object({
1676
+ type: z.literal("turn.abort"),
1677
+ requestId: id
1678
+ }),
1679
+ z.object({
1680
+ type: z.literal("turn.ack"),
1681
+ requestId: id,
1682
+ revision: z.string(),
1683
+ turnId: id
1684
+ })
1685
+ ]);
1686
+ //#endregion
1208
1687
  //#region ../protocol/dist/public-identifiers.js
1209
1688
  const USERNAME_PATTERN = /^(?!-)(?!.*--)[a-z0-9-]{1,39}(?<!-)$/;
1210
1689
  const SPACE_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9_-]{0,78}[a-z0-9])?$/;
@@ -2187,6 +2666,18 @@ function attachAppEmbed(frame, options) {
2187
2666
  }
2188
2667
  //#endregion
2189
2668
  //#region src/app-runtime.ts
2669
+ var AppRuntimeError = class extends Error {
2670
+ code;
2671
+ requestId;
2672
+ retryable;
2673
+ constructor(code, message, requestId) {
2674
+ super(message);
2675
+ this.code = code;
2676
+ this.requestId = requestId;
2677
+ this.name = "AppRuntimeError";
2678
+ this.retryable = code === "host_timeout" || code === "login_timeout" || code === "request_failed";
2679
+ }
2680
+ };
2190
2681
  const isBrowser$1 = () => typeof window !== "undefined" && typeof window.parent !== "undefined";
2191
2682
  const hasParent = () => isBrowser$1() && window.parent !== window;
2192
2683
  const getParentOrigin = () => {
@@ -2258,7 +2749,7 @@ var ParentBridgeTransport = class {
2258
2749
  };
2259
2750
  }
2260
2751
  subscribeContextChanged(listener) {
2261
- if (!hasParent()) return () => {};
2752
+ if (!hasParent() || typeof window.addEventListener !== "function") return () => {};
2262
2753
  this.contextListeners.add(listener);
2263
2754
  if (!this.contextListener) {
2264
2755
  this.contextListener = (event) => {
@@ -2321,7 +2812,7 @@ var ParentBridgeTransport = class {
2321
2812
  cleanup();
2322
2813
  this.trustedParentOrigin = event.origin;
2323
2814
  if (data.type === "cohub.app.error") {
2324
- reject(new Error(data.message));
2815
+ reject(new AppRuntimeError(data.code ?? "request_failed", data.message, requestId));
2325
2816
  return;
2326
2817
  }
2327
2818
  resolve(data);
@@ -2362,6 +2853,7 @@ var PopupBrokerTransport = class {
2362
2853
  if (message.type === "cohub.app.context") return {
2363
2854
  type: "cohub.app.context.result",
2364
2855
  context: {
2856
+ mode: "broker",
2365
2857
  app: {
2366
2858
  id: await this.resolveAppId() ?? "",
2367
2859
  slug: "",
@@ -2397,6 +2889,7 @@ var PopupBrokerTransport = class {
2397
2889
  return;
2398
2890
  }
2399
2891
  let ready = false;
2892
+ let loginPending = false;
2400
2893
  let settled = false;
2401
2894
  let timer = null;
2402
2895
  let closeChecker = null;
@@ -2422,8 +2915,20 @@ var PopupBrokerTransport = class {
2422
2915
  if (event.origin !== this.brokerOrigin) return;
2423
2916
  const data = event.data;
2424
2917
  if (!data) return;
2918
+ if (data.type === "cohub.app.broker.progress" && !loginPending && !ready) {
2919
+ loginPending = true;
2920
+ if (timer) clearTimeout(timer);
2921
+ timer = setTimeout(() => finish(() => reject(new AppRuntimeError("login_timeout", "Login did not complete in time."))), 6e5);
2922
+ return;
2923
+ }
2425
2924
  if (data.type === "cohub.app.broker.ready" && !ready) {
2925
+ if (message.type === "cohub.app.authorize.v2" && data.authorizationVersion !== 2) {
2926
+ finish(() => reject(new AppRuntimeError("unsupported", "This host does not support structured authorization.")));
2927
+ return;
2928
+ }
2426
2929
  ready = true;
2930
+ if (timer) clearTimeout(timer);
2931
+ timer = setTimeout(() => finish(() => reject(new AppRuntimeError("host_timeout", "Authorization timed out."))), timeoutMs);
2427
2932
  try {
2428
2933
  popup.postMessage({
2429
2934
  ...message,
@@ -2437,7 +2942,7 @@ var PopupBrokerTransport = class {
2437
2942
  if (data.requestId !== requestId) return;
2438
2943
  finish(() => {
2439
2944
  if (data.type === "cohub.app.error") {
2440
- reject(new Error(data.message));
2945
+ reject(new AppRuntimeError(data.code ?? "request_failed", data.message, requestId));
2441
2946
  return;
2442
2947
  }
2443
2948
  resolve(data);
@@ -2446,7 +2951,8 @@ var PopupBrokerTransport = class {
2446
2951
  window.addEventListener("message", onMessage);
2447
2952
  closeChecker = setInterval(() => {
2448
2953
  if (popup.closed) finish(() => {
2449
- if (!ready) reject(/* @__PURE__ */ new Error("Authorization window was closed."));
2954
+ if (message.type === "cohub.app.authorize.v2") resolve({ result: { status: "cancelled" } });
2955
+ else if (!ready) reject(/* @__PURE__ */ new Error("Authorization window was closed."));
2450
2956
  else resolve(null);
2451
2957
  });
2452
2958
  }, 500);
@@ -2564,6 +3070,7 @@ var AppRuntimeApi = class {
2564
3070
  }
2565
3071
  constructor(transport = new ParentBridgeTransport(), appId, appIdResolver) {
2566
3072
  this.transport = transport;
3073
+ this.contextUnsubscribe = transport.subscribeContextChanged?.((context) => this.observeContext(context)) ?? null;
2567
3074
  this.appIdResolver = appIdResolver;
2568
3075
  this.diagnosticUnsubscribe = transport.subscribeDiagnostics?.((diagnostic) => {
2569
3076
  console.warn(`[cohub] ${diagnostic.message} (${diagnostic.code})`, diagnostic.detail ?? {});
@@ -2605,6 +3112,10 @@ var AppRuntimeApi = class {
2605
3112
  return this.storageKeysReady;
2606
3113
  }
2607
3114
  readStoredToken() {
3115
+ if (this.transport instanceof PopupBrokerTransport) {
3116
+ this.writeStoredToken(null);
3117
+ return null;
3118
+ }
2608
3119
  if (!this.tokenStorageKey || typeof localStorage === "undefined") return null;
2609
3120
  try {
2610
3121
  return localStorage.getItem(this.tokenStorageKey);
@@ -2613,6 +3124,7 @@ var AppRuntimeApi = class {
2613
3124
  }
2614
3125
  }
2615
3126
  writeStoredToken(token) {
3127
+ if (this.transport instanceof PopupBrokerTransport) token = null;
2616
3128
  if (!this.tokenStorageKey || typeof localStorage === "undefined") return;
2617
3129
  try {
2618
3130
  if (token) localStorage.setItem(this.tokenStorageKey, token);
@@ -2638,11 +3150,30 @@ var AppRuntimeApi = class {
2638
3150
  else localStorage.removeItem(this.grantsStorageKey);
2639
3151
  } catch {}
2640
3152
  }
3153
+ serverGrants = false;
3154
+ viewerIdentity;
3155
+ identityVersion = 0;
3156
+ contextUnsubscribe = null;
3157
+ observeContext(context) {
3158
+ if (context.capabilities?.serverGrants) this.serverGrants = true;
3159
+ if (context.viewer === void 0) return;
3160
+ const viewer = context.viewer?.userUuid ?? null;
3161
+ if (this.viewerIdentity !== void 0 && viewer !== this.viewerIdentity) {
3162
+ this.identityVersion++;
3163
+ this.token = null;
3164
+ this.authorizedGrants = null;
3165
+ this.writeStoredToken(null);
3166
+ this.writeStoredGrants(null);
3167
+ }
3168
+ this.viewerIdentity = viewer;
3169
+ }
2641
3170
  async context() {
2642
- return (await this.transport.request({ type: "cohub.app.context" }, {
3171
+ const response = await this.transport.request({ type: "cohub.app.context" }, {
2643
3172
  timeoutMs: 8e3,
2644
3173
  retryIntervalMs: 250
2645
- }))?.context ?? null;
3174
+ });
3175
+ if (response?.context) this.observeContext(response.context);
3176
+ return response?.context ?? null;
2646
3177
  }
2647
3178
  onContextChanged(listener) {
2648
3179
  return this.transport.subscribeContextChanged?.(listener) ?? (() => {});
@@ -2659,6 +3190,8 @@ var AppRuntimeApi = class {
2659
3190
  const unsubscribe = this.diagnosticUnsubscribe;
2660
3191
  this.diagnosticUnsubscribe = null;
2661
3192
  unsubscribe?.();
3193
+ this.contextUnsubscribe?.();
3194
+ this.contextUnsubscribe = null;
2662
3195
  this.pointerForwarding = false;
2663
3196
  this.pointerPending = null;
2664
3197
  if (this.pointerFrame !== null) {
@@ -2720,12 +3253,13 @@ var AppRuntimeApi = class {
2720
3253
  }
2721
3254
  async getAccessToken(options) {
2722
3255
  await this.ensureStorageKeys();
3256
+ const identityVersion = this.identityVersion;
2723
3257
  if (this.token && !options?.forceRefresh) return this.token;
2724
3258
  if (options?.forceRefresh) {
2725
3259
  this.token = null;
2726
3260
  this.writeStoredToken(null);
2727
3261
  }
2728
- if (options?.forceRefresh && this.authorizedGrants && this.authorizedGrants.length > 0) {
3262
+ if (!this.serverGrants && options?.forceRefresh && this.authorizedGrants && this.authorizedGrants.length > 0) {
2729
3263
  let refreshed = false;
2730
3264
  let next = [];
2731
3265
  for (const grant of this.authorizedGrants) try {
@@ -2734,12 +3268,14 @@ var AppRuntimeApi = class {
2734
3268
  scopes: grant.scopes,
2735
3269
  spaceId: grant.spaceId
2736
3270
  }, { timeoutMs: 12e4 });
3271
+ if (identityVersion !== this.identityVersion) return null;
2737
3272
  const token = response?.token ?? null;
2738
3273
  if (!token) continue;
2739
3274
  this.token = token;
2740
3275
  next = recordConsent(next, responseSpaceId(response?.space?.id) ?? grant.spaceId, grant.scopes);
2741
3276
  refreshed = true;
2742
3277
  } catch {
3278
+ if (identityVersion !== this.identityVersion) return null;
2743
3279
  next = recordConsent(next, grant.spaceId, grant.scopes);
2744
3280
  }
2745
3281
  this.authorizedGrants = next;
@@ -2753,11 +3289,37 @@ var AppRuntimeApi = class {
2753
3289
  type: "cohub.app.token",
2754
3290
  forceRefresh: Boolean(options?.forceRefresh)
2755
3291
  }, { timeoutMs: 2e4 });
3292
+ if (identityVersion !== this.identityVersion) return null;
2756
3293
  this.token = response?.token ?? null;
2757
3294
  this.writeStoredToken(this.token);
2758
3295
  return this.token;
2759
3296
  }
3297
+ /** Structured authorization. Legacy hosts cannot execute this message. */
3298
+ async authorize(input) {
3299
+ const parsed = appAuthorizationRequestSchema.safeParse(input);
3300
+ if (!parsed.success) throw new AppRuntimeError("invalid_request", "Invalid authorization request.");
3301
+ await this.ensureStorageKeys();
3302
+ const context = await this.context();
3303
+ if (context?.mode !== "broker" && context?.capabilities?.authorization !== 2) throw new AppRuntimeError("unsupported", "This host does not support structured authorization.");
3304
+ const identityVersion = this.identityVersion;
3305
+ const response = await this.transport.request({
3306
+ type: "cohub.app.authorize.v2",
3307
+ ...parsed.data
3308
+ }, { timeoutMs: 12e4 });
3309
+ if (identityVersion !== this.identityVersion) throw new AppRuntimeError("session_changed", "The signed-in account changed. Please try again.");
3310
+ if (!response) throw new AppRuntimeError("host_timeout", "Authorization host did not respond. It may not support structured authorization.");
3311
+ const result = appAuthorizationResultSchema.safeParse(response.result);
3312
+ if (!result.success) throw new AppRuntimeError("invalid_response", "Invalid authorization result.");
3313
+ this.serverGrants = true;
3314
+ if (result.data.status === "granted") {
3315
+ if (typeof response.token !== "string" || !response.token) throw new AppRuntimeError("invalid_response", "Authorization token is missing.");
3316
+ this.token = response.token;
3317
+ this.writeStoredToken(this.token);
3318
+ }
3319
+ return result.data;
3320
+ }
2760
3321
  /**
3322
+ * @deprecated Use authorize() to receive the actual target and grant.
2761
3323
  * Requests viewer consent. With an accessible `spaceId` the grant targets
2762
3324
  * that Space; otherwise the host resolves a viewer-controlled Space (the
2763
3325
  * invocation or embedding Space, then the viewer's last picked Space, then
@@ -2788,6 +3350,7 @@ var AppRuntimeApi = class {
2788
3350
  return Boolean(token);
2789
3351
  }
2790
3352
  /**
3353
+ * @deprecated Use authorize() with a pick-space target.
2791
3354
  * Asks the viewer to pick a Space and grant the scopes on it — one consent
2792
3355
  * dialog covers both. Resolves with the picked space so the app knows where
2793
3356
  * it may act; `space` is null when the viewer denied.
@@ -2887,7 +3450,8 @@ function createSlugAppIdResolver(deps) {
2887
3450
  if (typeof doFetch !== "function") return null;
2888
3451
  const response = await doFetch(`${deps.apiBaseUrl}/api/apps/by-slug/${encodeURIComponent(deps.ownerUsername)}/${encodeURIComponent(deps.spaceSlug)}/${encodeURIComponent(deps.appSlug)}`);
2889
3452
  if (!response.ok) throw new Error(`getBySlug failed: ${response.status}`);
2890
- return (await response.json())?.work?.id ?? null;
3453
+ const data = await response.json();
3454
+ return data?.app?.id ?? data?.work?.id ?? null;
2891
3455
  })().catch(() => {
2892
3456
  cached = null;
2893
3457
  return null;
@@ -3027,14 +3591,16 @@ var CohubClient = class {
3027
3591
  this.appRuntime.dispose();
3028
3592
  }
3029
3593
  auth = {
3594
+ authorize: (input) => this.appRuntime.authorize(input),
3030
3595
  /**
3596
+ * @deprecated Use authorize() for the actual target and structured result.
3031
3597
  * Ensure the app holds these scopes. Without an accessible `spaceId` the
3032
3598
  * host targets a viewer-controlled Space (never the app author's home
3033
3599
  * Space) — use `requestSpace` when the app needs to know which Space.
3034
3600
  * Silent when a grant already covers them; `alwaysAsk` forces the dialog.
3035
3601
  */
3036
3602
  request: (input) => this.appRuntime.requestAuthorization(input),
3037
- /** One consent: the viewer picks a Space and grants the scopes on it. `alwaysAsk` re-opens the picker. */
3603
+ /** @deprecated Use authorize({ target: { kind: "pick-space" }, scopes }). */
3038
3604
  requestSpace: (input) => this.appRuntime.requestSpaceAuthorization(input),
3039
3605
  /** One consent: create a viewer-owned Space and grant the scopes on it. `space` is `CreateSpaceInput`. */
3040
3606
  requestCreateSpace: (input) => this.appRuntime.requestCreateSpaceAuthorization(input)
@@ -3393,6 +3959,7 @@ function clearGrantedAppScopes(userUuid, appId, spaceId) {
3393
3959
  }
3394
3960
  //#endregion
3395
3961
  //#region src/app-bridge-core.ts
3962
+ var AppLoginRedirect = class extends Error {};
3396
3963
  function readTokenResponse(value) {
3397
3964
  if (!value || typeof value !== "object") return null;
3398
3965
  const token = value.token;
@@ -3572,18 +4139,95 @@ function createAppBridgeCore(config) {
3572
4139
  const authorizationContext = config.authorizationContext ?? (config.isBackground ? { surface: "background" } : { surface: "page" });
3573
4140
  const onStateChange = config.onStateChange;
3574
4141
  let appToken = null;
4142
+ let tokenViewer;
4143
+ function synchronizeViewer(viewer) {
4144
+ if (tokenViewer !== void 0 && tokenViewer !== viewer) {
4145
+ appToken = null;
4146
+ sessionViewerGrants.clear();
4147
+ authoritativeGrants.clear();
4148
+ }
4149
+ tokenViewer = viewer;
4150
+ }
3575
4151
  /** Consents made through this host, keyed by target space. */
3576
4152
  const sessionViewerGrants = /* @__PURE__ */ new Map();
3577
4153
  let activeInvocation;
3578
4154
  let contextChangeVersion = 0;
3579
4155
  const legacyRequestIds = /* @__PURE__ */ new Set();
4156
+ const authorizationRequests = /* @__PURE__ */ new Map();
4157
+ const authoritativeGrants = /* @__PURE__ */ new Map();
4158
+ function canJoin(pending, next, requestId) {
4159
+ const previous = authorizationRequests.get(pending.requestId);
4160
+ const current = authorizationRequests.get(requestId);
4161
+ return Boolean(previous) === Boolean(current) && previous?.fallback === current?.fallback && isSameConsent(pending, next);
4162
+ }
4163
+ let signInFlight = null;
4164
+ const pendingLoginKey = `cohub:app-login:${app.id}`;
4165
+ function rememberAuthorization(data) {
4166
+ if (data.createSpace) return;
4167
+ try {
4168
+ const structured = typeof data.requestId === "string" ? authorizationRequests.get(data.requestId) : void 0;
4169
+ sessionStorage.setItem(pendingLoginKey, JSON.stringify({
4170
+ at: Date.now(),
4171
+ data: {
4172
+ ...structured ? {
4173
+ ...structured,
4174
+ type: "cohub.app.authorize.v2"
4175
+ } : { type: data.type },
4176
+ requestId: data.requestId,
4177
+ scopes: data.scopes,
4178
+ reason: sanitizeReason(data.reason),
4179
+ spaceId: data.spaceId,
4180
+ selectSpace: data.selectSpace,
4181
+ alwaysAsk: data.alwaysAsk
4182
+ }
4183
+ }));
4184
+ } catch {}
4185
+ }
4186
+ function clearAuthorizationIntent(requestId) {
4187
+ try {
4188
+ const raw = sessionStorage.getItem(pendingLoginKey);
4189
+ if (!raw) return;
4190
+ const saved = JSON.parse(raw);
4191
+ if (isRecord(saved) && isRecord(saved.data) && saved.data.requestId === requestId) sessionStorage.removeItem(pendingLoginKey);
4192
+ } catch {}
4193
+ }
4194
+ async function resumeAuthorization() {
4195
+ if (state.pendingAuth || !await getViewerUuid()) return;
4196
+ try {
4197
+ const raw = sessionStorage.getItem(pendingLoginKey);
4198
+ if (!raw) return;
4199
+ const saved = JSON.parse(raw);
4200
+ if (!isRecord(saved) || typeof saved.at !== "number" || Date.now() - saved.at > 6e5 || !isRecord(saved.data)) {
4201
+ sessionStorage.removeItem(pendingLoginKey);
4202
+ return;
4203
+ }
4204
+ await handleMessage({ data: saved.data });
4205
+ } catch {}
4206
+ }
4207
+ async function startSignIn() {
4208
+ if (state.pendingAuth) rememberAuthorization({
4209
+ ...state.pendingAuth,
4210
+ type: "cohub.app.authorize"
4211
+ });
4212
+ signInFlight ??= config.requestSignIn(typeof location !== "undefined" ? location.pathname + location.search + location.hash : "/").catch((error) => {
4213
+ signInFlight = null;
4214
+ throw error;
4215
+ });
4216
+ await signInFlight;
4217
+ }
3580
4218
  async function getContext() {
3581
4219
  const invocation = activeInvocation !== void 0 ? activeInvocation : config.getInvocation?.() ?? config.invocation;
3582
4220
  const shell = config.getShell?.() ?? config.shell;
3583
4221
  const appScopes = clonePermissionScopes(app.appScopes);
3584
4222
  const viewerUuid = await getViewerUuid();
4223
+ synchronizeViewer(viewerUuid);
3585
4224
  const viewerGrants = mergeViewerGrants(viewerUuid, Array.from(sessionViewerGrants.values()));
3586
4225
  return {
4226
+ capabilities: {
4227
+ authorization: 2,
4228
+ serverGrants: true
4229
+ },
4230
+ mode: authorizationContext.surface === "broker" ? "broker" : "bridge",
3587
4231
  app: {
3588
4232
  id: app.id,
3589
4233
  slug: app.slug,
@@ -3625,13 +4269,63 @@ function createAppBridgeCore(config) {
3625
4269
  };
3626
4270
  }
3627
4271
  function replyForRequest(requestId, payload, complete = false) {
4272
+ const request = authorizationRequests.get(requestId);
4273
+ if (request && payload.type === "cohub.app.error" && [
4274
+ "space_inaccessible",
4275
+ "scope_not_held",
4276
+ "app_not_accessible",
4277
+ "consent_required"
4278
+ ].includes(String(payload.code))) payload = {
4279
+ ...payload,
4280
+ type: "cohub.app.authorize.result",
4281
+ token: null,
4282
+ result: {
4283
+ status: "denied",
4284
+ code: payload.code
4285
+ }
4286
+ };
4287
+ if (request && payload.type === "cohub.app.authorize.result" && !payload.result) {
4288
+ const space = payload.space;
4289
+ const grant = space ? authoritativeGrants.get(space.id) : void 0;
4290
+ let result = { status: "cancelled" };
4291
+ if (payload.token && space && grant) result = {
4292
+ status: "granted",
4293
+ requestedTarget: request.target,
4294
+ target: request.target.kind === "account" ? { kind: "account" } : {
4295
+ kind: "space",
4296
+ spaceId: space.id,
4297
+ name: space.name
4298
+ },
4299
+ resolution: request.target.kind === "pick-space" ? "selected" : request.target.kind === "space" && request.target.spaceId !== space.id ? "fallback" : "requested",
4300
+ grant
4301
+ };
4302
+ else if (payload.token) payload = {
4303
+ type: "cohub.app.error",
4304
+ code: "invalid_response",
4305
+ message: "Missing authoritative grant."
4306
+ };
4307
+ if (payload.type !== "cohub.app.error") payload = {
4308
+ ...payload,
4309
+ result
4310
+ };
4311
+ }
4312
+ if (complete && (payload.type === "cohub.app.authorize.result" || payload.type === "cohub.app.error" && [
4313
+ "invalid_request",
4314
+ "space_inaccessible",
4315
+ "scope_not_held",
4316
+ "app_not_accessible",
4317
+ "consent_required"
4318
+ ].includes(String(payload.code)))) clearAuthorizationIntent(requestId);
3628
4319
  const namespace = legacyRequestIds.has(requestId) ? "work" : "app";
3629
4320
  const type = payload.type;
3630
4321
  reply(requestId, {
3631
4322
  ...payload,
3632
4323
  ...typeof type === "string" && type.startsWith("cohub.app.") ? { type: type.replace("cohub.app.", `cohub.${namespace}.`) } : {}
3633
4324
  });
3634
- if (complete) legacyRequestIds.delete(requestId);
4325
+ if (complete) {
4326
+ legacyRequestIds.delete(requestId);
4327
+ authorizationRequests.delete(requestId);
4328
+ }
3635
4329
  }
3636
4330
  function toLegacyWorkContext(context) {
3637
4331
  const permissions = context.permissions ? {
@@ -3710,12 +4404,11 @@ function createAppBridgeCore(config) {
3710
4404
  return authorizationContext.surface === "background" || authorizationContext.surface === "app" || authorizationContext.surface === "overlay";
3711
4405
  }
3712
4406
  async function ensureBaseToken(forceRefresh = false) {
4407
+ const viewer = await getViewerUuid();
4408
+ synchronizeViewer(viewer);
3713
4409
  if (appToken && !forceRefresh) return appToken;
3714
4410
  const userToken = await getAccessToken({ forceRefresh });
3715
- if (!userToken) {
3716
- await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
3717
- return null;
3718
- }
4411
+ if (!userToken) return null;
3719
4412
  const response = await fetch(`${apiOrigin}/api/apps/${app.id}/session`, {
3720
4413
  method: "POST",
3721
4414
  headers: { Authorization: `Bearer ${userToken}` }
@@ -3723,6 +4416,7 @@ function createAppBridgeCore(config) {
3723
4416
  if (!response.ok) throw new Error("Failed to create app session.");
3724
4417
  const token = readTokenResponse(await response.json());
3725
4418
  if (!token) throw new Error("Invalid app session response.");
4419
+ if (viewer !== await getViewerUuid()) return null;
3726
4420
  appToken = token;
3727
4421
  return appToken;
3728
4422
  }
@@ -3733,11 +4427,14 @@ function createAppBridgeCore(config) {
3733
4427
  * fresh dialog.
3734
4428
  */
3735
4429
  async function authorize(scopes, spaceId, options) {
4430
+ const incremental = Boolean(state.pendingAuth && authorizationRequests.has(state.pendingAuth.requestId));
3736
4431
  const userToken = await getAccessToken(options?.forceRefreshToken ? { forceRefresh: true } : void 0);
3737
4432
  if (!userToken) {
3738
- await config.requestSignIn(typeof location !== "undefined" ? location.pathname : "/");
3739
- throw new Error("Sign in is required to authorize this app.");
4433
+ if (mintedSpace) throw new AppAuthorizationError("Sign in to finish authorization.", 401, "login_required");
4434
+ await startSignIn();
4435
+ throw new AppLoginRedirect();
3740
4436
  }
4437
+ const authorizingViewer = await getViewerUuid();
3741
4438
  const response = await fetch(`${apiOrigin}/api/apps/${app.id}/authorize`, {
3742
4439
  method: "POST",
3743
4440
  signal: timeoutSignal(AUTHORIZE_TIMEOUT_MS),
@@ -3748,13 +4445,18 @@ function createAppBridgeCore(config) {
3748
4445
  body: JSON.stringify({
3749
4446
  scopes,
3750
4447
  ...spaceId ? { spaceId } : {},
3751
- ...options?.silent ? { silent: true } : {}
4448
+ ...options?.silent ? { silent: true } : {},
4449
+ ...incremental ? { scopeMode: "extend" } : {}
3752
4450
  })
3753
4451
  });
3754
4452
  const payload = await response.json().catch(() => null);
3755
4453
  if (!response.ok) throw new AppAuthorizationError(typeof payload?.message === "string" ? payload.message : "Authorization failed.", response.status, typeof payload?.code === "string" ? payload.code : void 0);
4454
+ if (authorizingViewer !== await getViewerUuid()) throw new AppAuthorizationError("The signed-in account changed. Please try again.", 409, "session_changed");
4455
+ synchronizeViewer(authorizingViewer);
3756
4456
  const token = readTokenResponse(payload);
3757
4457
  if (!token) throw new Error("Invalid app authorization response.");
4458
+ const parsedGrant = appAuthorizationGrantSchema.safeParse(payload?.grant);
4459
+ if (parsedGrant.success) authoritativeGrants.set(parsedGrant.data.spaceId, parsedGrant.data);
3758
4460
  const canonicalSpaceId = typeof payload?.grant?.spaceId === "string" && payload.grant.spaceId ? payload.grant.spaceId : spaceId ?? app.spaceId;
3759
4461
  const grantedScopes = sanitizeRequestedScopes(payload?.grant?.scopes);
3760
4462
  const canonicalScopes = grantedScopes.length > 0 ? grantedScopes : clonePermissionScopes(scopes);
@@ -3836,7 +4538,10 @@ function createAppBridgeCore(config) {
3836
4538
  async function listViewerSpaces() {
3837
4539
  const request = async (forceRefresh = false) => {
3838
4540
  const userToken = await getAccessToken({ forceRefresh });
3839
- if (!userToken) return null;
4541
+ if (!userToken) {
4542
+ await startSignIn();
4543
+ throw new AppLoginRedirect();
4544
+ }
3840
4545
  return fetch(`${apiOrigin}/api/spaces`, {
3841
4546
  headers: { Authorization: `Bearer ${userToken}` },
3842
4547
  signal: spaceListSignal()
@@ -3852,7 +4557,8 @@ function createAppBridgeCore(config) {
3852
4557
  const option = toSpaceOption(space);
3853
4558
  return option ? [option] : [];
3854
4559
  });
3855
- } catch {
4560
+ } catch (error) {
4561
+ if (error instanceof AppLoginRedirect) throw error;
3856
4562
  return null;
3857
4563
  }
3858
4564
  }
@@ -4006,8 +4712,38 @@ function createAppBridgeCore(config) {
4006
4712
  return (await response.json()).checkout ?? null;
4007
4713
  }
4008
4714
  async function handleMessage(event) {
4009
- const data = event.data;
4715
+ let data = event.data;
4010
4716
  if (!data?.requestId) return;
4717
+ if (data.type === "cohub.app.authorize.v2") {
4718
+ const parsed = appAuthorizationRequestSchema.safeParse(event.data);
4719
+ if (!parsed.success || parsed.data.scopes.some((scope) => !PERMISSIONS.includes(scope))) {
4720
+ replyForRequest(data.requestId, {
4721
+ type: "cohub.app.error",
4722
+ code: "invalid_request",
4723
+ message: "Invalid authorization request."
4724
+ }, true);
4725
+ return;
4726
+ }
4727
+ const input = parsed.data;
4728
+ if (input.target.kind === "account" && input.scopes.some((scope) => !isUserLevelPermission(scope))) {
4729
+ replyForRequest(data.requestId, {
4730
+ type: "cohub.app.error",
4731
+ code: "invalid_request",
4732
+ message: "Space permissions require a Space target."
4733
+ }, true);
4734
+ return;
4735
+ }
4736
+ authorizationRequests.set(data.requestId, input);
4737
+ data = {
4738
+ requestId: data.requestId,
4739
+ ...input,
4740
+ type: "cohub.app.authorize",
4741
+ scopes: input.scopes,
4742
+ spaceId: input.target.kind === "space" ? input.target.spaceId : void 0,
4743
+ selectSpace: input.target.kind === "pick-space"
4744
+ };
4745
+ }
4746
+ if (!data.requestId) return;
4011
4747
  const isLegacyWork = data.type?.startsWith("cohub.work.") === true;
4012
4748
  if (isLegacyWork) legacyRequestIds.add(data.requestId);
4013
4749
  let reservedAuth = null;
@@ -4018,6 +4754,7 @@ function createAppBridgeCore(config) {
4018
4754
  type: "cohub.app.context.result",
4019
4755
  context: isLegacyWork ? toLegacyWorkContext(context) : context
4020
4756
  }, true);
4757
+ await resumeAuthorization();
4021
4758
  }
4022
4759
  if (data.type === "cohub.app.token" || data.type === "cohub.work.token") {
4023
4760
  const token = await ensureBaseToken(Boolean(data.forceRefresh));
@@ -4125,18 +4862,22 @@ function createAppBridgeCore(config) {
4125
4862
  return;
4126
4863
  }
4127
4864
  if (state.pendingAuth) {
4128
- if (isSameConsent(state.pendingAuth, {
4865
+ if (canJoin(state.pendingAuth, {
4129
4866
  scopes,
4130
4867
  spaceId,
4131
4868
  selectSpace,
4132
4869
  createSpace
4133
- })) {
4870
+ }, data.requestId)) {
4134
4871
  state.pendingAuth.joinedRequestIds = [...state.pendingAuth.joinedRequestIds ?? [], data.requestId];
4135
4872
  return;
4136
4873
  }
4137
4874
  dismissPendingAuth();
4138
4875
  }
4139
4876
  if (createSpace) {
4877
+ if (!await getViewerUuid()) {
4878
+ await startSignIn();
4879
+ return;
4880
+ }
4140
4881
  mintedSpace = null;
4141
4882
  const pendingCreate = {
4142
4883
  requestId: data.requestId,
@@ -4154,7 +4895,7 @@ function createAppBridgeCore(config) {
4154
4895
  notify();
4155
4896
  return;
4156
4897
  }
4157
- if (!selectSpace && !alwaysAsk && allowsOwnerAutoAuthorization() && await isCurrentViewerAppOwner()) try {
4898
+ if (!selectSpace && !authorizationRequests.has(data.requestId) && !alwaysAsk && allowsOwnerAutoAuthorization() && await isCurrentViewerAppOwner()) try {
4158
4899
  const result = await authorizeSilent(scopes, spaceId);
4159
4900
  replyForRequest(data.requestId, authorizeResult(result.token, result.spaceId, result.spaceId === app.spaceId ? app.spaceName ?? null : null), true);
4160
4901
  return;
@@ -4168,12 +4909,12 @@ function createAppBridgeCore(config) {
4168
4909
  }
4169
4910
  }
4170
4911
  if (state.pendingAuth) {
4171
- if (isSameConsent(state.pendingAuth, {
4912
+ if (canJoin(state.pendingAuth, {
4172
4913
  scopes,
4173
4914
  spaceId,
4174
4915
  selectSpace,
4175
4916
  createSpace
4176
- })) {
4917
+ }, data.requestId)) {
4177
4918
  state.pendingAuth.joinedRequestIds = [...state.pendingAuth.joinedRequestIds ?? [], data.requestId];
4178
4919
  return;
4179
4920
  }
@@ -4194,6 +4935,11 @@ function createAppBridgeCore(config) {
4194
4935
  state.authError = null;
4195
4936
  const viewerUuid = await getViewerUuid();
4196
4937
  if (state.pendingAuth !== reserved) return;
4938
+ if (!viewerUuid) {
4939
+ rememberAuthorization(data);
4940
+ await startSignIn();
4941
+ return;
4942
+ }
4197
4943
  const spaceLevel = Boolean(spaceId) || selectSpace || scopes.some((scope) => !isUserLevelPermission(scope));
4198
4944
  const lastPicked = readLastPickedSpace();
4199
4945
  const contextSpaceId = resolveContextSpaceId();
@@ -4208,7 +4954,26 @@ function createAppBridgeCore(config) {
4208
4954
  if (fallback) spaces = [fallback];
4209
4955
  }
4210
4956
  const candidates = spaces ?? null;
4957
+ if (spaceLevel && spaces === null) {
4958
+ reserved.spaces = null;
4959
+ state.authError = "Couldn't load your Spaces. Please try again.";
4960
+ state.authOpen = true;
4961
+ state.canChangeSpace = false;
4962
+ notify();
4963
+ return;
4964
+ }
4211
4965
  const explicitAccessible = Boolean(spaceId) && candidates?.some((space) => space.id === spaceId) === true;
4966
+ const structuredRequest = authorizationRequests.get(data.requestId);
4967
+ if (spaceId && candidates && !explicitAccessible && structuredRequest?.fallback === "none") {
4968
+ replyPendingAuth(reserved, {
4969
+ type: "cohub.app.error",
4970
+ code: "space_inaccessible",
4971
+ message: "The requested Space is unavailable."
4972
+ });
4973
+ resetDialogState();
4974
+ safeNotify();
4975
+ return;
4976
+ }
4212
4977
  const defaultSpaceId = explicitAccessible ? spaceId : resolveDefaultSpaceId(candidates);
4213
4978
  const silentTargets = (!spaceLevel ? [] : [selectSpace ? lastPicked && candidates?.some((space) => space.id === lastPicked) ? lastPicked : null : explicitAccessible ? spaceId : spaceId === void 0 ? defaultSpaceId : null].filter((target) => Boolean(target) && hasGrantedAppScopes(viewerUuid, app.id, scopes, target ?? void 0))).slice(0, MAX_SILENT_SPACE_ATTEMPTS);
4214
4979
  if (!alwaysAsk && await attemptSilentRenewal(reserved, viewerUuid, scopes, silentTargets)) return;
@@ -4230,11 +4995,19 @@ function createAppBridgeCore(config) {
4230
4995
  notify();
4231
4996
  }
4232
4997
  } catch (error) {
4998
+ if (error instanceof AppLoginRedirect) {
4999
+ rememberAuthorization(data);
5000
+ resetDialogState();
5001
+ safeNotify();
5002
+ return;
5003
+ }
4233
5004
  const message = error instanceof Error ? error.message : "Request failed.";
5005
+ const code = error instanceof AppAuthorizationError ? error.code : "request_failed";
4234
5006
  if (reservedAuth && state.pendingAuth === reservedAuth) {
4235
5007
  replyPendingAuth(reservedAuth, {
4236
5008
  type: "cohub.app.error",
4237
- message
5009
+ message,
5010
+ code
4238
5011
  });
4239
5012
  resetDialogState();
4240
5013
  safeNotify();
@@ -4242,7 +5015,8 @@ function createAppBridgeCore(config) {
4242
5015
  }
4243
5016
  replyForRequest(data.requestId, {
4244
5017
  type: "cohub.app.error",
4245
- message
5018
+ message,
5019
+ code
4246
5020
  }, true);
4247
5021
  }
4248
5022
  }
@@ -4262,7 +5036,14 @@ function createAppBridgeCore(config) {
4262
5036
  if (!state.pendingAuth) return;
4263
5037
  replyPendingAuth(state.pendingAuth, {
4264
5038
  type: "cohub.app.authorize.result",
4265
- token: null
5039
+ token: null,
5040
+ ...mintedSpace ? {
5041
+ space: {
5042
+ id: mintedSpace.id,
5043
+ name: mintedSpace.name
5044
+ },
5045
+ stage: mintedSpace.provisioned ? "authorization" : "bootstrap"
5046
+ } : {}
4266
5047
  });
4267
5048
  resetDialogState();
4268
5049
  mintedSpace = null;
@@ -4323,6 +5104,11 @@ function createAppBridgeCore(config) {
4323
5104
  if (!state.pendingAuth || state.authSaving) return;
4324
5105
  const pending = state.pendingAuth;
4325
5106
  let requestedSpaceId = (state.canChangeSpace ? pickedSpaceId : void 0) ?? state.selectedSpaceId ?? void 0;
5107
+ if (pending.spaces === null) {
5108
+ state.authError = "Couldn't load your Spaces. Please try again.";
5109
+ notify();
5110
+ return;
5111
+ }
4326
5112
  if (pending.spaces !== void 0) {
4327
5113
  const candidates = pending.spaces;
4328
5114
  if (!(requestedSpaceId !== void 0 && candidates?.some((space) => space.id === requestedSpaceId) === true)) {
@@ -4360,6 +5146,13 @@ function createAppBridgeCore(config) {
4360
5146
  resetDialogState();
4361
5147
  mintedSpace = null;
4362
5148
  } catch (error) {
5149
+ if (error instanceof AppLoginRedirect) return;
5150
+ if (mintedSpace && error instanceof AppAuthorizationError && error.code === "login_required") {
5151
+ replyPendingAuth(pending, authorizeResult(null, mintedSpace.id, mintedSpace.name));
5152
+ resetDialogState();
5153
+ mintedSpace = null;
5154
+ return;
5155
+ }
4363
5156
  if (error instanceof AppAuthorizationError) emitDiagnostic({
4364
5157
  code: error.code ?? "authorize_failed",
4365
5158
  message: error.message,
@@ -4626,4 +5419,4 @@ function createBoardExtensionRegistry() {
4626
5419
  }
4627
5420
  const BOARD_CHANNELS = BOARD_ANIMATION_CHANNELS;
4628
5421
  //#endregion
4629
- export { APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppSurfaceApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BillingApi, BoardAnimationSpecSchema, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardDealParamsSchema, BoardEffectInputSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, BoardPlaybackPolicySchema, BoardSemanticCommandSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, DESKTOP_COMMAND_PENDING_TTL_SECONDS, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, DESKTOP_COMMAND_VERSION, DesktopCommandsApi, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, SpacePublicFilesApi, SpaceWebhooksApi, USER_LEVEL_PERMISSIONS, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, assertGenerationRequestAllowedByPolicy, attachAppEmbed, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileComposition, composition, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, filterSpacePickerItems, findGenerationModelPolicy, formatAppRef, formatWorkRef, getAllowedGenerationModelIds, getCohubContext, hasGrantedAppScopes, hasRequestSourceIdentity, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isUserLevelPermission, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeSpacePickerQuery, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, orderSpacePickerItems, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardEffectInput, parseBoardPlaybackPolicy, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseWorkRef, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveOpenSurface, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, scopeListHasPermission, selectSpacePickerItems, setGrantedAppScopes, track };
5422
+ export { APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppRuntimeError, AppSurfaceApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BillingApi, BoardAnimationSpecSchema, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardDealParamsSchema, BoardEffectInputSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, BoardPlaybackPolicySchema, BoardSemanticCommandSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, DESKTOP_COMMAND_PENDING_TTL_SECONDS, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, DESKTOP_COMMAND_VERSION, DesktopCommandsApi, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, RUNTIME_ARCHIVE_SEGMENT_BYTES, RUNTIME_MAX_FRAME_BYTES, RUNTIME_PROTOCOL_VERSION, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, SpacePublicFilesApi, SpaceWebhooksApi, USER_LEVEL_PERMISSIONS, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, assertGenerationRequestAllowedByPolicy, attachAppEmbed, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileComposition, composition, contextToPiMessages, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, filterSpacePickerItems, findGenerationModelPolicy, formatAppRef, formatWorkRef, getAllowedGenerationModelIds, getCohubContext, harnessArchiveIndexSchema, hasGrantedAppScopes, hasRequestSourceIdentity, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isLocalHarness, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isUserLevelPermission, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeSpacePickerQuery, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, orderSpacePickerItems, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardEffectInput, parseBoardPlaybackPolicy, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseWorkRef, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveHarness, resolveOpenSurface, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, runtimeCommandSchema, runtimeEventSchema, runtimeReadySchema, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, scopeListHasPermission, selectRuntimeContextMessages, selectSpacePickerItems, setGrantedAppScopes, track, validateArchiveBoundary };