@neta-art/cohub 10.0.0 → 11.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.
Files changed (129) hide show
  1. package/README.md +11 -2
  2. package/dist/board/editor/animation.d.ts +3 -0
  3. package/dist/board/editor/animation.js +16 -1
  4. package/dist/board/editor/clipboard.js +7 -0
  5. package/dist/board/editor/copy.js +23 -18
  6. package/dist/board/editor/creation.d.ts +5 -1
  7. package/dist/board/editor/creation.js +2 -1
  8. package/dist/board/editor/deletion.js +3 -3
  9. package/dist/board/editor/document.d.ts +8 -2
  10. package/dist/board/editor/document.js +54 -7
  11. package/dist/board/editor/editor.d.ts +18 -3
  12. package/dist/board/editor/editor.js +11 -1
  13. package/dist/board/editor/query.d.ts +5 -5
  14. package/dist/board/editor/query.js +14 -12
  15. package/dist/board/editor/selection.js +2 -1
  16. package/dist/board/export/index.d.ts +25 -4
  17. package/dist/board/export/index.js +45 -12
  18. package/dist/board/export/node/index.d.ts +5 -4
  19. package/dist/board/export/node/index.js +16 -11
  20. package/dist/board/export/node/scripts.d.ts +16 -0
  21. package/dist/board/export/node/scripts.js +258 -0
  22. package/dist/board/export/scene.d.ts +2 -1
  23. package/dist/board/export/scene.js +20 -6
  24. package/dist/board/model/animation.d.ts +4 -1
  25. package/dist/board/model/animation.js +34 -7
  26. package/dist/board/model/authoring.d.ts +20 -0
  27. package/dist/board/model/authoring.js +185 -0
  28. package/dist/board/model/export-plan.js +1 -0
  29. package/dist/board/model/file-preview.js +1 -1
  30. package/dist/board/model/file-snapshot.js +3 -2
  31. package/dist/board/model/image-key.js +6 -2
  32. package/dist/board/model/index.d.ts +13 -6
  33. package/dist/board/model/index.js +14 -8
  34. package/dist/board/model/items/builtin.js +2 -2
  35. package/dist/board/model/items/create.d.ts +4 -2
  36. package/dist/board/model/items/create.js +6 -5
  37. package/dist/board/model/items/index.d.ts +2 -2
  38. package/dist/board/model/items/index.js +2 -2
  39. package/dist/board/model/media-playback.d.ts +2 -1
  40. package/dist/board/model/media-playback.js +14 -4
  41. package/dist/board/model/media.js +7 -1
  42. package/dist/board/model/sampling.d.ts +19 -0
  43. package/dist/board/model/sampling.js +96 -0
  44. package/dist/board/model/script-example.d.ts +4 -0
  45. package/dist/board/model/script-example.js +21 -0
  46. package/dist/board/model/script-hit.d.ts +10 -0
  47. package/dist/board/model/script-hit.js +52 -0
  48. package/dist/board/model/script-index.d.ts +7 -0
  49. package/dist/board/model/script-index.js +15 -0
  50. package/dist/board/model/script-scene.d.ts +24 -0
  51. package/dist/board/model/script-scene.js +267 -0
  52. package/dist/board/model/script.d.ts +105 -0
  53. package/dist/board/model/script.js +1 -0
  54. package/dist/board/render/css-color.d.ts +6 -1
  55. package/dist/board/render/css-color.js +34 -20
  56. package/dist/board/render/diagnostics.d.ts +20 -0
  57. package/dist/board/render/diagnostics.js +117 -0
  58. package/dist/board/render/index.d.ts +9 -6
  59. package/dist/board/render/index.js +9 -6
  60. package/dist/board/render/palette.d.ts +2 -1
  61. package/dist/board/render/palette.js +6 -2
  62. package/dist/board/render/renderers/arrow-card-renderer.js +3 -2
  63. package/dist/board/render/renderers/audio-card-renderer.js +2 -1
  64. package/dist/board/render/renderers/board-renderer-registry.d.ts +10 -5
  65. package/dist/board/render/renderers/board-renderer-registry.js +3 -3
  66. package/dist/board/render/renderers/custom-card-renderer.d.ts +5 -0
  67. package/dist/board/render/renderers/{sketch-card-renderer.js → custom-card-renderer.js} +16 -15
  68. package/dist/board/render/renderers/draw-card-renderer.js +3 -2
  69. package/dist/board/render/renderers/effect-card-renderer.js +22 -5
  70. package/dist/board/render/renderers/frame-card-renderer.js +30 -14
  71. package/dist/board/render/renderers/image-card-renderer.js +43 -4
  72. package/dist/board/render/renderers/shape-card-renderer.js +10 -27
  73. package/dist/board/render/renderers/text-card-renderer.js +5 -3
  74. package/dist/board/render/renderers/unknown-card-renderer.js +1 -0
  75. package/dist/board/render/renderers/video-card-renderer.js +2 -1
  76. package/dist/board/render/sampling.d.ts +22 -0
  77. package/dist/board/render/sampling.js +21 -0
  78. package/dist/board/render/script-export.d.ts +11 -0
  79. package/dist/board/render/script-export.js +86 -0
  80. package/dist/board/render/script-host.d.ts +31 -0
  81. package/dist/board/render/script-host.js +421 -0
  82. package/dist/board/render/script-modules.d.ts +2 -0
  83. package/dist/board/render/script-modules.js +2 -0
  84. package/dist/board/render/script-runtime.d.ts +29 -0
  85. package/dist/board/render/script-runtime.js +213 -0
  86. package/dist/board/render/script-sandbox.d.ts +4 -0
  87. package/dist/board/render/script-sandbox.js +173 -0
  88. package/dist/board/render/stroke.d.ts +2 -1
  89. package/dist/board/render/stroke.js +22 -1
  90. package/dist/board/render/text-measurement.js +1 -1
  91. package/dist/board/stage/assets.js +6 -1
  92. package/dist/board/stage/maintenance.d.ts +5 -0
  93. package/dist/board/stage/maintenance.js +11 -0
  94. package/dist/board/stage/scene.js +5 -2
  95. package/dist/board/stage/script-pointer.d.ts +19 -0
  96. package/dist/board/stage/script-pointer.js +35 -0
  97. package/dist/board/stage/stage.d.ts +10 -0
  98. package/dist/board/stage/stage.js +249 -43
  99. package/dist/board/stage/texture-pool.js +2 -3
  100. package/dist/chunks/environment.d.ts +266 -23
  101. package/dist/chunks/host-bridge.d.ts +2 -2
  102. package/dist/chunks/http.d.ts +88 -7
  103. package/dist/chunks/http.js +155 -63
  104. package/dist/chunks/transport.js +3 -1
  105. package/dist/chunks/websocket.d.ts +9 -1
  106. package/dist/chunks/websocket.js +16 -2
  107. package/dist/host-bridge.js +2 -1
  108. package/dist/http.d.ts +2 -2
  109. package/dist/index.d.ts +182 -4
  110. package/dist/index.js +1374 -126
  111. package/dist/protocol/dist/board-assets.d.ts +1 -0
  112. package/dist/protocol/dist/board-constants.js +2 -2
  113. package/dist/protocol/dist/board-model.d.ts +201 -11
  114. package/dist/protocol/dist/board-model.js +33 -14
  115. package/dist/protocol/dist/board-patch.js +2 -1
  116. package/dist/protocol/dist/board-schema.d.ts +4 -2
  117. package/dist/protocol/dist/board-schema.js +18 -4
  118. package/dist/protocol/dist/board-script-modules.d.ts +25 -0
  119. package/dist/protocol/dist/board-script-modules.js +127 -0
  120. package/dist/protocol/dist/display/index.d.ts +1 -0
  121. package/dist/protocol/dist/index.d.ts +4 -2
  122. package/dist/protocol/dist/realtime/types.d.ts +1 -0
  123. package/dist/protocol/dist/rtc/index.d.ts +1 -0
  124. package/package.json +2 -1
  125. package/dist/board/export/node/sketch.d.ts +0 -19
  126. package/dist/board/export/node/sketch.js +0 -146
  127. package/dist/board/render/renderers/sketch-card-renderer.d.ts +0 -5
  128. package/dist/board/render/sketch-host.d.ts +0 -14
  129. package/dist/board/render/sketch-host.js +0 -216
