@neta-art/cohub 5.10.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -46
- package/dist/board/animation.d.ts +156 -67
- package/dist/board/animation.js +161 -305
- package/dist/board/geometry.js +4 -4
- package/dist/board/index.d.ts +4 -4
- package/dist/board/index.js +3 -4
- package/dist/board/mutation.d.ts +5 -11
- package/dist/board/mutation.js +9 -46
- package/dist/chunks/http.d.ts +23 -12
- package/dist/chunks/http.js +674 -316
- package/dist/chunks/websocket.d.ts +2623 -201
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +158 -299
- package/dist/index.js +164 -306
- package/dist/protocol/dist/board-authoring.d.ts +1 -0
- package/dist/protocol/dist/board-authoring.js +217 -0
- package/dist/protocol/dist/board-capability-registry.d.ts +2 -0
- package/dist/protocol/dist/board-capability-registry.js +74 -0
- package/dist/protocol/dist/board-codec.d.ts +2 -0
- package/dist/protocol/dist/board-codec.js +4 -0
- package/dist/protocol/dist/board-composition.d.ts +258 -0
- package/dist/protocol/dist/board-composition.js +318 -0
- package/dist/protocol/dist/board-constants.js +0 -25
- package/dist/protocol/dist/board-node.d.ts +1 -12
- package/dist/protocol/dist/board-node.js +1 -81
- package/dist/protocol/dist/board-upgrade.d.ts +1 -0
- package/dist/protocol/dist/board-upgrade.js +2 -0
- package/dist/protocol/dist/board.d.ts +19 -92
- package/dist/protocol/dist/board.js +18 -78
- package/dist/protocol/dist/index.d.ts +8 -3
- package/dist/protocol/dist/index.js +9 -4
- package/dist/types.d.ts +2 -1
- package/docs/work-runtime-guide.md +19 -3
- package/package.json +3 -2
- package/dist/board/nodes.d.ts +0 -113
- package/dist/board/nodes.js +0 -154
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as BOARD_GEO_KINDS, A as buildWorkComposerChipSet, B as UI_COMMAND_MAX_TIMEOUT_MS, C as ensureRealtimeConnected, Ct as SkillsApi, D as WORK_SURFACE_READY_TIMEOUT_MS, Dt as CronJobsApi, E as WORK_COMPOSER_CHIP_LABEL_MAX_LENGTH, Et as GenerationsApi, F as parseWorkComposerChipSet, G as UI_COMMAND_VERSION, H as UI_COMMAND_PENDING_TTL_SECONDS, I as parseWorkSurfaceReady, J as parseUiCommand, K as isTerminalUiCommandStatus, L as parseWorkSurfaceRequest, M as buildWorkSurfaceRequest, N as buildWorkSurfaceResponse, O as WORK_SURFACE_REQUEST_TIMEOUT_MS, Ot as ChannelsApi, P as parseWorkComposerChipClear, Q as BOARD_COLOR_IDS, R as parseWorkSurfaceResponse, S as createSessionPatchReducer, St as PublicAssetsApi, T as WORK_COMPOSER_CHIP_KEY_MAX_LENGTH, Tt as ModelsApi, U as UI_COMMAND_SETTLEMENT_GRACE_SECONDS, V as UI_COMMAND_PAYLOAD_MAX_BYTES, W as UI_COMMAND_TERMINAL_TTL_SECONDS, X as parseUsername, Y as parseSpaceSlug, Z as BoardAwarenessClientPayloadSchema, _ as buildSpacePath, _t as BOARD_BUILTIN_CAPABILITIES, a as ReferralsApi, at as BoardEffectSchema, b as parseAssistantMessageCommit, bt as ReferencesApi, c as UiCommandsApi, ct as BoardAuthoringItemSchema, d as BoardTransactionError, dt as BOARD_ANIMATION_CHANNEL_CAPABILITIES, et as BOARD_NATIVE_NODE_TYPES, f as SpaceClient, ft as BoardCompositionInputSchema, g as buildSpaceInvitePath, gt as parseBoardCompositionInput, h as PublicInviteApi, ht as BoardTrackSchema, i as WorksApi, it as validateBuiltinBoardClip, j as buildWorkSurfaceReady, k as buildWorkComposerChipClear, l as TasksApi, lt as BoardItemPatchSchema, m as SpacesApi, mt as BoardProceduralClipSchema, n as createHttpClient, nt as validateBoardNodeInput, o as UsersApi, ot as BoardPlaybackPolicySchema, p as SpacePublicFilesApi, pt as BoardCompositionSchema, q as isUiSurfaceMethod, r as WorkCommerceApi, rt as estimateBuiltinBoardClipCost, s as UserApi, st as parseBoardPlaybackPolicy, t as CohubHttpClient, tt as BOARD_NODE_CONTRACT, u as BoardClient, ut as BOARD_ANIMATION_CHANNELS, v as SessionGenerationStreamClient, vt as DEFAULT_BOARD_RENDER_LIMITS, w as WORK_COMPOSER_CHIP_CONTENT_MAX_BYTES, wt as PromptsApi, x as SessionPatchReducer, xt as SearchApi, y as createSessionGenerationStreamClient, yt as SessionAccessApi, z as UI_COMMAND_DEFAULT_TIMEOUT_MS } from "./chunks/http.js";
|
|
2
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";
|
|
@@ -1934,6 +1934,7 @@ function createWorkBridgeCore(config) {
|
|
|
1934
1934
|
try {
|
|
1935
1935
|
if (data.type === "cohub.work.context") {
|
|
1936
1936
|
const workScopes = clonePermissionScopes(work.workScopes);
|
|
1937
|
+
const viewerUuid = await getViewerUuid();
|
|
1937
1938
|
reply(data.requestId, {
|
|
1938
1939
|
type: "cohub.work.context.result",
|
|
1939
1940
|
context: {
|
|
@@ -1943,6 +1944,8 @@ function createWorkBridgeCore(config) {
|
|
|
1943
1944
|
url: typeof location !== "undefined" ? location.href : ""
|
|
1944
1945
|
},
|
|
1945
1946
|
space: { id: work.spaceId },
|
|
1947
|
+
viewer: viewerUuid ? { userUuid: viewerUuid } : null,
|
|
1948
|
+
...config.invocation ? { invocation: { ...config.invocation } } : {},
|
|
1946
1949
|
permissions: {
|
|
1947
1950
|
scopes: workScopes,
|
|
1948
1951
|
workScopes,
|
|
@@ -2135,281 +2138,146 @@ function createWorkBridgeCore(config) {
|
|
|
2135
2138
|
}
|
|
2136
2139
|
//#endregion
|
|
2137
2140
|
//#region src/board/animation.ts
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
vertices: 0,
|
|
2141
|
-
dynamicVertices: 0,
|
|
2142
|
-
drawCalls: 0,
|
|
2143
|
-
filterPasses: 0,
|
|
2144
|
-
renderTexturePixels: 0,
|
|
2145
|
-
textureBytes: 0,
|
|
2146
|
-
bufferBytes: 0,
|
|
2147
|
-
simulationSteps: 0
|
|
2148
|
-
};
|
|
2149
|
-
const DEFAULT_BOARD_LIMITS = DEFAULT_BOARD_RENDER_LIMITS;
|
|
2150
|
-
const BUILTIN_CAPABILITIES = BOARD_BUILTIN_CAPABILITIES;
|
|
2151
|
-
function numericParam(params, key, fallback) {
|
|
2152
|
-
const value = params[key];
|
|
2153
|
-
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
2141
|
+
function track(input) {
|
|
2142
|
+
return BoardTrackSchema.parse(input);
|
|
2154
2143
|
}
|
|
2155
|
-
function
|
|
2156
|
-
return {
|
|
2157
|
-
...
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
path: "params.bounds",
|
|
2174
|
-
coordinateSpace: "world"
|
|
2175
|
-
});
|
|
2176
|
-
else {
|
|
2177
|
-
const value = bounds;
|
|
2178
|
-
if (![
|
|
2179
|
-
value.x,
|
|
2180
|
-
value.y,
|
|
2181
|
-
value.width,
|
|
2182
|
-
value.height
|
|
2183
|
-
].every((item) => typeof item === "number" && Number.isFinite(item)) || value.width <= 0 || value.height <= 0) diagnostics.push({
|
|
2184
|
-
severity: "error",
|
|
2185
|
-
code: "INVALID_PARTICLE_BOUNDS",
|
|
2186
|
-
message: "particle bounds must have a positive finite size",
|
|
2187
|
-
path: "params.bounds",
|
|
2188
|
-
coordinateSpace: "world"
|
|
2189
|
-
});
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
if (capability.id === "motion.path") {
|
|
2193
|
-
const points = params.points;
|
|
2194
|
-
if (!Array.isArray(points) || points.length < 2 || points.length > 1e4) diagnostics.push({
|
|
2195
|
-
severity: "error",
|
|
2196
|
-
code: "INVALID_MOTION_PATH",
|
|
2197
|
-
message: "motion path must contain 2 to 10000 world-offset points",
|
|
2198
|
-
path: "params.points",
|
|
2199
|
-
coordinateSpace: "world-offset"
|
|
2200
|
-
});
|
|
2201
|
-
}
|
|
2202
|
-
if (capability.id === "camera.focus") {
|
|
2203
|
-
const parsed = BoardCameraFocusParamsSchema.safeParse(params);
|
|
2204
|
-
if (!parsed.success) diagnostics.push({
|
|
2205
|
-
severity: "error",
|
|
2206
|
-
code: "INVALID_CAMERA_FOCUS",
|
|
2207
|
-
message: parsed.error.issues[0]?.message ?? "invalid camera focus",
|
|
2208
|
-
path: "params",
|
|
2209
|
-
coordinateSpace: "world"
|
|
2210
|
-
});
|
|
2211
|
-
}
|
|
2212
|
-
return diagnostics;
|
|
2144
|
+
function proceduralClip(input) {
|
|
2145
|
+
return BoardProceduralClipSchema.parse({
|
|
2146
|
+
...input,
|
|
2147
|
+
kindVersion: input.kindVersion ?? 1
|
|
2148
|
+
});
|
|
2149
|
+
}
|
|
2150
|
+
function composition(input) {
|
|
2151
|
+
return BoardCompositionSchema.parse(input);
|
|
2152
|
+
}
|
|
2153
|
+
function compileComposition(input) {
|
|
2154
|
+
return composition({
|
|
2155
|
+
id: input.id,
|
|
2156
|
+
name: input.name,
|
|
2157
|
+
timeline: {
|
|
2158
|
+
duration: input.duration,
|
|
2159
|
+
tracks: (input.tracks ?? []).map(track),
|
|
2160
|
+
clips: (input.clips ?? []).map(proceduralClip),
|
|
2161
|
+
markers: input.markers ?? []
|
|
2213
2162
|
},
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
return [
|
|
2219
|
-
value.x,
|
|
2220
|
-
value.y,
|
|
2221
|
-
value.width,
|
|
2222
|
-
value.height
|
|
2223
|
-
].every((item) => typeof item === "number" && Number.isFinite(item)) ? value : null;
|
|
2163
|
+
playback: input.playback ?? {
|
|
2164
|
+
loop: false,
|
|
2165
|
+
endBehavior: "hold",
|
|
2166
|
+
reducedMotion: { mode: "base" }
|
|
2224
2167
|
},
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
const particles = Math.max(0, Math.floor(numericParam(params, "count", 0)));
|
|
2229
|
-
return {
|
|
2230
|
-
particles,
|
|
2231
|
-
vertices: particles * 4,
|
|
2232
|
-
dynamicVertices: particles * 4,
|
|
2233
|
-
drawCalls: 1,
|
|
2234
|
-
bufferBytes: particles * 48,
|
|
2235
|
-
simulationSteps: particles
|
|
2236
|
-
};
|
|
2237
|
-
}
|
|
2238
|
-
case "effects.trail": return {
|
|
2239
|
-
vertices: 32,
|
|
2240
|
-
dynamicVertices: 32,
|
|
2241
|
-
drawCalls: 1,
|
|
2242
|
-
bufferBytes: 1024,
|
|
2243
|
-
simulationSteps: 16
|
|
2244
|
-
};
|
|
2245
|
-
case "effects.impact":
|
|
2246
|
-
case "effects.flash": return {
|
|
2247
|
-
vertices: 64,
|
|
2248
|
-
drawCalls: 1
|
|
2249
|
-
};
|
|
2250
|
-
case "effects.color": return {
|
|
2251
|
-
drawCalls: 1,
|
|
2252
|
-
filterPasses: 1
|
|
2253
|
-
};
|
|
2254
|
-
case "draw.reveal":
|
|
2255
|
-
case "draw.handwrite": return {
|
|
2256
|
-
drawCalls: 1,
|
|
2257
|
-
dynamicVertices: 1
|
|
2258
|
-
};
|
|
2259
|
-
default: return {};
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2262
|
-
};
|
|
2168
|
+
metadata: input.metadata ?? {},
|
|
2169
|
+
revision: 0
|
|
2170
|
+
});
|
|
2263
2171
|
}
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2172
|
+
const clamp01 = (value) => Math.max(0, Math.min(1, value));
|
|
2173
|
+
function sampleEasing(easing, value) {
|
|
2174
|
+
const t = clamp01(value);
|
|
2175
|
+
switch (easing) {
|
|
2176
|
+
case "ease-in-quad": return t * t;
|
|
2177
|
+
case "ease-out-quad": return 1 - (1 - t) ** 2;
|
|
2178
|
+
case "ease-in-out-quad": return t < .5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
2179
|
+
case "ease-in-cubic": return t ** 3;
|
|
2180
|
+
case "ease-out-cubic": return 1 - (1 - t) ** 3;
|
|
2181
|
+
case "ease-in-out-cubic": return t < .5 ? 4 * t ** 3 : 1 - (-2 * t + 2) ** 3 / 2;
|
|
2182
|
+
case "ease-out-quart": return 1 - (1 - t) ** 4;
|
|
2183
|
+
case "ease-out-expo": return t === 1 ? 1 : 1 - 2 ** (-10 * t);
|
|
2184
|
+
default: return t;
|
|
2269
2185
|
}
|
|
2270
|
-
return (hash >>> 0).toString(36).padStart(7, "0");
|
|
2271
|
-
}
|
|
2272
|
-
function stableId(prefix, seed, path) {
|
|
2273
|
-
return `${prefix}_${stableHash(`${seed}:${path}`)}`;
|
|
2274
|
-
}
|
|
2275
|
-
function assertDuration(value, field) {
|
|
2276
|
-
if (!Number.isFinite(value) || value < 0) throw new TypeError(`${field} must be a finite non-negative number`);
|
|
2277
2186
|
}
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
};
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
return {
|
|
2287
|
-
type: "parallel",
|
|
2288
|
-
children
|
|
2289
|
-
};
|
|
2290
|
-
},
|
|
2291
|
-
sequence(...children) {
|
|
2292
|
-
return {
|
|
2293
|
-
type: "sequence",
|
|
2294
|
-
children
|
|
2295
|
-
};
|
|
2296
|
-
},
|
|
2297
|
-
stagger(each, ...children) {
|
|
2298
|
-
assertDuration(each, "stagger each");
|
|
2299
|
-
return {
|
|
2300
|
-
type: "stagger",
|
|
2301
|
-
each,
|
|
2302
|
-
children
|
|
2303
|
-
};
|
|
2304
|
-
},
|
|
2305
|
-
delay(duration, child) {
|
|
2306
|
-
assertDuration(duration, "delay duration");
|
|
2307
|
-
return {
|
|
2308
|
-
type: "delay",
|
|
2309
|
-
duration,
|
|
2310
|
-
child
|
|
2311
|
-
};
|
|
2312
|
-
},
|
|
2313
|
-
repeat(count, child) {
|
|
2314
|
-
if (!Number.isSafeInteger(count) || count < 1 || count > 1e3) throw new TypeError("repeat count must be an integer between 1 and 1000");
|
|
2315
|
-
return {
|
|
2316
|
-
type: "repeat",
|
|
2317
|
-
count,
|
|
2318
|
-
child
|
|
2319
|
-
};
|
|
2187
|
+
function interpolate(left, right, progress) {
|
|
2188
|
+
if (typeof left === "number" && typeof right === "number") return left + (right - left) * progress;
|
|
2189
|
+
if (left && right && typeof left === "object" && typeof right === "object" && !Array.isArray(left) && !Array.isArray(right)) {
|
|
2190
|
+
const a = left;
|
|
2191
|
+
const b = right;
|
|
2192
|
+
const result = {};
|
|
2193
|
+
for (const key of /* @__PURE__ */ new Set([...Object.keys(a), ...Object.keys(b)])) result[key] = interpolate(a[key], b[key], progress);
|
|
2194
|
+
return result;
|
|
2320
2195
|
}
|
|
2321
|
-
|
|
2322
|
-
function clip(input) {
|
|
2323
|
-
assertDuration(input.duration, "clip duration");
|
|
2324
|
-
if (input.duration === 0) throw new TypeError("clip duration must be greater than zero");
|
|
2325
|
-
return timeline.clip({
|
|
2326
|
-
id: input.id,
|
|
2327
|
-
kind: input.kind,
|
|
2328
|
-
kindVersion: input.kindVersion ?? 1,
|
|
2329
|
-
target: input.target,
|
|
2330
|
-
duration: input.duration,
|
|
2331
|
-
layer: input.layer ?? "content",
|
|
2332
|
-
fill: input.fill ?? "none",
|
|
2333
|
-
easing: input.easing ?? "linear",
|
|
2334
|
-
params: input.params ?? {},
|
|
2335
|
-
keyframes: input.keyframes ?? [],
|
|
2336
|
-
assetRefs: input.assetRefs ?? [],
|
|
2337
|
-
seed: input.seed,
|
|
2338
|
-
metadata: input.metadata ?? {}
|
|
2339
|
-
});
|
|
2196
|
+
return progress < 1 ? left : right;
|
|
2340
2197
|
}
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2198
|
+
/** Deterministically sample one validated Track without touching scene state. */
|
|
2199
|
+
function sampleTrack(trackValue, time) {
|
|
2200
|
+
const frames = trackValue.keyframes;
|
|
2201
|
+
const first = frames[0];
|
|
2202
|
+
const last = frames.at(-1);
|
|
2203
|
+
if (!first || !last) return null;
|
|
2204
|
+
if (time < first.time) {
|
|
2205
|
+
if (trackValue.fill !== "backwards" && trackValue.fill !== "both") return null;
|
|
2344
2206
|
return {
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
id: input.clip.id ?? stableId("clip", sequenceSeed, path),
|
|
2349
|
-
start: offset,
|
|
2350
|
-
seed: clipSeed
|
|
2351
|
-
}]
|
|
2207
|
+
target: trackValue.target,
|
|
2208
|
+
channel: trackValue.channel,
|
|
2209
|
+
value: first.value
|
|
2352
2210
|
};
|
|
2353
2211
|
}
|
|
2354
|
-
if (
|
|
2355
|
-
|
|
2212
|
+
if (time > last.time) {
|
|
2213
|
+
if (trackValue.fill !== "forwards" && trackValue.fill !== "both") return null;
|
|
2356
2214
|
return {
|
|
2357
|
-
|
|
2358
|
-
|
|
2215
|
+
target: trackValue.target,
|
|
2216
|
+
channel: trackValue.channel,
|
|
2217
|
+
value: last.value
|
|
2359
2218
|
};
|
|
2360
2219
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
const
|
|
2377
|
-
let duration = 0;
|
|
2378
|
-
for (const [index, child] of input.children.entries()) {
|
|
2379
|
-
const childOffset = input.type === "sequence" ? duration : input.type === "stagger" ? input.each * index : 0;
|
|
2380
|
-
const nested = flatten(child, offset + childOffset, sequenceSeed, `${path}.${index}`);
|
|
2381
|
-
clips.push(...nested.clips);
|
|
2382
|
-
duration = input.type === "sequence" ? duration + nested.duration : Math.max(duration, childOffset + nested.duration);
|
|
2383
|
-
}
|
|
2220
|
+
let low = 0;
|
|
2221
|
+
let high = frames.length;
|
|
2222
|
+
while (low < high) {
|
|
2223
|
+
const middle = low + high >>> 1;
|
|
2224
|
+
if ((frames[middle]?.time ?? Number.POSITIVE_INFINITY) <= time) low = middle + 1;
|
|
2225
|
+
else high = middle;
|
|
2226
|
+
}
|
|
2227
|
+
const left = frames[Math.max(0, low - 1)] ?? first;
|
|
2228
|
+
const right = frames[Math.min(frames.length - 1, low)] ?? last;
|
|
2229
|
+
if (left === right || trackValue.interpolation === "step") return {
|
|
2230
|
+
target: trackValue.target,
|
|
2231
|
+
channel: trackValue.channel,
|
|
2232
|
+
value: left.value
|
|
2233
|
+
};
|
|
2234
|
+
const span = Math.max(Number.EPSILON, right.time - left.time);
|
|
2235
|
+
const progress = sampleEasing(right.easing ?? "linear", (time - left.time) / span);
|
|
2384
2236
|
return {
|
|
2385
|
-
|
|
2386
|
-
|
|
2237
|
+
target: trackValue.target,
|
|
2238
|
+
channel: trackValue.channel,
|
|
2239
|
+
value: interpolate(left.value, right.value, progress)
|
|
2387
2240
|
};
|
|
2388
2241
|
}
|
|
2389
|
-
function
|
|
2390
|
-
const
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2242
|
+
function sampleCompositionTracks(value, time) {
|
|
2243
|
+
const position = Math.max(0, Math.min(value.timeline.duration, time));
|
|
2244
|
+
return value.timeline.tracks.flatMap((item) => {
|
|
2245
|
+
const sampled = sampleTrack(item, position);
|
|
2246
|
+
return sampled ? [sampled] : [];
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
const ZERO_COST = {
|
|
2250
|
+
particles: 0,
|
|
2251
|
+
vertices: 0,
|
|
2252
|
+
dynamicVertices: 0,
|
|
2253
|
+
drawCalls: 0,
|
|
2254
|
+
filterPasses: 0,
|
|
2255
|
+
renderTexturePixels: 0,
|
|
2256
|
+
textureBytes: 0,
|
|
2257
|
+
bufferBytes: 0,
|
|
2258
|
+
simulationSteps: 0
|
|
2259
|
+
};
|
|
2260
|
+
const DEFAULT_BOARD_LIMITS = DEFAULT_BOARD_RENDER_LIMITS;
|
|
2261
|
+
function builtinDefinition(capability) {
|
|
2394
2262
|
return {
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
duration: flattened.duration,
|
|
2399
|
-
seed: input.seed,
|
|
2400
|
-
restPose: input.restPose ?? {},
|
|
2401
|
-
metadata: input.metadata ?? {}
|
|
2263
|
+
...capability,
|
|
2264
|
+
validate() {
|
|
2265
|
+
return [];
|
|
2402
2266
|
},
|
|
2403
|
-
|
|
2404
|
-
|
|
2267
|
+
estimateCost(params) {
|
|
2268
|
+
return estimateBuiltinBoardClipCost({
|
|
2269
|
+
kind: capability.id,
|
|
2270
|
+
params
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2405
2273
|
};
|
|
2406
2274
|
}
|
|
2407
|
-
function addCost(target, source) {
|
|
2408
|
-
for (const key of Object.keys(target)) target[key] += source[key] ?? 0;
|
|
2409
|
-
}
|
|
2410
2275
|
var BoardExtensionRegistry = class {
|
|
2411
2276
|
#extensions = /* @__PURE__ */ new Map();
|
|
2412
2277
|
#presets = /* @__PURE__ */ new Map();
|
|
2278
|
+
constructor() {
|
|
2279
|
+
for (const capability of BOARD_BUILTIN_CAPABILITIES) this.register(builtinDefinition(capability));
|
|
2280
|
+
}
|
|
2413
2281
|
register(definition) {
|
|
2414
2282
|
const key = `${definition.kind}:${definition.id}@${definition.version}`;
|
|
2415
2283
|
const target = definition.kind === "preset" ? this.#presets : this.#extensions;
|
|
@@ -2418,9 +2286,15 @@ var BoardExtensionRegistry = class {
|
|
|
2418
2286
|
return this;
|
|
2419
2287
|
}
|
|
2420
2288
|
capabilities() {
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2289
|
+
return [...this.#extensions.values(), ...this.#presets.values()].map((definition) => ({
|
|
2290
|
+
kind: definition.kind,
|
|
2291
|
+
id: definition.id,
|
|
2292
|
+
version: definition.version,
|
|
2293
|
+
...definition.digest ? { digest: definition.digest } : {},
|
|
2294
|
+
...definition.renderers ? { renderers: definition.renderers } : {},
|
|
2295
|
+
...definition.fallbackId ? { fallbackId: definition.fallbackId } : {},
|
|
2296
|
+
...definition.schema ? { schema: definition.schema } : {}
|
|
2297
|
+
}));
|
|
2424
2298
|
}
|
|
2425
2299
|
compilePreset(id, version, params) {
|
|
2426
2300
|
const preset = this.#presets.get(`preset:${id}@${version}`);
|
|
@@ -2428,88 +2302,72 @@ var BoardExtensionRegistry = class {
|
|
|
2428
2302
|
return preset.compile(params);
|
|
2429
2303
|
}
|
|
2430
2304
|
validate(input) {
|
|
2305
|
+
const parsed = BoardCompositionSchema.safeParse(input.composition);
|
|
2306
|
+
if (!parsed.success) return {
|
|
2307
|
+
valid: false,
|
|
2308
|
+
diagnostics: parsed.error.issues.map((issue) => ({
|
|
2309
|
+
severity: "error",
|
|
2310
|
+
code: "INVALID_COMPOSITION",
|
|
2311
|
+
message: issue.message,
|
|
2312
|
+
path: issue.path.join(".")
|
|
2313
|
+
})),
|
|
2314
|
+
peakCost: { ...ZERO_COST }
|
|
2315
|
+
};
|
|
2431
2316
|
const diagnostics = [];
|
|
2317
|
+
const composition = parsed.data;
|
|
2318
|
+
const cost = { ...ZERO_COST };
|
|
2432
2319
|
const events = [];
|
|
2433
|
-
const
|
|
2434
|
-
const persistentCost = { ...ZERO_COST };
|
|
2435
|
-
for (const [index, effect] of (input.effects ?? []).entries()) {
|
|
2436
|
-
const definition = this.#extensions.get(`effect:${effect.kind}@${effect.kindVersion}`);
|
|
2437
|
-
if (!definition) {
|
|
2438
|
-
diagnostics.push({
|
|
2439
|
-
severity: "warning",
|
|
2440
|
-
code: "UNKNOWN_EFFECT",
|
|
2441
|
-
message: `No renderer is registered for ${effect.kind}@${effect.kindVersion}`,
|
|
2442
|
-
path: `effects.${index}`
|
|
2443
|
-
});
|
|
2444
|
-
continue;
|
|
2445
|
-
}
|
|
2446
|
-
diagnostics.push(...definition.validate?.(effect.params) ?? []);
|
|
2447
|
-
addCost(persistentCost, definition.estimateCost(effect.params, profile));
|
|
2448
|
-
}
|
|
2449
|
-
for (const [index, clip] of input.clips.entries()) {
|
|
2320
|
+
for (const clip of composition.timeline.clips) {
|
|
2450
2321
|
const definition = this.#extensions.get(`clip:${clip.kind}@${clip.kindVersion}`);
|
|
2451
2322
|
if (!definition) {
|
|
2452
2323
|
diagnostics.push({
|
|
2453
2324
|
severity: "warning",
|
|
2454
2325
|
code: "UNKNOWN_CLIP",
|
|
2455
|
-
message: `No renderer is registered for ${clip.kind}@${clip.kindVersion}
|
|
2456
|
-
path: `clips.${index}`
|
|
2326
|
+
message: `No renderer is registered for ${clip.kind}@${clip.kindVersion}`
|
|
2457
2327
|
});
|
|
2458
2328
|
continue;
|
|
2459
2329
|
}
|
|
2330
|
+
diagnostics.push(...validateBuiltinBoardClip(clip, `composition.timeline.clips.${clip.id}`));
|
|
2460
2331
|
diagnostics.push(...definition.validate?.(clip.params) ?? []);
|
|
2461
|
-
const
|
|
2462
|
-
|
|
2332
|
+
const estimate = definition.estimateCost(clip.params, input.profile ?? "high");
|
|
2333
|
+
const clipCost = { ...ZERO_COST };
|
|
2334
|
+
for (const key of Object.keys(clipCost)) clipCost[key] = estimate[key] ?? 0;
|
|
2463
2335
|
events.push({
|
|
2464
2336
|
at: clip.start,
|
|
2465
2337
|
direction: 1,
|
|
2466
|
-
cost
|
|
2467
|
-
}
|
|
2338
|
+
cost: clipCost
|
|
2339
|
+
});
|
|
2340
|
+
events.push({
|
|
2468
2341
|
at: clip.start + clip.duration,
|
|
2469
2342
|
direction: -1,
|
|
2470
|
-
cost
|
|
2471
|
-
});
|
|
2472
|
-
}
|
|
2473
|
-
const cameraFocusClips = input.clips.map((clip, index) => ({
|
|
2474
|
-
clip,
|
|
2475
|
-
index
|
|
2476
|
-
})).filter(({ clip }) => clip.kind === "camera.focus").sort((left, right) => left.clip.start - right.clip.start);
|
|
2477
|
-
for (let index = 1; index < cameraFocusClips.length; index += 1) {
|
|
2478
|
-
const previous = cameraFocusClips[index - 1];
|
|
2479
|
-
const currentFocus = cameraFocusClips[index];
|
|
2480
|
-
if (previous && currentFocus && currentFocus.clip.start < previous.clip.start + previous.clip.duration) diagnostics.push({
|
|
2481
|
-
severity: "error",
|
|
2482
|
-
code: "OVERLAPPING_CAMERA_FOCUS",
|
|
2483
|
-
message: "camera.focus clips must not overlap",
|
|
2484
|
-
path: `clips.${currentFocus.index}.start`
|
|
2343
|
+
cost: clipCost
|
|
2485
2344
|
});
|
|
2486
2345
|
}
|
|
2487
2346
|
events.sort((left, right) => left.at - right.at || left.direction - right.direction);
|
|
2488
|
-
const
|
|
2489
|
-
const
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
peak[key] = Math.max(peak[key], current[key]);
|
|
2347
|
+
const active = { ...ZERO_COST };
|
|
2348
|
+
for (const event of events) for (const key of Object.keys(active)) {
|
|
2349
|
+
active[key] += event.cost[key] * event.direction;
|
|
2350
|
+
cost[key] = Math.max(cost[key], active[key]);
|
|
2493
2351
|
}
|
|
2352
|
+
for (const effect of input.effects ?? []) if (effect.kind === "effects.pulse" || effect.kind === "effects.float") cost.drawCalls += 1;
|
|
2494
2353
|
const limits = input.limits ?? DEFAULT_BOARD_LIMITS;
|
|
2495
|
-
for (const key of Object.keys(
|
|
2354
|
+
for (const key of Object.keys(cost)) if (cost[key] > limits[key]) diagnostics.push({
|
|
2496
2355
|
severity: "warning",
|
|
2497
2356
|
code: "RENDER_BUDGET_EXCEEDED",
|
|
2498
|
-
message: `${key} peaks at ${
|
|
2357
|
+
message: `${key} peaks at ${cost[key]}, above ${limits[key]}`,
|
|
2499
2358
|
path: key,
|
|
2500
2359
|
adaptation: { quality: "lower" }
|
|
2501
2360
|
});
|
|
2502
2361
|
return {
|
|
2503
2362
|
valid: !diagnostics.some((item) => item.severity === "error"),
|
|
2504
2363
|
diagnostics,
|
|
2505
|
-
peakCost:
|
|
2364
|
+
peakCost: cost
|
|
2506
2365
|
};
|
|
2507
2366
|
}
|
|
2508
2367
|
};
|
|
2509
|
-
function createBoardExtensionRegistry(
|
|
2510
|
-
|
|
2511
|
-
if (input.builtins !== false) for (const capability of BUILTIN_CAPABILITIES) registry.register(builtinDefinition(capability));
|
|
2512
|
-
return registry;
|
|
2368
|
+
function createBoardExtensionRegistry() {
|
|
2369
|
+
return new BoardExtensionRegistry();
|
|
2513
2370
|
}
|
|
2371
|
+
const BOARD_CHANNELS = BOARD_ANIMATION_CHANNELS;
|
|
2514
2372
|
//#endregion
|
|
2515
|
-
export { BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BOARD_NATIVE_NODE_TYPES, BOARD_NODE_CONTRACT, BillingApi, BoardClient, BoardExtensionRegistry,
|
|
2373
|
+
export { BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BOARD_NATIVE_NODE_TYPES, BOARD_NODE_CONTRACT, BillingApi, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, 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, assertGenerationRequestAllowedByPolicy, buildSpaceInvitePath, buildSpacePath, buildWorkSurfaceRequest, clearGrantedWorkScopes, compileComposition, composition, 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, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardPlaybackPolicy, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseUiCommand, parseWorkRef, parseWorkSurfaceReady, parseWorkSurfaceResponse, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveCohubEnvironment, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, resolveWorkTransport, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, setGrantedWorkScopes, track, validateBoardNodeInput };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { z } from "zod";
|