@neta-art/cohub 5.7.0 → 5.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/README.md +18 -5
  2. package/dist/board/core/palette.d.ts +3 -2
  3. package/dist/board/core/shape-types.d.ts +3 -1
  4. package/dist/board/core/shape-types.js +3 -7
  5. package/dist/board/core/tool-styles.d.ts +2 -1
  6. package/dist/board/image-key.js +3 -5
  7. package/dist/board/index.d.ts +9 -4
  8. package/dist/board/index.js +7 -3
  9. package/dist/board/media-playback.d.ts +22 -0
  10. package/dist/board/media-playback.js +67 -0
  11. package/dist/board/media.d.ts +7 -0
  12. package/dist/board/media.js +70 -0
  13. package/dist/board/nodes.d.ts +113 -0
  14. package/dist/board/nodes.js +154 -0
  15. package/dist/board/render/index.d.ts +3 -1
  16. package/dist/board/render/index.js +4 -2
  17. package/dist/board/render/media-interaction.d.ts +19 -0
  18. package/dist/board/render/media-interaction.js +26 -0
  19. package/dist/board/render/renderers/audio-card-renderer.js +1 -1
  20. package/dist/board/render/renderers/board-renderer-registry.js +2 -2
  21. package/dist/board/render/renderers/draw-card-renderer.js +1 -1
  22. package/dist/board/render/renderers/file-card-renderer.js +1 -1
  23. package/dist/board/render/renderers/frame-card-renderer.js +1 -1
  24. package/dist/board/render/renderers/geo-card-renderer.js +1 -1
  25. package/dist/board/render/renderers/image-card-renderer.js +1 -1
  26. package/dist/board/render/renderers/task-card-renderer.js +16 -13
  27. package/dist/board/render/renderers/text-card-renderer.js +1 -1
  28. package/dist/board/render/renderers/unknown-card-renderer.js +1 -1
  29. package/dist/board/render/renderers/video-card-renderer.js +1 -1
  30. package/dist/board/render/video-thumbnail.d.ts +16 -0
  31. package/dist/board/render/video-thumbnail.js +86 -0
  32. package/dist/board/task.d.ts +10 -5
  33. package/dist/board/task.js +159 -103
  34. package/dist/chunks/environment.d.ts +6 -6
  35. package/dist/chunks/environment.js +6 -6
  36. package/dist/chunks/http.d.ts +152 -5
  37. package/dist/chunks/http.js +1707 -169
  38. package/dist/chunks/transport.js +24 -4
  39. package/dist/chunks/websocket.d.ts +144 -2
  40. package/dist/chunks/websocket.js +1 -1
  41. package/dist/http.d.ts +3 -3
  42. package/dist/index.d.ts +273 -4
  43. package/dist/index.js +275 -741
  44. package/dist/protocol/dist/board-connection.d.ts +7 -0
  45. package/dist/protocol/dist/board-connection.js +4 -0
  46. package/dist/protocol/dist/board-content.d.ts +1 -0
  47. package/dist/protocol/dist/board-content.js +26 -0
  48. package/dist/protocol/dist/board-document.d.ts +157 -48
  49. package/dist/protocol/dist/board-document.js +40 -19
  50. package/dist/protocol/dist/board-node.d.ts +18 -0
  51. package/dist/protocol/dist/board-node.js +239 -0
  52. package/dist/protocol/dist/board-url.d.ts +12 -0
  53. package/dist/protocol/dist/board-url.js +83 -0
  54. package/dist/protocol/dist/board.d.ts +5 -0
  55. package/dist/protocol/dist/identifiers.js +10 -0
  56. package/dist/protocol/dist/index.d.ts +3 -1
  57. package/dist/protocol/dist/index.js +7 -1
  58. package/dist/protocol/dist/provenance.js +2 -0
  59. package/dist/protocol/dist/ui-command.js +2 -0
  60. package/dist/protocol/dist/work-promotion-stats.js +11 -0
  61. package/dist/protocol/dist/work-surface.js +2 -0
  62. package/dist/protocol/dist/work-view-stats.js +1 -0
  63. package/docs/work-runtime-guide.md +7 -7
  64. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,9 +1,249 @@
1
- import { A as parseAssistantMessageCommit, B as ReferencesApi, C as SpaceClient, D as buildSpacePath, E as buildSpaceInvitePath, F as BOARD_ARROW_STROKE_SIZE, G as ModelsApi, H as PublicAssetsApi, I as BOARD_BUILTIN_CAPABILITIES, J as ChannelsApi, K as GenerationsApi, L as BOARD_CONNECTION_STROKE_SIZE, M as createSessionPatchReducer, N as ensureRealtimeConnected, O as SessionGenerationStreamClient, P as BoardConnectionSchema, R as DEFAULT_BOARD_RENDER_LIMITS, S as BoardTransactionError, T as PublicInviteApi, U as SkillsApi, V as SearchApi, W as PromptsApi, _ as isUiSurfaceMethod, a as ReferralsApi, b as TasksApi, c as UiCommandsApi, d as UI_COMMAND_PAYLOAD_MAX_BYTES, f as UI_COMMAND_PENDING_TTL_SECONDS, g as isTerminalUiCommandStatus, h as UI_COMMAND_VERSION, i as WorksApi, j as SessionPatchReducer, k as createSessionGenerationStreamClient, l as UI_COMMAND_DEFAULT_TIMEOUT_MS, m as UI_COMMAND_TERMINAL_TTL_SECONDS, n as createHttpClient, o as UsersApi, p as UI_COMMAND_SETTLEMENT_GRACE_SECONDS, q as CronJobsApi, r as WorkCommerceApi, s as UserApi, t as CohubHttpClient, u as UI_COMMAND_MAX_TIMEOUT_MS, v as parseUiCommand, w as SpacesApi, x as BoardClient, y as parseUiCommandId, z as SessionAccessApi } from "./chunks/http.js";
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 REALTIME_DOMAINS } from "./chunks/transport.js";
1
+ import { $ as parseUsername, A as WORK_SURFACE_READY_TIMEOUT_MS, B as parseWorkSurfaceRequest, C as BoardInputError, D as WORK_COMPOSER_CHIP_CONTENT_MAX_BYTES, E as validateBoardNodes, F as buildWorkSurfaceRequest, G as UI_COMMAND_PENDING_TTL_SECONDS, H as UI_COMMAND_DEFAULT_TIMEOUT_MS, I as buildWorkSurfaceResponse, J as UI_COMMAND_VERSION, K as UI_COMMAND_SETTLEMENT_GRACE_SECONDS, L as parseWorkComposerChipClear, M as buildWorkComposerChipClear, N as buildWorkComposerChipSet, O as WORK_COMPOSER_CHIP_KEY_MAX_LENGTH, P as buildWorkSurfaceReady, Q as parseSpaceSlug, R as parseWorkComposerChipSet, S as createSessionPatchReducer, T as createBoardNode, U as UI_COMMAND_MAX_TIMEOUT_MS, V as parseWorkSurfaceResponse, W as UI_COMMAND_PAYLOAD_MAX_BYTES, X as isUiSurfaceMethod, Y as isTerminalUiCommandStatus, Z as parseUiCommand, _ as buildSpacePath, _t as ModelsApi, a as ReferralsApi, at as validateBoardNodeInput, b as parseAssistantMessageCommit, bt as ChannelsApi, c as UiCommandsApi, ct as ensureRealtimeConnected, d as BoardTransactionError, dt as SessionAccessApi, et as BoardAwarenessClientPayloadSchema, f as SpaceClient, ft as ReferencesApi, g as buildSpaceInvitePath, gt as PromptsApi, h as PublicInviteApi, ht as SkillsApi, i as WorksApi, it as BOARD_NODE_CONTRACT, j as WORK_SURFACE_REQUEST_TIMEOUT_MS, k as WORK_COMPOSER_CHIP_LABEL_MAX_LENGTH, l as TasksApi, lt as BOARD_BUILTIN_CAPABILITIES, m as SpacesApi, mt as PublicAssetsApi, n as createHttpClient, nt as BOARD_GEO_KINDS, o as UsersApi, ot as BoardPlaybackPolicySchema, p as SpacePublicFilesApi, pt as SearchApi, q as UI_COMMAND_TERMINAL_TTL_SECONDS, r as WorkCommerceApi, rt as BOARD_NATIVE_NODE_TYPES, s as UserApi, st as parseBoardPlaybackPolicy, t as CohubHttpClient, tt as BOARD_COLOR_IDS, u as BoardClient, ut as DEFAULT_BOARD_RENDER_LIMITS, v as SessionGenerationStreamClient, vt as GenerationsApi, w as assertBoardNodes, x as SessionPatchReducer, y as createSessionGenerationStreamClient, yt as CronJobsApi, z as parseWorkSurfaceReady } from "./chunks/http.js";
2
+ import { _ as requestSourceToHeaders, a as sanitizeAccessToken, b as REALTIME_DOMAINS, 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, x as REALTIME_ROOM_EVENT_NAME_PATTERN, y as isUuid } 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";
6
6
  import { z } from "zod";