@@ -0,0 +1,25 @@
1
+ //#region ../protocol/dist/board-script-modules.d.ts
2
+ declare const BOARD_SCRIPT_MAX_BYTES = 2000000;
3
+ type BoardScriptSource = {
4
+ code: string;
5
+ imports: Array<{
6
+ start: number;
7
+ end: number;
8
+ path: string;
9
+ dynamic: boolean;
10
+ }>;
11
+ };
12
+ type BoardScriptSources = Record<string, BoardScriptSource>;
13
+ declare function createBoardScriptModuleReader(read: (path: string) => Promise<string>, timeoutMs?: number): {
14
+ read(path: string): Promise<string>;
15
+ invalidate(path?: string): void;
16
+ destroy(): void;
17
+ };
18
+ declare function resolveScriptImport(from: string, specifier: string): string;
19
+ declare function loadBoardScriptSources(src: string, read: (path: string) => Promise<string>, timeoutMs?: number): Promise<BoardScriptSources>;
20
+ declare function scriptModuleUrls(sources: BoardScriptSources): {
21
+ urls: Record<string, string>;
22
+ dispose(): void;
23
+ };
24
+ //#endregion
25
+ export { BOARD_SCRIPT_MAX_BYTES, BoardScriptSource, BoardScriptSources, createBoardScriptModuleReader, loadBoardScriptSources, resolveScriptImport, scriptModuleUrls };
@@ -0,0 +1,127 @@
1
+ import { isSafeBoardSourcePath } from "./board-model.js";
2
+ //#region ../protocol/dist/board-script-modules.js
3
+ const BOARD_SCRIPT_MAX_BYTES = 2e6;
4
+ function createBoardScriptModuleReader(read, timeoutMs = 15e3) {
5
+ const cache = /* @__PURE__ */ new Map();
6
+ const queue = [];
7
+ let active = 0;
8
+ let disposed = false;
9
+ function pump() {
10
+ while (active < 4 && queue.length) queue.shift()?.();
11
+ }
12
+ return {
13
+ read(path) {
14
+ if (disposed) return Promise.reject(/* @__PURE__ */ new Error("Module reader is disposed."));
15
+ const cached = cache.get(path);
16
+ if (cached) return cached;
17
+ const promise = new Promise((resolve, reject) => {
18
+ queue.push(() => {
19
+ if (disposed) {
20
+ reject(/* @__PURE__ */ new Error("Module reader is disposed."));
21
+ return;
22
+ }
23
+ active++;
24
+ let timer;
25
+ const timeout = new Promise((_resolve, rejectRead) => {
26
+ timer = setTimeout(() => rejectRead(/* @__PURE__ */ new Error(`Module read timed out: ${path}`)), timeoutMs);
27
+ });
28
+ Promise.race([Promise.resolve().then(() => read(path)), timeout]).then(resolve, reject).finally(() => {
29
+ clearTimeout(timer);
30
+ active--;
31
+ pump();
32
+ });
33
+ });
34
+ pump();
35
+ });
36
+ cache.set(path, promise);
37
+ promise.catch(() => {
38
+ if (cache.get(path) === promise) cache.delete(path);
39
+ });
40
+ return promise;
41
+ },
42
+ invalidate(path) {
43
+ if (path) cache.delete(path);
44
+ else cache.clear();
45
+ },
46
+ destroy() {
47
+ disposed = true;
48
+ cache.clear();
49
+ for (const job of queue.splice(0)) job();
50
+ }
51
+ };
52
+ }
53
+ function resolveScriptImport(from, specifier) {
54
+ if (!specifier.startsWith("./") && !specifier.startsWith("../")) throw new Error(`Only relative module imports are supported: ${specifier}`);
55
+ const parts = from.split("/").slice(0, -1);
56
+ for (const part of specifier.split("/")) {
57
+ if (part === ".") continue;
58
+ if (part === "..") {
59
+ if (!parts.length) throw new Error("Module import leaves the Space.");
60
+ parts.pop();
61
+ } else parts.push(part);
62
+ }
63
+ const path = parts.join("/");
64
+ if (!isSafeBoardSourcePath(path) || !/\.m?js$/.test(path)) throw new Error(`Invalid module path: ${path}`);
65
+ return path;
66
+ }
67
+ async function loadBoardScriptSources(src, read, timeoutMs = 15e3) {
68
+ if (!isSafeBoardSourcePath(src) || !/\.m?js$/.test(src)) throw new Error("Invalid script entry path.");
69
+ const { init, parse } = await import("es-module-lexer");
70
+ await init;
71
+ const sources = {};
72
+ const visiting = /* @__PURE__ */ new Set();
73
+ let bytes = 0;
74
+ async function visit(path) {
75
+ if (visiting.has(path)) throw new Error(`Circular module dependency: ${path}`);
76
+ if (sources[path]) return;
77
+ if (Object.keys(sources).length + visiting.size >= 64) throw new Error("A script may load at most 64 modules.");
78
+ visiting.add(path);
79
+ let timer;
80
+ const code = await Promise.race([Promise.resolve().then(() => read(path)), new Promise((_resolve, reject) => {
81
+ timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Module read timed out: ${path}`)), timeoutMs);
82
+ })]).finally(() => clearTimeout(timer));
83
+ bytes += new TextEncoder().encode(code).byteLength;
84
+ if (bytes > 2e6) throw new Error("Script modules exceed the 2 MB limit.");
85
+ const [imports] = parse(code, path);
86
+ const resolved = [];
87
+ for (const entry of imports) {
88
+ if (entry.d === -2) throw new Error("import.meta is not available in Board scripts.");
89
+ if (entry.n === void 0) throw new Error("Dynamic imports must use a literal relative path.");
90
+ const dependency = resolveScriptImport(path, entry.n);
91
+ await visit(dependency);
92
+ resolved.push({
93
+ start: entry.s,
94
+ end: entry.e,
95
+ path: dependency,
96
+ dynamic: entry.d >= 0
97
+ });
98
+ }
99
+ sources[path] = {
100
+ code,
101
+ imports: resolved
102
+ };
103
+ visiting.delete(path);
104
+ }
105
+ await visit(src);
106
+ return sources;
107
+ }
108
+ function scriptModuleUrls(sources) {
109
+ const urls = {};
110
+ for (const [path, source] of Object.entries(sources)) {
111
+ let code = source.code;
112
+ for (const entry of [...source.imports].reverse()) {
113
+ const url = urls[entry.path];
114
+ if (!url) throw new Error(`Unresolved module: ${entry.path}`);
115
+ code = code.slice(0, entry.start) + (entry.dynamic ? JSON.stringify(url) : url) + code.slice(entry.end);
116
+ }
117
+ urls[path] = URL.createObjectURL(new Blob([`${code}\n//# sourceURL=cohub-script/${path.split("/").map(encodeURIComponent).join("/")}`], { type: "text/javascript" }));
118
+ }
119
+ return {
120
+ urls,
121
+ dispose: () => {
122
+ for (const url of Object.values(urls)) URL.revokeObjectURL(url);
123
+ }
124
+ };
125
+ }
126
+ //#endregion
127
+ export { BOARD_SCRIPT_MAX_BYTES, createBoardScriptModuleReader, loadBoardScriptSources, resolveScriptImport, scriptModuleUrls };
@@ -1,2 +1,3 @@
1
1
  import "./actions.js";
2
+ import "../rtc/index.js";
2
3
  import { z } from "zod";
@@ -1,4 +1,4 @@
1
- import { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_CAMERA_TARGET, BOARD_COLOR_TOKENS, BOARD_DASHES, BOARD_DERIVED_SIZE_TYPES, BOARD_EFFECT_KINDS, BOARD_EFFECT_KIND_INFO, BOARD_ENTER_PRESETS, BOARD_EXTENSION_TYPE_PATTERN, BOARD_GRID_DEFAULT_SIZE, BOARD_GRID_MAX_SIZE, BOARD_GRID_MIN_SIZE, BOARD_ID_MAX_LENGTH, BOARD_ITEM_SCHEMAS, BOARD_ITEM_TYPES, BOARD_PLAY_MODES, BOARD_SHAPE_GEOMETRIES, BOARD_TASK_ARTIFACT_LIMIT, BOARD_TEXT_ALIGNS, BoardAnchorSide, BoardAnimation, BoardAnimationHeader, BoardAnimationHeaderSchema, BoardAnimationSchema, BoardArrowAnchor, BoardArrowAnchorSchema, BoardArrowBinding, BoardArrowBindingSchema, BoardArrowEnd, BoardArrowEndSchema, BoardArrowItem, BoardArrowItemSchema, BoardArrowRoute, BoardAudioItem, BoardAudioItemSchema, BoardBackgroundSchema, BoardBuiltinItem, BoardBuiltinItemType, BoardColor, BoardColorSchema, BoardColorToken, BoardCropSchema, BoardDash, BoardDelta, BoardDiagnostic, BoardDocument, BoardDrawItem, BoardDrawItemSchema, BoardDrawPoint, BoardDrawPointSchema, BoardEaseSchema, BoardEffectItem, BoardEffectItemSchema, BoardEffectKind, BoardEnterPreset, BoardExtensionItem, BoardExtensionItemSchema, BoardFileBackedItem, BoardFileItem, BoardFileItemSchema, BoardFrameItem, BoardFrameItemSchema, BoardIdSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemType, BoardKeyframe, BoardKeyframeSchema, BoardMarker, BoardMarkerSchema, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardPatch, BoardPatchSchema, BoardPlayMode, BoardSettings, BoardSettingsSchema, BoardShapeGeometry, BoardShapeItem, BoardShapeItemSchema, BoardSize, BoardSizeSchema, BoardSketchItem, BoardSketchItemSchema, BoardStyle, BoardStyleSchema, BoardTaskArtifact, BoardTaskArtifactSchema, BoardTaskItem, BoardTaskItemSchema, BoardTaskSnapshot, BoardTaskSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardTrack, BoardTrackSchema, BoardVec2, BoardVec2Schema, BoardVideoItem, BoardVideoItemSchema, boardItemSchema, emptyBoardDocument, hasAuthoredSize, isBoardColorString, isBoardEase, isBuiltinItem, isBuiltinItemType, isEmptyBoardDelta, isFileBackedItem, isMediaItem, isSafeBoardSourcePath, parseBoardItem } from "./board-model.js";
1
+ import { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_CAMERA_TARGET, BOARD_COLOR_TOKENS, BOARD_DASHES, BOARD_DERIVED_SIZE_TYPES, BOARD_EFFECT_KINDS, BOARD_EFFECT_KIND_INFO, BOARD_ENTER_PRESETS, BOARD_EXTENSION_TYPE_PATTERN, BOARD_GRID_DEFAULT_SIZE, BOARD_GRID_MAX_SIZE, BOARD_GRID_MIN_SIZE, BOARD_ID_MAX_LENGTH, BOARD_ITEM_SCHEMAS, BOARD_ITEM_TYPES, BOARD_PLAY_MODES, BOARD_SHAPE_GEOMETRIES, BOARD_TASK_ARTIFACT_LIMIT, BOARD_TEXT_ALIGNS, BoardAnchorSide, BoardAnimation, BoardAnimationHeader, BoardAnimationHeaderSchema, BoardAnimationSchema, BoardArrowAnchor, BoardArrowAnchorSchema, BoardArrowBinding, BoardArrowBindingSchema, BoardArrowEnd, BoardArrowEndSchema, BoardArrowItem, BoardArrowItemSchema, BoardArrowRoute, BoardAudioItem, BoardAudioItemSchema, BoardBackgroundSchema, BoardBuiltinItem, BoardBuiltinItemType, BoardColor, BoardColorSchema, BoardColorToken, BoardCropSchema, BoardCustomItem, BoardCustomItemSchema, BoardDash, BoardDelta, BoardDiagnostic, BoardDocument, BoardDrawItem, BoardDrawItemSchema, BoardDrawPoint, BoardDrawPointSchema, BoardEaseSchema, BoardEffectItem, BoardEffectItemSchema, BoardEffectKind, BoardEnterPreset, BoardExtensionItem, BoardExtensionItemSchema, BoardFileBackedItem, BoardFileItem, BoardFileItemSchema, BoardFrameItem, BoardFrameItemSchema, BoardIdSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemType, BoardKeySchema, BoardKeyframe, BoardKeyframeSchema, BoardMarker, BoardMarkerSchema, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardMediaSource, BoardMediaSourceSchema, BoardPatch, BoardPatchSchema, BoardPlayMode, BoardScript, BoardScriptSchema, BoardSettings, BoardSettingsSchema, BoardShapeGeometry, BoardShapeItem, BoardShapeItemSchema, BoardSize, BoardSizeSchema, BoardStyle, BoardStyleSchema, BoardTaskArtifact, BoardTaskArtifactSchema, BoardTaskItem, BoardTaskItemSchema, BoardTaskSnapshot, BoardTaskSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardTrack, BoardTrackSchema, BoardVec2, BoardVec2Schema, BoardVideoItem, BoardVideoItemSchema, boardItemSchema, emptyBoardDocument, hasAuthoredSize, isBoardColorString, isBoardEase, isBuiltinItem, isBuiltinItemType, isEmptyBoardDelta, isFileBackedItem, isMediaItem, isSafeBoardSourcePath, parseBoardItem, parseBoardMediaSource } from "./board-model.js";
2
2
  import { BoardFrame, BoardItemLookup, BoardLayout, BoardMatrix, BoardRect, BoardTextLayout, BoardTextMeasurer, IDENTITY_MATRIX, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextMeasurer, sideAnchor } from "./board-layout.js";
3
3
  import { BoardApplyOptions, BoardPatchResult, BoardPropertySpec, BoardState, BoardValueKind, applyBoardDelta, applyBoardPatch, applyBoardPatchToDocument, boardPatchTouches, createDocumentState, diffBoardDocuments, diffMergePatch, isEmptyBoardPatch, listBoardProperties, mergePatch, parseBoardDocument, pruneBoardTrack, resolveBoardProperty, trackReferences } from "./board-patch.js";
4
4
  import "./app-authorization.js";
@@ -6,9 +6,11 @@ import { RequestSource, RequestSourceVia } from "./provenance.js";
6
6
  import { BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME, BoardApplyResult, BoardChangeSummary, BoardHistoryPage, BoardManifest, BoardManifestSchema, BoardPlaybackCommand, BoardPlaybackCommandSchema, BoardPlaybackSnapshot, BoardPlaybackStatus, BoardReadResult, BoardTransactionRecord, isBoardPath, parseBoardManifest, serializeBoardManifest } from "./board.js";
7
7
  import { BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, clampBoardStrokeSize } from "./board-constants.js";
8
8
  import "./board-content.js";
9
+ import "./board-assets.js";
9
10
  import { BOARD_SCHEMA_TARGETS, BoardJsonSchemaResult, boardJsonSchema, boardSchemaOverview } from "./board-schema.js";
10
11
  import "./board-upgrade.js";
11
12
  import { isPublicBoardRemoteAddress, normalizeBoardRemoteUrl } from "./board-url.js";
13
+ import "./rtc/index.js";
12
14
  import "./display/index.js";
13
15
  import "./runtime/index.js";
14
16
  import "./model/turn.js";
@@ -18,4 +20,4 @@ import "./app.js";
18
20
  import "./realtime/types.js";
19
21
  import "./app-catalog.js";
20
22
  import "./host-bridge.js";
21
- export { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_CAMERA_TARGET, BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME, BOARD_COLOR_TOKENS, BOARD_DASHES, BOARD_DERIVED_SIZE_TYPES, BOARD_EFFECT_KINDS, BOARD_EFFECT_KIND_INFO, BOARD_ENTER_PRESETS, BOARD_EXTENSION_TYPE_PATTERN, BOARD_GRID_DEFAULT_SIZE, BOARD_GRID_MAX_SIZE, BOARD_GRID_MIN_SIZE, BOARD_ID_MAX_LENGTH, BOARD_ITEM_SCHEMAS, BOARD_ITEM_TYPES, BOARD_PLAY_MODES, BOARD_SCHEMA_TARGETS, BOARD_SHAPE_GEOMETRIES, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BOARD_TASK_ARTIFACT_LIMIT, BOARD_TEXT_ALIGNS, BoardAnchorSide, BoardAnimation, BoardAnimationHeader, BoardAnimationHeaderSchema, BoardAnimationSchema, BoardApplyOptions, BoardApplyResult, BoardArrowAnchor, BoardArrowAnchorSchema, BoardArrowBinding, BoardArrowBindingSchema, BoardArrowEnd, BoardArrowEndSchema, BoardArrowItem, BoardArrowItemSchema, BoardArrowRoute, BoardAudioItem, BoardAudioItemSchema, BoardBackgroundSchema, BoardBuiltinItem, BoardBuiltinItemType, BoardChangeSummary, BoardColor, BoardColorSchema, BoardColorToken, BoardCropSchema, BoardDash, BoardDelta, BoardDiagnostic, BoardDocument, BoardDrawItem, BoardDrawItemSchema, BoardDrawPoint, BoardDrawPointSchema, BoardEaseSchema, BoardEffectItem, BoardEffectItemSchema, BoardEffectKind, BoardEnterPreset, BoardExtensionItem, BoardExtensionItemSchema, BoardFileBackedItem, BoardFileItem, BoardFileItemSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardHistoryPage, BoardIdSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemLookup, BoardItemType, BoardJsonSchemaResult, BoardKeyframe, BoardKeyframeSchema, BoardLayout, BoardManifest, BoardManifestSchema, BoardMarker, BoardMarkerSchema, BoardMatrix, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardPatch, BoardPatchResult, BoardPatchSchema, BoardPlayMode, BoardPlaybackCommand, BoardPlaybackCommandSchema, BoardPlaybackSnapshot, BoardPlaybackStatus, BoardPropertySpec, BoardReadResult, BoardRect, BoardSettings, BoardSettingsSchema, BoardShapeGeometry, BoardShapeItem, BoardShapeItemSchema, BoardSize, BoardSizeSchema, BoardSketchItem, BoardSketchItemSchema, BoardState, BoardStyle, BoardStyleSchema, BoardTaskArtifact, BoardTaskArtifactSchema, BoardTaskItem, BoardTaskItemSchema, BoardTaskSnapshot, BoardTaskSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardTextLayout, BoardTextMeasurer, BoardTrack, BoardTrackSchema, BoardTransactionRecord, BoardValueKind, BoardVec2, BoardVec2Schema, BoardVideoItem, BoardVideoItemSchema, IDENTITY_MATRIX, RequestSource, RequestSourceVia, anchorPoint, applyBoardDelta, applyBoardPatch, applyBoardPatchToDocument, applyMatrix, arrowBindings, autoAnchorSide, bendControl, boardItemSchema, boardJsonSchema, boardPatchTouches, boardSchemaOverview, clampBoardFontSize, clampBoardStrokeSize, createBoardLayout, createDocumentLayout, createDocumentState, diffBoardDocuments, diffMergePatch, drawPointsBounds, drawSampleRadius, emptyBoardDocument, estimateTextWidth, framePoint, hasAuthoredSize, invertMatrix, isArrowBinding, isBoardColorString, isBoardEase, isBoardPath, isBuiltinItem, isBuiltinItemType, isEmptyBoardDelta, isEmptyBoardPatch, isFileBackedItem, isMediaItem, isPublicBoardRemoteAddress, isSafeBoardSourcePath, layoutBoardText, listBoardProperties, mergePatch, multiplyMatrix, normalizeBoardRemoteUrl, parseBoardDocument, parseBoardItem, parseBoardManifest, pointsRect, pruneBoardTrack, resolveBoardProperty, rotateAround, scaleVector, serializeBoardManifest, setBoardTextMeasurer, sideAnchor, trackReferences };
23
+ export { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_CAMERA_TARGET, BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME, BOARD_COLOR_TOKENS, BOARD_DASHES, BOARD_DERIVED_SIZE_TYPES, BOARD_EFFECT_KINDS, BOARD_EFFECT_KIND_INFO, BOARD_ENTER_PRESETS, BOARD_EXTENSION_TYPE_PATTERN, BOARD_GRID_DEFAULT_SIZE, BOARD_GRID_MAX_SIZE, BOARD_GRID_MIN_SIZE, BOARD_ID_MAX_LENGTH, BOARD_ITEM_SCHEMAS, BOARD_ITEM_TYPES, BOARD_PLAY_MODES, BOARD_SCHEMA_TARGETS, BOARD_SHAPE_GEOMETRIES, BOARD_STROKE_MAX_SIZE, BOARD_STROKE_MIN_SIZE, BOARD_TASK_ARTIFACT_LIMIT, BOARD_TEXT_ALIGNS, BoardAnchorSide, BoardAnimation, BoardAnimationHeader, BoardAnimationHeaderSchema, BoardAnimationSchema, BoardApplyOptions, BoardApplyResult, BoardArrowAnchor, BoardArrowAnchorSchema, BoardArrowBinding, BoardArrowBindingSchema, BoardArrowEnd, BoardArrowEndSchema, BoardArrowItem, BoardArrowItemSchema, BoardArrowRoute, BoardAudioItem, BoardAudioItemSchema, BoardBackgroundSchema, BoardBuiltinItem, BoardBuiltinItemType, BoardChangeSummary, BoardColor, BoardColorSchema, BoardColorToken, BoardCropSchema, BoardCustomItem, BoardCustomItemSchema, BoardDash, BoardDelta, BoardDiagnostic, BoardDocument, BoardDrawItem, BoardDrawItemSchema, BoardDrawPoint, BoardDrawPointSchema, BoardEaseSchema, BoardEffectItem, BoardEffectItemSchema, BoardEffectKind, BoardEnterPreset, BoardExtensionItem, BoardExtensionItemSchema, BoardFileBackedItem, BoardFileItem, BoardFileItemSchema, BoardFrame, BoardFrameItem, BoardFrameItemSchema, BoardHistoryPage, BoardIdSchema, BoardImageItem, BoardImageItemSchema, BoardItem, BoardItemLookup, BoardItemType, BoardJsonSchemaResult, BoardKeySchema, BoardKeyframe, BoardKeyframeSchema, BoardLayout, BoardManifest, BoardManifestSchema, BoardMarker, BoardMarkerSchema, BoardMatrix, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardMediaSource, BoardMediaSourceSchema, BoardPatch, BoardPatchResult, BoardPatchSchema, BoardPlayMode, BoardPlaybackCommand, BoardPlaybackCommandSchema, BoardPlaybackSnapshot, BoardPlaybackStatus, BoardPropertySpec, BoardReadResult, BoardRect, BoardScript, BoardScriptSchema, BoardSettings, BoardSettingsSchema, BoardShapeGeometry, BoardShapeItem, BoardShapeItemSchema, BoardSize, BoardSizeSchema, BoardState, BoardStyle, BoardStyleSchema, BoardTaskArtifact, BoardTaskArtifactSchema, BoardTaskItem, BoardTaskItemSchema, BoardTaskSnapshot, BoardTaskSnapshotSchema, BoardTextItem, BoardTextItemSchema, BoardTextLayout, BoardTextMeasurer, BoardTrack, BoardTrackSchema, BoardTransactionRecord, BoardValueKind, BoardVec2, BoardVec2Schema, BoardVideoItem, BoardVideoItemSchema, IDENTITY_MATRIX, RequestSource, RequestSourceVia, anchorPoint, applyBoardDelta, applyBoardPatch, applyBoardPatchToDocument, applyMatrix, arrowBindings, autoAnchorSide, bendControl, boardItemSchema, boardJsonSchema, boardPatchTouches, boardSchemaOverview, clampBoardFontSize, clampBoardStrokeSize, createBoardLayout, createDocumentLayout, createDocumentState, diffBoardDocuments, diffMergePatch, drawPointsBounds, drawSampleRadius, emptyBoardDocument, estimateTextWidth, framePoint, hasAuthoredSize, invertMatrix, isArrowBinding, isBoardColorString, isBoardEase, isBoardPath, isBuiltinItem, isBuiltinItemType, isEmptyBoardDelta, isEmptyBoardPatch, isFileBackedItem, isMediaItem, isPublicBoardRemoteAddress, isSafeBoardSourcePath, layoutBoardText, listBoardProperties, mergePatch, multiplyMatrix, normalizeBoardRemoteUrl, parseBoardDocument, parseBoardItem, parseBoardManifest, parseBoardMediaSource, pointsRect, pruneBoardTrack, resolveBoardProperty, rotateAround, scaleVector, serializeBoardManifest, setBoardTextMeasurer, sideAnchor, trackReferences };
@@ -1,5 +1,6 @@
1
1
  import "../board-model.js";
2
2
  import "../board.js";
3
+ import "../rtc/index.js";
3
4
  import "../model/turn.js";
4
5
  import "../model/metrics.js";
5
6
  import "../model/session.js";
@@ -0,0 +1 @@
1
+ import { z } from "zod";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub",
3
- "version": "10.0.0",
3
+ "version": "11.0.0",
4
4
  "description": "Cohub SDK for spaces, sessions, boards, and realtime agent collaboration.",
5
5
  "license": "Apache-2.0",
6
6
  "private": false,
@@ -98,6 +98,7 @@
98
98
  "NOTICE"
99
99
  ],
100
100
  "dependencies": {
101
+ "es-module-lexer": "2.3.2",
101
102
  "perfect-freehand": "1.2.3",
102
103
  "zod": "^4.6.5"
103
104
  },
@@ -1,19 +0,0 @@
1
- import { BoardSketchItem } from "../../../protocol/dist/board-model.js";
2
- import "../../../protocol/dist/index.js";
3
- import { SceneItem } from "../../model/scene.js";
4
- import { BoardSketchHost } from "../../render/renderers/board-renderer-registry.js";
5
- import { BoardNodeRenderer } from "./index.js";
6
- //#region src/board/export/node/sketch.d.ts
7
- type SketchFrame = SceneItem<BoardSketchItem>;
8
- type PreparedSketchHost = BoardSketchHost & {
9
- prepare: (items: readonly SketchFrame[], times: readonly number[], zoom: number) => Promise<void>;
10
- destroy: () => void;
11
- };
12
- type BoardNodeSketchOptions = {
13
- readModule: (src: string) => Promise<string>;
14
- timeoutMs?: number;
15
- readTimeoutMs?: number;
16
- };
17
- declare function createNodeBoardSketchHost(renderer: BoardNodeRenderer, options: BoardNodeSketchOptions): PreparedSketchHost;
18
- //#endregion
19
- export { BoardNodeSketchOptions, createNodeBoardSketchHost };
@@ -1,146 +0,0 @@
1
- import { ImageSource, Texture } from "pixi.js";
2
- import { Script, createContext } from "node:vm";
3
- //#region src/board/export/node/sketch.ts
4
- const MAX_EDGE = 2048;
5
- const DEFAULT_TIMEOUT_MS = 2e3;
6
- const DEFAULT_READ_TIMEOUT_MS = 15e3;
7
- const MAX_PREPARE_CONCURRENCY = 4;
8
- function transformModule(code, src) {
9
- return `(function(module, exports) {\n${code.replace(/export\s+default\s+/g, "module.exports.default = ").replace(/export\s+(async\s+)?function\s+draw\b/g, (_match, asyncKeyword = "") => `module.exports.draw = ${asyncKeyword}function draw`).replace(/export\s+(const|let|var)\s+draw\s*=/g, "module.exports.draw =")}\n})(module, module.exports);\n//# sourceURL=${JSON.stringify(src)}`;
10
- }
11
- function runModule(code, src, timeoutMs) {
12
- const module = { exports: {} };
13
- const context = createContext({
14
- module,
15
- exports: module.exports,
16
- console: {
17
- log() {},
18
- warn() {},
19
- error() {}
20
- },
21
- fetch: void 0,
22
- XMLHttpRequest: void 0,
23
- WebSocket: void 0,
24
- EventSource: void 0,
25
- importScripts: void 0,
26
- indexedDB: void 0,
27
- caches: void 0,
28
- process: void 0,
29
- require: void 0
30
- });
31
- new Script(transformModule(code, src), { filename: src }).runInContext(context, { timeout: timeoutMs });
32
- const value = module.exports.default && typeof module.exports.default === "object" ? {
33
- ...module.exports.default,
34
- ...module.exports
35
- } : module.exports;
36
- if (typeof value.draw !== "function") throw new Error(`${src} does not export draw(ctx, frame)`);
37
- if (value.draw.constructor?.name === "AsyncFunction") throw new Error(`${src} must export a synchronous draw(ctx, frame) for Node export.`);
38
- return {
39
- module: value,
40
- context
41
- };
42
- }
43
- function withTimeout(promise, timeoutMs, src) {
44
- return new Promise((resolve, reject) => {
45
- const timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`${src} exceeded the ${timeoutMs}ms sketch timeout.`)), timeoutMs);
46
- promise.then(resolve, reject).finally(() => clearTimeout(timer));
47
- });
48
- }
49
- function frameKey(item, time, scale) {
50
- return `${item.id}|${time}|${item.frame.width}|${item.frame.height}|${scale}|${item.props.seed ?? item.id}|${JSON.stringify(item.props.params)}`;
51
- }
52
- function frameScale(resolution, width, height) {
53
- return Math.min(4, Math.max(.25, resolution), MAX_EDGE / Math.max(1, width), MAX_EDGE / Math.max(1, height));
54
- }
55
- function textureFromCanvas(canvas) {
56
- return new Texture({ source: new ImageSource({
57
- resource: canvas,
58
- width: canvas.width,
59
- height: canvas.height
60
- }) });
61
- }
62
- function createNodeBoardSketchHost(renderer, options) {
63
- const textures = /* @__PURE__ */ new Map();
64
- const errors = /* @__PURE__ */ new Map();
65
- const lastErrors = /* @__PURE__ */ new Map();
66
- const modules = /* @__PURE__ */ new Map();
67
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
68
- const readTimeoutMs = options.readTimeoutMs ?? DEFAULT_READ_TIMEOUT_MS;
69
- const loadModule = (src) => {
70
- let pending = modules.get(src);
71
- if (!pending) {
72
- pending = withTimeout(options.readModule(src), readTimeoutMs, src).then((code) => runModule(code, src, timeoutMs));
73
- modules.set(src, pending);
74
- pending.catch(() => modules.delete(src));
75
- }
76
- return pending;
77
- };
78
- const render = async (item, time, scale) => {
79
- const key = frameKey(item, time, scale);
80
- if (textures.has(key) || errors.has(key)) return;
81
- try {
82
- const runtime = await loadModule(item.props.src);
83
- const width = Math.max(1, Math.round(item.frame.width * scale));
84
- const height = Math.max(1, Math.round(item.frame.height * scale));
85
- const canvas = renderer.canvasModule.createCanvas(width, height);
86
- const context = canvas.getContext("2d");
87
- context.scale(scale, scale);
88
- const frame = {
89
- ...item.props,
90
- t: time,
91
- width: item.frame.width,
92
- height: item.frame.height,
93
- seed: item.props.seed ?? item.id
94
- };
95
- runtime.context.__boardDraw = runtime.module.draw;
96
- runtime.context.__boardDrawContext = context;
97
- runtime.context.__boardFrame = frame;
98
- try {
99
- const drawResult = new Script("__boardDraw(__boardDrawContext, __boardFrame)", { filename: item.props.src }).runInContext(runtime.context, { timeout: timeoutMs });
100
- if (drawResult && typeof drawResult.then === "function") throw new Error(`${item.props.src} must export a synchronous draw(ctx, frame) for Node export.`);
101
- } finally {
102
- delete runtime.context.__boardDraw;
103
- delete runtime.context.__boardDrawContext;
104
- delete runtime.context.__boardFrame;
105
- }
106
- textures.set(key, textureFromCanvas(canvas));
107
- lastErrors.delete(item.id);
108
- } catch (error) {
109
- errors.set(key, error instanceof Error ? error.message : String(error));
110
- lastErrors.set(item.id, error instanceof Error ? error.message : String(error));
111
- }
112
- };
113
- return {
114
- frame(item, time, resolution) {
115
- const scale = frameScale(resolution, item.frame.width, item.frame.height);
116
- return textures.get(frameKey(item, time, scale)) ?? null;
117
- },
118
- error: (id) => lastErrors.get(id) ?? null,
119
- release: () => {},
120
- async prepare(items, times, zoom) {
121
- const sketches = items.filter((item) => item.type === "sketch");
122
- const jobs = [];
123
- for (const item of sketches) {
124
- const scale = frameScale(zoom, item.frame.width, item.frame.height);
125
- for (const time of times) jobs.push(() => render(item, time, scale));
126
- }
127
- let next = 0;
128
- const worker = async () => {
129
- while (next < jobs.length) {
130
- const job = jobs[next++];
131
- if (job) await job();
132
- }
133
- };
134
- await Promise.all(Array.from({ length: Math.min(MAX_PREPARE_CONCURRENCY, jobs.length) }, worker));
135
- },
136
- destroy() {
137
- for (const texture of textures.values()) texture.destroy(true);
138
- textures.clear();
139
- errors.clear();
140
- lastErrors.clear();
141
- modules.clear();
142
- }
143
- };
144
- }
145
- //#endregion
146
- export { createNodeBoardSketchHost };
@@ -1,5 +0,0 @@
1
- import { BoardCardRenderer } from "./board-renderer-registry.js";
2
- //#region src/board/render/renderers/sketch-card-renderer.d.ts
3
- declare const sketchCardRenderer: BoardCardRenderer;
4
- //#endregion
5
- export { sketchCardRenderer };
@@ -1,14 +0,0 @@
1
- import { BoardSketchHost } from "./renderers/board-renderer-registry.js";
2
- //#region src/board/render/sketch-host.d.ts
3
- type BoardSketchHostOptions = {
4
- readModule: (src: string) => Promise<string>;
5
- onFrame?: () => void;
6
- timeoutMs?: number;
7
- };
8
- type BrowserBoardSketchHost = BoardSketchHost & {
9
- invalidate: (src?: string) => void;
10
- destroy: () => void;
11
- };
12
- declare function createBoardSketchHost(options: BoardSketchHostOptions): BrowserBoardSketchHost;
13
- //#endregion
14
- export { BoardSketchHostOptions, BrowserBoardSketchHost, createBoardSketchHost };
@@ -1,216 +0,0 @@
1
- import { Texture } from "pixi.js";
2
- //#region src/board/render/sketch-host.ts
3
- const MAX_EDGE = 2048;
4
- const FRAME_SOURCE = `<!doctype html><meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'unsafe-inline' blob:; worker-src blob:">
5
- <script>
6
- const workerUrl = URL.createObjectURL(new Blob([${JSON.stringify(`
7
- const modules = new Map();
8
- for (const name of ["fetch", "XMLHttpRequest", "WebSocket", "EventSource", "importScripts", "indexedDB", "caches"]) {
9
- try { Object.defineProperty(self, name, { value: undefined, configurable: false }); } catch {}
10
- }
11
- self.onmessage = async (event) => {
12
- const { id, src, code, t, width, height, scale, seed, params, request } = event.data;
13
- try {
14
- let entry = modules.get(id);
15
- if (!entry || entry.code !== code) {
16
- const url = URL.createObjectURL(new Blob([code], { type: "text/javascript" }));
17
- try { entry = { code, module: await import(url) }; } finally { URL.revokeObjectURL(url); }
18
- modules.set(id, entry);
19
- }
20
- if (typeof entry.module.draw !== "function") throw new Error(src + " does not export draw(ctx, frame)");
21
- const canvas = new OffscreenCanvas(Math.max(1, Math.round(width * scale)), Math.max(1, Math.round(height * scale)));
22
- const ctx = canvas.getContext("2d");
23
- ctx.scale(scale, scale);
24
- await entry.module.draw(ctx, { t, width, height, seed, params });
25
- const bitmap = canvas.transferToImageBitmap();
26
- self.postMessage({ id, request, bitmap }, [bitmap]);
27
- } catch (error) {
28
- self.postMessage({ id, request, error: String(error && error.message || error) });
29
- }
30
- };
31
- `)}], { type: "text/javascript" }));
32
- const makeWorker = () => {
33
- const next = new Worker(workerUrl, { type: "module" });
34
- next.onmessage = (event) => parent.postMessage(event.data, "*", event.data.bitmap ? [event.data.bitmap] : []);
35
- return next;
36
- };
37
- let worker = makeWorker();
38
- addEventListener("message", (event) => {
39
- if (event.source !== parent) return;
40
- if (event.data?.reset) {
41
- worker.terminate();
42
- worker = makeWorker();
43
- return;
44
- }
45
- worker.postMessage(event.data);
46
- });
47
- parent.postMessage({ ready: true }, "*");
48
- <\/script>`;
49
- function frameKey(item, time, width, height, scale) {
50
- return `${time}|${width}|${height}|${scale}|${item.props.seed ?? ""}|${JSON.stringify(item.props.params)}`;
51
- }
52
- function createBoardSketchHost(options) {
53
- const timeoutMs = options.timeoutMs ?? 2e3;
54
- const entries = /* @__PURE__ */ new Map();
55
- const sources = /* @__PURE__ */ new Map();
56
- const iframe = document.createElement("iframe");
57
- iframe.setAttribute("sandbox", "allow-scripts");
58
- iframe.setAttribute("aria-hidden", "true");
59
- iframe.style.cssText = "position:fixed;width:0;height:0;border:0;visibility:hidden";
60
- iframe.srcdoc = FRAME_SOURCE;
61
- let ready = false;
62
- const queue = [];
63
- const post = (message) => {
64
- if (ready) iframe.contentWindow?.postMessage(message, "*");
65
- else queue.push(message);
66
- };
67
- const resetWorker = () => {
68
- for (const entry of entries.values()) {
69
- if (entry.pending === null) continue;
70
- if (entry.timeout) clearTimeout(entry.timeout);
71
- entry.timeout = null;
72
- entry.pending = null;
73
- entry.shown = "";
74
- entry.request += 1;
75
- }
76
- post({ reset: true });
77
- };
78
- const onMessage = (event) => {
79
- if (event.source !== iframe.contentWindow) return;
80
- const data = event.data;
81
- if (data.ready) {
82
- ready = true;
83
- for (const message of queue.splice(0)) iframe.contentWindow?.postMessage(message, "*");
84
- return;
85
- }
86
- const entry = data.id ? entries.get(data.id) : void 0;
87
- if (!entry || data.request !== entry.request) {
88
- data.bitmap?.close();
89
- return;
90
- }
91
- if (data.bitmap) {
92
- if (entry.timeout) clearTimeout(entry.timeout);
93
- entry.timeout = null;
94
- entry.texture?.destroy(true);
95
- entry.texture = Texture.from(data.bitmap);
96
- entry.error = null;
97
- } else {
98
- if (entry.timeout) clearTimeout(entry.timeout);
99
- entry.timeout = null;
100
- entry.error = data.error ?? "Sketch failed.";
101
- }
102
- entry.shown = entry.pending ?? entry.shown;
103
- entry.pending = null;
104
- options.onFrame?.();
105
- };
106
- window.addEventListener("message", onMessage);
107
- document.body.appendChild(iframe);
108
- function source(src) {
109
- let promise = sources.get(src);
110
- if (!promise) {
111
- promise = options.readModule(src);
112
- sources.set(src, promise);
113
- promise.catch(() => sources.delete(src));
114
- }
115
- return promise;
116
- }
117
- return {
118
- frame(item, time, resolution) {
119
- let entry = entries.get(item.id);
120
- if (!entry) {
121
- entry = {
122
- texture: null,
123
- error: null,
124
- shown: "",
125
- pending: null,
126
- request: 0,
127
- code: null,
128
- loading: false,
129
- timeout: null,
130
- sourceError: null
131
- };
132
- entries.set(item.id, entry);
133
- }
134
- const { width, height } = item.frame;
135
- const scale = Math.min(resolution, MAX_EDGE / Math.max(1, width), MAX_EDGE / Math.max(1, height));
136
- const key = frameKey(item, time, width, height, scale);
137
- if (key !== entry.shown && entry.pending === null) {
138
- const current = entry;
139
- if (current.code === null) {
140
- if (!current.sourceError && !current.loading) {
141
- current.loading = true;
142
- source(item.props.src).then((code) => {
143
- current.code = code;
144
- current.sourceError = null;
145
- current.loading = false;
146
- options.onFrame?.();
147
- }, (error) => {
148
- current.loading = false;
149
- current.sourceError = error instanceof Error ? error.message : String(error);
150
- current.error = current.sourceError;
151
- options.onFrame?.();
152
- });
153
- }
154
- } else {
155
- current.pending = key;
156
- current.request += 1;
157
- const request = current.request;
158
- current.timeout = setTimeout(() => {
159
- if (current.request !== request || current.pending !== key) return;
160
- resetWorker();
161
- current.shown = key;
162
- current.pending = null;
163
- current.timeout = null;
164
- current.error = `${item.props.src} exceeded the ${timeoutMs}ms sketch timeout.`;
165
- options.onFrame?.();
166
- }, timeoutMs);
167
- post({
168
- id: item.id,
169
- src: item.props.src,
170
- code: current.code,
171
- t: time,
172
- width,
173
- height,
174
- scale,
175
- seed: item.props.seed ?? item.id,
176
- params: item.props.params,
177
- request: current.request
178
- });
179
- }
180
- }
181
- return entry.texture;
182
- },
183
- error: (id) => entries.get(id)?.error ?? null,
184
- release(id) {
185
- const entry = entries.get(id);
186
- if (entry?.timeout) clearTimeout(entry.timeout);
187
- entry?.texture?.destroy(true);
188
- entries.delete(id);
189
- },
190
- invalidate(src) {
191
- if (src) sources.delete(src);
192
- else sources.clear();
193
- for (const entry of entries.values()) {
194
- entry.code = null;
195
- entry.sourceError = null;
196
- entry.pending = null;
197
- entry.request += 1;
198
- if (entry.timeout) clearTimeout(entry.timeout);
199
- entry.timeout = null;
200
- entry.shown = "";
201
- }
202
- options.onFrame?.();
203
- },
204
- destroy() {
205
- window.removeEventListener("message", onMessage);
206
- for (const entry of entries.values()) {
207
- if (entry.timeout) clearTimeout(entry.timeout);
208
- entry.texture?.destroy(true);
209
- }
210
- entries.clear();
211
- iframe.remove();
212
- }
213
- };
214
- }
215
- //#endregion
216
- export { createBoardSketchHost };