@neta-art/cohub 8.11.0 → 8.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/board/animation.js +14 -2
- package/dist/board/core/file-preview.d.ts +2 -2
- package/dist/board/core/file-preview.js +2 -2
- package/dist/board/index.d.ts +2 -1
- package/dist/board/index.js +2 -1
- package/dist/board/mutation.js +2 -1
- package/dist/board/render/board-background.d.ts +16 -0
- package/dist/board/render/{themes/clean-theme.js → board-background.js} +28 -35
- package/dist/board/render/index.d.ts +3 -3
- package/dist/board/render/index.js +2 -2
- package/dist/board/render/renderers/file-card-renderer.js +3 -32
- package/dist/board/replay.d.ts +52 -0
- package/dist/board/replay.js +261 -0
- package/dist/board/semantic-document.d.ts +9 -2
- package/dist/board/semantic-document.js +1 -3
- package/dist/chunks/environment.d.ts +272 -7
- package/dist/chunks/environment.js +1 -0
- package/dist/chunks/http.d.ts +76 -5
- package/dist/chunks/http.js +47 -10
- package/dist/chunks/websocket.d.ts +1 -1
- package/dist/http.d.ts +3 -3
- package/dist/index.d.ts +9 -4
- package/dist/index.js +167 -46
- package/dist/protocol/dist/board-animation.d.ts +1 -0
- package/dist/protocol/dist/board-animation.js +34 -0
- package/dist/protocol/dist/board-authoring.d.ts +2 -1
- package/dist/protocol/dist/board-capability-registry.js +53 -3
- package/dist/protocol/dist/board-codec.js +149 -2
- package/dist/protocol/dist/board-constants.js +29 -7
- package/dist/protocol/dist/board-document.d.ts +30 -16
- package/dist/protocol/dist/board-document.js +15 -12
- package/dist/protocol/dist/board-effect.d.ts +4 -2
- package/dist/protocol/dist/board-effect.js +3 -2
- package/dist/protocol/dist/board.d.ts +148 -3
- package/dist/protocol/dist/board.js +7 -0
- package/dist/protocol/dist/index.d.ts +4 -2
- package/dist/protocol/dist/provenance.d.ts +21 -0
- package/dist/types.d.ts +1 -1
- package/docs/app-runtime-guide.md +7 -4
- package/package.json +1 -1
- package/dist/board/render/themes/board-theme-registry.d.ts +0 -22
- package/dist/board/render/themes/board-theme-registry.js +0 -13
- package/dist/board/render/themes/clean-theme.d.ts +0 -5
package/dist/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import { z } from "zod";
|
|
|
8
8
|
const BOARD_DOCUMENT_KIND = "cohub.board";
|
|
9
9
|
const BOARD_MANIFEST_KIND = "cohub.board.manifest";
|
|
10
10
|
const idSchema = z.string().min(1).max(160);
|
|
11
|
-
const jsonObjectSchema = z.record(z.string(), z.unknown());
|
|
12
|
-
const finiteSchema = z.number().finite();
|
|
11
|
+
const jsonObjectSchema$1 = z.record(z.string(), z.unknown());
|
|
12
|
+
const finiteSchema$1 = z.number().finite();
|
|
13
13
|
z.object({
|
|
14
14
|
kind: z.literal(BOARD_MANIFEST_KIND),
|
|
15
15
|
version: z.literal(1),
|
|
@@ -17,18 +17,18 @@ z.object({
|
|
|
17
17
|
title: z.string().min(1).max(255)
|
|
18
18
|
});
|
|
19
19
|
z.object({
|
|
20
|
-
centerX: finiteSchema,
|
|
21
|
-
centerY: finiteSchema,
|
|
22
|
-
zoom: finiteSchema.positive()
|
|
20
|
+
centerX: finiteSchema$1,
|
|
21
|
+
centerY: finiteSchema$1,
|
|
22
|
+
zoom: finiteSchema$1.positive()
|
|
23
23
|
});
|
|
24
24
|
const BoardCameraFocusSchema = z.discriminatedUnion("type", [
|
|
25
25
|
z.object({
|
|
26
26
|
type: z.literal("rect"),
|
|
27
27
|
rect: z.object({
|
|
28
|
-
x: finiteSchema,
|
|
29
|
-
y: finiteSchema,
|
|
30
|
-
width: finiteSchema.positive(),
|
|
31
|
-
height: finiteSchema.positive()
|
|
28
|
+
x: finiteSchema$1,
|
|
29
|
+
y: finiteSchema$1,
|
|
30
|
+
width: finiteSchema$1.positive(),
|
|
31
|
+
height: finiteSchema$1.positive()
|
|
32
32
|
})
|
|
33
33
|
}),
|
|
34
34
|
z.object({
|
|
@@ -47,9 +47,9 @@ const BoardCameraFocusSchema = z.discriminatedUnion("type", [
|
|
|
47
47
|
const BoardCameraFocusParamsSchema = z.object({
|
|
48
48
|
focus: BoardCameraFocusSchema,
|
|
49
49
|
fit: z.enum(["contain", "cover"]).default("contain"),
|
|
50
|
-
padding: finiteSchema.nonnegative().default(32),
|
|
51
|
-
minZoom: finiteSchema.positive().optional(),
|
|
52
|
-
maxZoom: finiteSchema.positive().optional()
|
|
50
|
+
padding: finiteSchema$1.nonnegative().default(32),
|
|
51
|
+
minZoom: finiteSchema$1.positive().optional(),
|
|
52
|
+
maxZoom: finiteSchema$1.positive().optional()
|
|
53
53
|
}).superRefine((value, context) => {
|
|
54
54
|
if (value.minZoom !== void 0 && value.maxZoom !== void 0 && value.minZoom > value.maxZoom) context.addIssue({
|
|
55
55
|
code: "custom",
|
|
@@ -62,17 +62,17 @@ z.object({
|
|
|
62
62
|
type: z.string().min(1).max(40),
|
|
63
63
|
parentId: idSchema.nullable(),
|
|
64
64
|
orderKey: z.string().max(4096).nullable(),
|
|
65
|
-
x: finiteSchema,
|
|
66
|
-
y: finiteSchema,
|
|
67
|
-
width: finiteSchema.positive(),
|
|
68
|
-
height: finiteSchema.positive(),
|
|
69
|
-
rotation: finiteSchema,
|
|
65
|
+
x: finiteSchema$1,
|
|
66
|
+
y: finiteSchema$1,
|
|
67
|
+
width: finiteSchema$1.positive(),
|
|
68
|
+
height: finiteSchema$1.positive(),
|
|
69
|
+
rotation: finiteSchema$1,
|
|
70
70
|
refKind: z.string().max(40).nullable(),
|
|
71
71
|
refPath: z.string().max(4096).nullable(),
|
|
72
72
|
refUrl: z.string().max(4096).nullable(),
|
|
73
|
-
view: jsonObjectSchema,
|
|
74
|
-
style: jsonObjectSchema,
|
|
75
|
-
data: jsonObjectSchema
|
|
73
|
+
view: jsonObjectSchema$1,
|
|
74
|
+
style: jsonObjectSchema$1,
|
|
75
|
+
data: jsonObjectSchema$1
|
|
76
76
|
});
|
|
77
77
|
const stripBoardServerFields = (value) => {
|
|
78
78
|
if (!value || typeof value !== "object" || Array.isArray(value)) return value;
|
|
@@ -86,7 +86,7 @@ const BoardCreateInputSchema = z.object({
|
|
|
86
86
|
/** Reused by clients when board creation is interrupted and retried. */
|
|
87
87
|
mutationId: z.string().max(128).optional(),
|
|
88
88
|
title: z.string().min(1).max(255).optional(),
|
|
89
|
-
metadata: jsonObjectSchema.optional(),
|
|
89
|
+
metadata: jsonObjectSchema$1.optional(),
|
|
90
90
|
items: z.array(BoardAuthoringItemSchema).max(5e4).optional(),
|
|
91
91
|
connections: z.array(BoardConnectionSchema).max(5e4).optional(),
|
|
92
92
|
effects: z.array(BoardCreateEffectInputSchema).max(5e4).optional(),
|
|
@@ -132,17 +132,24 @@ z.object({
|
|
|
132
132
|
effectIds: z.array(idSchema).max(5e4).optional(),
|
|
133
133
|
compositionIds: z.array(idSchema).max(5e4).optional(),
|
|
134
134
|
viewport: z.object({
|
|
135
|
-
x: finiteSchema,
|
|
136
|
-
y: finiteSchema,
|
|
137
|
-
width: finiteSchema.positive(),
|
|
138
|
-
height: finiteSchema.positive()
|
|
135
|
+
x: finiteSchema$1,
|
|
136
|
+
y: finiteSchema$1,
|
|
137
|
+
width: finiteSchema$1.positive(),
|
|
138
|
+
height: finiteSchema$1.positive()
|
|
139
139
|
}).optional()
|
|
140
140
|
});
|
|
141
|
+
z.object({
|
|
142
|
+
/** Return transactions with `version < before`. Omit for the newest page. */
|
|
143
|
+
before: z.number().int().positive().optional(),
|
|
144
|
+
limit: z.number().int().min(1).max(500).default(200),
|
|
145
|
+
/** Include the current rows on the newest page (default true). Tail refreshes turn this off. */
|
|
146
|
+
snapshot: z.boolean().default(true)
|
|
147
|
+
});
|
|
141
148
|
/** Persisted on `boards.metadata.playback`: how a Board plays when opened. */
|
|
142
149
|
const BoardPlaybackPolicySchema = z.object({
|
|
143
150
|
compositionId: idSchema,
|
|
144
151
|
/** Delay before the first local playback after opening the Board, in milliseconds. */
|
|
145
|
-
delayMs: finiteSchema.nonnegative().default(0)
|
|
152
|
+
delayMs: finiteSchema$1.nonnegative().default(0)
|
|
146
153
|
});
|
|
147
154
|
function parseBoardPlaybackPolicy(metadata) {
|
|
148
155
|
const parsed = BoardPlaybackPolicySchema.safeParse(metadata.playback);
|
|
@@ -153,8 +160,8 @@ z.discriminatedUnion("type", [
|
|
|
153
160
|
commandId: idSchema,
|
|
154
161
|
type: z.literal("play"),
|
|
155
162
|
compositionId: idSchema,
|
|
156
|
-
position: finiteSchema.nonnegative().optional(),
|
|
157
|
-
timeScale: finiteSchema.positive().max(4).optional(),
|
|
163
|
+
position: finiteSchema$1.nonnegative().optional(),
|
|
164
|
+
timeScale: finiteSchema$1.positive().max(4).optional(),
|
|
158
165
|
shared: z.boolean().optional(),
|
|
159
166
|
seed: idSchema.optional()
|
|
160
167
|
}),
|
|
@@ -167,7 +174,7 @@ z.discriminatedUnion("type", [
|
|
|
167
174
|
commandId: idSchema,
|
|
168
175
|
type: z.literal("seek"),
|
|
169
176
|
playbackId: z.string().uuid(),
|
|
170
|
-
position: finiteSchema.nonnegative()
|
|
177
|
+
position: finiteSchema$1.nonnegative()
|
|
171
178
|
}),
|
|
172
179
|
z.object({
|
|
173
180
|
commandId: idSchema,
|
|
@@ -176,9 +183,49 @@ z.discriminatedUnion("type", [
|
|
|
176
183
|
})
|
|
177
184
|
]);
|
|
178
185
|
//#endregion
|
|
186
|
+
//#region ../protocol/dist/board-animation.js
|
|
187
|
+
const extensionKindSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
|
|
188
|
+
const jsonObjectSchema = z.record(z.string(), z.unknown());
|
|
189
|
+
const finiteSchema = z.number().finite();
|
|
190
|
+
/** Parameters shared by the built-in deal entrance preset. */
|
|
191
|
+
const BoardDealParamsSchema = z.object({
|
|
192
|
+
lift: finiteSchema.nonnegative().max(2e3).optional(),
|
|
193
|
+
swing: finiteSchema.nonnegative().max(2e3).optional(),
|
|
194
|
+
curve: finiteSchema.nonnegative().max(2e3).optional(),
|
|
195
|
+
tilt: finiteSchema.nonnegative().max(180).optional(),
|
|
196
|
+
scale: finiteSchema.positive().max(2).optional(),
|
|
197
|
+
duration: finiteSchema.positive().max(1e4).optional(),
|
|
198
|
+
landing: finiteSchema.nonnegative().max(1e4).optional()
|
|
199
|
+
}).strict();
|
|
200
|
+
/** A versioned, reusable animation preset reference. */
|
|
201
|
+
const BoardAnimationSpecSchema = z.object({
|
|
202
|
+
kind: extensionKindSchema,
|
|
203
|
+
kindVersion: z.number().int().positive().default(1),
|
|
204
|
+
params: jsonObjectSchema.default({})
|
|
205
|
+
}).strict().superRefine((spec, context) => {
|
|
206
|
+
if (spec.kind !== "effects.deal" || spec.kindVersion !== 1) return;
|
|
207
|
+
const parsed = BoardDealParamsSchema.safeParse(spec.params);
|
|
208
|
+
if (parsed.success) return;
|
|
209
|
+
context.addIssue({
|
|
210
|
+
code: "custom",
|
|
211
|
+
message: parsed.error.issues[0]?.message ?? "invalid effects.deal parameters",
|
|
212
|
+
path: ["params", ...parsed.error.issues[0]?.path ?? []]
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
/** Board-wide default motion policies. Omitted policies mean no motion. */
|
|
216
|
+
const BoardMotionSchema = z.object({ enter: BoardAnimationSpecSchema.optional() }).strict();
|
|
217
|
+
//#endregion
|
|
179
218
|
//#region ../protocol/dist/board-capability-registry.js
|
|
180
219
|
const CLIPS = new Set(BOARD_BUILTIN_CLIP_KINDS);
|
|
181
|
-
new Set(BOARD_BUILTIN_EFFECT_KINDS);
|
|
220
|
+
const EFFECTS = new Set(BOARD_BUILTIN_EFFECT_KINDS);
|
|
221
|
+
const BUILTIN_VERSIONS = new Set(BOARD_BUILTIN_CAPABILITIES.map((c) => `${c.kind}:${c.id}@${c.version}`));
|
|
222
|
+
/**
|
|
223
|
+
* True when a built-in renderer exists for exactly this kind@version. A known
|
|
224
|
+
* kind at an unknown version is not built-in: it must not pass as one.
|
|
225
|
+
*/
|
|
226
|
+
function isBuiltinBoardCapability(kind, id, version) {
|
|
227
|
+
return BUILTIN_VERSIONS.has(`${kind}:${id}@${version}`);
|
|
228
|
+
}
|
|
182
229
|
const record = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
183
230
|
const finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
184
231
|
function validateBuiltinBoardClip(clip, path = "clip") {
|
|
@@ -212,6 +259,47 @@ function validateBuiltinBoardClip(clip, path = "clip") {
|
|
|
212
259
|
}
|
|
213
260
|
return errors;
|
|
214
261
|
}
|
|
262
|
+
function validateBuiltinBoardEffect(effect, path = "effect") {
|
|
263
|
+
const diagnostics = [];
|
|
264
|
+
if (effect.lifecycle === "on-enter") {
|
|
265
|
+
if (effect.target.type !== "item") diagnostics.push({
|
|
266
|
+
severity: "error",
|
|
267
|
+
code: "INVALID_BOARD_EFFECT",
|
|
268
|
+
message: "on-enter effects must target an item",
|
|
269
|
+
path: `${path}.target`
|
|
270
|
+
});
|
|
271
|
+
if (effect.timeOrigin !== "activation") diagnostics.push({
|
|
272
|
+
severity: "error",
|
|
273
|
+
code: "INVALID_BOARD_EFFECT",
|
|
274
|
+
message: "on-enter effects must use activation time",
|
|
275
|
+
path: `${path}.timeOrigin`
|
|
276
|
+
});
|
|
277
|
+
} else if (EFFECTS.has(effect.kind) && effect.target.type !== "item") diagnostics.push({
|
|
278
|
+
severity: "error",
|
|
279
|
+
code: "INVALID_BOARD_EFFECT",
|
|
280
|
+
message: `${effect.kind} must target an item`,
|
|
281
|
+
path: `${path}.target`
|
|
282
|
+
});
|
|
283
|
+
if (effect.kind === "effects.deal" && effect.kindVersion === 1) {
|
|
284
|
+
if (effect.lifecycle !== "on-enter") diagnostics.push({
|
|
285
|
+
severity: "error",
|
|
286
|
+
code: "INVALID_BOARD_EFFECT",
|
|
287
|
+
message: "effects.deal must use the on-enter lifecycle",
|
|
288
|
+
path: `${path}.lifecycle`
|
|
289
|
+
});
|
|
290
|
+
const parsed = BoardDealParamsSchema.safeParse(effect.params);
|
|
291
|
+
if (!parsed.success) diagnostics.push({
|
|
292
|
+
severity: "error",
|
|
293
|
+
code: "INVALID_BOARD_EFFECT",
|
|
294
|
+
message: parsed.error.issues[0]?.message ?? "invalid effects.deal parameters",
|
|
295
|
+
path: `${path}.params`
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
return diagnostics;
|
|
299
|
+
}
|
|
300
|
+
function estimateBuiltinBoardEffectCost(effect) {
|
|
301
|
+
return isBuiltinBoardCapability("effect", effect.kind, effect.kindVersion) ? { drawCalls: 1 } : {};
|
|
302
|
+
}
|
|
215
303
|
function estimateBuiltinBoardClipCost(clip) {
|
|
216
304
|
switch (clip.kind) {
|
|
217
305
|
case "effects.particles": {
|
|
@@ -352,7 +440,18 @@ const BoardViewportSchema = z.object({
|
|
|
352
440
|
zoom: z.number().finite().min(.05).max(8)
|
|
353
441
|
});
|
|
354
442
|
const BoardAppearanceSchema = z.object({
|
|
355
|
-
|
|
443
|
+
/** Legacy field retained when reading older Board documents; not used for rendering. */
|
|
444
|
+
theme: z.string().min(1).optional(),
|
|
445
|
+
/** Board-wide motion policies. Omitted policies mean no motion. */
|
|
446
|
+
motion: BoardMotionSchema.optional(),
|
|
447
|
+
/** Legacy field retained when reading older Board documents; not used for rendering. */
|
|
448
|
+
mood: z.enum([
|
|
449
|
+
"clean",
|
|
450
|
+
"playful",
|
|
451
|
+
"arcane",
|
|
452
|
+
"cyber",
|
|
453
|
+
"natural"
|
|
454
|
+
]).optional(),
|
|
356
455
|
background: z.object({
|
|
357
456
|
kind: z.enum([
|
|
358
457
|
"solid",
|
|
@@ -386,14 +485,7 @@ const BoardAppearanceSchema = z.object({
|
|
|
386
485
|
visible: false,
|
|
387
486
|
size: 24,
|
|
388
487
|
opacity: .12
|
|
389
|
-
})
|
|
390
|
-
mood: z.enum([
|
|
391
|
-
"clean",
|
|
392
|
-
"playful",
|
|
393
|
-
"arcane",
|
|
394
|
-
"cyber",
|
|
395
|
-
"natural"
|
|
396
|
-
]).default("clean")
|
|
488
|
+
})
|
|
397
489
|
});
|
|
398
490
|
/** Optional visual chrome still carried by a few older shapes. */
|
|
399
491
|
const BoardItemStyleSchema = z.object({
|
|
@@ -695,14 +787,12 @@ z.object({
|
|
|
695
787
|
kind: z.literal(BOARD_DOCUMENT_KIND),
|
|
696
788
|
version: z.literal(1),
|
|
697
789
|
appearance: BoardAppearanceSchema.default({
|
|
698
|
-
theme: "clean",
|
|
699
790
|
background: { kind: "solid" },
|
|
700
791
|
grid: {
|
|
701
792
|
visible: false,
|
|
702
793
|
size: 24,
|
|
703
794
|
opacity: .12
|
|
704
|
-
}
|
|
705
|
-
mood: "clean"
|
|
795
|
+
}
|
|
706
796
|
}),
|
|
707
797
|
viewport: BoardViewportSchema,
|
|
708
798
|
items: z.array(BoardItemSchema),
|
|
@@ -1294,6 +1384,12 @@ const buildAppRuntimeCloseRequest = () => ({
|
|
|
1294
1384
|
version: 1,
|
|
1295
1385
|
type: "close.request"
|
|
1296
1386
|
});
|
|
1387
|
+
const buildAppRuntimeConfigureRequest = (input) => ({
|
|
1388
|
+
protocol: APP_RUNTIME_PROTOCOL,
|
|
1389
|
+
version: 1,
|
|
1390
|
+
type: "configure.request",
|
|
1391
|
+
...input
|
|
1392
|
+
});
|
|
1297
1393
|
//#endregion
|
|
1298
1394
|
//#region ../protocol/dist/app-navigation.js
|
|
1299
1395
|
const APP_NAVIGATION_PROTOCOL = "cohub.app.navigation";
|
|
@@ -2452,6 +2548,14 @@ var AppRuntimeApi = class {
|
|
|
2452
2548
|
requestClose() {
|
|
2453
2549
|
this.transport.notify?.(buildAppRuntimeCloseRequest());
|
|
2454
2550
|
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Requests the host to update the overlay's geometry or pointer hit regions.
|
|
2553
|
+
* Only meaningful when the App was opened as an `overlay` surface; the host
|
|
2554
|
+
* is free to clamp or ignore values that violate its layout policy.
|
|
2555
|
+
*/
|
|
2556
|
+
requestConfigure(input) {
|
|
2557
|
+
this.transport.notify?.(buildAppRuntimeConfigureRequest(input));
|
|
2558
|
+
}
|
|
2455
2559
|
async getAccessToken(options) {
|
|
2456
2560
|
await this.ensureStorageKeys();
|
|
2457
2561
|
if (this.token && !options?.forceRefresh) return this.token;
|
|
@@ -2553,7 +2657,7 @@ var AppRuntimeApi = class {
|
|
|
2553
2657
|
* One consent: create a viewer-owned Space (full `CreateSpaceInput`, same
|
|
2554
2658
|
* as `spaces.create`) and grant the scopes on it. Never silent — each
|
|
2555
2659
|
* confirm mints a new Space. The host creates with the viewer's account
|
|
2556
|
-
* token
|
|
2660
|
+
* token.
|
|
2557
2661
|
* `{ granted: false, space }` means the Space was created but not provisioned;
|
|
2558
2662
|
* no grant was issued. A viewer deny is `{ granted: false, space: null }`.
|
|
2559
2663
|
*/
|
|
@@ -2766,6 +2870,11 @@ var CohubClient = class {
|
|
|
2766
2870
|
onContextChanged: (listener) => this.appRuntime.onContextChanged(listener),
|
|
2767
2871
|
/** Ask the host to close this App's surface. */
|
|
2768
2872
|
requestClose: () => this.appRuntime.requestClose(),
|
|
2873
|
+
/**
|
|
2874
|
+
* Request that the host update this overlay's geometry or pointer hit
|
|
2875
|
+
* regions. Only meaningful for `overlay` surfaces; ignored otherwise.
|
|
2876
|
+
*/
|
|
2877
|
+
requestConfigure: (input) => this.appRuntime.requestConfigure(input),
|
|
2769
2878
|
embed: {
|
|
2770
2879
|
/** Host another App's public page in an iframe and forward the shell location to it. */
|
|
2771
2880
|
attach: attachAppEmbed },
|
|
@@ -3352,7 +3461,7 @@ function createAppBridgeCore(config) {
|
|
|
3352
3461
|
return Array.from(bySpace.values());
|
|
3353
3462
|
}
|
|
3354
3463
|
function allowsOwnerAutoAuthorization() {
|
|
3355
|
-
return authorizationContext.surface === "background" || authorizationContext.surface === "app";
|
|
3464
|
+
return authorizationContext.surface === "background" || authorizationContext.surface === "app" || authorizationContext.surface === "overlay";
|
|
3356
3465
|
}
|
|
3357
3466
|
async function ensureBaseToken(forceRefresh = false) {
|
|
3358
3467
|
if (appToken && !forceRefresh) return appToken;
|
|
@@ -4033,6 +4142,15 @@ var BoardExtensionRegistry = class {
|
|
|
4033
4142
|
const diagnostics = [];
|
|
4034
4143
|
const composition = parsed.data;
|
|
4035
4144
|
const cost = { ...ZERO_COST };
|
|
4145
|
+
for (const effect of input.effects ?? []) {
|
|
4146
|
+
diagnostics.push(...validateBuiltinBoardEffect(effect, `effects.${effect.id}`));
|
|
4147
|
+
if (!this.#extensions.has(`effect:${effect.kind}@${effect.kindVersion}`)) diagnostics.push({
|
|
4148
|
+
severity: "warning",
|
|
4149
|
+
code: "UNKNOWN_EFFECT",
|
|
4150
|
+
message: `No renderer is registered for ${effect.kind}@${effect.kindVersion}`,
|
|
4151
|
+
path: `effects.${effect.id}`
|
|
4152
|
+
});
|
|
4153
|
+
}
|
|
4036
4154
|
const events = [];
|
|
4037
4155
|
for (const clip of composition.timeline.clips) {
|
|
4038
4156
|
const definition = this.#extensions.get(`clip:${clip.kind}@${clip.kindVersion}`);
|
|
@@ -4066,7 +4184,10 @@ var BoardExtensionRegistry = class {
|
|
|
4066
4184
|
active[key] += event.cost[key] * event.direction;
|
|
4067
4185
|
cost[key] = Math.max(cost[key], active[key]);
|
|
4068
4186
|
}
|
|
4069
|
-
for (const effect of input.effects ?? [])
|
|
4187
|
+
for (const effect of input.effects ?? []) {
|
|
4188
|
+
const estimate = estimateBuiltinBoardEffectCost(effect);
|
|
4189
|
+
for (const key of Object.keys(cost)) cost[key] += estimate[key] ?? 0;
|
|
4190
|
+
}
|
|
4070
4191
|
const limits = input.limits ?? DEFAULT_BOARD_LIMITS;
|
|
4071
4192
|
for (const key of Object.keys(cost)) if (cost[key] > limits[key]) diagnostics.push({
|
|
4072
4193
|
severity: "warning",
|
|
@@ -4087,4 +4208,4 @@ function createBoardExtensionRegistry() {
|
|
|
4087
4208
|
}
|
|
4088
4209
|
const BOARD_CHANNELS = BOARD_ANIMATION_CHANNELS;
|
|
4089
4210
|
//#endregion
|
|
4090
|
-
export { APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppSurfaceApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BillingApi, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardEffectInputSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, BoardPlaybackPolicySchema, BoardSemanticCommandSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, DESKTOP_COMMAND_PENDING_TTL_SECONDS, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, DESKTOP_COMMAND_VERSION, DesktopCommandsApi, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, SpacePublicFilesApi, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, assertGenerationRequestAllowedByPolicy, attachAppEmbed, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileComposition, composition, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, formatAppRef, formatWorkRef, getAllowedGenerationModelIds, getCohubContext, hasGrantedAppScopes, hasRequestSourceIdentity, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardEffectInput, parseBoardPlaybackPolicy, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseWorkRef, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, scopeListHasPermission, setGrantedAppScopes, track };
|
|
4211
|
+
export { APP_COMPOSER_CHIP_CONTENT_MAX_BYTES, APP_COMPOSER_CHIP_KEY_MAX_LENGTH, APP_COMPOSER_CHIP_LABEL_MAX_LENGTH, APP_SURFACE_READY_TIMEOUT_MS, APP_SURFACE_REQUEST_TIMEOUT_MS, AppCommerceApi, AppRealtimeApi, AppRefParseError, AppRoom, AppRuntimeApi, AppRuntimeApi as WorkRuntimeApi, AppSurfaceApi, AppsApi, BILLING_ACCESS_BLOCKED_ERROR_CODE, BOARD_ANIMATION_CHANNEL_CAPABILITIES, BOARD_CHANNELS, BOARD_COLOR_IDS, BOARD_GEO_KINDS, BillingApi, BoardAnimationSpecSchema, BoardAuthoringItemSchema, BoardClient, BoardCompositionInputSchema, BoardCompositionSchema, BoardDealParamsSchema, BoardEffectInputSchema, BoardEffectSchema, BoardExtensionRegistry, BoardItemPatchSchema, BoardPlaybackPolicySchema, BoardSemanticCommandSchema, COHUB_ENVIRONMENTS, COHUB_SOURCE_HEADER, COHUB_SOURCE_HEADER_NAMES, CohubClient, CohubHttpClient, DEFAULT_BOARD_LIMITS, DESKTOP_COMMAND_DEFAULT_TIMEOUT_MS, DESKTOP_COMMAND_MAX_TIMEOUT_MS, DESKTOP_COMMAND_PAYLOAD_MAX_BYTES, DESKTOP_COMMAND_PENDING_TTL_SECONDS, DESKTOP_COMMAND_SETTLEMENT_GRACE_SECONDS, DESKTOP_COMMAND_TERMINAL_TTL_SECONDS, DESKTOP_COMMAND_VERSION, DesktopCommandsApi, FEATURE_NOT_ENTITLED_ERROR_CODE, GenerationPolicyError, HttpError, PERMISSIONS, ParentBridgeTransport, PopupBrokerTransport, REQUEST_SOURCE_VIA_MAX_LENGTH, ReferencesApi, ReferralsApi, SessionGenerationStreamClient, SessionPatchReducer, SpacePublicFilesApi, UiCommandsApi, UsersApi, VoiceApi, VoiceInputClient, WebsocketClient, WorkCommerceApi, WorkRealtimeApi, WorkRefParseError, WorkRoom, WorkSurfaceApi, assertGenerationRequestAllowedByPolicy, attachAppEmbed, buildAppSurfaceRequest, buildSpaceInvitePath, buildSpacePath, clearGrantedAppScopes, compileComposition, composition, createAppBridgeCore, createAppBridgeCore as createWorkBridgeCore, createAppRuntime, createAppRuntime as createWorkRuntime, createBoardExtensionRegistry, createCohubClient, createHttpClient, createSessionGenerationStreamClient, createSessionPatchReducer, createSlugAppIdResolver, createSlugAppIdResolver as createSlugWorkIdResolver, createVoiceInputClient, createWebsocketClient, decodeGenerationPolicy, encodeGenerationPolicy, extractBillingPayload, filterDiscoverableGenerationModels, filterGenerationDeclarationsByPolicy, findGenerationModelPolicy, formatAppRef, formatWorkRef, getAllowedGenerationModelIds, getCohubContext, hasGrantedAppScopes, hasRequestSourceIdentity, isAppId, isBillingAccessBlockedCode, isBillingAccessBlockedError, isDesktopCallMethod, isFeatureNotEntitledError, isGenerationModelHidden, isHttpErrorCode, isRequestSourceClientId, isRequestSourceEmpty, isRequestSourceUuid, isTerminalDesktopCommandStatus, isUuid, isWorkId, joinApiUrl, matchesUnauthorizedErrorToken, mergeRequestSourceIntoMeta, normalizeBaseUrl, normalizeGenerationPolicy, normalizeRequestSource, normalizeVoiceInputWebsocketUrl, normalizeWebsocketUrl, parseAppRef, parseAppSurfaceReady, parseAppSurfaceResponse, parseAssistantMessageCommit, parseBoardCompositionInput, parseBoardEffectInput, parseBoardPlaybackPolicy, parseDesktopCommand, parseGenerationPolicyFromEnv, parseRequestSourceFromHeaders, parseWorkRef, proceduralClip, readRequestSourceFromEnv, requestSourceToHeaders, resolveApiBaseUrl, resolveAppTransport, resolveAppTransport as resolveWorkTransport, resolveCohubEnvironment, resolveExecutionAppId, resolveExecutionToken, resolveRequestSourceChannel, resolveVoiceInputWebsocketUrl, resolveWebsocketUrl, sampleCompositionTracks, sampleEasing, sampleTrack, sanitizeAccessToken, scopeListHasPermission, setGrantedAppScopes, track };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region ../protocol/dist/board-animation.js
|
|
3
|
+
const extensionKindSchema = z.string().regex(/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/).max(160);
|
|
4
|
+
const jsonObjectSchema = z.record(z.string(), z.unknown());
|
|
5
|
+
const finiteSchema = z.number().finite();
|
|
6
|
+
/** Parameters shared by the built-in deal entrance preset. */
|
|
7
|
+
const BoardDealParamsSchema = z.object({
|
|
8
|
+
lift: finiteSchema.nonnegative().max(2e3).optional(),
|
|
9
|
+
swing: finiteSchema.nonnegative().max(2e3).optional(),
|
|
10
|
+
curve: finiteSchema.nonnegative().max(2e3).optional(),
|
|
11
|
+
tilt: finiteSchema.nonnegative().max(180).optional(),
|
|
12
|
+
scale: finiteSchema.positive().max(2).optional(),
|
|
13
|
+
duration: finiteSchema.positive().max(1e4).optional(),
|
|
14
|
+
landing: finiteSchema.nonnegative().max(1e4).optional()
|
|
15
|
+
}).strict();
|
|
16
|
+
/** A versioned, reusable animation preset reference. */
|
|
17
|
+
const BoardAnimationSpecSchema = z.object({
|
|
18
|
+
kind: extensionKindSchema,
|
|
19
|
+
kindVersion: z.number().int().positive().default(1),
|
|
20
|
+
params: jsonObjectSchema.default({})
|
|
21
|
+
}).strict().superRefine((spec, context) => {
|
|
22
|
+
if (spec.kind !== "effects.deal" || spec.kindVersion !== 1) return;
|
|
23
|
+
const parsed = BoardDealParamsSchema.safeParse(spec.params);
|
|
24
|
+
if (parsed.success) return;
|
|
25
|
+
context.addIssue({
|
|
26
|
+
code: "custom",
|
|
27
|
+
message: parsed.error.issues[0]?.message ?? "invalid effects.deal parameters",
|
|
28
|
+
path: ["params", ...parsed.error.issues[0]?.path ?? []]
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
/** Board-wide default motion policies. Omitted policies mean no motion. */
|
|
32
|
+
const BoardMotionSchema = z.object({ enter: BoardAnimationSpecSchema.optional() }).strict();
|
|
33
|
+
//#endregion
|
|
34
|
+
export { BoardAnimationSpecSchema, BoardDealParamsSchema, BoardMotionSchema };
|
|
@@ -1140,10 +1140,11 @@ declare const BoardSemanticCommandSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
1140
1140
|
type: z.ZodLiteral<"board">;
|
|
1141
1141
|
}, z.core.$strict>], "type">;
|
|
1142
1142
|
kind: z.ZodString;
|
|
1143
|
-
kindVersion: z.ZodNumber
|
|
1143
|
+
kindVersion: z.ZodDefault<z.ZodNumber>;
|
|
1144
1144
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1145
1145
|
lifecycle: z.ZodEnum<{
|
|
1146
1146
|
manual: "manual";
|
|
1147
|
+
"on-enter": "on-enter";
|
|
1147
1148
|
persistent: "persistent";
|
|
1148
1149
|
"when-visible": "when-visible";
|
|
1149
1150
|
}>;
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import { BOARD_BUILTIN_CLIP_KINDS, BOARD_BUILTIN_EFFECT_KINDS, DEFAULT_BOARD_RENDER_LIMITS } from "./board-constants.js";
|
|
1
|
+
import { BOARD_BUILTIN_CAPABILITIES, BOARD_BUILTIN_CLIP_KINDS, BOARD_BUILTIN_EFFECT_KINDS, DEFAULT_BOARD_RENDER_LIMITS } from "./board-constants.js";
|
|
2
2
|
import { BoardCameraFocusParamsSchema } from "./board.js";
|
|
3
|
+
import { BoardDealParamsSchema } from "./board-animation.js";
|
|
3
4
|
//#region ../protocol/dist/board-capability-registry.js
|
|
4
5
|
const CLIPS = new Set(BOARD_BUILTIN_CLIP_KINDS);
|
|
5
|
-
new Set(BOARD_BUILTIN_EFFECT_KINDS);
|
|
6
|
+
const EFFECTS = new Set(BOARD_BUILTIN_EFFECT_KINDS);
|
|
7
|
+
const BUILTIN_VERSIONS = new Set(BOARD_BUILTIN_CAPABILITIES.map((c) => `${c.kind}:${c.id}@${c.version}`));
|
|
8
|
+
/**
|
|
9
|
+
* True when a built-in renderer exists for exactly this kind@version. A known
|
|
10
|
+
* kind at an unknown version is not built-in: it must not pass as one.
|
|
11
|
+
*/
|
|
12
|
+
function isBuiltinBoardCapability(kind, id, version) {
|
|
13
|
+
return BUILTIN_VERSIONS.has(`${kind}:${id}@${version}`);
|
|
14
|
+
}
|
|
6
15
|
const record = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
7
16
|
const finite = (value) => typeof value === "number" && Number.isFinite(value);
|
|
8
17
|
function validateBuiltinBoardClip(clip, path = "clip") {
|
|
@@ -36,6 +45,47 @@ function validateBuiltinBoardClip(clip, path = "clip") {
|
|
|
36
45
|
}
|
|
37
46
|
return errors;
|
|
38
47
|
}
|
|
48
|
+
function validateBuiltinBoardEffect(effect, path = "effect") {
|
|
49
|
+
const diagnostics = [];
|
|
50
|
+
if (effect.lifecycle === "on-enter") {
|
|
51
|
+
if (effect.target.type !== "item") diagnostics.push({
|
|
52
|
+
severity: "error",
|
|
53
|
+
code: "INVALID_BOARD_EFFECT",
|
|
54
|
+
message: "on-enter effects must target an item",
|
|
55
|
+
path: `${path}.target`
|
|
56
|
+
});
|
|
57
|
+
if (effect.timeOrigin !== "activation") diagnostics.push({
|
|
58
|
+
severity: "error",
|
|
59
|
+
code: "INVALID_BOARD_EFFECT",
|
|
60
|
+
message: "on-enter effects must use activation time",
|
|
61
|
+
path: `${path}.timeOrigin`
|
|
62
|
+
});
|
|
63
|
+
} else if (EFFECTS.has(effect.kind) && effect.target.type !== "item") diagnostics.push({
|
|
64
|
+
severity: "error",
|
|
65
|
+
code: "INVALID_BOARD_EFFECT",
|
|
66
|
+
message: `${effect.kind} must target an item`,
|
|
67
|
+
path: `${path}.target`
|
|
68
|
+
});
|
|
69
|
+
if (effect.kind === "effects.deal" && effect.kindVersion === 1) {
|
|
70
|
+
if (effect.lifecycle !== "on-enter") diagnostics.push({
|
|
71
|
+
severity: "error",
|
|
72
|
+
code: "INVALID_BOARD_EFFECT",
|
|
73
|
+
message: "effects.deal must use the on-enter lifecycle",
|
|
74
|
+
path: `${path}.lifecycle`
|
|
75
|
+
});
|
|
76
|
+
const parsed = BoardDealParamsSchema.safeParse(effect.params);
|
|
77
|
+
if (!parsed.success) diagnostics.push({
|
|
78
|
+
severity: "error",
|
|
79
|
+
code: "INVALID_BOARD_EFFECT",
|
|
80
|
+
message: parsed.error.issues[0]?.message ?? "invalid effects.deal parameters",
|
|
81
|
+
path: `${path}.params`
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return diagnostics;
|
|
85
|
+
}
|
|
86
|
+
function estimateBuiltinBoardEffectCost(effect) {
|
|
87
|
+
return isBuiltinBoardCapability("effect", effect.kind, effect.kindVersion) ? { drawCalls: 1 } : {};
|
|
88
|
+
}
|
|
39
89
|
function estimateBuiltinBoardClipCost(clip) {
|
|
40
90
|
switch (clip.kind) {
|
|
41
91
|
case "effects.particles": {
|
|
@@ -70,4 +120,4 @@ function estimateBuiltinBoardClipCost(clip) {
|
|
|
70
120
|
}
|
|
71
121
|
}
|
|
72
122
|
//#endregion
|
|
73
|
-
export { estimateBuiltinBoardClipCost, validateBuiltinBoardClip };
|
|
123
|
+
export { estimateBuiltinBoardClipCost, estimateBuiltinBoardEffectCost, isBuiltinBoardCapability, validateBuiltinBoardClip, validateBuiltinBoardEffect };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BoardAuthoringItemSchema, BoardItemPatchSchema } from "./board-authoring.js";
|
|
2
2
|
import { BoardNodeInputSchema } from "./board.js";
|
|
3
|
-
import { boardArrowFrame, boardDrawBounds, boardDrawPointsToLocal } from "./board-geometry.js";
|
|
3
|
+
import { boardArrowFrame, boardDrawBounds, boardDrawPointsToLocal, boardDrawPointsToWorld } from "./board-geometry.js";
|
|
4
4
|
import { BOARD_NATIVE_NODE_TYPES, validateBoardNodeInput } from "./board-node.js";
|
|
5
5
|
//#region ../protocol/dist/board-codec.js
|
|
6
6
|
var BoardItemValidationError = class extends Error {
|
|
@@ -30,6 +30,153 @@ function authoringDiagnostic(diagnostic, path) {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
33
|
+
function baseItem(node) {
|
|
34
|
+
return {
|
|
35
|
+
id: node.nodeId,
|
|
36
|
+
position: {
|
|
37
|
+
x: node.x,
|
|
38
|
+
y: node.y
|
|
39
|
+
},
|
|
40
|
+
size: {
|
|
41
|
+
width: node.width,
|
|
42
|
+
height: node.height
|
|
43
|
+
},
|
|
44
|
+
rotation: node.rotation,
|
|
45
|
+
...node.parentId ? { parentId: node.parentId } : {},
|
|
46
|
+
...node.data.locked === true ? { locked: true } : {},
|
|
47
|
+
...isRecord(node.data.metadata) ? { metadata: node.data.metadata } : {}
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function filePath(node) {
|
|
51
|
+
if (!node.refPath) throw new Error(`Board item ${node.nodeId} is missing its source path`);
|
|
52
|
+
return node.refPath;
|
|
53
|
+
}
|
|
54
|
+
function style(node) {
|
|
55
|
+
const value = {};
|
|
56
|
+
if (typeof node.data.color === "string") value.color = node.data.color;
|
|
57
|
+
if (typeof node.data.size === "number") value.strokeWidth = node.data.size;
|
|
58
|
+
if (typeof node.data.fillOpacity === "number") value.fillOpacity = node.data.fillOpacity;
|
|
59
|
+
return Object.keys(value).length ? value : void 0;
|
|
60
|
+
}
|
|
61
|
+
function boardNodeToAuthoringItem(node) {
|
|
62
|
+
const base = baseItem(node);
|
|
63
|
+
if (node.type === "draw" || node.type === "arrow") {
|
|
64
|
+
delete base.size;
|
|
65
|
+
delete base.position;
|
|
66
|
+
}
|
|
67
|
+
const visual = style(node);
|
|
68
|
+
let candidate;
|
|
69
|
+
switch (node.type) {
|
|
70
|
+
case "text":
|
|
71
|
+
candidate = {
|
|
72
|
+
...base,
|
|
73
|
+
type: "text",
|
|
74
|
+
props: {
|
|
75
|
+
text: node.data.text ?? "",
|
|
76
|
+
fontSize: node.data.fontSize ?? 24
|
|
77
|
+
},
|
|
78
|
+
...visual ? { style: visual } : {}
|
|
79
|
+
};
|
|
80
|
+
break;
|
|
81
|
+
case "geo":
|
|
82
|
+
candidate = {
|
|
83
|
+
...base,
|
|
84
|
+
type: "geo",
|
|
85
|
+
props: {
|
|
86
|
+
shape: node.data.geo ?? "rectangle",
|
|
87
|
+
text: node.data.text ?? ""
|
|
88
|
+
},
|
|
89
|
+
...visual ? { style: visual } : {}
|
|
90
|
+
};
|
|
91
|
+
break;
|
|
92
|
+
case "draw":
|
|
93
|
+
candidate = {
|
|
94
|
+
...base,
|
|
95
|
+
type: "draw",
|
|
96
|
+
props: { points: Array.isArray(node.data.points) ? boardDrawPointsToWorld(node.data.points, node.x, node.y) : [] },
|
|
97
|
+
...visual ? { style: visual } : {}
|
|
98
|
+
};
|
|
99
|
+
break;
|
|
100
|
+
case "arrow":
|
|
101
|
+
candidate = {
|
|
102
|
+
...base,
|
|
103
|
+
type: "arrow",
|
|
104
|
+
props: {
|
|
105
|
+
start: node.data.start,
|
|
106
|
+
end: node.data.end,
|
|
107
|
+
bend: node.data.bend ?? 0,
|
|
108
|
+
arrowStart: node.data.arrowStart ?? false,
|
|
109
|
+
arrowEnd: node.data.arrowEnd ?? true,
|
|
110
|
+
label: node.data.label ?? ""
|
|
111
|
+
},
|
|
112
|
+
...visual ? { style: visual } : {}
|
|
113
|
+
};
|
|
114
|
+
break;
|
|
115
|
+
case "frame":
|
|
116
|
+
candidate = {
|
|
117
|
+
...base,
|
|
118
|
+
type: "frame",
|
|
119
|
+
props: { label: node.data.label ?? "Frame" },
|
|
120
|
+
...visual ? { style: visual } : {}
|
|
121
|
+
};
|
|
122
|
+
break;
|
|
123
|
+
case "image":
|
|
124
|
+
candidate = {
|
|
125
|
+
...base,
|
|
126
|
+
type: "image",
|
|
127
|
+
props: isRecord(node.data.crop) ? { crop: node.data.crop } : {},
|
|
128
|
+
source: {
|
|
129
|
+
kind: "space-file",
|
|
130
|
+
path: filePath(node),
|
|
131
|
+
...Object.keys(node.view).length ? { snapshot: node.view } : {}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
break;
|
|
135
|
+
case "video":
|
|
136
|
+
case "audio":
|
|
137
|
+
case "file":
|
|
138
|
+
candidate = {
|
|
139
|
+
...base,
|
|
140
|
+
type: node.type,
|
|
141
|
+
props: {},
|
|
142
|
+
source: {
|
|
143
|
+
kind: "space-file",
|
|
144
|
+
path: filePath(node),
|
|
145
|
+
...Object.keys(node.view).length ? { snapshot: node.view } : {}
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
break;
|
|
149
|
+
case "task":
|
|
150
|
+
candidate = {
|
|
151
|
+
...base,
|
|
152
|
+
type: "task",
|
|
153
|
+
props: {
|
|
154
|
+
taskRunId: node.data.taskRunId,
|
|
155
|
+
snapshot: node.view
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
break;
|
|
159
|
+
default: {
|
|
160
|
+
const props = { ...node.data };
|
|
161
|
+
delete props.locked;
|
|
162
|
+
delete props.metadata;
|
|
163
|
+
delete props.kindVersion;
|
|
164
|
+
candidate = {
|
|
165
|
+
...base,
|
|
166
|
+
type: node.type,
|
|
167
|
+
kindVersion: typeof node.data.kindVersion === "number" ? node.data.kindVersion : 1,
|
|
168
|
+
props,
|
|
169
|
+
...Object.keys(node.style).length ? { style: node.style } : {},
|
|
170
|
+
...node.refPath ? { source: {
|
|
171
|
+
kind: node.refKind ?? "space-file",
|
|
172
|
+
ref: node.refPath,
|
|
173
|
+
...Object.keys(node.view).length ? { snapshot: node.view } : {}
|
|
174
|
+
} } : {}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return BoardAuthoringItemSchema.parse(candidate);
|
|
179
|
+
}
|
|
33
180
|
function commonData(item) {
|
|
34
181
|
return {
|
|
35
182
|
...item.locked ? { locked: true } : {},
|
|
@@ -233,4 +380,4 @@ function mergePatch(current, patch) {
|
|
|
233
380
|
return result;
|
|
234
381
|
}
|
|
235
382
|
//#endregion
|
|
236
|
-
export { BoardItemValidationError, applyBoardItemPatch, authoringSchemaDiagnostics, boardAuthoringItemToNode };
|
|
383
|
+
export { BoardItemValidationError, applyBoardItemPatch, authoringSchemaDiagnostics, boardAuthoringItemToNode, boardNodeToAuthoringItem };
|