7
+ //#region ../protocol/dist/generation/catalog.js
8
+ function isGenerationModelHidden(model) {
9
+ return model.hidden === true;
10
+ }
11
+ function filterDiscoverableGenerationModels(models, options = {}) {
12
+ const includeModelIds = new Set(options.includeModelIds);
13
+ return models.filter((model) => !isGenerationModelHidden(model) || includeModelIds.has(model.model));
14
+ }
15
+ //#endregion
16
+ //#region ../protocol/dist/generation/policy.js
17
+ const GENERATION_POLICY_ENV_KEY = "COHUB_GENERATION_POLICY_B64";
18
+ var GenerationPolicyError = class extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "GenerationPolicyError";
22
+ }
23
+ };
24
+ function isRecord(value) {
25
+ return !!value && typeof value === "object" && !Array.isArray(value);
26
+ }
27
+ function isPrimitiveEnumValue(value) {
28
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
29
+ }
30
+ function normalizeConstraint(value) {
31
+ if (!isRecord(value) || typeof value.kind !== "string") return null;
32
+ if (value.kind === "enum") {
33
+ if (!Array.isArray(value.values) || value.values.length === 0 || !value.values.every(isPrimitiveEnumValue)) return null;
34
+ return {
35
+ kind: "enum",
36
+ values: value.values
37
+ };
38
+ }
39
+ if (value.kind === "number" || value.kind === "integer") {
40
+ const result = { kind: value.kind };
41
+ if (typeof value.min === "number" && Number.isFinite(value.min)) result.min = value.min;
42
+ if (typeof value.max === "number" && Number.isFinite(value.max)) result.max = value.max;
43
+ if (result.min !== void 0 && result.max !== void 0 && result.min > result.max) return null;
44
+ if (Array.isArray(value.values) && value.values.every((item) => typeof item === "number" && Number.isFinite(item))) {
45
+ if (value.kind === "integer" && !value.values.every(Number.isInteger)) return null;
46
+ const min = result.min;
47
+ const max = result.max;
48
+ if (min !== void 0 && value.values.some((item) => item < min)) return null;
49
+ if (max !== void 0 && value.values.some((item) => item > max)) return null;
50
+ result.values = value.values;
51
+ }
52
+ return result;
53
+ }
54
+ if (value.kind === "boolean") return typeof value.value === "boolean" ? {
55
+ kind: "boolean",
56
+ value: value.value
57
+ } : { kind: "boolean" };
58
+ return null;
59
+ }
60
+ function normalizeGenerationPolicy(value) {
61
+ if (!isRecord(value) || value.version !== 1) return null;
62
+ if (value.mode === "auto") return {
63
+ version: 1,
64
+ mode: "auto"
65
+ };
66
+ if (value.mode !== "limited" || !Array.isArray(value.models) || value.models.length === 0) return null;
67
+ const models = [];
68
+ for (const item of value.models) {
69
+ if (!isRecord(item) || typeof item.model !== "string" || !item.model.trim()) return null;
70
+ const modelPolicy = { model: item.model.trim() };
71
+ if (item.parameters !== void 0) {
72
+ if (!isRecord(item.parameters)) return null;
73
+ const parameters = {};
74
+ for (const [key, rawConstraint] of Object.entries(item.parameters)) {
75
+ if (!key.trim()) return null;
76
+ const constraint = normalizeConstraint(rawConstraint);
77
+ if (!constraint) return null;
78
+ parameters[key] = constraint;
79
+ }
80
+ if (Object.keys(parameters).length > 0) modelPolicy.parameters = parameters;
81
+ }
82
+ models.push(modelPolicy);
83
+ }
84
+ return {
85
+ version: 1,
86
+ mode: "limited",
87
+ models
88
+ };
89
+ }
90
+ function bytesToBase64(bytes) {
91
+ let binary = "";
92
+ for (const byte of bytes) binary += String.fromCharCode(byte);
93
+ return btoa(binary);
94
+ }
95
+ function base64ToBytes(value) {
96
+ const binary = atob(value);
97
+ const bytes = new Uint8Array(binary.length);
98
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
99
+ return bytes;
100
+ }
101
+ function toBase64Url(value) {
102
+ return bytesToBase64(new TextEncoder().encode(value)).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
103
+ }
104
+ function fromBase64Url(value) {
105
+ const base64 = value.replaceAll("-", "+").replaceAll("_", "/");
106
+ const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
107
+ return new TextDecoder().decode(base64ToBytes(padded));
108
+ }
109
+ function encodeGenerationPolicy(policy) {
110
+ return toBase64Url(JSON.stringify(policy));
111
+ }
112
+ function decodeGenerationPolicy(value) {
113
+ try {
114
+ return normalizeGenerationPolicy(JSON.parse(fromBase64Url(value)));
115
+ } catch {
116
+ return null;
117
+ }
118
+ }
119
+ function parseGenerationPolicyFromEnv(env) {
120
+ const value = env[GENERATION_POLICY_ENV_KEY]?.trim();
121
+ return value ? decodeGenerationPolicy(value) : null;
122
+ }
123
+ function getAllowedGenerationModelIds(policy) {
124
+ if (!policy || policy.mode === "auto") return null;
125
+ return [...new Set((policy.models ?? []).map((item) => item.model))];
126
+ }
127
+ function findGenerationModelPolicy(policy, model) {
128
+ if (!policy || policy.mode === "auto") return null;
129
+ return policy.models?.find((item) => item.model === model) ?? null;
130
+ }
131
+ function formatList(values) {
132
+ return values.map((value) => `- ${String(value)}`).join("\n");
133
+ }
134
+ function modelNotSupportedMessage(allowedModels) {
135
+ return [
136
+ "This turn supports the following generation models:",
137
+ "",
138
+ formatList(allowedModels),
139
+ "",
140
+ "Choose one of these models or update Generation settings in the Models panel."
141
+ ].join("\n");
142
+ }
143
+ function valuesNotSupportedMessage(model, name, values, received) {
144
+ return [
145
+ `This turn supports selected values for ${model}.${name}:`,
146
+ "",
147
+ formatList(values),
148
+ "",
149
+ "Received:",
150
+ `- ${String(received)}`
151
+ ].join("\n");
152
+ }
153
+ function rangeNotSupportedMessage(model, name, min, max, received) {
154
+ return [
155
+ `This turn supports ${model}.${name} in the range ${min !== void 0 && max !== void 0 ? `${min}–${max}` : min !== void 0 ? `at least ${min}` : `at most ${max}`}.`,
156
+ "",
157
+ "Received:",
158
+ `- ${String(received)}`
159
+ ].join("\n");
160
+ }
161
+ function booleanNotSupportedMessage(model, name, expected, received) {
162
+ return [
163
+ `This turn supports ${model}.${name}=${String(expected)}.`,
164
+ "",
165
+ "Received:",
166
+ `- ${String(received)}`
167
+ ].join("\n");
168
+ }
169
+ function sameEnumValue(a, b) {
170
+ return typeof a === typeof b && a === b;
171
+ }
172
+ function validateConstraint(input) {
173
+ const { model, name, value, constraint } = input;
174
+ if (constraint.kind === "enum") {
175
+ if (!constraint.values.some((item) => sameEnumValue(item, value))) throw new GenerationPolicyError(valuesNotSupportedMessage(model, name, constraint.values, value));
176
+ return;
177
+ }
178
+ if (constraint.kind === "number" || constraint.kind === "integer") {
179
+ if (typeof value !== "number" || !Number.isFinite(value)) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
180
+ if (constraint.kind === "integer" && !Number.isInteger(value)) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
181
+ if (constraint.values?.length && !constraint.values.includes(value)) throw new GenerationPolicyError(valuesNotSupportedMessage(model, name, constraint.values, value));
182
+ if (constraint.min !== void 0 && value < constraint.min) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
183
+ if (constraint.max !== void 0 && value > constraint.max) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
184
+ return;
185
+ }
186
+ if (constraint.kind === "boolean" && constraint.value !== void 0 && value !== constraint.value) throw new GenerationPolicyError(booleanNotSupportedMessage(model, name, constraint.value, value));
187
+ }
188
+ function assertGenerationRequestAllowedByPolicy(input) {
189
+ const allowedModels = getAllowedGenerationModelIds(input.policy);
190
+ if (!allowedModels) return;
191
+ const modelPolicy = findGenerationModelPolicy(input.policy, input.model);
192
+ if (!modelPolicy) throw new GenerationPolicyError(modelNotSupportedMessage(allowedModels));
193
+ const parameters = input.parameters ?? {};
194
+ for (const [name, value] of Object.entries(parameters)) {
195
+ const constraint = modelPolicy.parameters?.[name];
196
+ if (!constraint) continue;
197
+ validateConstraint({
198
+ model: input.model,
199
+ name,
200
+ value,
201
+ constraint
202
+ });
203
+ }
204
+ }
205
+ function cloneDeclaration(declaration) {
206
+ return {
207
+ ...declaration,
208
+ content: {
209
+ ...declaration.content,
210
+ input: [...declaration.content.input]
211
+ },
212
+ parameters: declaration.parameters ? Object.fromEntries(Object.entries(declaration.parameters).map(([key, value]) => [key, { ...value }])) : declaration.parameters,
213
+ examples: declaration.examples ? [...declaration.examples] : declaration.examples
214
+ };
215
+ }
216
+ function narrowParameterSpec(spec, constraint) {
217
+ const next = { ...spec };
218
+ if (constraint.kind === "enum") {
219
+ if ("enum" in next && Array.isArray(next.enum)) next.enum = next.enum.filter((value) => constraint.values.some((allowed) => sameEnumValue(allowed, value)));
220
+ return next;
221
+ }
222
+ if (constraint.kind === "number" || constraint.kind === "integer") {
223
+ if ("min" in next && typeof next.min === "number" && constraint.min !== void 0) next.min = Math.max(next.min, constraint.min);
224
+ else if ("min" in next && constraint.min !== void 0) next.min = constraint.min;
225
+ if ("max" in next && typeof next.max === "number" && constraint.max !== void 0) next.max = Math.min(next.max, constraint.max);
226
+ else if ("max" in next && constraint.max !== void 0) next.max = constraint.max;
227
+ if (constraint.values?.length && "enum" in next && Array.isArray(next.enum)) next.enum = next.enum.filter((value) => constraint.values?.some((allowed) => sameEnumValue(allowed, value)));
228
+ }
229
+ return next;
230
+ }
231
+ function filterGenerationDeclarationsByPolicy(declarations, policy) {
232
+ const allowedModels = getAllowedGenerationModelIds(policy);
233
+ if (!allowedModels) return declarations;
234
+ const allowedSet = new Set(allowedModels);
235
+ return declarations.filter((declaration) => allowedSet.has(declaration.model)).map((declaration) => {
236
+ const cloned = cloneDeclaration(declaration);
237
+ const modelPolicy = findGenerationModelPolicy(policy, declaration.model);
238
+ if (!modelPolicy?.parameters || !cloned.parameters) return cloned;
239
+ for (const [name, constraint] of Object.entries(modelPolicy.parameters)) {
240
+ const spec = cloned.parameters[name];
241
+ if (spec) cloned.parameters[name] = narrowParameterSpec(spec, constraint);
242
+ }
243
+ return cloned;
244
+ });
245
+ }
246
+ //#endregion
7
247
  //#region src/apis/billing.ts
