@neta-art/cohub 12.1.1 → 12.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -8
- package/dist/board/editor/clipboard.js +1 -1
- package/dist/board/editor/creation.js +1 -1
- package/dist/board/editor/document.d.ts +3 -1
- package/dist/board/editor/document.js +8 -6
- package/dist/board/editor/editor.d.ts +8 -3
- package/dist/board/editor/editor.js +8 -2
- package/dist/board/editor/index.d.ts +3 -3
- package/dist/board/editor/index.js +2 -2
- package/dist/board/editor/interaction.d.ts +23 -2
- package/dist/board/editor/interaction.js +93 -4
- package/dist/board/editor/query.d.ts +1 -1
- package/dist/board/editor/query.js +3 -7
- package/dist/board/editor/selection.js +1 -1
- package/dist/board/editor/snapshots.js +5 -57
- package/dist/board/editor/tool.d.ts +4 -1
- package/dist/board/editor/tool.js +6 -1
- package/dist/board/export/index.d.ts +2 -2
- package/dist/board/export/index.js +1 -1
- package/dist/board/export/node/fonts.js +4 -0
- package/dist/board/export/node/index.d.ts +2 -0
- package/dist/board/export/node/index.js +8 -1
- package/dist/board/export/node/scripts.js +1 -1
- package/dist/board/export/scene.d.ts +2 -2
- package/dist/board/export/scene.js +2 -2
- package/dist/board/model/asset-key.d.ts +24 -0
- package/dist/board/model/asset-key.js +104 -0
- package/dist/board/model/export-assets.d.ts +7 -3
- package/dist/board/model/export-assets.js +34 -13
- package/dist/board/model/index.d.ts +9 -7
- package/dist/board/model/index.js +22 -20
- package/dist/board/model/items/create.js +3 -3
- package/dist/board/model/items/definition.d.ts +9 -1
- package/dist/board/model/items/index.d.ts +2 -2
- package/dist/board/model/items/registry.d.ts +2 -1
- package/dist/board/model/items/registry.js +1 -0
- package/dist/board/model/media-sizes.d.ts +28 -0
- package/dist/board/model/media-sizes.js +64 -0
- package/dist/board/model/palette.d.ts +1 -0
- package/dist/board/model/palette.js +20 -130
- package/dist/board/model/sampling.js +1 -1
- package/dist/board/model/text-metrics.d.ts +28 -3
- package/dist/board/model/text-metrics.js +36 -2
- package/dist/board/model/themes.d.ts +495 -0
- package/dist/board/model/themes.js +500 -0
- package/dist/board/render/card-tag.js +2 -2
- package/dist/board/render/index.d.ts +11 -7
- package/dist/board/render/index.js +9 -5
- package/dist/board/render/labels.d.ts +15 -0
- package/dist/board/render/labels.js +14 -0
- package/dist/board/render/lod.d.ts +30 -0
- package/dist/board/render/lod.js +33 -0
- package/dist/board/render/media-interaction.d.ts +5 -2
- package/dist/board/render/media-interaction.js +15 -3
- package/dist/board/render/palette.js +2 -25
- package/dist/board/render/renderers/arrow-card-renderer.js +7 -5
- package/dist/board/render/renderers/audio-card-renderer.js +3 -2
- package/dist/board/render/renderers/board-renderer-registry.d.ts +22 -1
- package/dist/board/render/renderers/board-renderer-registry.js +9 -4
- package/dist/board/render/renderers/custom-card-renderer.js +5 -5
- package/dist/board/render/renderers/draw-card-renderer.js +1 -1
- package/dist/board/render/renderers/far-plate.d.ts +14 -1
- package/dist/board/render/renderers/far-plate.js +31 -8
- package/dist/board/render/renderers/file-card-renderer.js +49 -31
- package/dist/board/render/renderers/frame-card-renderer.js +9 -3
- package/dist/board/render/renderers/image-card-renderer.js +34 -8
- package/dist/board/render/renderers/model-card-renderer.js +6 -6
- package/dist/board/render/renderers/shape-card-renderer.js +25 -24
- package/dist/board/render/renderers/task-card-renderer.js +9 -10
- package/dist/board/render/renderers/text-card-renderer.js +86 -41
- package/dist/board/render/renderers/video-card-renderer.js +5 -4
- package/dist/board/render/script-export.js +1 -1
- package/dist/board/render/script-host.js +3 -3
- package/dist/board/render/style.d.ts +8 -2
- package/dist/board/render/style.js +8 -2
- package/dist/board/render/surface.d.ts +5 -0
- package/dist/board/render/surface.js +13 -3
- package/dist/board/render/text-edit.d.ts +32 -0
- package/dist/board/render/text-edit.js +134 -0
- package/dist/board/render/text-fit.d.ts +1 -3
- package/dist/board/render/text-fit.js +6 -49
- package/dist/board/render/text-measurement.d.ts +25 -1
- package/dist/board/render/text-measurement.js +157 -19
- package/dist/board/render/text-resolution.d.ts +1 -6
- package/dist/board/render/text-resolution.js +1 -10
- package/dist/board/render/theme.d.ts +15 -0
- package/dist/board/render/theme.js +15 -0
- package/dist/board/replica/index.d.ts +4 -2
- package/dist/board/replica/index.js +28 -17
- package/dist/board/replica/indexeddb.d.ts +16 -0
- package/dist/board/replica/indexeddb.js +155 -0
- package/dist/board/stage/assets.d.ts +28 -5
- package/dist/board/stage/assets.js +293 -102
- package/dist/board/stage/bench.d.ts +35 -0
- package/dist/board/stage/bench.js +153 -0
- package/dist/board/stage/device.d.ts +41 -0
- package/dist/board/stage/device.js +62 -0
- package/dist/board/stage/frame-budget.d.ts +19 -0
- package/dist/board/stage/frame-budget.js +69 -0
- package/dist/board/stage/idle.d.ts +4 -0
- package/dist/board/stage/idle.js +26 -0
- package/dist/board/stage/index.d.ts +11 -7
- package/dist/board/stage/index.js +7 -4
- package/dist/board/stage/lru.d.ts +13 -9
- package/dist/board/stage/lru.js +38 -20
- package/dist/board/stage/presses.d.ts +21 -0
- package/dist/board/stage/presses.js +66 -0
- package/dist/board/stage/scene.d.ts +15 -1
- package/dist/board/stage/scene.js +248 -141
- package/dist/board/stage/stage.d.ts +28 -2
- package/dist/board/stage/stage.js +404 -112
- package/dist/board/stage/texture-pool.d.ts +10 -1
- package/dist/board/stage/texture-pool.js +72 -2
- package/dist/chunks/environment.d.ts +6 -0
- package/dist/chunks/http.d.ts +9 -1
- package/dist/chunks/http.js +791 -4
- package/dist/index.d.ts +52 -1
- package/dist/index.js +202 -862
- package/dist/media.d.ts +3 -27
- package/dist/media.js +3 -82
- package/dist/protocol/dist/board-constants.js +3 -3
- package/dist/protocol/dist/board-layout.d.ts +17 -3
- package/dist/protocol/dist/board-layout.js +68 -11
- package/dist/protocol/dist/board-model.d.ts +15 -1
- package/dist/protocol/dist/board-model.js +12 -2
- package/dist/protocol/dist/board-patch.js +1 -1
- package/dist/protocol/dist/board-schema.d.ts +2 -1
- package/dist/protocol/dist/board-schema.js +4 -1
- package/dist/protocol/dist/core/media.d.ts +35 -1
- package/dist/protocol/dist/core/media.js +127 -1
- package/dist/protocol/dist/index.d.ts +3 -3
- package/package.json +4 -2
- package/dist/board/model/image-key.d.ts +0 -9
- package/dist/board/model/image-key.js +0 -33
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as AppRtcError, i as WorkRoom, n as AppRoom, o as AppRoomRtc, r as WorkRealtimeApi, s as AppRtcChannel, t as AppRealtimeApi } from "./chunks/app-realtime.js";
|
|
2
|
-
import { $ as isTerminalDesktopCommandStatus, A as BoardClient, B as CronJobsApi, C as SessionPatchReducer, D as connectDisplay, E as DisplayConnection, F as PublicAssetsApi, G as DESKTOP_COMMAND_OPEN_TIMEOUT_MS, H as DESKTOP_COMMAND_ACCEPT_TIMEOUT_MS, I as SkillsApi, J as DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, K as DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, L as PromptsApi, M as SessionAccessApi, N as ReferencesApi, P as SearchApi, Q as isDesktopCallMethod, R as ModelsApi, S as parseAssistantMessageCommit, T as SpaceDisplaysApi, U as DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, V as ChannelsApi, W as DESKTOP_COMMAND_MAX_TIMEOUT_MS, X as DESKTOP_COMMAND_VERSION, Y as DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, Z as defaultDesktopCommandTimeoutMs, _ as PublicInviteApi, a as WorkCommerceApi, b as SessionGenerationStreamClient, c as AppsApi, ct as normalizeDisplayPoint, d as UserApi, et as parseDesktopCommand, f as TasksApi, g as SpacesApi, h as SpaceWebhooksApi, i as AppCommerceApi, it as DISPLAY_ELEMENT_REF_PATTERN, j as ensureRealtimeConnected, l as ReferralsApi, lt as splitDisplayText, m as SpacePublicFilesApi, n as createHttpClient, nt as resolveOpenSurface, o as DesktopCommandsApi, ot as DISPLAY_INPUT_MAX_TEXT, p as SpaceClient, q as DESKTOP_COMMAND_PENDING_TTL_SECONDS, r as RoomsApi, rt as NAVIGATION_ERROR_MESSAGE_MAX_LENGTH, s as UiCommandsApi, st as DISPLAY_SYSTEM_ACTIONS, t as CohubHttpClient, tt as parseDesktopCommandId, u as UsersApi, v as buildSpaceInvitePath, w as createSessionPatchReducer, x as createSessionGenerationStreamClient, y as buildSpacePath, z as GenerationsApi } from "./chunks/http.js";
|
|
2
|
+
import { $ as isTerminalDesktopCommandStatus, A as BoardClient, B as CronJobsApi, C as SessionPatchReducer, Ct as isBuiltinItemType, D as connectDisplay, Dt as boardDefaultSize, E as DisplayConnection, F as PublicAssetsApi, G as DESKTOP_COMMAND_OPEN_TIMEOUT_MS, H as DESKTOP_COMMAND_ACCEPT_TIMEOUT_MS, I as SkillsApi, J as DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, K as DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, L as PromptsApi, M as SessionAccessApi, N as ReferencesApi, P as SearchApi, Q as isDesktopCallMethod, R as ModelsApi, S as parseAssistantMessageCommit, St as boardItemSchema, T as SpaceDisplaysApi, Tt as normalizeBoardRemoteUrl, U as DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, V as ChannelsApi, W as DESKTOP_COMMAND_MAX_TIMEOUT_MS, X as DESKTOP_COMMAND_VERSION, Y as DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, Z as defaultDesktopCommandTimeoutMs, _ as PublicInviteApi, _t as BoardColorSchema, a as WorkCommerceApi, b as SessionGenerationStreamClient, bt as BoardTrackSchema, c as AppsApi, ct as normalizeDisplayPoint, d as UserApi, dt as BOARD_MIME_TYPE, et as parseDesktopCommand, f as TasksApi, ft as BOARD_CAMERA_TARGET, g as SpacesApi, gt as BoardAnimationSchema, h as SpaceWebhooksApi, ht as BoardAnimationHeaderSchema, i as AppCommerceApi, it as DISPLAY_ELEMENT_REF_PATTERN, j as ensureRealtimeConnected, l as ReferralsApi, lt as splitDisplayText, m as SpacePublicFilesApi, mt as BOARD_ITEM_TYPES, n as createHttpClient, nt as resolveOpenSurface, o as DesktopCommandsApi, ot as DISPLAY_INPUT_MAX_TEXT, p as SpaceClient, pt as BOARD_COLOR_TOKENS, q as DESKTOP_COMMAND_PENDING_TTL_SECONDS, r as RoomsApi, rt as NAVIGATION_ERROR_MESSAGE_MAX_LENGTH, s as UiCommandsApi, st as DISPLAY_SYSTEM_ACTIONS, t as CohubHttpClient, tt as parseDesktopCommandId, u as UsersApi, ut as BOARD_EXTENSION, v as buildSpaceInvitePath, vt as BoardPatchSchema, w as createSessionPatchReducer, wt as parseBoardItem, x as createSessionGenerationStreamClient, xt as BoardVec2Schema, y as buildSpacePath, yt as BoardSettingsSchema, z as GenerationsApi } from "./chunks/http.js";
|
|
3
3
|
import { A as isRequestSourceClientId, B as isUuidLike, D as COHUB_SOURCE_HEADER_NAMES, E as COHUB_SOURCE_HEADER, F as parseRequestSourceFromHeaders, I as readRequestSourceFromEnv, L as requestSourceToHeaders, M as isRequestSourceUuid, N as mergeRequestSourceIntoMeta, O as REQUEST_SOURCE_VIA_MAX_LENGTH, P as normalizeRequestSource, R as resolveRequestSourceChannel, V as isUuidOrShortUuid, a as isBillingAccessBlockedError, c as HttpError, d as matchesUnauthorizedErrorToken, f as sanitizeAccessToken, i as isBillingAccessBlockedCode, j as isRequestSourceEmpty, k as hasRequestSourceIdentity, l as HttpTransport, n as FEATURE_NOT_ENTITLED_ERROR_CODE, o as isFeatureNotEntitledError, r as extractBillingPayload, s as isHttpErrorCode, t as BILLING_ACCESS_BLOCKED_ERROR_CODE, u as joinApiUrl, z as isUuid } from "./chunks/http-error.js";
|
|
4
4
|
import { a as normalizeWebsocketUrl, c as resolveExecutionAppId, d as resolveWebBaseUrl, f as resolveWebsocketUrl, g as scopeListHasPermission, h as isUserLevelPermission, i as normalizeVoiceInputWebsocketUrl, l as resolveExecutionToken, m as USER_LEVEL_PERMISSIONS, n as getCohubContext, o as resolveApiBaseUrl, p as PERMISSIONS, r as normalizeBaseUrl, s as resolveCohubEnvironment, t as COHUB_ENVIRONMENTS, u as resolveVoiceInputWebsocketUrl } from "./chunks/environment.js";
|
|
5
5
|
import { WebsocketClient, createWebsocketClient } from "./websocket.js";
|
|
@@ -72,6 +72,69 @@ const appAuthorizationResultSchema = z.discriminatedUnion("status", [
|
|
|
72
72
|
code: z.string()
|
|
73
73
|
})
|
|
74
74
|
]);
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region ../protocol/dist/attachments.js
|
|
77
|
+
const escapeAttachmentPath = (path) => path.replace(/[\r\n`]/g, "_");
|
|
78
|
+
const escapeAttachmentUrl = (url) => url.replace(/[\r\n`]/g, "_");
|
|
79
|
+
function formatVisibleLines(range) {
|
|
80
|
+
if (!range) return "";
|
|
81
|
+
const start = Math.max(1, Math.floor(range.start));
|
|
82
|
+
const end = Math.max(start, Math.floor(range.end));
|
|
83
|
+
return start === end ? `L${start}` : `L${start}-${end}`;
|
|
84
|
+
}
|
|
85
|
+
function formatVisibleRect(rect) {
|
|
86
|
+
if (!rect) return "";
|
|
87
|
+
return `view ${Math.round(rect.width)}×${Math.round(rect.height)} at (${Math.round(rect.x)}, ${Math.round(rect.y)})`;
|
|
88
|
+
}
|
|
89
|
+
function escapeViewportLabel(value) {
|
|
90
|
+
return value.replace(/[\r\n`]/g, "_").trim();
|
|
91
|
+
}
|
|
92
|
+
function formatSelectedNodes(nodes) {
|
|
93
|
+
if (!nodes || nodes.length === 0) return "";
|
|
94
|
+
return `selected: ${nodes.map((node) => {
|
|
95
|
+
return (node.title ? escapeViewportLabel(node.title) : "") || escapeViewportLabel(node.id);
|
|
96
|
+
}).join(", ")}`;
|
|
97
|
+
}
|
|
98
|
+
function formatViewportContextLine(context) {
|
|
99
|
+
if (context.kind === "file") {
|
|
100
|
+
const lines = formatVisibleLines(context.visibleLines);
|
|
101
|
+
const suffix = lines ? ` (${lines})` : "";
|
|
102
|
+
return `- file: \`${escapeAttachmentPath(context.path)}\`${suffix}`;
|
|
103
|
+
}
|
|
104
|
+
if (context.kind === "board") {
|
|
105
|
+
const details = [
|
|
106
|
+
...context.boardId ? [`id: ${escapeViewportLabel(context.boardId)}`] : [],
|
|
107
|
+
formatSelectedNodes(context.selectedNodes),
|
|
108
|
+
formatVisibleRect(context.visibleRect)
|
|
109
|
+
].filter(Boolean);
|
|
110
|
+
const suffix = details.length > 0 ? ` (${details.join("; ")})` : "";
|
|
111
|
+
return `- board: \`${escapeAttachmentPath(context.path)}\`${suffix}`;
|
|
112
|
+
}
|
|
113
|
+
if (context.kind === "app") {
|
|
114
|
+
const label = escapeViewportLabel(context.label);
|
|
115
|
+
const content = context.content.replace(/\r\n?/g, "\n").trim();
|
|
116
|
+
return `- app: \`${escapeAttachmentPath(context.appId)}\` (${label})\n${content}`;
|
|
117
|
+
}
|
|
118
|
+
const url = context.url?.trim();
|
|
119
|
+
const suffix = url ? ` (${escapeAttachmentUrl(url)})` : "";
|
|
120
|
+
return `- port: \`${escapeAttachmentPath(context.port)}\`${suffix}`;
|
|
121
|
+
}
|
|
122
|
+
function buildViewportReferencesText(contexts) {
|
|
123
|
+
if (contexts.length === 0) return "";
|
|
124
|
+
return ["Viewport:", ...contexts.map(formatViewportContextLine)].join("\n");
|
|
125
|
+
}
|
|
126
|
+
function buildViewportContentBlock(contexts) {
|
|
127
|
+
const text = buildViewportReferencesText(contexts);
|
|
128
|
+
if (!text) return null;
|
|
129
|
+
return {
|
|
130
|
+
type: "text",
|
|
131
|
+
text,
|
|
132
|
+
_meta: {
|
|
133
|
+
attachmentKind: "viewport",
|
|
134
|
+
viewports: contexts
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
75
138
|
const GiB = 1073741824;
|
|
76
139
|
/** Maximum size of a single uploaded file. */
|
|
77
140
|
const UPLOAD_MAX_FILE_BYTES = 2 * GiB;
|
|
@@ -118,737 +181,6 @@ function batchUploadEntries(entries, sizeOf, options = {}) {
|
|
|
118
181
|
if (batch.length > 0) batches.push(batch);
|
|
119
182
|
return batches;
|
|
120
183
|
}
|
|
121
|
-
const BOARD_DEFAULT_ITEM_SIZE = {
|
|
122
|
-
width: 240,
|
|
123
|
-
height: 160
|
|
124
|
-
};
|
|
125
|
-
const BOARD_DEFAULT_SIZES = {
|
|
126
|
-
frame: {
|
|
127
|
-
width: 480,
|
|
128
|
-
height: 320
|
|
129
|
-
},
|
|
130
|
-
shape: {
|
|
131
|
-
width: 200,
|
|
132
|
-
height: 140
|
|
133
|
-
},
|
|
134
|
-
image: {
|
|
135
|
-
width: 480,
|
|
136
|
-
height: 270
|
|
137
|
-
},
|
|
138
|
-
video: {
|
|
139
|
-
width: 480,
|
|
140
|
-
height: 270
|
|
141
|
-
},
|
|
142
|
-
audio: {
|
|
143
|
-
width: 320,
|
|
144
|
-
height: 112
|
|
145
|
-
},
|
|
146
|
-
file: {
|
|
147
|
-
width: 260,
|
|
148
|
-
height: 132
|
|
149
|
-
},
|
|
150
|
-
task: {
|
|
151
|
-
width: 480,
|
|
152
|
-
height: 270
|
|
153
|
-
},
|
|
154
|
-
effect: {
|
|
155
|
-
width: 240,
|
|
156
|
-
height: 240
|
|
157
|
-
},
|
|
158
|
-
custom: {
|
|
159
|
-
width: 480,
|
|
160
|
-
height: 320
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
function boardDefaultSize(type) {
|
|
164
|
-
return { ...Object.hasOwn(BOARD_DEFAULT_SIZES, type) ? BOARD_DEFAULT_SIZES[type] : BOARD_DEFAULT_ITEM_SIZE };
|
|
165
|
-
}
|
|
166
|
-
//#endregion
|
|
167
|
-
//#region ../protocol/dist/board-url.js
|
|
168
|
-
const BOARD_REMOTE_URL_MAX_LENGTH = 4096;
|
|
169
|
-
function parseIpv4(host) {
|
|
170
|
-
const parts = host.split(".").map(Number);
|
|
171
|
-
return parts.length === 4 && parts.every((part) => Number.isInteger(part) && part >= 0 && part <= 255) ? parts : null;
|
|
172
|
-
}
|
|
173
|
-
function isBlockedIpv4(host) {
|
|
174
|
-
const parts = parseIpv4(host);
|
|
175
|
-
if (!parts) return false;
|
|
176
|
-
const [first, second, third] = parts;
|
|
177
|
-
if (first === 0 || first === 10 || first === 127) return true;
|
|
178
|
-
if (first === 100 && second >= 64 && second <= 127) return true;
|
|
179
|
-
if (first === 169 && second === 254) return true;
|
|
180
|
-
if (first === 172 && second >= 16 && second <= 31) return true;
|
|
181
|
-
if (first === 192 && second === 168) return true;
|
|
182
|
-
if (first === 192 && second === 0 && (third === 0 || third === 2)) return true;
|
|
183
|
-
if (first === 192 && second === 88 && third === 99) return true;
|
|
184
|
-
if (first === 198 && (second === 18 || second === 19)) return true;
|
|
185
|
-
if (first === 198 && second === 51 && third === 100) return true;
|
|
186
|
-
if (first === 203 && second === 0 && third === 113) return true;
|
|
187
|
-
return first >= 224;
|
|
188
|
-
}
|
|
189
|
-
function expandIpv6(host) {
|
|
190
|
-
const [head, tail, extra] = host.toLowerCase().split("::");
|
|
191
|
-
if (extra !== void 0) return null;
|
|
192
|
-
const headParts = head ? head.split(":").filter(Boolean) : [];
|
|
193
|
-
const tailParts = tail ? tail.split(":").filter(Boolean) : [];
|
|
194
|
-
const missing = 8 - headParts.length - tailParts.length;
|
|
195
|
-
if (missing < 0 || tail === void 0 && missing !== 0) return null;
|
|
196
|
-
const parts = [
|
|
197
|
-
...headParts,
|
|
198
|
-
...Array.from({ length: missing }, () => "0"),
|
|
199
|
-
...tailParts
|
|
200
|
-
];
|
|
201
|
-
if (parts.length !== 8 || parts.some((part) => !/^[0-9a-f]{1,4}$/.test(part))) return null;
|
|
202
|
-
return parts.map((part) => part.padStart(4, "0"));
|
|
203
|
-
}
|
|
204
|
-
function isBlockedIpv6(host) {
|
|
205
|
-
const parts = expandIpv6(host);
|
|
206
|
-
if (!parts) return true;
|
|
207
|
-
if (parts.every((part) => part === "0000")) return true;
|
|
208
|
-
if (parts.slice(0, 7).every((part) => part === "0000") && parts[7] === "0001") return true;
|
|
209
|
-
if (parts.slice(0, 5).every((part) => part === "0000") && parts[5] === "ffff") {
|
|
210
|
-
const high = Number.parseInt(parts[6] ?? "0", 16);
|
|
211
|
-
const low = Number.parseInt(parts[7] ?? "0", 16);
|
|
212
|
-
return isBlockedIpv4(`${high >> 8}.${high & 255}.${low >> 8}.${low & 255}`);
|
|
213
|
-
}
|
|
214
|
-
if (parts.slice(0, 6).every((part) => part === "0000")) return true;
|
|
215
|
-
const first = Number.parseInt(parts[0] ?? "0", 16);
|
|
216
|
-
if ((first & 65024) === 64512) return true;
|
|
217
|
-
if ((first & 65472) === 65152 || (first & 65472) === 65216) return true;
|
|
218
|
-
if ((first & 65280) === 65280) return true;
|
|
219
|
-
return parts[0] === "2001" && parts[1] === "0db8";
|
|
220
|
-
}
|
|
221
|
-
function isPublicBoardRemoteAddress(value) {
|
|
222
|
-
const address = value.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
223
|
-
if (parseIpv4(address)) return !isBlockedIpv4(address);
|
|
224
|
-
return address.includes(":") && !isBlockedIpv6(address);
|
|
225
|
-
}
|
|
226
|
-
function isBlockedHost(hostname) {
|
|
227
|
-
const host = hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
|
|
228
|
-
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local") || host.endsWith(".internal")) return true;
|
|
229
|
-
if (parseIpv4(host) || host.includes(":")) return !isPublicBoardRemoteAddress(host);
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* Normalize a browser-loadable public HTTP(S) URL. This blocks explicit local
|
|
234
|
-
* addresses; any future server-side fetcher must additionally validate DNS
|
|
235
|
-
* resolution to defend against rebinding.
|
|
236
|
-
*/
|
|
237
|
-
function normalizeBoardRemoteUrl(value) {
|
|
238
|
-
if (typeof value !== "string") return void 0;
|
|
239
|
-
const input = value.trim();
|
|
240
|
-
if (!input || input.length > 4096) return void 0;
|
|
241
|
-
try {
|
|
242
|
-
const url = new URL(input);
|
|
243
|
-
if (url.protocol !== "https:" && url.protocol !== "http:") return void 0;
|
|
244
|
-
if (url.username || url.password || isBlockedHost(url.hostname)) return;
|
|
245
|
-
const normalized = url.toString();
|
|
246
|
-
return normalized.length <= 4096 ? normalized : void 0;
|
|
247
|
-
} catch {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
z.string().max(BOARD_REMOTE_URL_MAX_LENGTH).refine((value) => normalizeBoardRemoteUrl(value) !== void 0, { message: "URL must be a public HTTP(S) URL without credentials" });
|
|
252
|
-
const BOARD_CAMERA_TARGET = "camera";
|
|
253
|
-
const BoardKeySchema = z.string().min(1).max(160).regex(/^[^\s/]+$/, "ids must not contain whitespace or '/'");
|
|
254
|
-
const BoardIdSchema = BoardKeySchema.refine((value) => value !== BOARD_CAMERA_TARGET, "\"camera\" is reserved");
|
|
255
|
-
const finite$1 = z.number().finite();
|
|
256
|
-
const nonNegative = finite$1.nonnegative();
|
|
257
|
-
const ratio = finite$1.min(0).max(1);
|
|
258
|
-
const BoardVec2Schema = z.object({
|
|
259
|
-
x: finite$1,
|
|
260
|
-
y: finite$1
|
|
261
|
-
}).strict();
|
|
262
|
-
const BoardSizeSchema = z.object({
|
|
263
|
-
width: finite$1.positive(),
|
|
264
|
-
height: finite$1.positive()
|
|
265
|
-
}).strict();
|
|
266
|
-
const BOARD_COLOR_TOKENS = [
|
|
267
|
-
"brand",
|
|
268
|
-
"neutral",
|
|
269
|
-
"black",
|
|
270
|
-
"white",
|
|
271
|
-
"blue",
|
|
272
|
-
"green",
|
|
273
|
-
"amber",
|
|
274
|
-
"violet",
|
|
275
|
-
"rose"
|
|
276
|
-
];
|
|
277
|
-
const CSS_NAMED_COLORS = new Set("transparent aliceblue antiquewhite aqua aquamarine azure beige bisque blanchedalmond blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite gold goldenrod gray grey greenyellow honeydew hotpink indianred indigo ivory khaki lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet wheat whitesmoke yellow yellowgreen".split(" "));
|
|
278
|
-
function isBoardColorString(value) {
|
|
279
|
-
const color = value.trim().toLowerCase();
|
|
280
|
-
return BOARD_COLOR_TOKENS.includes(color) || CSS_NAMED_COLORS.has(color) || /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/.test(color) || /^(?:rgba?|hsla?|hwb|lab|lch|oklab|oklch|color)\([^()]*\)$/.test(color);
|
|
281
|
-
}
|
|
282
|
-
const colorString = z.string().max(120).refine(isBoardColorString, "expected a palette token or a CSS color");
|
|
283
|
-
const BoardColorSchema = z.union([colorString, z.object({
|
|
284
|
-
light: colorString,
|
|
285
|
-
dark: colorString
|
|
286
|
-
}).strict()]).describe("Palette token (follows the theme), CSS color, or { light, dark }.");
|
|
287
|
-
const BoardStyleSchema = z.object({
|
|
288
|
-
fill: BoardColorSchema.optional(),
|
|
289
|
-
fillOpacity: ratio.optional().describe("Fill opacity, independent of the item's opacity."),
|
|
290
|
-
stroke: BoardColorSchema.optional(),
|
|
291
|
-
strokeWidth: finite$1.min(0).max(64).optional(),
|
|
292
|
-
dash: z.enum([
|
|
293
|
-
"solid",
|
|
294
|
-
"dashed",
|
|
295
|
-
"dotted"
|
|
296
|
-
]).optional(),
|
|
297
|
-
radius: nonNegative.optional().describe("Corner radius in board units."),
|
|
298
|
-
trim: ratio.optional().describe("Fraction of the outline drawn; animate 0 → 1 to draw it in.")
|
|
299
|
-
}).strict();
|
|
300
|
-
function isSafeBoardSourcePath(value) {
|
|
301
|
-
return value.length > 0 && value.length <= 4096 && !value.startsWith("/") && !/^[a-z][a-z\d+.-]*:/i.test(value.trimStart()) && !value.includes("\\") && value.split("/").every((part) => part.length > 0 && part !== "." && part !== "..");
|
|
302
|
-
}
|
|
303
|
-
const srcSchema = z.string().refine(isSafeBoardSourcePath, "src must be a relative Space file path");
|
|
304
|
-
function parseBoardMediaSource(src) {
|
|
305
|
-
if (isSafeBoardSourcePath(src)) return {
|
|
306
|
-
kind: "file",
|
|
307
|
-
value: src
|
|
308
|
-
};
|
|
309
|
-
return normalizeBoardRemoteUrl(src) ? {
|
|
310
|
-
kind: "url",
|
|
311
|
-
value: src
|
|
312
|
-
} : null;
|
|
313
|
-
}
|
|
314
|
-
const BoardMediaSourceSchema = z.string().max(4096).refine((src) => parseBoardMediaSource(src) !== null, "src must be a public HTTP(S) URL or relative Space file path").describe("Prefer a public HTTP(S) URL; a Space path relative to the workspace root also works.");
|
|
315
|
-
const BoardScriptSchema = z.object({
|
|
316
|
-
src: srcSchema.refine((path) => /\.m?js$/.test(path), "script src must be a .js or .mjs module").describe("A .js or .mjs Space file."),
|
|
317
|
-
params: z.record(z.string(), z.json()).default({}).describe("Values the module reads as params."),
|
|
318
|
-
targets: z.record(z.string().min(1).max(80), BoardIdSchema).default({}).describe("Named items the module can reach, as ctx.targets."),
|
|
319
|
-
seed: z.string().min(1).max(160).optional().describe("Seed for ctx.random(); defaults to the item id."),
|
|
320
|
-
enabled: z.boolean().default(true)
|
|
321
|
-
}).strict().describe("A JavaScript module attached to the item; `cohub boards schema script` lists its API.");
|
|
322
|
-
const itemEnvelope = {
|
|
323
|
-
script: BoardScriptSchema.optional(),
|
|
324
|
-
parent: BoardIdSchema.optional().describe("A frame id; position becomes relative to the frame, and the item moves with it."),
|
|
325
|
-
z: finite$1.optional().describe("Order among siblings; new items go on top."),
|
|
326
|
-
position: BoardVec2Schema.default({
|
|
327
|
-
x: 0,
|
|
328
|
-
y: 0
|
|
329
|
-
}),
|
|
330
|
-
rotation: finite$1.default(0),
|
|
331
|
-
scale: z.union([finite$1, BoardVec2Schema]).default(1),
|
|
332
|
-
origin: BoardVec2Schema.default({
|
|
333
|
-
x: .5,
|
|
334
|
-
y: .5
|
|
335
|
-
}).describe("Rotation and scale origin as fractions of the size."),
|
|
336
|
-
opacity: ratio.default(1),
|
|
337
|
-
style: BoardStyleSchema.default({}),
|
|
338
|
-
locked: z.boolean().optional(),
|
|
339
|
-
metadata: z.record(z.string(), z.unknown()).optional()
|
|
340
|
-
};
|
|
341
|
-
const boxed = (size) => ({
|
|
342
|
-
...itemEnvelope,
|
|
343
|
-
size: BoardSizeSchema.default({ ...size })
|
|
344
|
-
});
|
|
345
|
-
const unsized = { ...itemEnvelope };
|
|
346
|
-
const fontSize = finite$1.min(2).max(512);
|
|
347
|
-
const BOARD_TEXT_ALIGNS = [
|
|
348
|
-
"left",
|
|
349
|
-
"center",
|
|
350
|
-
"right"
|
|
351
|
-
];
|
|
352
|
-
const BOARD_SHAPE_GEOMETRIES = [
|
|
353
|
-
"rectangle",
|
|
354
|
-
"rounded",
|
|
355
|
-
"ellipse",
|
|
356
|
-
"diamond",
|
|
357
|
-
"triangle",
|
|
358
|
-
"path"
|
|
359
|
-
];
|
|
360
|
-
const BoardFrameItemSchema = z.object({
|
|
361
|
-
...boxed(BOARD_DEFAULT_SIZES.frame),
|
|
362
|
-
type: z.literal("frame"),
|
|
363
|
-
props: z.object({
|
|
364
|
-
label: z.string().max(280).default(""),
|
|
365
|
-
decoration: z.enum(["frame", "none"]).optional().describe("none hides the title, border and background: an invisible group whose tracks move every child."),
|
|
366
|
-
clip: z.boolean().default(true).describe("Hide children outside the frame.")
|
|
367
|
-
}).strict().prefault({})
|
|
368
|
-
}).strict();
|
|
369
|
-
const BoardTextItemSchema = z.object({
|
|
370
|
-
...unsized,
|
|
371
|
-
type: z.literal("text"),
|
|
372
|
-
props: z.object({
|
|
373
|
-
text: z.string().default(""),
|
|
374
|
-
fontSize: fontSize.default(24),
|
|
375
|
-
fontWeight: finite$1.min(100).max(900).default(500),
|
|
376
|
-
font: z.string().min(1).max(120).default("sans").describe("sans, serif, mono, or a font family name."),
|
|
377
|
-
align: z.enum(BOARD_TEXT_ALIGNS).default("left"),
|
|
378
|
-
lineHeight: finite$1.min(.5).max(4).default(4 / 3),
|
|
379
|
-
width: finite$1.positive().optional().describe("Wrap width; the height follows the text."),
|
|
380
|
-
reveal: ratio.default(1).describe("Fraction of the text shown; animate 0 → 1 to type it."),
|
|
381
|
-
caret: z.boolean().default(false).describe("Blink a caret while the text is being revealed.")
|
|
382
|
-
}).strict().prefault({})
|
|
383
|
-
}).strict();
|
|
384
|
-
const BoardShapeItemSchema = z.object({
|
|
385
|
-
...boxed(BOARD_DEFAULT_SIZES.shape),
|
|
386
|
-
type: z.literal("shape"),
|
|
387
|
-
props: z.object({
|
|
388
|
-
geometry: z.enum(BOARD_SHAPE_GEOMETRIES).default("rectangle"),
|
|
389
|
-
path: z.string().min(1).max(2e5).optional().describe("SVG path data for path geometry, fitted to the item size."),
|
|
390
|
-
text: z.string().default(""),
|
|
391
|
-
fontSize: fontSize.default(20),
|
|
392
|
-
align: z.enum(BOARD_TEXT_ALIGNS).default("center")
|
|
393
|
-
}).strict().refine((props) => props.geometry !== "path" || Boolean(props.path), {
|
|
394
|
-
message: "path geometry requires props.path",
|
|
395
|
-
path: ["path"]
|
|
396
|
-
}).prefault({})
|
|
397
|
-
}).strict();
|
|
398
|
-
const BoardDrawPointSchema = z.object({
|
|
399
|
-
x: finite$1,
|
|
400
|
-
y: finite$1,
|
|
401
|
-
p: ratio.default(.5).describe("Pen pressure.")
|
|
402
|
-
}).strict();
|
|
403
|
-
const BoardDrawItemSchema = z.object({
|
|
404
|
-
...unsized,
|
|
405
|
-
type: z.literal("draw"),
|
|
406
|
-
props: z.object({ points: z.array(BoardDrawPointSchema).min(1).max(1e5).describe("Stroke points relative to position; the size follows them.") }).strict()
|
|
407
|
-
}).strict();
|
|
408
|
-
const BoardArrowAnchorSchema = z.union([
|
|
409
|
-
z.literal("auto"),
|
|
410
|
-
z.object({
|
|
411
|
-
side: z.enum([
|
|
412
|
-
"top",
|
|
413
|
-
"right",
|
|
414
|
-
"bottom",
|
|
415
|
-
"left"
|
|
416
|
-
]),
|
|
417
|
-
offset: ratio.default(.5)
|
|
418
|
-
}).strict(),
|
|
419
|
-
z.object({
|
|
420
|
-
x: ratio,
|
|
421
|
-
y: ratio
|
|
422
|
-
}).strict()
|
|
423
|
-
]);
|
|
424
|
-
const BoardArrowBindingSchema = z.object({
|
|
425
|
-
item: BoardIdSchema,
|
|
426
|
-
anchor: BoardArrowAnchorSchema.default("auto").describe("auto uses the side facing the other end; or a side with an offset, or a point as fractions of the item."),
|
|
427
|
-
port: z.string().min(1).max(120).optional()
|
|
428
|
-
}).strict();
|
|
429
|
-
const BoardArrowEndSchema = z.union([BoardVec2Schema, BoardArrowBindingSchema]).describe("A point relative to position, or { item } to follow that item.");
|
|
430
|
-
const BOARD_ARROW_ROUTES = [
|
|
431
|
-
"straight",
|
|
432
|
-
"curve",
|
|
433
|
-
"orthogonal"
|
|
434
|
-
];
|
|
435
|
-
const BoardArrowItemSchema = z.object({
|
|
436
|
-
...unsized,
|
|
437
|
-
type: z.literal("arrow"),
|
|
438
|
-
props: z.object({
|
|
439
|
-
start: BoardArrowEndSchema,
|
|
440
|
-
end: BoardArrowEndSchema,
|
|
441
|
-
route: z.enum(BOARD_ARROW_ROUTES).default("straight"),
|
|
442
|
-
bend: finite$1.min(-.85).max(.85).default(0).describe("Sideways curve as a fraction of the length; the sign picks the side."),
|
|
443
|
-
waypoints: z.array(BoardVec2Schema).max(64).default([]).describe("Points the route passes through."),
|
|
444
|
-
arrowStart: z.boolean().default(false),
|
|
445
|
-
arrowEnd: z.boolean().default(true),
|
|
446
|
-
label: z.string().max(280).default(""),
|
|
447
|
-
fontSize: fontSize.default(14),
|
|
448
|
-
relation: z.string().max(64).regex(/^[a-z0-9]+(?:[.-][a-z0-9]+)*$/, "relation must be a lowercase slug").optional().describe("What the arrow means, as a slug such as triggers or depends-on.")
|
|
449
|
-
}).strict()
|
|
450
|
-
}).strict();
|
|
451
|
-
const fileProps = {
|
|
452
|
-
src: BoardMediaSourceSchema,
|
|
453
|
-
snapshot: z.object({
|
|
454
|
-
title: z.string().optional(),
|
|
455
|
-
mimeType: z.string().optional(),
|
|
456
|
-
size: nonNegative.optional(),
|
|
457
|
-
mtimeMs: nonNegative.optional(),
|
|
458
|
-
naturalWidth: finite$1.positive().optional(),
|
|
459
|
-
naturalHeight: finite$1.positive().optional(),
|
|
460
|
-
durationMs: nonNegative.optional(),
|
|
461
|
-
excerpt: z.string().optional(),
|
|
462
|
-
coverPath: z.string().optional(),
|
|
463
|
-
coverUrl: z.string().optional()
|
|
464
|
-
}).strict().describe("Cached facts for an instant preview; filled in when the media loads.").optional()
|
|
465
|
-
};
|
|
466
|
-
const BoardMediaOriginSchema = z.object({
|
|
467
|
-
taskRunId: z.string().min(1).max(160),
|
|
468
|
-
artifactId: z.string().min(1).max(240)
|
|
469
|
-
}).strict().describe("The generation run and result this media came from.");
|
|
470
|
-
const mediaProps = {
|
|
471
|
-
...fileProps,
|
|
472
|
-
origin: BoardMediaOriginSchema.optional()
|
|
473
|
-
};
|
|
474
|
-
const timedFileProps = {
|
|
475
|
-
...mediaProps,
|
|
476
|
-
time: nonNegative.optional().describe("Playback position in milliseconds; animate props.time to play it on a timeline.")
|
|
477
|
-
};
|
|
478
|
-
const BoardCropSchema = z.object({
|
|
479
|
-
x: ratio,
|
|
480
|
-
y: ratio,
|
|
481
|
-
w: ratio,
|
|
482
|
-
h: ratio
|
|
483
|
-
}).strict().describe("Region shown, as fractions of the image. Without it the whole image fits inside size.");
|
|
484
|
-
const BoardImageItemSchema = z.object({
|
|
485
|
-
...boxed(BOARD_DEFAULT_SIZES.image),
|
|
486
|
-
type: z.literal("image"),
|
|
487
|
-
props: z.object({
|
|
488
|
-
...mediaProps,
|
|
489
|
-
crop: BoardCropSchema.optional()
|
|
490
|
-
}).strict()
|
|
491
|
-
}).strict();
|
|
492
|
-
const BoardVideoItemSchema = z.object({
|
|
493
|
-
...boxed(BOARD_DEFAULT_SIZES.video),
|
|
494
|
-
type: z.literal("video"),
|
|
495
|
-
props: z.object(timedFileProps).strict()
|
|
496
|
-
}).strict();
|
|
497
|
-
const BoardAudioItemSchema = z.object({
|
|
498
|
-
...boxed(BOARD_DEFAULT_SIZES.audio),
|
|
499
|
-
type: z.literal("audio"),
|
|
500
|
-
props: z.object(timedFileProps).strict()
|
|
501
|
-
}).strict();
|
|
502
|
-
const BoardFileItemSchema = z.object({
|
|
503
|
-
...boxed(BOARD_DEFAULT_SIZES.file),
|
|
504
|
-
type: z.literal("file"),
|
|
505
|
-
props: z.object(fileProps).strict()
|
|
506
|
-
}).strict();
|
|
507
|
-
const httpsUrl = z.string().max(4096).url();
|
|
508
|
-
const artifactBase = {
|
|
509
|
-
id: z.string().min(1).max(240),
|
|
510
|
-
title: z.string().max(240).optional(),
|
|
511
|
-
url: httpsUrl,
|
|
512
|
-
mimeType: z.string().max(160).optional()
|
|
513
|
-
};
|
|
514
|
-
const BoardTaskArtifactSchema = z.discriminatedUnion("type", [
|
|
515
|
-
z.object({
|
|
516
|
-
...artifactBase,
|
|
517
|
-
type: z.literal("image"),
|
|
518
|
-
naturalWidth: finite$1.positive().optional(),
|
|
519
|
-
naturalHeight: finite$1.positive().optional()
|
|
520
|
-
}).strict(),
|
|
521
|
-
z.object({
|
|
522
|
-
...artifactBase,
|
|
523
|
-
type: z.literal("video"),
|
|
524
|
-
previewUrl: httpsUrl.optional(),
|
|
525
|
-
durationMs: z.number().int().positive().optional(),
|
|
526
|
-
naturalWidth: finite$1.positive().optional(),
|
|
527
|
-
naturalHeight: finite$1.positive().optional()
|
|
528
|
-
}).strict(),
|
|
529
|
-
z.object({
|
|
530
|
-
...artifactBase,
|
|
531
|
-
type: z.literal("audio"),
|
|
532
|
-
previewUrl: httpsUrl.optional(),
|
|
533
|
-
durationMs: z.number().int().positive().optional()
|
|
534
|
-
}).strict(),
|
|
535
|
-
z.object({
|
|
536
|
-
id: z.string().min(1).max(240),
|
|
537
|
-
type: z.literal("text"),
|
|
538
|
-
title: z.string().max(240).optional(),
|
|
539
|
-
textExcerpt: z.string().min(1).max(480)
|
|
540
|
-
}).strict()
|
|
541
|
-
]);
|
|
542
|
-
const BoardTaskSnapshotSchema = z.object({
|
|
543
|
-
taskType: z.string().min(1).max(120),
|
|
544
|
-
status: z.enum([
|
|
545
|
-
"pending",
|
|
546
|
-
"running",
|
|
547
|
-
"completed",
|
|
548
|
-
"failed"
|
|
549
|
-
]),
|
|
550
|
-
title: z.string().min(1).max(240),
|
|
551
|
-
model: z.string().max(160).optional(),
|
|
552
|
-
promptExcerpt: z.string().max(480).optional(),
|
|
553
|
-
errorExcerpt: z.string().max(240).optional(),
|
|
554
|
-
artifactCount: z.number().int().nonnegative(),
|
|
555
|
-
artifacts: z.array(BoardTaskArtifactSchema).max(6).default([]),
|
|
556
|
-
startedAt: z.string().max(64).optional(),
|
|
557
|
-
updatedAt: z.string().optional()
|
|
558
|
-
}).strict();
|
|
559
|
-
const BoardTaskItemSchema = z.object({
|
|
560
|
-
...boxed(BOARD_DEFAULT_SIZES.task),
|
|
561
|
-
type: z.literal("task"),
|
|
562
|
-
props: z.object({
|
|
563
|
-
taskRunId: z.string().min(1).max(160).describe("The generation run shown; the server keeps the card's status and results up to date."),
|
|
564
|
-
snapshot: BoardTaskSnapshotSchema.describe("Maintained by the server; omit it.")
|
|
565
|
-
}).strict()
|
|
566
|
-
}).strict();
|
|
567
|
-
const BOARD_EFFECT_KINDS = [
|
|
568
|
-
"particles",
|
|
569
|
-
"trail",
|
|
570
|
-
"impact",
|
|
571
|
-
"flash",
|
|
572
|
-
"glow"
|
|
573
|
-
];
|
|
574
|
-
const BoardEffectItemSchema = z.object({
|
|
575
|
-
...boxed(BOARD_DEFAULT_SIZES.effect),
|
|
576
|
-
type: z.literal("effect"),
|
|
577
|
-
props: z.object({
|
|
578
|
-
kind: z.enum(BOARD_EFFECT_KINDS),
|
|
579
|
-
rate: nonNegative.max(2e4).default(40),
|
|
580
|
-
life: finite$1.positive().max(6e4).default(1200),
|
|
581
|
-
particleSize: finite$1.positive().max(512).default(6),
|
|
582
|
-
speed: nonNegative.max(1e4).default(120),
|
|
583
|
-
direction: finite$1.default(-90),
|
|
584
|
-
spread: finite$1.min(0).max(360).default(360),
|
|
585
|
-
gravity: finite$1.default(0),
|
|
586
|
-
intensity: nonNegative.max(10).default(1),
|
|
587
|
-
follow: BoardIdSchema.optional().describe("trail: the item to follow."),
|
|
588
|
-
seed: z.string().min(1).max(160).optional().describe("Makes procedural motion repeatable.")
|
|
589
|
-
}).strict()
|
|
590
|
-
}).strict();
|
|
591
|
-
const BoardCustomItemSchema = z.object({
|
|
592
|
-
...boxed(BOARD_DEFAULT_SIZES.custom),
|
|
593
|
-
type: z.literal("custom"),
|
|
594
|
-
script: BoardScriptSchema,
|
|
595
|
-
props: z.object({}).strict().default({})
|
|
596
|
-
}).strict();
|
|
597
|
-
const BOARD_EXTENSION_TYPE_PATTERN = /^[a-z][a-z0-9]*(?:\.[a-z0-9-]+)+$/;
|
|
598
|
-
const BoardExtensionItemSchema = z.object({
|
|
599
|
-
...boxed(BOARD_DEFAULT_ITEM_SIZE),
|
|
600
|
-
type: z.string().regex(BOARD_EXTENSION_TYPE_PATTERN),
|
|
601
|
-
props: z.record(z.string(), z.unknown()).default({})
|
|
602
|
-
}).strict();
|
|
603
|
-
const BOARD_ITEM_SCHEMAS = {
|
|
604
|
-
frame: BoardFrameItemSchema,
|
|
605
|
-
text: BoardTextItemSchema,
|
|
606
|
-
shape: BoardShapeItemSchema,
|
|
607
|
-
draw: BoardDrawItemSchema,
|
|
608
|
-
arrow: BoardArrowItemSchema,
|
|
609
|
-
image: BoardImageItemSchema,
|
|
610
|
-
video: BoardVideoItemSchema,
|
|
611
|
-
audio: BoardAudioItemSchema,
|
|
612
|
-
file: BoardFileItemSchema,
|
|
613
|
-
task: BoardTaskItemSchema,
|
|
614
|
-
effect: BoardEffectItemSchema,
|
|
615
|
-
custom: BoardCustomItemSchema
|
|
616
|
-
};
|
|
617
|
-
const BOARD_ITEM_TYPES = Object.keys(BOARD_ITEM_SCHEMAS);
|
|
618
|
-
function isBuiltinItemType(type) {
|
|
619
|
-
return Object.hasOwn(BOARD_ITEM_SCHEMAS, type);
|
|
620
|
-
}
|
|
621
|
-
function boardItemSchema(type) {
|
|
622
|
-
if (isBuiltinItemType(type)) return BOARD_ITEM_SCHEMAS[type];
|
|
623
|
-
return BOARD_EXTENSION_TYPE_PATTERN.test(type) ? BoardExtensionItemSchema : null;
|
|
624
|
-
}
|
|
625
|
-
function issuesToDiagnostics(error, path) {
|
|
626
|
-
return error.issues.map((issue) => {
|
|
627
|
-
return {
|
|
628
|
-
severity: "error",
|
|
629
|
-
code: "INVALID_ITEM",
|
|
630
|
-
path: [path, ...issue.path.map(String)].filter(Boolean).join("."),
|
|
631
|
-
message: issue.code === "unrecognized_keys" ? `unknown ${issue.keys.length === 1 ? "property" : "properties"} ${issue.keys.join(", ")}` : issue.message
|
|
632
|
-
};
|
|
633
|
-
});
|
|
634
|
-
}
|
|
635
|
-
function parseBoardItem(value, path = "item") {
|
|
636
|
-
const type = value && typeof value === "object" && !Array.isArray(value) ? value.type : void 0;
|
|
637
|
-
if (typeof type !== "string") return {
|
|
638
|
-
ok: false,
|
|
639
|
-
diagnostics: [{
|
|
640
|
-
severity: "error",
|
|
641
|
-
code: "INVALID_ITEM",
|
|
642
|
-
path: `${path}.type`,
|
|
643
|
-
message: "type is required"
|
|
644
|
-
}]
|
|
645
|
-
};
|
|
646
|
-
const schema = boardItemSchema(type);
|
|
647
|
-
if (!schema) return {
|
|
648
|
-
ok: false,
|
|
649
|
-
diagnostics: [{
|
|
650
|
-
severity: "error",
|
|
651
|
-
code: "INVALID_ITEM",
|
|
652
|
-
path: `${path}.type`,
|
|
653
|
-
message: `unknown type ${type}; expected ${BOARD_ITEM_TYPES.join(", ")} or a namespaced extension type`
|
|
654
|
-
}]
|
|
655
|
-
};
|
|
656
|
-
const parsed = schema.safeParse(value);
|
|
657
|
-
return parsed.success ? {
|
|
658
|
-
ok: true,
|
|
659
|
-
item: parsed.data
|
|
660
|
-
} : {
|
|
661
|
-
ok: false,
|
|
662
|
-
diagnostics: issuesToDiagnostics(parsed.error, path)
|
|
663
|
-
};
|
|
664
|
-
}
|
|
665
|
-
const CSS_EASE_KEYWORDS = /* @__PURE__ */ new Set([
|
|
666
|
-
"linear",
|
|
667
|
-
"ease",
|
|
668
|
-
"ease-in",
|
|
669
|
-
"ease-out",
|
|
670
|
-
"ease-in-out",
|
|
671
|
-
"step-start",
|
|
672
|
-
"step-end"
|
|
673
|
-
]);
|
|
674
|
-
function isBoardEase(value) {
|
|
675
|
-
const ease = value.trim();
|
|
676
|
-
if (CSS_EASE_KEYWORDS.has(ease)) return true;
|
|
677
|
-
const bezier = /^cubic-bezier\(\s*([^,()]+),\s*([^,()]+),\s*([^,()]+),\s*([^,()]+)\)$/.exec(ease);
|
|
678
|
-
if (bezier) {
|
|
679
|
-
const [x1, , x2] = bezier.slice(1).map(Number);
|
|
680
|
-
return bezier.slice(1).every((part) => Number.isFinite(Number(part))) && x1 >= 0 && x1 <= 1 && x2 >= 0 && x2 <= 1;
|
|
681
|
-
}
|
|
682
|
-
return /^steps\(\s*[1-9]\d*\s*(?:,\s*(?:start|end|jump-start|jump-end|jump-none|jump-both)\s*)?\)$/.test(ease);
|
|
683
|
-
}
|
|
684
|
-
const BoardEaseSchema = z.string().max(120).refine(isBoardEase, "expected a CSS easing: linear, ease-in-out, cubic-bezier(…) or steps(…)");
|
|
685
|
-
const BoardKeyframeSchema = z.object({
|
|
686
|
-
at: nonNegative.describe("Time in milliseconds."),
|
|
687
|
-
value: z.unknown(),
|
|
688
|
-
ease: BoardEaseSchema.optional().describe("Easing into this keyframe: a CSS keyword, cubic-bezier() or steps(); defaults to linear.")
|
|
689
|
-
}).strict();
|
|
690
|
-
const BoardTrackSchema = z.object({
|
|
691
|
-
target: z.string().min(1).max(160).describe("An item id, camera, or another animation id (its time property nests that timeline)."),
|
|
692
|
-
property: z.string().min(1).max(200).describe("JSON path in the target, e.g. position, opacity, style.fill, props.text."),
|
|
693
|
-
keyframes: z.array(BoardKeyframeSchema).min(1).max(1e5).describe("Ordered by at. The value holds before the first and after the last keyframe."),
|
|
694
|
-
composite: z.enum(["replace", "add"]).default("replace").describe("replace: the latest-started track wins. add: positions and rotations add; scale and opacity multiply."),
|
|
695
|
-
interpolation: z.enum([
|
|
696
|
-
"auto",
|
|
697
|
-
"step",
|
|
698
|
-
"spline"
|
|
699
|
-
]).default("auto").describe("auto blends numbers, vectors and colors and steps other values; spline smooths position paths."),
|
|
700
|
-
orient: z.boolean().optional().describe("Rotate the item along its path.")
|
|
701
|
-
}).strict().superRefine((track, context) => {
|
|
702
|
-
for (let index = 1; index < track.keyframes.length; index += 1) if ((track.keyframes[index]?.at ?? 0) < (track.keyframes[index - 1]?.at ?? 0)) context.addIssue({
|
|
703
|
-
code: "custom",
|
|
704
|
-
message: "keyframes must be ordered by at",
|
|
705
|
-
path: [
|
|
706
|
-
"keyframes",
|
|
707
|
-
index,
|
|
708
|
-
"at"
|
|
709
|
-
]
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
const BoardMarkerSchema = z.object({
|
|
713
|
-
at: nonNegative,
|
|
714
|
-
label: z.string().max(280).optional(),
|
|
715
|
-
pause: z.boolean().optional().describe("Hold shared playback here until next.")
|
|
716
|
-
}).strict();
|
|
717
|
-
const BoardAnimationHeaderSchema = z.object({
|
|
718
|
-
name: z.string().max(280).optional(),
|
|
719
|
-
duration: finite$1.positive().max(864e5).describe("Milliseconds; a new animation without it ends at its last keyframe."),
|
|
720
|
-
play: z.enum([
|
|
721
|
-
"manual",
|
|
722
|
-
"auto",
|
|
723
|
-
"always"
|
|
724
|
-
]).default("manual").describe("manual: only shared playback starts it. auto: plays when the Board opens. always: loops continuously."),
|
|
725
|
-
delay: nonNegative.default(0),
|
|
726
|
-
loop: z.boolean().default(false),
|
|
727
|
-
end: z.enum(["hold", "reset"]).default("hold").describe("hold keeps the last frame; reset returns to the start."),
|
|
728
|
-
markers: z.array(BoardMarkerSchema).max(1e4).default([]).describe("Labeled points on this timeline; a nested animation's markers do not carry over.")
|
|
729
|
-
}).strict();
|
|
730
|
-
const BoardAnimationSchema = BoardAnimationHeaderSchema.extend({ tracks: z.record(BoardKeySchema, BoardTrackSchema).default({}) }).strict();
|
|
731
|
-
const BOARD_ENTER_PRESETS = [
|
|
732
|
-
"fade-in",
|
|
733
|
-
"rise",
|
|
734
|
-
"drop",
|
|
735
|
-
"pop",
|
|
736
|
-
"deal"
|
|
737
|
-
];
|
|
738
|
-
const BoardBackgroundSchema = z.object({
|
|
739
|
-
kind: z.enum([
|
|
740
|
-
"solid",
|
|
741
|
-
"dots",
|
|
742
|
-
"grid",
|
|
743
|
-
"image"
|
|
744
|
-
]).default("dots"),
|
|
745
|
-
color: BoardColorSchema.optional(),
|
|
746
|
-
imageUrl: z.string().url().max(4096).optional().describe("Background image for kind image."),
|
|
747
|
-
fit: z.enum([
|
|
748
|
-
"cover",
|
|
749
|
-
"contain",
|
|
750
|
-
"repeat"
|
|
751
|
-
]).optional(),
|
|
752
|
-
opacity: ratio.optional()
|
|
753
|
-
}).strict();
|
|
754
|
-
const BoardSettingsSchema = z.object({
|
|
755
|
-
title: z.string().min(1).max(255).optional(),
|
|
756
|
-
background: BoardBackgroundSchema.default({ kind: "dots" }),
|
|
757
|
-
grid: z.object({
|
|
758
|
-
visible: z.boolean().default(false).describe("Show the grid overlay."),
|
|
759
|
-
size: finite$1.min(4).max(512).default(24)
|
|
760
|
-
}).strict().optional(),
|
|
761
|
-
enter: z.object({
|
|
762
|
-
preset: z.enum(BOARD_ENTER_PRESETS),
|
|
763
|
-
duration: finite$1.positive().max(1e4).optional()
|
|
764
|
-
}).strict().optional().describe("Motion for items as they are added.")
|
|
765
|
-
}).strict();
|
|
766
|
-
const patchObject = z.record(z.string(), z.unknown());
|
|
767
|
-
const BoardPatchSchema = z.object({
|
|
768
|
-
board: patchObject.nullable().optional(),
|
|
769
|
-
items: z.record(BoardIdSchema, patchObject.nullable()).optional(),
|
|
770
|
-
animations: z.record(BoardIdSchema, patchObject.and(z.object({ tracks: z.record(BoardKeySchema, patchObject.nullable()).optional() })).nullable()).optional()
|
|
771
|
-
}).strict();
|
|
772
|
-
//#endregion
|
|
773
|
-
//#region ../protocol/dist/board.js
|
|
774
|
-
const BOARD_EXTENSION = ".board";
|
|
775
|
-
const BOARD_MIME_TYPE = "application/json";
|
|
776
|
-
z.object({
|
|
777
|
-
kind: z.literal("cohub.board.manifest"),
|
|
778
|
-
version: z.literal(1),
|
|
779
|
-
boardId: z.string().uuid(),
|
|
780
|
-
title: z.string().min(1).max(255)
|
|
781
|
-
});
|
|
782
|
-
const BOARD_READ_SECTIONS = ["items", "animations"];
|
|
783
|
-
const rectSchema = z.object({
|
|
784
|
-
x: z.number().finite(),
|
|
785
|
-
y: z.number().finite(),
|
|
786
|
-
width: z.number().finite().positive(),
|
|
787
|
-
height: z.number().finite().positive()
|
|
788
|
-
}).strict();
|
|
789
|
-
z.object({
|
|
790
|
-
only: z.array(z.enum(BOARD_READ_SECTIONS)).optional(),
|
|
791
|
-
rect: rectSchema.optional(),
|
|
792
|
-
within: BoardIdSchema.optional(),
|
|
793
|
-
items: z.array(z.string().min(1)).max(5e4).optional(),
|
|
794
|
-
animations: z.array(z.string().min(1)).max(1e4).optional(),
|
|
795
|
-
limit: z.number().int().min(1).max(5e4).optional(),
|
|
796
|
-
cursor: z.string().min(1).optional()
|
|
797
|
-
}).strict().refine((read) => !(read.cursor && (read.rect || read.within)), {
|
|
798
|
-
path: ["cursor"],
|
|
799
|
-
message: "cursor pages by id, so it cannot be combined with rect or within"
|
|
800
|
-
});
|
|
801
|
-
z.object({
|
|
802
|
-
patch: BoardPatchSchema,
|
|
803
|
-
replace: z.boolean().default(false),
|
|
804
|
-
cascade: z.boolean().default(false),
|
|
805
|
-
dryRun: z.boolean().default(false),
|
|
806
|
-
baseVersion: z.number().int().nonnegative().optional(),
|
|
807
|
-
mutationId: z.string().min(1).max(160).optional(),
|
|
808
|
-
clientId: z.string().min(1).max(160).optional()
|
|
809
|
-
}).strict();
|
|
810
|
-
z.object({
|
|
811
|
-
path: z.string().min(1),
|
|
812
|
-
title: z.string().min(1).max(255).optional(),
|
|
813
|
-
document: BoardPatchSchema.optional(),
|
|
814
|
-
mutationId: z.string().max(160).optional()
|
|
815
|
-
}).strict();
|
|
816
|
-
z.object({
|
|
817
|
-
before: z.number().int().positive().optional(),
|
|
818
|
-
limit: z.number().int().min(1).max(500).default(200)
|
|
819
|
-
}).strict();
|
|
820
|
-
const commandId = z.string().min(1).max(160);
|
|
821
|
-
z.discriminatedUnion("type", [
|
|
822
|
-
z.object({
|
|
823
|
-
commandId,
|
|
824
|
-
type: z.literal("play"),
|
|
825
|
-
animationId: z.string().min(1),
|
|
826
|
-
position: z.number().finite().nonnegative().optional(),
|
|
827
|
-
timeScale: z.number().finite().positive().max(4).optional(),
|
|
828
|
-
seed: z.string().min(1).max(160).optional()
|
|
829
|
-
}).strict(),
|
|
830
|
-
z.object({
|
|
831
|
-
commandId,
|
|
832
|
-
type: z.literal("pause")
|
|
833
|
-
}).strict(),
|
|
834
|
-
z.object({
|
|
835
|
-
commandId,
|
|
836
|
-
type: z.literal("resume")
|
|
837
|
-
}).strict(),
|
|
838
|
-
z.object({
|
|
839
|
-
commandId,
|
|
840
|
-
type: z.literal("seek"),
|
|
841
|
-
position: z.number().finite().nonnegative()
|
|
842
|
-
}).strict(),
|
|
843
|
-
z.object({
|
|
844
|
-
commandId,
|
|
845
|
-
type: z.literal("next")
|
|
846
|
-
}).strict(),
|
|
847
|
-
z.object({
|
|
848
|
-
commandId,
|
|
849
|
-
type: z.literal("stop")
|
|
850
|
-
}).strict()
|
|
851
|
-
]);
|
|
852
184
|
//#endregion
|
|
853
185
|
//#region ../protocol/dist/board-json.js
|
|
854
186
|
/** Structural equality for JSON-shaped semantic values. */
|
|
@@ -865,6 +197,128 @@ function boardJsonEquals(a, b) {
|
|
|
865
197
|
return keys.length === Object.keys(bRecord).length && keys.every((key) => Object.hasOwn(bRecord, key) && boardJsonEquals(aRecord[key], bRecord[key]));
|
|
866
198
|
}
|
|
867
199
|
//#endregion
|
|
200
|
+
//#region ../protocol/dist/generation/blocks.js
|
|
201
|
+
const EXCERPT_LIMIT = 240;
|
|
202
|
+
function asRecord(value) {
|
|
203
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
204
|
+
}
|
|
205
|
+
function cleanExcerpt(value, limit = EXCERPT_LIMIT) {
|
|
206
|
+
if (typeof value !== "string") return void 0;
|
|
207
|
+
const clean = value.replace(/\s+/g, " ").trim();
|
|
208
|
+
if (!clean) return void 0;
|
|
209
|
+
return clean.length > limit ? `${clean.slice(0, limit - 3).trimEnd()}...` : clean;
|
|
210
|
+
}
|
|
211
|
+
function blockText(block) {
|
|
212
|
+
return cleanExcerpt(block.text ?? block.content ?? block.value);
|
|
213
|
+
}
|
|
214
|
+
function blockUrl(block) {
|
|
215
|
+
const source = asRecord(block.source);
|
|
216
|
+
return normalizeBoardRemoteUrl(source?.url ?? source?.src ?? block.url ?? block.src);
|
|
217
|
+
}
|
|
218
|
+
function blockMimeType(block) {
|
|
219
|
+
const source = asRecord(block.source);
|
|
220
|
+
const value = source?.mediaType ?? source?.media_type ?? source?.mimeType ?? block.mediaType ?? block.media_type ?? block.mimeType;
|
|
221
|
+
return typeof value === "string" ? value : void 0;
|
|
222
|
+
}
|
|
223
|
+
function positiveNumber(value) {
|
|
224
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
225
|
+
}
|
|
226
|
+
function blockNaturalSize(block) {
|
|
227
|
+
const source = asRecord(block.source);
|
|
228
|
+
const naturalWidth = positiveNumber(source?.width ?? source?.naturalWidth ?? block.width ?? block.naturalWidth);
|
|
229
|
+
const naturalHeight = positiveNumber(source?.height ?? source?.naturalHeight ?? block.height ?? block.naturalHeight);
|
|
230
|
+
return {
|
|
231
|
+
...naturalWidth ? { naturalWidth } : {},
|
|
232
|
+
...naturalHeight ? { naturalHeight } : {}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function contentBlocks(value) {
|
|
236
|
+
return Array.isArray(value) ? value.filter((item) => asRecord(item)) : [];
|
|
237
|
+
}
|
|
238
|
+
function taskData(run) {
|
|
239
|
+
const payload = asRecord(run.payload);
|
|
240
|
+
return asRecord(payload?.data) ?? payload;
|
|
241
|
+
}
|
|
242
|
+
function generationOutput(run) {
|
|
243
|
+
return contentBlocks(asRecord(run.result)?.output);
|
|
244
|
+
}
|
|
245
|
+
function generationPrompt(run) {
|
|
246
|
+
for (const block of contentBlocks(taskData(run)?.content)) {
|
|
247
|
+
const text = blockText(block);
|
|
248
|
+
if (text) return text;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function blockMeta(block) {
|
|
252
|
+
return asRecord(block.meta);
|
|
253
|
+
}
|
|
254
|
+
function blockIdentity(block) {
|
|
255
|
+
const meta = blockMeta(block);
|
|
256
|
+
const value = meta?.id ?? meta?.clip_id ?? meta?.clipId ?? block.id ?? block.clip_id ?? block.clipId;
|
|
257
|
+
if (typeof value !== "string" && typeof value !== "number") return void 0;
|
|
258
|
+
return cleanExcerpt(String(value), 220);
|
|
259
|
+
}
|
|
260
|
+
function blockTitle(block) {
|
|
261
|
+
return cleanExcerpt(blockMeta(block)?.title ?? block.title ?? block.name, 240);
|
|
262
|
+
}
|
|
263
|
+
function blockDurationMs(block) {
|
|
264
|
+
const source = asRecord(block.source);
|
|
265
|
+
const meta = blockMeta(block);
|
|
266
|
+
const milliseconds = positiveNumber(source?.durationMs ?? meta?.durationMs ?? block.durationMs);
|
|
267
|
+
if (milliseconds) return Math.round(milliseconds);
|
|
268
|
+
const seconds = positiveNumber(source?.duration ?? meta?.duration ?? block.duration);
|
|
269
|
+
return seconds ? Math.round(seconds * 1e3) : void 0;
|
|
270
|
+
}
|
|
271
|
+
function blockPreviewUrl(block) {
|
|
272
|
+
const source = asRecord(block.source);
|
|
273
|
+
return normalizeBoardRemoteUrl(source?.poster ?? source?.thumbnail ?? source?.previewUrl ?? block.poster ?? block.thumbnail ?? block.previewUrl);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Image roles that depict playable media, by the media types they may cover;
|
|
277
|
+
* `last_frame` stays a result of its own.
|
|
278
|
+
*/
|
|
279
|
+
const COVER_ROLES = /* @__PURE__ */ new Map([
|
|
280
|
+
["first_frame", /* @__PURE__ */ new Set(["video"])],
|
|
281
|
+
["cover", /* @__PURE__ */ new Set(["video", "audio"])],
|
|
282
|
+
["poster", /* @__PURE__ */ new Set(["video", "audio"])],
|
|
283
|
+
["thumbnail", /* @__PURE__ */ new Set(["video", "audio"])]
|
|
284
|
+
]);
|
|
285
|
+
function isPlayable(block) {
|
|
286
|
+
return block.type === "video" || block.type === "audio";
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Pair playable media with its cover image, returning media index → cover
|
|
290
|
+
* index. An image sharing the provider id wins (music tracks and their art,
|
|
291
|
+
* shared by every media of that id); otherwise cover-role images pair in
|
|
292
|
+
* order with remaining media their role fits (a video and its `first_frame`).
|
|
293
|
+
* Covers need a remote URL, so an inline image is never folded away.
|
|
294
|
+
*/
|
|
295
|
+
function generationCovers(blocks) {
|
|
296
|
+
const covers = /* @__PURE__ */ new Map();
|
|
297
|
+
const isCover = (block) => block.type === "image" && blockUrl(block) !== void 0 && blockMeta(block)?.role !== "last_frame";
|
|
298
|
+
blocks.forEach((block, index) => {
|
|
299
|
+
const id = blockIdentity(block);
|
|
300
|
+
if (!isPlayable(block) || id === void 0) return;
|
|
301
|
+
const cover = blocks.findIndex((candidate) => isCover(candidate) && blockIdentity(candidate) === id);
|
|
302
|
+
if (cover >= 0) covers.set(index, cover);
|
|
303
|
+
});
|
|
304
|
+
const paired = new Set(covers.values());
|
|
305
|
+
const roleCovers = blocks.flatMap((block, index) => {
|
|
306
|
+
const role = blockMeta(block)?.role;
|
|
307
|
+
const types = typeof role === "string" ? COVER_ROLES.get(role) : void 0;
|
|
308
|
+
return isCover(block) && !paired.has(index) && types ? [{
|
|
309
|
+
index,
|
|
310
|
+
types
|
|
311
|
+
}] : [];
|
|
312
|
+
});
|
|
313
|
+
blocks.forEach((block, index) => {
|
|
314
|
+
if (!isPlayable(block) || covers.has(index)) return;
|
|
315
|
+
const at = roleCovers.findIndex(({ types }) => types.has(String(block.type)));
|
|
316
|
+
const [cover] = at < 0 ? [] : roleCovers.splice(at, 1);
|
|
317
|
+
if (cover) covers.set(index, cover.index);
|
|
318
|
+
});
|
|
319
|
+
return covers;
|
|
320
|
+
}
|
|
321
|
+
//#endregion
|
|
868
322
|
//#region ../protocol/dist/board-layout.js
|
|
869
323
|
const IDENTITY_MATRIX = [
|
|
870
324
|
1,
|
|
@@ -927,8 +381,14 @@ function estimateTextWidth(text, fontSize) {
|
|
|
927
381
|
}
|
|
928
382
|
return ems * fontSize;
|
|
929
383
|
}
|
|
930
|
-
function
|
|
931
|
-
|
|
384
|
+
function estimateLines(text, { fontSize }, maxWidth) {
|
|
385
|
+
const measure = (line) => estimateTextWidth(line, fontSize);
|
|
386
|
+
const paragraphs = text.split("\n");
|
|
387
|
+
const lines = maxWidth ? paragraphs.flatMap((paragraph) => wrapParagraph(paragraph, maxWidth, measure)) : paragraphs;
|
|
388
|
+
return {
|
|
389
|
+
lines,
|
|
390
|
+
width: lines.reduce((max, line) => Math.max(max, measure(line)), 0)
|
|
391
|
+
};
|
|
932
392
|
}
|
|
933
393
|
function wrapParagraph(paragraph, width, measure) {
|
|
934
394
|
if (!paragraph) return [""];
|
|
@@ -957,13 +417,15 @@ function layoutBoardText(props) {
|
|
|
957
417
|
const key = `${fontSize}|${props.fontWeight}|${props.font}|${props.lineHeight}|${props.width ?? ""}|${props.text}`;
|
|
958
418
|
const cached = textSizeCache.get(key);
|
|
959
419
|
if (cached) return cached;
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
420
|
+
const font = {
|
|
421
|
+
fontSize,
|
|
422
|
+
fontWeight: props.fontWeight ?? 500,
|
|
423
|
+
font: props.font ?? "sans"
|
|
424
|
+
};
|
|
425
|
+
const { lines, width } = estimateLines(props.text || "", font, props.width || void 0);
|
|
963
426
|
const lineHeight = fontSize * (props.lineHeight ?? 4 / 3);
|
|
964
|
-
const widest = lines.reduce((max, line) => Math.max(max, measure(line)), 0);
|
|
965
427
|
const layout = {
|
|
966
|
-
width: Math.max(props.width ?? 0,
|
|
428
|
+
width: Math.max(props.width ?? 0, width, fontSize * .5),
|
|
967
429
|
height: Math.max(1, lines.length) * lineHeight,
|
|
968
430
|
lines,
|
|
969
431
|
lineHeight
|
|
@@ -1918,128 +1380,6 @@ function parseBoardDocument(input) {
|
|
|
1918
1380
|
} : result;
|
|
1919
1381
|
}
|
|
1920
1382
|
//#endregion
|
|
1921
|
-
//#region ../protocol/dist/generation/blocks.js
|
|
1922
|
-
const EXCERPT_LIMIT = 240;
|
|
1923
|
-
function asRecord(value) {
|
|
1924
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1925
|
-
}
|
|
1926
|
-
function cleanExcerpt(value, limit = EXCERPT_LIMIT) {
|
|
1927
|
-
if (typeof value !== "string") return void 0;
|
|
1928
|
-
const clean = value.replace(/\s+/g, " ").trim();
|
|
1929
|
-
if (!clean) return void 0;
|
|
1930
|
-
return clean.length > limit ? `${clean.slice(0, limit - 3).trimEnd()}...` : clean;
|
|
1931
|
-
}
|
|
1932
|
-
function blockText(block) {
|
|
1933
|
-
return cleanExcerpt(block.text ?? block.content ?? block.value);
|
|
1934
|
-
}
|
|
1935
|
-
function blockUrl(block) {
|
|
1936
|
-
const source = asRecord(block.source);
|
|
1937
|
-
return normalizeBoardRemoteUrl(source?.url ?? source?.src ?? block.url ?? block.src);
|
|
1938
|
-
}
|
|
1939
|
-
function blockMimeType(block) {
|
|
1940
|
-
const source = asRecord(block.source);
|
|
1941
|
-
const value = source?.mediaType ?? source?.media_type ?? source?.mimeType ?? block.mediaType ?? block.media_type ?? block.mimeType;
|
|
1942
|
-
return typeof value === "string" ? value : void 0;
|
|
1943
|
-
}
|
|
1944
|
-
function positiveNumber(value) {
|
|
1945
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
1946
|
-
}
|
|
1947
|
-
function blockNaturalSize(block) {
|
|
1948
|
-
const source = asRecord(block.source);
|
|
1949
|
-
const naturalWidth = positiveNumber(source?.width ?? source?.naturalWidth ?? block.width ?? block.naturalWidth);
|
|
1950
|
-
const naturalHeight = positiveNumber(source?.height ?? source?.naturalHeight ?? block.height ?? block.naturalHeight);
|
|
1951
|
-
return {
|
|
1952
|
-
...naturalWidth ? { naturalWidth } : {},
|
|
1953
|
-
...naturalHeight ? { naturalHeight } : {}
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
function contentBlocks(value) {
|
|
1957
|
-
return Array.isArray(value) ? value.filter((item) => asRecord(item)) : [];
|
|
1958
|
-
}
|
|
1959
|
-
function taskData(run) {
|
|
1960
|
-
const payload = asRecord(run.payload);
|
|
1961
|
-
return asRecord(payload?.data) ?? payload;
|
|
1962
|
-
}
|
|
1963
|
-
function generationOutput(run) {
|
|
1964
|
-
return contentBlocks(asRecord(run.result)?.output);
|
|
1965
|
-
}
|
|
1966
|
-
function generationPrompt(run) {
|
|
1967
|
-
for (const block of contentBlocks(taskData(run)?.content)) {
|
|
1968
|
-
const text = blockText(block);
|
|
1969
|
-
if (text) return text;
|
|
1970
|
-
}
|
|
1971
|
-
}
|
|
1972
|
-
function blockMeta(block) {
|
|
1973
|
-
return asRecord(block.meta);
|
|
1974
|
-
}
|
|
1975
|
-
function blockIdentity(block) {
|
|
1976
|
-
const meta = blockMeta(block);
|
|
1977
|
-
const value = meta?.id ?? meta?.clip_id ?? meta?.clipId ?? block.id ?? block.clip_id ?? block.clipId;
|
|
1978
|
-
if (typeof value !== "string" && typeof value !== "number") return void 0;
|
|
1979
|
-
return cleanExcerpt(String(value), 220);
|
|
1980
|
-
}
|
|
1981
|
-
function blockTitle(block) {
|
|
1982
|
-
return cleanExcerpt(blockMeta(block)?.title ?? block.title ?? block.name, 240);
|
|
1983
|
-
}
|
|
1984
|
-
function blockDurationMs(block) {
|
|
1985
|
-
const source = asRecord(block.source);
|
|
1986
|
-
const meta = blockMeta(block);
|
|
1987
|
-
const milliseconds = positiveNumber(source?.durationMs ?? meta?.durationMs ?? block.durationMs);
|
|
1988
|
-
if (milliseconds) return Math.round(milliseconds);
|
|
1989
|
-
const seconds = positiveNumber(source?.duration ?? meta?.duration ?? block.duration);
|
|
1990
|
-
return seconds ? Math.round(seconds * 1e3) : void 0;
|
|
1991
|
-
}
|
|
1992
|
-
function blockPreviewUrl(block) {
|
|
1993
|
-
const source = asRecord(block.source);
|
|
1994
|
-
return normalizeBoardRemoteUrl(source?.poster ?? source?.thumbnail ?? source?.previewUrl ?? block.poster ?? block.thumbnail ?? block.previewUrl);
|
|
1995
|
-
}
|
|
1996
|
-
/**
|
|
1997
|
-
* Image roles that depict playable media, by the media types they may cover;
|
|
1998
|
-
* `last_frame` stays a result of its own.
|
|
1999
|
-
*/
|
|
2000
|
-
const COVER_ROLES = /* @__PURE__ */ new Map([
|
|
2001
|
-
["first_frame", /* @__PURE__ */ new Set(["video"])],
|
|
2002
|
-
["cover", /* @__PURE__ */ new Set(["video", "audio"])],
|
|
2003
|
-
["poster", /* @__PURE__ */ new Set(["video", "audio"])],
|
|
2004
|
-
["thumbnail", /* @__PURE__ */ new Set(["video", "audio"])]
|
|
2005
|
-
]);
|
|
2006
|
-
function isPlayable(block) {
|
|
2007
|
-
return block.type === "video" || block.type === "audio";
|
|
2008
|
-
}
|
|
2009
|
-
/**
|
|
2010
|
-
* Pair playable media with its cover image, returning media index → cover
|
|
2011
|
-
* index. An image sharing the provider id wins (music tracks and their art,
|
|
2012
|
-
* shared by every media of that id); otherwise cover-role images pair in
|
|
2013
|
-
* order with remaining media their role fits (a video and its `first_frame`).
|
|
2014
|
-
* Covers need a remote URL, so an inline image is never folded away.
|
|
2015
|
-
*/
|
|
2016
|
-
function generationCovers(blocks) {
|
|
2017
|
-
const covers = /* @__PURE__ */ new Map();
|
|
2018
|
-
const isCover = (block) => block.type === "image" && blockUrl(block) !== void 0 && blockMeta(block)?.role !== "last_frame";
|
|
2019
|
-
blocks.forEach((block, index) => {
|
|
2020
|
-
const id = blockIdentity(block);
|
|
2021
|
-
if (!isPlayable(block) || id === void 0) return;
|
|
2022
|
-
const cover = blocks.findIndex((candidate) => isCover(candidate) && blockIdentity(candidate) === id);
|
|
2023
|
-
if (cover >= 0) covers.set(index, cover);
|
|
2024
|
-
});
|
|
2025
|
-
const paired = new Set(covers.values());
|
|
2026
|
-
const roleCovers = blocks.flatMap((block, index) => {
|
|
2027
|
-
const role = blockMeta(block)?.role;
|
|
2028
|
-
const types = typeof role === "string" ? COVER_ROLES.get(role) : void 0;
|
|
2029
|
-
return isCover(block) && !paired.has(index) && types ? [{
|
|
2030
|
-
index,
|
|
2031
|
-
types
|
|
2032
|
-
}] : [];
|
|
2033
|
-
});
|
|
2034
|
-
blocks.forEach((block, index) => {
|
|
2035
|
-
if (!isPlayable(block) || covers.has(index)) return;
|
|
2036
|
-
const at = roleCovers.findIndex(({ types }) => types.has(String(block.type)));
|
|
2037
|
-
const [cover] = at < 0 ? [] : roleCovers.splice(at, 1);
|
|
2038
|
-
if (cover) covers.set(index, cover.index);
|
|
2039
|
-
});
|
|
2040
|
-
return covers;
|
|
2041
|
-
}
|
|
2042
|
-
//#endregion
|
|
2043
1383
|
//#region ../protocol/dist/turn-origin.js
|
|
2044
1384
|
const record$1 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2045
1385
|
const normalizeSessionTurnOrigin = (value) => {
|
|
@@ -7795,4 +7135,4 @@ function generationOutputSource(result, outputIndex) {
|
|
|
7795
7135
|
return `data:${declared && MEDIA_TYPE_PATTERN.test(declared) ? declared : DEFAULT_MEDIA_TYPES[String(block.type)] ?? "application/octet-stream"};base64,${data}`;
|
|
7796
7136
|
}
|
|
7797
7137
|
//#endregion
|
|
7798
|
-
export { APP_APPEARANCE_TOKENS, APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_DEVICES, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRoomRtc, AppRtcChannel, AppRtcError, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppRuntimeError, AppSurfaceApi, AppWindowApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_COLOR_TOKENS, BOARD_ITEM_TYPES, BillingApi, BoardAnimationSchema, BoardClient, BoardPatchSchema, BoardTrackSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DESKTOP_COMMAND_ACCEPT_TIMEOUT_MS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_OPEN_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, DISPLAY_ACTION_TYPES, DISPLAY_ELEMENT_REF_PATTERN, DISPLAY_SYSTEM_ACTIONS, DesktopCommandsApi, DisplayActionError, DisplayConnection, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HOME_SPACE_SLUG, HttpError, LOCAL_HARNESSES, LOCAL_HARNESS_SPECS, NATIVE_INGEST_MAX_TURNS, NATIVE_SYNC_SOURCE, OriginBrokerTransport, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, RUNTIME_ARCHIVE_SEGMENT_BYTES, RUNTIME_MAX_FRAME_BYTES, RUNTIME_PROTOCOL_VERSION, RUNTIME_RECOVERY_BATCH_SIZE, ReferencesApi, ReferralsApi, RoomsApi, SETTLED_TURN_STATUSES, SessionGenerationStreamClient, SessionPatchReducer, SpaceDisplaysApi, SpacePublicFilesApi, SpaceWebhooksApi, UPLOAD_ERROR_BATCH_TOO_LARGE, UPLOAD_ERROR_FILE_TOO_LARGE, UPLOAD_ERROR_RATE_LIMITED, UPLOAD_ERROR_TOO_MANY_FILES, UPLOAD_MAX_BATCH_BYTES, UPLOAD_MAX_BATCH_FILES, UPLOAD_MAX_FILE_BYTES, USER_LEVEL_PERMISSIONS, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, appAppearanceVar, applyAppAppearance, assertGenerationRequestAllowedByPolicy, assertHarnessAccess, attachAppEmbed, batchUploadEntries, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileDisplayActions, connectDisplay, contextToPiMessages, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createCohubClient, createHttpClient, createOriginAppResolver, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, defaultDesktopCommandTimeoutMs, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, filterSpacePickerItems, findGenerationModelPolicy, fingerprintProjectionTurns, formatAppRef, formatWorkRef, generationOutputSource, getAllowedGenerationModelIds, getCohubContext, harnessArchiveIndexSchema, harnessLabel, harnessSchema, hasGrantedAppScopes, hasRequestSourceIdentity, isActiveGenerationTask, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isLocalHarness, isNativeClientTurn, isProjectionCompaction, isProjectionPendingGeneration, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isTextMime, isUserLevelPermission, isUuid, isWorkId, joinApiUrl, localHarnessSchema, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, mimeTypeForPath, nativeIngestTurnSchema, nativeRuntimeEventSchema, nativeTurnCompleteSchema, nativeTurnProgressSchema, normalizeBaseUrl, normalizeDisplayPoint, normalizeGenerationPolicy, normalizeRequestSource, normalizeSessionTurnOrigin, normalizeSpacePickerQuery, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, orderSpacePickerItems, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardDocument, parseBoardItem, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseSpaceRef, parseWorkRef, projectNativeMessageMeta, projectNativeSession, readRequestSourceFromEnv, readSentTurns, readSessionTurnOrigin, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveHarness, resolveOpenSurface, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebBaseUrl, resolveWebsocketUrl, runtimeCommandSchema, runtimeEventSchema, runtimeNativeStopSchema, runtimeReadySchema, sanitizeAccessToken, scopeListHasPermission, selectRuntimeContextMessages, selectSpacePickerItems, serializeProjection, serializeProjectionRecords, setGrantedAppScopes, toGenerationTaskView, trimProjectionTurnsToCompaction, validateArchiveBoundary };
|
|
7138
|
+
export { APP_APPEARANCE_TOKENS, APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_DEVICES, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRoomRtc, AppRtcChannel, AppRtcError, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppRuntimeError, AppSurfaceApi, AppWindowApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_COLOR_TOKENS, BOARD_ITEM_TYPES, BillingApi, BoardAnimationSchema, BoardClient, BoardPatchSchema, BoardTrackSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DESKTOP_COMMAND_ACCEPT_TIMEOUT_MS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_OPEN_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, DISPLAY_ACTION_TYPES, DISPLAY_ELEMENT_REF_PATTERN, DISPLAY_SYSTEM_ACTIONS, DesktopCommandsApi, DisplayActionError, DisplayConnection, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HOME_SPACE_SLUG, HttpError, LOCAL_HARNESSES, LOCAL_HARNESS_SPECS, NATIVE_INGEST_MAX_TURNS, NATIVE_SYNC_SOURCE, OriginBrokerTransport, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, RUNTIME_ARCHIVE_SEGMENT_BYTES, RUNTIME_MAX_FRAME_BYTES, RUNTIME_PROTOCOL_VERSION, RUNTIME_RECOVERY_BATCH_SIZE, ReferencesApi, ReferralsApi, RoomsApi, SETTLED_TURN_STATUSES, SessionGenerationStreamClient, SessionPatchReducer, SpaceDisplaysApi, SpacePublicFilesApi, SpaceWebhooksApi, UPLOAD_ERROR_BATCH_TOO_LARGE, UPLOAD_ERROR_FILE_TOO_LARGE, UPLOAD_ERROR_RATE_LIMITED, UPLOAD_ERROR_TOO_MANY_FILES, UPLOAD_MAX_BATCH_BYTES, UPLOAD_MAX_BATCH_FILES, UPLOAD_MAX_FILE_BYTES, USER_LEVEL_PERMISSIONS, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, appAppearanceVar, applyAppAppearance, assertGenerationRequestAllowedByPolicy, assertHarnessAccess, attachAppEmbed, batchUploadEntries, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, buildViewportContentBlock, clearGrantedAppScopes, compileDisplayActions, connectDisplay, contextToPiMessages, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createCohubClient, createHttpClient, createOriginAppResolver, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, defaultDesktopCommandTimeoutMs, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, filterSpacePickerItems, findGenerationModelPolicy, fingerprintProjectionTurns, formatAppRef, formatWorkRef, generationOutputSource, getAllowedGenerationModelIds, getCohubContext, harnessArchiveIndexSchema, harnessLabel, harnessSchema, hasGrantedAppScopes, hasRequestSourceIdentity, isActiveGenerationTask, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isLocalHarness, isNativeClientTurn, isProjectionCompaction, isProjectionPendingGeneration, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isTextMime, isUserLevelPermission, isUuid, isWorkId, joinApiUrl, localHarnessSchema, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, mimeTypeForPath, nativeIngestTurnSchema, nativeRuntimeEventSchema, nativeTurnCompleteSchema, nativeTurnProgressSchema, normalizeBaseUrl, normalizeDisplayPoint, normalizeGenerationPolicy, normalizeRequestSource, normalizeSessionTurnOrigin, normalizeSpacePickerQuery, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, orderSpacePickerItems, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardDocument, parseBoardItem, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseSpaceRef, parseWorkRef, projectNativeMessageMeta, projectNativeSession, readRequestSourceFromEnv, readSentTurns, readSessionTurnOrigin, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveHarness, resolveOpenSurface, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebBaseUrl, resolveWebsocketUrl, runtimeCommandSchema, runtimeEventSchema, runtimeNativeStopSchema, runtimeReadySchema, sanitizeAccessToken, scopeListHasPermission, selectRuntimeContextMessages, selectSpacePickerItems, serializeProjection, serializeProjectionRecords, setGrantedAppScopes, toGenerationTaskView, trimProjectionTurnsToCompaction, validateArchiveBoundary };
|