8
248
  var BillingApi = class {
9
249
  transport;
@@ -35,6 +275,12 @@ var BillingApi = class {
35
275
  const query = params.toString();
36
276
  return this.transport.request(`/api/billing/subscriptions${query ? `?${query}` : ""}`);
37
277
  }
278
+ async previewPromotionCode(input) {
279
+ return this.transport.request("/api/billing/promotion-code-preview", {
280
+ method: "POST",
281
+ body: JSON.stringify(input)
282
+ });
283
+ }
38
284
  async createOrder(productKey, input) {
39
285
  return this.transport.request("/api/billing/orders", {
40
286
  method: "POST",
@@ -70,130 +316,14 @@ var BillingApi = class {
70
316
  }
71
317
  };
72
318
  //#endregion
73
- //#region ../protocol/dist/realtime/board-awareness.js
74
- const idSchema$1 = z.string().min(1).max(160);
75
- const finiteSchema$1 = z.number().finite();
76
- const BoardAwarenessPointSchema = z.object({
77
- x: finiteSchema$1,
78
- y: finiteSchema$1
79
- });
80
- const BoardAwarenessDrawPointSchema = BoardAwarenessPointSchema.extend({ p: finiteSchema$1.min(0).max(1) });
81
- const BoardAwarenessFrameSchema = z.object({
82
- x: finiteSchema$1,
83
- y: finiteSchema$1,
84
- width: finiteSchema$1.positive(),
85
- height: finiteSchema$1.positive(),
86
- rotation: finiteSchema$1
87
- });
88
- const BoardAwarenessNodePreviewSchema = z.object({
89
- nodeId: idSchema$1,
90
- frame: BoardAwarenessFrameSchema,
91
- /** Live endpoints of a free arrow being dragged. */
92
- arrow: z.object({
93
- start: BoardAwarenessPointSchema,
94
- end: BoardAwarenessPointSchema,
95
- bend: finiteSchema$1
96
- }).optional()
97
- });
98
- const BoardAwarenessStateUpdateSchema = z.object({
99
- type: z.literal("state"),
100
- client: z.object({ formFactor: z.enum(["desktop", "mobile"]) }).optional(),
101
- cursor: BoardAwarenessPointSchema.extend({ pointerType: z.enum([
102
- "mouse",
103
- "pen",
104
- "touch"
105
- ]) }).nullable(),
106
- tool: z.string().min(1).max(40),
107
- selection: z.object({
108
- ids: z.array(idSchema$1).max(64),
109
- count: z.number().int().nonnegative().max(5e4),
110
- bounds: BoardAwarenessFrameSchema.nullable()
111
- }),
112
- editingId: idSchema$1.nullable()
113
- });
114
- const BoardAwarenessGestureSchema = z.discriminatedUnion("kind", [
319
+ //#region ../protocol/dist/realtime/schema.js
320
+ const contentBlockMetaSchema = z.record(z.string(), z.unknown());
321
+ const realtimeRoomSchema = z.string().regex(/^(space|user|board|room):[^:]+$/);
322
+ const contentBlockSchema = z.discriminatedUnion("type", [
115
323
  z.object({
116
- kind: z.literal("draw"),
117
- id: idSchema$1,
118
- nodeId: idSchema$1,
119
- color: z.string().min(1).max(64),
120
- size: finiteSchema$1.positive().max(256),
121
- from: z.number().int().nonnegative().max(1e5),
122
- points: z.array(BoardAwarenessDrawPointSchema).min(1).max(64)
123
- }),
124
- z.object({
125
- kind: z.literal("arrow"),
126
- id: idSchema$1,
127
- nodeId: idSchema$1,
128
- start: BoardAwarenessPointSchema,
129
- current: BoardAwarenessPointSchema,
130
- color: z.string().min(1).max(64),
131
- size: finiteSchema$1.positive().max(256).default(BOARD_ARROW_STROKE_SIZE)
132
- }),
133
- z.object({
134
- kind: z.literal("box"),
135
- id: idSchema$1,
136
- nodeId: idSchema$1,
137
- shape: z.enum(["geo", "frame"]),
138
- start: BoardAwarenessPointSchema,
139
- current: BoardAwarenessPointSchema,
140
- color: z.string().min(1).max(64),
141
- geo: z.string().min(1).max(40)
142
- }),
143
- z.object({
144
- kind: z.literal("connection"),
145
- id: idSchema$1,
146
- sourceNodeId: idSchema$1,
147
- targetNodeId: idSchema$1.nullable(),
148
- current: BoardAwarenessPointSchema,
149
- color: z.string().min(1).max(64),
150
- size: finiteSchema$1.positive().max(256).default(BOARD_CONNECTION_STROKE_SIZE)
151
- }),
152
- z.object({
153
- kind: z.literal("transform"),
154
- id: idSchema$1,
155
- mode: z.enum([
156
- "translate",
157
- "resize",
158
- "rotate",
159
- "arrow",
160
- "connection"
161
- ]),
162
- nodes: z.array(BoardAwarenessNodePreviewSchema).max(64),
163
- bounds: BoardAwarenessFrameSchema.nullable()
164
- })
165
- ]);
166
- const BoardAwarenessUpdateSchema = z.discriminatedUnion("type", [
167
- BoardAwarenessStateUpdateSchema,
168
- z.object({
169
- type: z.literal("gesture"),
170
- gesture: BoardAwarenessGestureSchema
171
- }),
172
- z.object({
173
- type: z.literal("gesture.end"),
174
- gestureId: idSchema$1,
175
- resultingNodeIds: z.array(idSchema$1).max(64)
176
- }),
177
- z.object({
178
- type: z.literal("gesture.cancel"),
179
- gestureId: idSchema$1
180
- })
181
- ]);
182
- const BoardAwarenessClientPayloadSchema = z.object({
183
- spaceId: z.string().uuid(),
184
- boardId: z.string().uuid(),
185
- seq: z.number().int().nonnegative(),
186
- update: BoardAwarenessUpdateSchema
187
- });
188
- //#endregion
189
- //#region ../protocol/dist/realtime/schema.js
190
- const contentBlockMetaSchema = z.record(z.string(), z.unknown());
191
- const realtimeRoomSchema = z.string().regex(/^(space|user|board|room):[^:]+$/);
192
- const contentBlockSchema = z.discriminatedUnion("type", [
193
- z.object({
194
- type: z.literal("text"),
195
- text: z.string(),
196
- _meta: contentBlockMetaSchema.optional()
324
+ type: z.literal("text"),
325
+ text: z.string(),
326
+ _meta: contentBlockMetaSchema.optional()
197
327
  }),
198
328
  z.object({
199
329
  type: z.literal("thinking"),
@@ -796,130 +926,16 @@ var WorkRealtimeApi = class {
796
926
  }
797
927
  };
798
928
  //#endregion
799
- //#region ../protocol/dist/work-surface.js
800
- const WORK_SURFACE_PROTOCOL = "cohub.surface";
801
- const WORK_SURFACE_READY_TIMEOUT_MS = 1e4;
802
- const WORK_SURFACE_REQUEST_TIMEOUT_MS = 15e3;
803
- const WORK_COMPOSER_CHIP_KEY_MAX_LENGTH = 80;
804
- const WORK_COMPOSER_CHIP_LABEL_MAX_LENGTH = 120;
805
- const WORK_COMPOSER_CHIP_CONTENT_MAX_BYTES = 32 * 1024;
806
- const isRecord$1 = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
807
- const isSurfaceEnvelope = (value) => isRecord$1(value) && value.protocol === "cohub.surface" && value.version === 1;
808
- const parseWorkSurfaceReady = (value) => {
809
- if (!isSurfaceEnvelope(value) || value.type !== "ready") return null;
810
- const methods = Array.isArray(value.methods) ? value.methods.filter((method) => typeof method === "string" && Boolean(method)) : [];
811
- return {
812
- protocol: WORK_SURFACE_PROTOCOL,
813
- version: 1,
814
- type: "ready",
815
- methods
816
- };
817
- };
818
- const parseWorkSurfaceResponse = (value) => {
819
- if (!isSurfaceEnvelope(value) || value.type !== "response") return null;
820
- if (typeof value.requestId !== "string" || !value.requestId) return null;
821
- const error = isRecord$1(value.error) ? {
822
- code: typeof value.error.code === "string" && value.error.code ? value.error.code : "surface_error",
823
- message: typeof value.error.message === "string" ? value.error.message : "Work surface call failed"
824
- } : void 0;
825
- return {
826
- protocol: WORK_SURFACE_PROTOCOL,
827
- version: 1,
828
- type: "response",
829
- requestId: value.requestId,
830
- ok: value.ok === true,
831
- ...error ? { error } : {}
832
- };
833
- };
834
- const parseComposerChipKey = (value) => {
835
- if (typeof value !== "string") return null;
836
- const key = value.trim();
837
- if (!key || key.length > 80) return null;
838
- return key;
839
- };
840
- const parseWorkComposerChipSet = (value) => {
841
- if (!isSurfaceEnvelope(value) || value.type !== "composer.chip.set" || !isRecord$1(value.chip)) return null;
842
- const key = parseComposerChipKey(value.chip.key);
843
- if (!key || typeof value.chip.label !== "string" || typeof value.chip.content !== "string") return null;
844
- const label = value.chip.label.trim();
845
- if (!label || label.length > 120) return null;
846
- if (!value.chip.content.trim()) return null;
847
- if (new TextEncoder().encode(value.chip.content).length > 32768) return null;
848
- return {
849
- protocol: WORK_SURFACE_PROTOCOL,
850
- version: 1,
851
- type: "composer.chip.set",
852
- chip: {
853
- key,
854
- label,
855
- content: value.chip.content
856
- }
857
- };
858
- };
859
- const parseWorkComposerChipClear = (value) => {
860
- if (!isSurfaceEnvelope(value) || value.type !== "composer.chip.clear") return null;
861
- const key = parseComposerChipKey(value.key);
862
- return key ? {
863
- protocol: WORK_SURFACE_PROTOCOL,
864
- version: 1,
865
- type: "composer.chip.clear",
866
- key
867
- } : null;
868
- };
869
- const parseWorkSurfaceRequest = (value) => {
870
- if (!isSurfaceEnvelope(value) || value.type !== "request") return null;
871
- if (typeof value.requestId !== "string" || !value.requestId) return null;
872
- if (typeof value.method !== "string" || !value.method) return null;
873
- const commandId = parseUiCommandId(value.commandId);
874
- if (!commandId) return null;
875
- return {
876
- protocol: WORK_SURFACE_PROTOCOL,
877
- version: 1,
878
- type: "request",
879
- requestId: value.requestId,
880
- method: value.method,
881
- ...value.input === void 0 ? {} : { input: value.input },
882
- commandId
883
- };
884
- };
885
- const buildWorkSurfaceReady = (methods) => ({
886
- protocol: WORK_SURFACE_PROTOCOL,
887
- version: 1,
888
- type: "ready",
889
- methods: [...methods]
890
- });
891
- const buildWorkSurfaceRequest = (input) => ({
892
- protocol: WORK_SURFACE_PROTOCOL,
893
- version: 1,
894
- type: "request",
895
- ...input
896
- });
897
- const buildWorkSurfaceResponse = (input) => ({
898
- protocol: WORK_SURFACE_PROTOCOL,
899
- version: 1,
900
- type: "response",
901
- ...input
902
- });
903
- const buildWorkComposerChipSet = (chip) => ({
904
- protocol: WORK_SURFACE_PROTOCOL,
905
- version: 1,
906
- type: "composer.chip.set",
907
- chip
908
- });
909
- const buildWorkComposerChipClear = (key) => ({
910
- protocol: WORK_SURFACE_PROTOCOL,
911
- version: 1,
912
- type: "composer.chip.clear",
913
- key
914
- });
915
- //#endregion
916
929
  //#region src/work-surface.ts
917
930
  /**
918
- * Explicit app origins, not a `*.cohub.run` suffix match: Works themselves are
931
+ * Explicit app origins, not a Cohub suffix match: Works themselves are
919
932
  * served from Cohub subdomains, so a suffix match would let one Work call into
920
933
  * another and turn a subdomain takeover into surface access.
921
934
  */
922
935
  const COHUB_APP_ORIGINS = [
936
+ "https://cohub.live",
937
+ "https://www.cohub.live",
938
+ "https://dev.cohub.live",
923
939
  "https://cohub.run",
924
940
  "https://www.cohub.run",
925
941
  "https://dev.cohub.run"
@@ -1607,66 +1623,8 @@ var CohubClient = class {
1607
1623
  };
1608
1624
  const createCohubClient = (options) => new CohubClient(options);
1609
1625
  //#endregion
1610
- //#region ../protocol/dist/public-identifiers.js
1611
- const USERNAME_PATTERN = /^(?!-)(?!.*--)[a-z0-9-]{1,39}(?<!-)$/;
1612
- const SPACE_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9_-]{0,78}[a-z0-9])?$/;
1613
- /**
1614
- * Platform-owned path segments that must not be newly assigned to public
1615
- * identities. Existing stored values remain readable through parse helpers.
1616
- */
1617
- const RESERVED_PLATFORM_PATH_SEGMENTS = Object.freeze([
1618
- "admin",
1619
- "api",
1620
- "assets",
1621
- "auth",
1622
- "callback",
1623
- "changelog",
1624
- "docs",
1625
- "explore",
1626
- "invite",
1627
- "landing",
1628
- "login",
1629
- "logout",
1630
- "new",
1631
- "org",
1632
- "pricing",
1633
- "pwa",
1634
- "referrals",
1635
- "sessions",
1636
- "settings",
1637
- "spaces",
1638
- "static",
1639
- "teams",
1640
- "trending",
1641
- "u",
1642
- "user",
1643
- "users",
1644
- "work-auth"
1645
- ]);
1646
- new Set(RESERVED_PLATFORM_PATH_SEGMENTS);
1647
- [...RESERVED_PLATFORM_PATH_SEGMENTS];
1648
- function parseUsername(value) {
1649
- if (value === null || value === void 0) return null;
1650
- const normalized = value.trim().toLowerCase();
1651
- return USERNAME_PATTERN.test(normalized) ? normalized : null;
1652
- }
1653
- function parseSpaceSlug(value) {
1654
- if (value === null || value === void 0) return null;
1655
- const normalized = value.trim();
1656
- return SPACE_SLUG_PATTERN.test(normalized) ? normalized : null;
1657
- }
1658
- //#endregion
1659
1626
  //#region src/work-ref.ts
1660
- /**
1661
- * Accepts every way a Work is named across Cohub — id, management URL, public
1662
- * URL, `cohub://works` URI, or `username/space/work` — and normalizes it.
1663
- *
1664
- * Public and mention forms may carry launch state (`?query#hash`); it is kept
1665
- * separately so it can be forwarded to the Work while the stable identity stays
1666
- * clean.
1667
- */
1668
- const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
1669
- const isWorkId = (value) => UUID_PATTERN.test(value.trim());
1627
+ const isWorkId = (value) => isUuid(value.trim());
1670
1628
  function decodePart(value) {
1671
1629
  try {
1672
1630
  return decodeURIComponent(value).trim();
@@ -1708,7 +1666,7 @@ function parseUrlRef(value) {
1708
1666
  } : null;
1709
1667
  }
1710
1668
  if (url.protocol !== "http:" && url.protocol !== "https:") return null;
1711
- if (parts.length === 4 && parts[0] === "spaces" && UUID_PATTERN.test(parts[1] ?? "") && parts[2] === "works" && UUID_PATTERN.test(parts[3] ?? "")) return { id: parts[3] };
1669
+ if (parts.length === 4 && parts[0] === "spaces" && isUuid(parts[1] ?? "") && parts[2] === "works" && isUuid(parts[3] ?? "")) return { id: parts[3] };
1712
1670
  if (parts.length === 4 && parts[2] === "w") {
1713
1671
  const ref = publicRef([
1714
1672
  parts[0],
@@ -1730,7 +1688,7 @@ var WorkRefParseError = class extends Error {
1730
1688
  };
1731
1689
  function parseWorkRef(input) {
1732
1690
  const value = input.trim();
1733
- if (UUID_PATTERN.test(value)) return { id: value };
1691
+ if (isUuid(value)) return { id: value };
1734
1692
  const parsedUrl = parseUrlRef(value.includes("://") ? value : value.startsWith("/") ? `https://cohub.invalid${value}` : value);
1735
1693
  if (parsedUrl) return parsedUrl;
1736
1694
  const parts = value.split("/").filter(Boolean);
@@ -1954,6 +1912,7 @@ function createWorkBridgeCore(config) {
1954
1912
  await config.requestSignIn(typeof location !== "undefined" ? location.pathname + location.search + location.hash : "/");
1955
1913
  return null;
1956
1914
  }
1915
+ const promotionAttribution = config.getPromotionAttribution?.() ?? null;
1957
1916
  const response = await fetch(`${apiOrigin}/api/works/${work.id}/commerce/purchase`, {
1958
1917
  method: "POST",
1959
1918
  headers: {
@@ -1962,7 +1921,8 @@ function createWorkBridgeCore(config) {
1962
1921
  },
1963
1922
  body: JSON.stringify({
1964
1923
  productKey,
1965
- purchaseAttemptId
1924
+ purchaseAttemptId,
1925
+ ...promotionAttribution ? { promotionAttribution } : {}
1966
1926
  })
1967
1927
  });
1968
1928
  if (!response.ok) throw new Error((await response.json().catch(() => null))?.message ?? "Purchase failed.");
@@ -2034,6 +1994,7 @@ function createWorkBridgeCore(config) {
2034
1994
  state.purchaseError = null;
2035
1995
  state.purchaseOpen = true;
2036
1996
  notify();
1997
+ config.onPurchaseRequested?.({ ...state.pendingPurchase });
2037
1998
  }
2038
1999
  if (data.type === "cohub.work.authorize") {
2039
2000
  const allowedViewerScopes = clonePermissionScopes(work.allowedViewerScopes);
@@ -2124,7 +2085,14 @@ function createWorkBridgeCore(config) {
2124
2085
  productKey: next.productKey
2125
2086
  });
2126
2087
  const url = next.checkoutUrl;
2127
- if (next.checkoutUsable === true && typeof url === "string" && url) window.location.href = url;
2088
+ if (next.checkoutUsable === true && typeof url === "string" && url) {
2089
+ config.onCheckoutStarted?.({
2090
+ ...state.pendingPurchase,
2091
+ ...typeof next.value === "number" ? { value: next.value } : {},
2092
+ ...typeof next.currency === "string" ? { currency: next.currency } : {}
2093
+ });
2094
+ window.location.href = url;
2095
+ }
2128
2096
  }
2129
2097
  state.purchaseOpen = false;
2130
2098
  state.pendingPurchase = null;
@@ -2166,440 +2134,6 @@ function createWorkBridgeCore(config) {
2166
2134
  };
2167
2135
  }
2168
2136
  //#endregion
2169
- //#region ../protocol/dist/generation/catalog.js
2170
- function isGenerationModelHidden(model) {
2171
- return model.hidden === true;
2172
- }
2173
- function filterDiscoverableGenerationModels(models, options = {}) {
2174
- const includeModelIds = new Set(options.includeModelIds);
2175
- return models.filter((model) => !isGenerationModelHidden(model) || includeModelIds.has(model.model));
2176
- }
2177
- //#endregion
2178
- //#region ../protocol/dist/generation/policy.js
2179
- const GENERATION_POLICY_ENV_KEY = "COHUB_GENERATION_POLICY_B64";
2180
- var GenerationPolicyError = class extends Error {
2181
- constructor(message) {
2182
- super(message);
2183
- this.name = "GenerationPolicyError";
2184
- }
2185
- };
2186
- function isRecord(value) {
2187
- return !!value && typeof value === "object" && !Array.isArray(value);
2188
- }
2189
- function isPrimitiveEnumValue(value) {
2190
- return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
2191
- }
2192
- function normalizeConstraint(value) {
2193
- if (!isRecord(value) || typeof value.kind !== "string") return null;
2194
- if (value.kind === "enum") {
2195
- if (!Array.isArray(value.values) || value.values.length === 0 || !value.values.every(isPrimitiveEnumValue)) return null;
2196
- return {
2197
- kind: "enum",
2198
- values: value.values
2199
- };
2200
- }
2201
- if (value.kind === "number" || value.kind === "integer") {
2202
- const result = { kind: value.kind };
2203
- if (typeof value.min === "number" && Number.isFinite(value.min)) result.min = value.min;
2204
- if (typeof value.max === "number" && Number.isFinite(value.max)) result.max = value.max;
2205
- if (result.min !== void 0 && result.max !== void 0 && result.min > result.max) return null;
2206
- if (Array.isArray(value.values) && value.values.every((item) => typeof item === "number" && Number.isFinite(item))) {
2207
- if (value.kind === "integer" && !value.values.every(Number.isInteger)) return null;
2208
- const min = result.min;
2209
- const max = result.max;
2210
- if (min !== void 0 && value.values.some((item) => item < min)) return null;
2211
- if (max !== void 0 && value.values.some((item) => item > max)) return null;
2212
- result.values = value.values;
2213
- }
2214
- return result;
2215
- }
2216
- if (value.kind === "boolean") return typeof value.value === "boolean" ? {
2217
- kind: "boolean",
2218
- value: value.value
2219
- } : { kind: "boolean" };
2220
- return null;
2221
- }
2222
- function normalizeGenerationPolicy(value) {
2223
- if (!isRecord(value) || value.version !== 1) return null;
2224
- if (value.mode === "auto") return {
2225
- version: 1,
2226
- mode: "auto"
2227
- };
2228
- if (value.mode !== "limited" || !Array.isArray(value.models) || value.models.length === 0) return null;
2229
- const models = [];
2230
- for (const item of value.models) {
2231
- if (!isRecord(item) || typeof item.model !== "string" || !item.model.trim()) return null;
2232
- const modelPolicy = { model: item.model.trim() };
2233
- if (item.parameters !== void 0) {
2234
- if (!isRecord(item.parameters)) return null;
2235
- const parameters = {};
2236
- for (const [key, rawConstraint] of Object.entries(item.parameters)) {
2237
- if (!key.trim()) return null;
2238
- const constraint = normalizeConstraint(rawConstraint);
2239
- if (!constraint) return null;
2240
- parameters[key] = constraint;
2241
- }
2242
- if (Object.keys(parameters).length > 0) modelPolicy.parameters = parameters;
2243
- }
2244
- models.push(modelPolicy);
2245
- }
2246
- return {
2247
- version: 1,
2248
- mode: "limited",
2249
- models
2250
- };
2251
- }
2252
- function bytesToBase64(bytes) {
2253
- let binary = "";
2254
- for (const byte of bytes) binary += String.fromCharCode(byte);
2255
- return btoa(binary);
2256
- }
2257
- function base64ToBytes(value) {
2258
- const binary = atob(value);
2259
- const bytes = new Uint8Array(binary.length);
2260
- for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
2261
- return bytes;
2262
- }
2263
- function toBase64Url(value) {
2264
- return bytesToBase64(new TextEncoder().encode(value)).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
2265
- }
2266
- function fromBase64Url(value) {
2267
- const base64 = value.replaceAll("-", "+").replaceAll("_", "/");
2268
- const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
2269
- return new TextDecoder().decode(base64ToBytes(padded));
2270
- }
2271
- function encodeGenerationPolicy(policy) {
2272
- return toBase64Url(JSON.stringify(policy));
2273
- }
2274
- function decodeGenerationPolicy(value) {
2275
- try {
2276
- return normalizeGenerationPolicy(JSON.parse(fromBase64Url(value)));
2277
- } catch {
2278
- return null;
2279
- }
2280
- }
2281
- function parseGenerationPolicyFromEnv(env) {
2282
- const value = env[GENERATION_POLICY_ENV_KEY]?.trim();
2283
- return value ? decodeGenerationPolicy(value) : null;
2284
- }
2285
- function getAllowedGenerationModelIds(policy) {
2286
- if (!policy || policy.mode === "auto") return null;
2287
- return [...new Set((policy.models ?? []).map((item) => item.model))];
2288
- }
2289
- function findGenerationModelPolicy(policy, model) {
2290
- if (!policy || policy.mode === "auto") return null;
2291
- return policy.models?.find((item) => item.model === model) ?? null;
2292
- }
2293
- function formatList(values) {
2294
- return values.map((value) => `- ${String(value)}`).join("\n");
2295
- }
2296
- function modelNotSupportedMessage(allowedModels) {
2297
- return [
2298
- "This turn supports the following generation models:",
2299
- "",
2300
- formatList(allowedModels),
2301
- "",
2302
- "Choose one of these models or update Generation settings in the Models panel."
2303
- ].join("\n");
2304
- }
2305
- function valuesNotSupportedMessage(model, name, values, received) {
2306
- return [
2307
- `This turn supports selected values for ${model}.${name}:`,
2308
- "",
2309
- formatList(values),
2310
- "",
2311
- "Received:",
2312
- `- ${String(received)}`
2313
- ].join("\n");
2314
- }
2315
- function rangeNotSupportedMessage(model, name, min, max, received) {
2316
- return [
2317
- `This turn supports ${model}.${name} in the range ${min !== void 0 && max !== void 0 ? `${min}–${max}` : min !== void 0 ? `at least ${min}` : `at most ${max}`}.`,
2318
- "",
2319
- "Received:",
2320
- `- ${String(received)}`
2321
- ].join("\n");
2322
- }
2323
- function booleanNotSupportedMessage(model, name, expected, received) {
2324
- return [
2325
- `This turn supports ${model}.${name}=${String(expected)}.`,
2326
- "",
2327
- "Received:",
2328
- `- ${String(received)}`
2329
- ].join("\n");
2330
- }
2331
- function sameEnumValue(a, b) {
2332
- return typeof a === typeof b && a === b;
2333
- }
2334
- function validateConstraint(input) {
2335
- const { model, name, value, constraint } = input;
2336
- if (constraint.kind === "enum") {
2337
- if (!constraint.values.some((item) => sameEnumValue(item, value))) throw new GenerationPolicyError(valuesNotSupportedMessage(model, name, constraint.values, value));
2338
- return;
2339
- }
2340
- if (constraint.kind === "number" || constraint.kind === "integer") {
2341
- if (typeof value !== "number" || !Number.isFinite(value)) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
2342
- if (constraint.kind === "integer" && !Number.isInteger(value)) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
2343
- if (constraint.values?.length && !constraint.values.includes(value)) throw new GenerationPolicyError(valuesNotSupportedMessage(model, name, constraint.values, value));
2344
- if (constraint.min !== void 0 && value < constraint.min) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
2345
- if (constraint.max !== void 0 && value > constraint.max) throw new GenerationPolicyError(rangeNotSupportedMessage(model, name, constraint.min, constraint.max, value));
2346
- return;
2347
- }
2348
- if (constraint.kind === "boolean" && constraint.value !== void 0 && value !== constraint.value) throw new GenerationPolicyError(booleanNotSupportedMessage(model, name, constraint.value, value));
2349
- }
2350
- function assertGenerationRequestAllowedByPolicy(input) {
2351
- const allowedModels = getAllowedGenerationModelIds(input.policy);
2352
- if (!allowedModels) return;
2353
- const modelPolicy = findGenerationModelPolicy(input.policy, input.model);
2354
- if (!modelPolicy) throw new GenerationPolicyError(modelNotSupportedMessage(allowedModels));
2355
- const parameters = input.parameters ?? {};
2356
- for (const [name, value] of Object.entries(parameters)) {
2357
- const constraint = modelPolicy.parameters?.[name];
2358
- if (!constraint) continue;
2359
- validateConstraint({
2360
- model: input.model,
2361
- name,
2362
- value,
2363
- constraint
2364
- });
2365
- }
2366
- }
2367
- function cloneDeclaration(declaration) {
2368
- return {
2369
- ...declaration,
2370
- content: {
2371
- ...declaration.content,
2372
- input: [...declaration.content.input]
2373
- },
2374
- parameters: declaration.parameters ? Object.fromEntries(Object.entries(declaration.parameters).map(([key, value]) => [key, { ...value }])) : declaration.parameters,
2375
- examples: declaration.examples ? [...declaration.examples] : declaration.examples
2376
- };
2377
- }
2378
- function narrowParameterSpec(spec, constraint) {
2379
- const next = { ...spec };
2380
- if (constraint.kind === "enum") {
2381
- if ("enum" in next && Array.isArray(next.enum)) next.enum = next.enum.filter((value) => constraint.values.some((allowed) => sameEnumValue(allowed, value)));
2382
- return next;
2383
- }
2384
- if (constraint.kind === "number" || constraint.kind === "integer") {
2385
- if ("min" in next && typeof next.min === "number" && constraint.min !== void 0) next.min = Math.max(next.min, constraint.min);
2386
- else if ("min" in next && constraint.min !== void 0) next.min = constraint.min;
2387
- if ("max" in next && typeof next.max === "number" && constraint.max !== void 0) next.max = Math.min(next.max, constraint.max);
2388
- else if ("max" in next && constraint.max !== void 0) next.max = constraint.max;
2389
- if (constraint.values?.length && "enum" in next && Array.isArray(next.enum)) next.enum = next.enum.filter((value) => constraint.values?.some((allowed) => sameEnumValue(allowed, value)));
2390
- }
2391
- return next;
2392
- }
2393
- function filterGenerationDeclarationsByPolicy(declarations, policy) {
2394
- const allowedModels = getAllowedGenerationModelIds(policy);
2395
- if (!allowedModels) return declarations;
2396
- const allowedSet = new Set(allowedModels);
2397
- return declarations.filter((declaration) => allowedSet.has(declaration.model)).map((declaration) => {
2398
- const cloned = cloneDeclaration(declaration);
2399
- const modelPolicy = findGenerationModelPolicy(policy, declaration.model);
2400
- if (!modelPolicy?.parameters || !cloned.parameters) return cloned;
2401
- for (const [name, constraint] of Object.entries(modelPolicy.parameters)) {
2402
- const spec = cloned.parameters[name];
2403
- if (spec) cloned.parameters[name] = narrowParameterSpec(spec, constraint);
2404
- }
2405
- return cloned;
2406
- });
2407
- }
2408
- //#endregion
2409
- //#region ../protocol/dist/board.js
2410
- const BOARD_MANIFEST_KIND = "cohub.board.manifest";
2411
- const idSchema = z.string().min(1).max(160);
2412
- const extensionIdSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
2413
- const jsonObjectSchema = z.record(z.string(), z.unknown());
2414
- const finiteSchema = z.number().finite();
2415
- z.object({
2416
- kind: z.literal(BOARD_MANIFEST_KIND),
2417
- version: z.literal(1),
2418
- boardId: z.string().uuid(),
2419
- title: z.string().min(1).max(255)
2420
- });
2421
- const BoardTargetSchema = z.discriminatedUnion("type", [
2422
- z.object({
2423
- type: z.literal("node"),
2424
- nodeId: idSchema
2425
- }),
2426
- z.object({
2427
- type: z.literal("effect"),
2428
- effectId: idSchema
2429
- }),
2430
- z.object({ type: z.literal("board") }),
2431
- z.object({ type: z.literal("camera") })
2432
- ]);
2433
- const BoardAssetRefSchema = z.object({
2434
- type: z.enum(["space-file", "extension"]),
2435
- ref: z.string().min(1).max(4096),
2436
- digest: z.string().min(16).max(160).optional()
2437
- });
2438
- const BoardKeyframeSchema = z.object({
2439
- at: finiteSchema.nonnegative(),
2440
- value: z.unknown(),
2441
- easing: z.string().min(1).max(80).optional()
2442
- });
2443
- const BoardClipSchema = z.object({
2444
- id: idSchema,
2445
- sequenceId: idSchema,
2446
- kind: extensionIdSchema,
2447
- kindVersion: z.number().int().positive(),
2448
- target: BoardTargetSchema,
2449
- start: finiteSchema.nonnegative(),
2450
- duration: finiteSchema.positive(),
2451
- layer: z.enum([
2452
- "behind",
2453
- "content",
2454
- "front",
2455
- "screen"
2456
- ]).default("content"),
2457
- fill: z.enum([
2458
- "none",
2459
- "backwards",
2460
- "forwards",
2461
- "both"
2462
- ]).default("none"),
2463
- easing: z.string().min(1).max(80).default("linear"),
2464
- params: jsonObjectSchema.default({}),
2465
- keyframes: z.array(BoardKeyframeSchema).default([]),
2466
- assetRefs: z.array(BoardAssetRefSchema).default([]),
2467
- seed: z.string().min(1).max(160),
2468
- metadata: jsonObjectSchema.default({})
2469
- });
2470
- const BoardEffectSchema = z.object({
2471
- id: idSchema,
2472
- boardId: z.string().uuid(),
2473
- target: z.discriminatedUnion("type", [z.object({
2474
- type: z.literal("node"),
2475
- nodeId: idSchema
2476
- }), z.object({ type: z.literal("board") })]),
2477
- kind: extensionIdSchema,
2478
- kindVersion: z.number().int().positive(),
2479
- enabled: z.boolean().default(true),
2480
- lifecycle: z.enum([
2481
- "persistent",
2482
- "when-visible",
2483
- "manual"
2484
- ]),
2485
- timeOrigin: z.enum([
2486
- "board",
2487
- "visible",
2488
- "activation"
2489
- ]),
2490
- layer: z.enum([
2491
- "behind",
2492
- "front",
2493
- "screen"
2494
- ]).default("front"),
2495
- seed: z.string().min(1).max(160),
2496
- params: jsonObjectSchema.default({}),
2497
- assetRefs: z.array(BoardAssetRefSchema).default([]),
2498
- metadata: jsonObjectSchema.default({}),
2499
- revision: z.number().int().nonnegative()
2500
- });
2501
- const BoardSequenceSchema = z.object({
2502
- id: idSchema,
2503
- boardId: z.string().uuid(),
2504
- name: z.string().min(1).max(255),
2505
- duration: finiteSchema.nonnegative(),
2506
- seed: z.string().min(1).max(160),
2507
- restPose: jsonObjectSchema.default({}),
2508
- metadata: jsonObjectSchema.default({}),
2509
- revision: z.number().int().nonnegative()
2510
- });
2511
- const BoardNodeInputSchema = z.object({
2512
- nodeId: idSchema,
2513
- type: z.string().min(1).max(40),
2514
- parentId: idSchema.nullable(),
2515
- orderKey: z.string().max(4096).nullable(),
2516
- x: finiteSchema,
2517
- y: finiteSchema,
2518
- width: finiteSchema.positive(),
2519
- height: finiteSchema.positive(),
2520
- rotation: finiteSchema,
2521
- refKind: z.string().max(40).nullable(),
2522
- refPath: z.string().max(4096).nullable(),
2523
- refUrl: z.string().max(4096).nullable(),
2524
- view: jsonObjectSchema,
2525
- style: jsonObjectSchema,
2526
- data: jsonObjectSchema
2527
- });
2528
- z.object({
2529
- path: z.string().min(1),
2530
- /** Reused by clients when board creation is interrupted and retried. */
2531
- mutationId: z.string().max(128).optional(),
2532
- title: z.string().min(1).max(255).optional(),
2533
- metadata: jsonObjectSchema.optional(),
2534
- nodes: z.array(BoardNodeInputSchema).max(5e4).optional(),
2535
- connections: z.array(BoardConnectionSchema).max(5e4).optional(),
2536
- effects: z.array(BoardEffectSchema.omit({
2537
- boardId: true,
2538
- revision: true
2539
- })).optional(),
2540
- sequences: z.array(z.object({
2541
- sequence: BoardSequenceSchema.omit({
2542
- boardId: true,
2543
- revision: true
2544
- }),
2545
- clips: z.array(BoardClipSchema.omit({ sequenceId: true }))
2546
- })).optional()
2547
- });
2548
- z.object({
2549
- include: z.array(z.enum([
2550
- "nodes",
2551
- "connections",
2552
- "effects",
2553
- "sequences",
2554
- "clips",
2555
- "playback"
2556
- ])).optional(),
2557
- viewport: z.object({
2558
- x: finiteSchema,
2559
- y: finiteSchema,
2560
- width: finiteSchema.positive(),
2561
- height: finiteSchema.positive()
2562
- }).optional()
2563
- });
2564
- /** Persisted on `boards.metadata.playback`: how a Board plays when opened. */
2565
- const BoardPlaybackPolicySchema = z.object({
2566
- sequenceId: idSchema,
2567
- /** Delay before the first local playback after opening the Board, in milliseconds. */
2568
- delayMs: finiteSchema.nonnegative().default(0),
2569
- loop: z.boolean().default(false)
2570
- });
2571
- function parseBoardPlaybackPolicy(metadata) {
2572
- const parsed = BoardPlaybackPolicySchema.safeParse(metadata.playback);
2573
- return parsed.success ? parsed.data : null;
2574
- }
2575
- z.discriminatedUnion("type", [
2576
- z.object({
2577
- commandId: idSchema,
2578
- type: z.literal("play"),
2579
- sequenceId: idSchema,
2580
- position: finiteSchema.nonnegative().optional(),
2581
- timeScale: finiteSchema.positive().max(4).optional(),
2582
- shared: z.boolean().optional(),
2583
- seed: idSchema.optional()
2584
- }),
2585
- z.object({
2586
- commandId: idSchema,
2587
- type: z.literal("pause"),
2588
- playbackId: z.string().uuid()
2589
- }),
2590
- z.object({
2591
- commandId: idSchema,
2592
- type: z.literal("seek"),
2593
- playbackId: z.string().uuid(),
2594
- position: finiteSchema.nonnegative()
2595
- }),
2596
- z.object({
2597
- commandId: idSchema,
2598
- type: z.literal("stop"),
2599
- playbackId: z.string().uuid()
2600
- })
2601
- ]);
2602
- //#endregion
2603
2137
  //#region src/board/animation.ts
2604
2138
  const ZERO_COST = {
2605
2139
  particles: 0,
@@ -2951,4 +2485,4 @@ function createBoardExtensionRegistry(input = {}) {
2951
2485
  return registry;
2952
2486
  }
2953
2487
  //#endregion
2954
- 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, UI_COMMAND_DEFAULT_TIMEOUT_MS, UI_COMMAND_MAX_TIMEOUT_MS, UI_COMMAND_PAYLOAD_MAX_BYTES, UI_COMMAND_PENDING_TTL_SECONDS, UI_COMMAND_SETTLEMENT_GRACE_SECONDS, UI_COMMAND_TERMINAL_TTL_SECONDS, UI_COMMAND_VERSION, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WORK_COMPOSER_CHIP_CONTENT_MAX_BYTES, WORK_COMPOSER_CHIP_KEY_MAX_LENGTH, WORK_COMPOSER_CHIP_LABEL_MAX_LENGTH, WORK_SURFACE_READY_TIMEOUT_MS, WORK_SURFACE_REQUEST_TIMEOUT_MS, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkRuntimeApi, WorkSurfaceApi, WorksApi, assertGenerationRequestAllowedByPolicy, buildSpaceInvitePath, buildSpacePath, buildWorkSurfaceRequest, clearGrantedWorkScopes, clip, compileSequence, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, formatWorkRef, getAllowedGenerationModelIds, hasGrantedWorkScopes, hasRequestSourceIdentity, isBillingAccessBlockedCode, isBillingAccessBlockedError, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalUiCommandStatus, isUiSurfaceMethod, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseBoardPlaybackPolicy, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseUiCommand, parseWorkRef, parseWorkSurfaceReady, parseWorkSurfaceResponse, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveCohubEnvironment, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, sanitizeAccessToken, setGrantedWorkScopes, timeline };
2488
+ export { BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BOARD_NATIVE_NODE_TYPES, BOARD_NODE_CONTRACT, BillingApi, BoardClient, BoardExtensionRegistry, BoardInputError, 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, SpacePublicFilesApi, UI_COMMAND_DEFAULT_TIMEOUT_MS, UI_COMMAND_MAX_TIMEOUT_MS, UI_COMMAND_PAYLOAD_MAX_BYTES, UI_COMMAND_PENDING_TTL_SECONDS, UI_COMMAND_SETTLEMENT_GRACE_SECONDS, UI_COMMAND_TERMINAL_TTL_SECONDS, UI_COMMAND_VERSION, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WORK_COMPOSER_CHIP_CONTENT_MAX_BYTES, WORK_COMPOSER_CHIP_KEY_MAX_LENGTH, WORK_COMPOSER_CHIP_LABEL_MAX_LENGTH, WORK_SURFACE_READY_TIMEOUT_MS, WORK_SURFACE_REQUEST_TIMEOUT_MS, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkRuntimeApi, WorkSurfaceApi, WorksApi, assertBoardNodes, assertGenerationRequestAllowedByPolicy, buildSpaceInvitePath, buildSpacePath, buildWorkSurfaceRequest, clearGrantedWorkScopes, clip, compileSequence, createBoardExtensionRegistry, createBoardNode, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, createWorkBridgeCore, createWorkRuntime, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, formatWorkRef, getAllowedGenerationModelIds, hasGrantedWorkScopes, hasRequestSourceIdentity, isBillingAccessBlockedCode, isBillingAccessBlockedError, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalUiCommandStatus, isUiSurfaceMethod, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseBoardPlaybackPolicy, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseUiCommand, parseWorkRef, parseWorkSurfaceReady, parseWorkSurfaceResponse, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveCohubEnvironment, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, sanitizeAccessToken, setGrantedWorkScopes, timeline, validateBoardNodeInput, validateBoardNodes };