@neta-art/cohub 12.5.0 → 13.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 (76) hide show
  1. package/README.md +35 -13
  2. package/dist/board/editor/editor.d.ts +7 -5
  3. package/dist/board/editor/index.js +1 -1
  4. package/dist/board/editor/interaction.js +1 -1
  5. package/dist/board/export/index.d.ts +1 -6
  6. package/dist/board/export/index.js +16 -10
  7. package/dist/board/export/node/index.d.ts +2 -7
  8. package/dist/board/export/node/index.js +2 -5
  9. package/dist/board/export/scene.d.ts +3 -7
  10. package/dist/board/export/scene.js +22 -26
  11. package/dist/board/model/asset-key.d.ts +5 -2
  12. package/dist/board/model/asset-key.js +13 -5
  13. package/dist/board/model/index.d.ts +5 -4
  14. package/dist/board/model/index.js +4 -3
  15. package/dist/board/model/media-playback.d.ts +4 -6
  16. package/dist/board/model/media-playback.js +4 -4
  17. package/dist/board/model/read.d.ts +7 -0
  18. package/dist/board/model/read.js +18 -0
  19. package/dist/board/model/themes.d.ts +50 -0
  20. package/dist/board/model/themes.js +44 -6
  21. package/dist/board/render/backdrop-layer.d.ts +21 -0
  22. package/dist/board/render/backdrop-layer.js +227 -0
  23. package/dist/board/render/backdrop.d.ts +45 -0
  24. package/dist/board/render/backdrop.js +62 -0
  25. package/dist/board/render/index.d.ts +3 -2
  26. package/dist/board/render/index.js +7 -6
  27. package/dist/board/render/renderers/arrow-card-renderer.js +1 -1
  28. package/dist/board/render/renderers/audio-card-renderer.js +2 -2
  29. package/dist/board/render/renderers/file-card-renderer.js +1 -1
  30. package/dist/board/render/renderers/frame-card-renderer.js +1 -1
  31. package/dist/board/render/renderers/model-card-renderer.js +1 -1
  32. package/dist/board/render/renderers/shape-card-renderer.js +1 -1
  33. package/dist/board/render/renderers/task-card-renderer.js +2 -2
  34. package/dist/board/render/renderers/text-card-renderer.js +2 -2
  35. package/dist/board/render/renderers/video-card-renderer.js +1 -1
  36. package/dist/board/render/theme.d.ts +2 -0
  37. package/dist/board/render/theme.js +4 -2
  38. package/dist/board/replica/index.d.ts +3 -2
  39. package/dist/board/replica/index.js +34 -24
  40. package/dist/board/replica/indexeddb.js +14 -85
  41. package/dist/board/stage/assets.d.ts +4 -3
  42. package/dist/board/stage/assets.js +186 -83
  43. package/dist/board/stage/backdrop.d.ts +25 -0
  44. package/dist/board/stage/backdrop.js +104 -0
  45. package/dist/board/stage/index.d.ts +2 -1
  46. package/dist/board/stage/scene.js +12 -5
  47. package/dist/board/stage/stage.d.ts +7 -2
  48. package/dist/board/stage/stage.js +44 -24
  49. package/dist/board/stage/texture-pool.d.ts +1 -1
  50. package/dist/board/stage/texture-pool.js +4 -5
  51. package/dist/chunks/app-realtime.js +1 -1
  52. package/dist/chunks/environment.d.ts +34 -21
  53. package/dist/chunks/environment.js +4 -3
  54. package/dist/chunks/http-error.js +28 -5
  55. package/dist/chunks/http.d.ts +87 -18
  56. package/dist/chunks/http.js +1855 -59
  57. package/dist/chunks/websocket.d.ts +9 -1
  58. package/dist/http.d.ts +2 -2
  59. package/dist/http.js +1 -1
  60. package/dist/index.d.ts +9 -3
  61. package/dist/index.js +6 -1080
  62. package/dist/indexeddb.js +79 -0
  63. package/dist/media.d.ts +18 -32
  64. package/dist/media.js +81 -67
  65. package/dist/protocol/dist/board-model.d.ts +33 -26
  66. package/dist/protocol/dist/board-model.js +21 -18
  67. package/dist/protocol/dist/board.d.ts +21 -1
  68. package/dist/protocol/dist/board.js +5 -1
  69. package/dist/protocol/dist/core/media.d.ts +32 -9
  70. package/dist/protocol/dist/core/media.js +203 -48
  71. package/dist/protocol/dist/index.d.ts +3 -3
  72. package/dist/voice-input.js +1 -1
  73. package/dist/websocket.js +37 -5
  74. package/package.json +1 -1
  75. package/dist/board/render/board-background.d.ts +0 -18
  76. package/dist/board/render/board-background.js +0 -104
@@ -5,12 +5,23 @@ const MEDIA_HOSTS = /* @__PURE__ */ new Map([
5
5
  metaHeaders: true
6
6
  }],
7
7
  ["oss.talesofai.com", { transform: "oss" }],
8
- ["public.cohub.live", { transform: "oss" }],
8
+ ["public.cohub.live", {
9
+ transform: "oss",
10
+ metaHeaders: true
11
+ }],
9
12
  ["public.cohub.run", { transform: "oss" }],
10
- ["sessions.cohub.live", { transform: "oss" }],
11
- ["works.cohub.live", { transform: "oss" }],
13
+ ["sessions.cohub.live", {
14
+ transform: "oss",
15
+ metaHeaders: true
16
+ }],
17
+ ["works.cohub.live", {
18
+ transform: "oss",
19
+ metaHeaders: true
20
+ }],
12
21
  ["works.cohub.run", { transform: "oss" }],
13
- ["cca.neta.art", { transform: "cloudflare" }]
22
+ ["cca.neta.art", { transform: "cloudflare" }],
23
+ ["static.neta.art", { transform: "cloudflare" }],
24
+ ["pages-r2.neta.art", { transform: "cloudflare" }]
14
25
  ]);
15
26
  const parseHttpsUrl = (url) => {
16
27
  if (!/^https:\/\//i.test(url)) return null;
@@ -24,6 +35,36 @@ function mediaHost(url) {
24
35
  const parsed = parseHttpsUrl(url);
25
36
  return parsed ? MEDIA_HOSTS.get(parsed.hostname) : void 0;
26
37
  }
38
+ /** Fixed variant edges keep CDN cache hits high; pick one with `mediaVariantSize`. */
39
+ const MEDIA_VARIANT_SIZES = [
40
+ 192,
41
+ 384,
42
+ 768,
43
+ 1536
44
+ ];
45
+ const MEDIA_VARIANT_MAX = 1536;
46
+ /** Smallest variant covering `pixels` device pixels, capped at the largest. */
47
+ function mediaVariantSize(pixels) {
48
+ return MEDIA_VARIANT_SIZES.find((size) => size >= pixels) ?? 1536;
49
+ }
50
+ const VARIANT_QUALITY = 82;
51
+ const FRAME_GUESS_MAX = 768;
52
+ function fitted(natural, edge, fit) {
53
+ const bound = fit === "cover" ? Math.min(natural.width, natural.height) : fit === "width" ? natural.width : Math.max(natural.width, natural.height);
54
+ const scale = Math.min(1, edge / bound);
55
+ return {
56
+ width: Math.max(1, Math.round(natural.width * scale)),
57
+ height: Math.max(1, Math.round(natural.height * scale))
58
+ };
59
+ }
60
+ const guessedBox = (edge, fit) => fit === "cover" ? edge * 2 : edge;
61
+ const aspectSize = (aspect, edge) => aspect >= 1 ? {
62
+ width: edge,
63
+ height: edge / aspect
64
+ } : {
65
+ width: edge * aspect,
66
+ height: edge
67
+ };
27
68
  const OSS_PROCESS_PATTERN = /[?&]x-oss-process=/;
28
69
  /** Append an OSS process to `url`, keeping its query and hash. */
29
70
  function ossProcessUrl(url, process) {
@@ -33,13 +74,107 @@ function ossProcessUrl(url, process) {
33
74
  const hash = hashIndex >= 0 ? url.slice(hashIndex) : "";
34
75
  return `${base}${base.includes("?") ? "&" : "?"}x-oss-process=${process}${hash}`;
35
76
  }
36
- const MODEL_IMAGE = {
37
- maxEdge: 1280,
38
- quality: 75
77
+ const ossProcess = (url, process) => OSS_PROCESS_PATTERN.test(url) ? null : ossProcessUrl(url, process);
78
+ const OSS_RESIZE = {
79
+ cover: (edge) => `m_mfit,w_${edge},h_${edge}`,
80
+ contain: (edge) => `m_lfit,w_${edge},h_${edge}`,
81
+ width: (edge) => `w_${edge}`
82
+ };
83
+ const oss = {
84
+ fitsFrames: false,
85
+ image: (url, edge, fit, quality) => ossProcess(url, `image/resize,${OSS_RESIZE[fit](edge)}/quality,q_${quality}/format,webp`),
86
+ frame: (url, { edge, fit, natural, aspect }) => {
87
+ const shape = natural ?? (aspect ? aspectSize(aspect, FRAME_GUESS_MAX) : null);
88
+ const width = shape ? fitted(shape, edge, fit).width : Math.min(guessedBox(edge, fit), FRAME_GUESS_MAX);
89
+ return ossProcess(url, `video/snapshot,t_0,f_jpg,w_${width},m_fast`);
90
+ },
91
+ sizeFrame: (url) => ossProcess(url, "video/snapshot,t_0,f_jpg,w_0,h_0,m_fast"),
92
+ frameLimit: Number.POSITIVE_INFINITY,
93
+ imageInfoUrl: (url) => ossProcess(url, "image/info"),
94
+ readImageInfo: (body) => {
95
+ const fields = body;
96
+ return {
97
+ width: positive(fields.ImageWidth?.value),
98
+ height: positive(fields.ImageHeight?.value),
99
+ bytes: positive(fields.FileSize?.value)
100
+ };
101
+ },
102
+ source: (url) => {
103
+ const match = /([?&])x-oss-process=([^&#]*)/.exec(url);
104
+ if (!match) return null;
105
+ const [segment, separator, process = ""] = match;
106
+ const head = url.slice(0, match.index);
107
+ const tail = url.slice(match.index + segment.length);
108
+ return {
109
+ url: separator === "?" && tail.startsWith("&") ? `${head}?${tail.slice(1)}` : head + tail,
110
+ type: process.startsWith("video/") ? "video" : "image"
111
+ };
112
+ }
113
+ };
114
+ const CLOUDFLARE_DERIVED = /^\/cdn-cgi\/(image|media)\/[^/]+(\/.*)$/;
115
+ function cdnCgi(url, kind, options) {
116
+ const { origin, pathname, search } = new URL(url);
117
+ return pathname.startsWith("/cdn-cgi/") ? null : `${origin}/cdn-cgi/${kind}/${options}${pathname}${search}`;
118
+ }
119
+ function cloudflareBox(edge, fit, natural, limit = Number.POSITIVE_INFINITY) {
120
+ if (natural) return `width=${Math.min(fitted(natural, edge, fit).width, limit)}`;
121
+ if (fit === "width") return `width=${Math.min(edge, limit)}`;
122
+ const box = Math.min(guessedBox(edge, fit), limit);
123
+ return `width=${box},height=${box}`;
124
+ }
125
+ const CLOUDFLARE_FRAME_MAX = 2e3;
126
+ const ADAPTERS = {
127
+ oss,
128
+ cloudflare: {
129
+ fitsFrames: true,
130
+ image: (url, edge, fit, quality, format) => cdnCgi(url, "image", `${cloudflareBox(edge, fit)},fit=scale-down,quality=${quality},format=${format},onerror=redirect`),
131
+ frame: (url, { edge, fit, natural }) => cdnCgi(url, "media", `mode=frame,time=0s,${cloudflareBox(edge, fit, natural, CLOUDFLARE_FRAME_MAX)},fit=scale-down,format=jpg`),
132
+ sizeFrame: (url) => cdnCgi(url, "media", `mode=frame,time=0s,width=${CLOUDFLARE_FRAME_MAX},height=${CLOUDFLARE_FRAME_MAX},fit=scale-down,format=jpg`),
133
+ frameLimit: CLOUDFLARE_FRAME_MAX,
134
+ imageInfoUrl: (url) => cdnCgi(url, "image", "format=json"),
135
+ readImageInfo: (body) => {
136
+ const original = body.original;
137
+ return {
138
+ width: positive(original?.width),
139
+ height: positive(original?.height),
140
+ bytes: positive(original?.file_size)
141
+ };
142
+ },
143
+ source: (url) => {
144
+ const parsed = new URL(url);
145
+ const match = CLOUDFLARE_DERIVED.exec(parsed.pathname);
146
+ return match ? {
147
+ url: `${parsed.origin}${match[2]}${parsed.search}${parsed.hash}`,
148
+ type: match[1] === "media" ? "video" : "image"
149
+ } : null;
150
+ }
151
+ }
39
152
  };
40
- const { maxEdge, quality } = MODEL_IMAGE;
41
- `${maxEdge}${maxEdge}${quality}`;
42
- `${maxEdge}${maxEdge}${quality}`;
153
+ function adapterFor(url) {
154
+ const host = mediaHost(url);
155
+ return host ? ADAPTERS[host.transform] : null;
156
+ }
157
+ const isGif = (url) => /\.gif$/i.test(new URL(url).pathname);
158
+ function resizedImageUrl(url, edge, fit, quality, format) {
159
+ const adapter = adapterFor(url);
160
+ return adapter && !isGif(url) ? adapter.image(url, edge, fit, quality, format) : null;
161
+ }
162
+ function imageVariantUrl(url, size, fit = "contain") {
163
+ return resizedImageUrl(url, size, fit, VARIANT_QUALITY, "auto");
164
+ }
165
+ function videoFrameUrl(url, size, options = {}) {
166
+ return adapterFor(url)?.frame(url, {
167
+ ...options,
168
+ edge: size,
169
+ fit: options.fit ?? "contain"
170
+ }) ?? null;
171
+ }
172
+ function fitsVideoFrames(url) {
173
+ return adapterFor(url)?.fitsFrames ?? false;
174
+ }
175
+ function variantSource(url) {
176
+ return adapterFor(url)?.source(url) ?? null;
177
+ }
43
178
  function positive(value) {
44
179
  const number = typeof value === "string" ? Number(value) : value;
45
180
  return typeof number === "number" && Number.isFinite(number) && number > 0 ? number : void 0;
@@ -56,6 +191,20 @@ function sameOriginUrl(value, origin) {
56
191
  function compact(info) {
57
192
  return Object.fromEntries(Object.entries(info).filter(([, value]) => value !== void 0));
58
193
  }
194
+ const MEDIA_FACTS_LIMITS = {
195
+ edge: 65535,
196
+ durationMs: 6048e5
197
+ };
198
+ const within = (value, max) => Number.isInteger(value) && value > 0 && value <= max;
199
+ function mediaFacts(facts) {
200
+ const { width, height, durationMs } = facts ?? {};
201
+ if (!within(width, MEDIA_FACTS_LIMITS.edge) || !within(height, MEDIA_FACTS_LIMITS.edge)) return null;
202
+ return {
203
+ width,
204
+ height,
205
+ ...within(durationMs, MEDIA_FACTS_LIMITS.durationMs) ? { durationMs } : {}
206
+ };
207
+ }
59
208
  /** Media facts from response headers; `x-oss-meta-*` need CORS exposure in browsers. */
60
209
  function mediaInfoFromHeaders(headers, url) {
61
210
  const origin = new URL(url).origin;
@@ -90,19 +239,15 @@ async function probeHeaders(url, options) {
90
239
  return response.ok ? mediaInfoFromHeaders(response.headers, url) : {};
91
240
  }
92
241
  async function probeImageInfo(url, options) {
93
- if (OSS_PROCESS_PATTERN.test(url)) return {};
94
- const response = await (options.fetch ?? globalThis.fetch)(ossProcessUrl(url, "image/info"), { signal: options.signal });
95
- if (!response.ok) return {};
96
- const body = await response.json();
97
- return compact({
98
- width: positive(body.ImageWidth?.value),
99
- height: positive(body.ImageHeight?.value),
100
- bytes: positive(body.FileSize?.value)
101
- });
242
+ const adapter = adapterFor(url);
243
+ const infoUrl = adapter?.imageInfoUrl(url);
244
+ if (!adapter || !infoUrl) return {};
245
+ const response = await (options.fetch ?? globalThis.fetch)(infoUrl, { signal: options.signal });
246
+ return response.ok ? compact(adapter.readImageInfo(await response.json())) : {};
102
247
  }
103
248
  async function probeMediaInfo(url, options) {
104
249
  const host = mediaHost(url);
105
- if (host?.transform !== "oss") return {};
250
+ if (!host) return {};
106
251
  let info = {};
107
252
  const attempt = async (strategy) => {
108
253
  try {
@@ -113,43 +258,53 @@ async function probeMediaInfo(url, options) {
113
258
  if (options.type === "image" && !hasDimensions(info)) await attempt(() => probeImageInfo(url, options));
114
259
  return info;
115
260
  }
116
- const PNG_SIGNATURE = [
117
- 137,
118
- 80,
119
- 78,
120
- 71,
121
- 13,
122
- 10,
123
- 26,
124
- 10
125
- ];
126
- /**
127
- * A video's dimensions, read from the header of its first frame rendered as a
128
- * full-size PNG by OSS; only the first 24 bytes are read. Throws on failure.
129
- */
261
+ function jpegSize(bytes, length) {
262
+ if (length >= 2 && (bytes[0] !== 255 || bytes[1] !== 216)) return null;
263
+ let index = 2;
264
+ while (index + 9 <= length) {
265
+ if (bytes[index] !== 255) return null;
266
+ const marker = bytes[index + 1];
267
+ if (marker === 255) {
268
+ index += 1;
269
+ continue;
270
+ }
271
+ if (marker >= 192 && marker <= 207 && marker !== 196 && marker !== 200 && marker !== 204) {
272
+ const height = bytes[index + 5] << 8 | bytes[index + 6];
273
+ const width = bytes[index + 7] << 8 | bytes[index + 8];
274
+ return width && height ? {
275
+ width,
276
+ height
277
+ } : null;
278
+ }
279
+ index += 2 + (bytes[index + 2] << 8 | bytes[index + 3]);
280
+ }
281
+ return length >= bytes.length ? null : void 0;
282
+ }
283
+ const FRAME_HEADER_BYTES = 65536;
130
284
  async function probeVideoFrameSize(url, options = {}) {
131
- if (mediaHost(url)?.transform !== "oss" || OSS_PROCESS_PATTERN.test(url)) return {};
132
- const response = await (options.fetch ?? globalThis.fetch)(ossProcessUrl(url, "video/snapshot,t_0,f_png,w_0,h_0,m_fast"), {
133
- headers: { Range: "bytes=0-23" },
285
+ const adapter = adapterFor(url);
286
+ const frame = adapter?.sizeFrame(url);
287
+ if (!adapter || !frame) return {};
288
+ const response = await (options.fetch ?? globalThis.fetch)(frame, {
289
+ headers: { Range: `bytes=0-65535` },
134
290
  signal: options.signal
135
291
  });
136
292
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
137
- const header = /* @__PURE__ */ new Uint8Array(24);
293
+ const header = new Uint8Array(FRAME_HEADER_BYTES);
138
294
  let length = 0;
295
+ let size;
139
296
  const reader = response.body?.getReader();
140
- while (reader && length < header.length) {
297
+ while (reader && size === void 0) {
141
298
  const { done, value } = await reader.read();
142
299
  if (done) break;
143
- header.set(value.subarray(0, header.length - length), length);
144
- length += Math.min(value.length, header.length - length);
300
+ const take = Math.min(value.length, header.length - length);
301
+ header.set(value.subarray(0, take), length);
302
+ length += take;
303
+ size = jpegSize(header, length);
145
304
  }
146
305
  await reader?.cancel().catch(() => void 0);
147
- if (length < header.length || PNG_SIGNATURE.some((byte, index) => header[index] !== byte)) return {};
148
- const view = new DataView(header.buffer);
149
- return compact({
150
- width: positive(view.getUint32(16)),
151
- height: positive(view.getUint32(20))
152
- });
306
+ if (!size || Math.max(size.width, size.height) >= adapter.frameLimit) return {};
307
+ return size;
153
308
  }
154
309
  async function probeMediaSize(url, type, options = {}) {
155
310
  const info = await probeMediaInfo(url, {
@@ -163,4 +318,4 @@ async function probeMediaSize(url, type, options = {}) {
163
318
  } : null;
164
319
  }
165
320
  //#endregion
166
- export { MODEL_IMAGE, OSS_PROCESS_PATTERN, mediaHost, mediaInfoFromHeaders, mergeMediaInfo, ossProcessUrl, probeMediaInfo, probeMediaSize, probeVideoFrameSize };
321
+ export { MEDIA_FACTS_LIMITS, MEDIA_VARIANT_MAX, MEDIA_VARIANT_SIZES, fitsVideoFrames, imageVariantUrl, mediaFacts, mediaHost, mediaInfoFromHeaders, mediaVariantSize, mergeMediaInfo, ossProcessUrl, probeMediaInfo, probeMediaSize, probeVideoFrameSize, variantSource, videoFrameUrl };
@@ -1,9 +1,9 @@
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, BoardItemPreview, BoardItemPreviewSchema, BoardItemType, BoardKeySchema, BoardKeyframe, BoardKeyframeSchema, BoardMarker, BoardMarkerSchema, BoardMediaOrigin, BoardMediaOriginSchema, 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, boardItemPreview, boardItemSchema, emptyBoardDocument, hasAuthoredSize, isBoardColorString, isBoardEase, isBuiltinItem, isBuiltinItemType, isEmptyBoardDelta, isFileBackedItem, isMediaItem, isSafeBoardSourcePath, parseBoardItem, parseBoardMediaSource } from "./board-model.js";
1
+ import { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_BACKGROUND_FITS, BOARD_BACKGROUND_PATTERNS, 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, BoardBackground, BoardBackgroundFit, BoardBackgroundPattern, 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, BoardItemPreview, BoardItemPreviewSchema, BoardItemType, BoardKeySchema, BoardKeyframe, BoardKeyframeSchema, BoardMarker, BoardMarkerSchema, BoardMediaOrigin, BoardMediaOriginSchema, 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, boardItemPreview, 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, BoardTextFont, BoardTextLayout, BoardTextLayouter, BoardTextLines, IDENTITY_MATRIX, adoptBoardNaturalSize, anchorPoint, applyMatrix, arrowBindings, autoAnchorSide, bendControl, clampBoardFontSize, createBoardLayout, createDocumentLayout, drawPointsBounds, drawSampleRadius, estimateTextWidth, fitBoardMediaSize, framePoint, invertMatrix, isArrowBinding, layoutBoardText, multiplyMatrix, pointsRect, rotateAround, scaleVector, setBoardTextLayouter, 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";
5
5
  import { RequestSource, RequestSourceVia } from "./provenance.js";
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";
6
+ import { BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME, BoardApplyResult, BoardChangeSummary, BoardHistoryPage, BoardManifest, BoardManifestSchema, BoardPlaybackCommand, BoardPlaybackCommandSchema, BoardPlaybackSnapshot, BoardPlaybackStatus, BoardReadInput, BoardReadInputSchema, 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
9
  import "./board-assets.js";
@@ -24,4 +24,4 @@ import "./app.js";
24
24
  import "./realtime/types.js";
25
25
  import "./app-catalog.js";
26
26
  import "./host-bridge.js";
27
- 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_TASK_SOURCE_PREFIX, 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, BoardItemPreview, BoardItemPreviewSchema, BoardItemType, BoardJsonSchemaResult, BoardKeySchema, BoardKeyframe, BoardKeyframeSchema, BoardLayout, BoardManifest, BoardManifestSchema, BoardMarker, BoardMarkerSchema, BoardMatrix, BoardMediaOrigin, BoardMediaOriginSchema, 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, BoardTaskRunSource, BoardTaskSnapshot, BoardTaskSnapshotSchema, BoardTextFont, BoardTextItem, BoardTextItemSchema, BoardTextLayout, BoardTextLayouter, BoardTextLines, BoardTrack, BoardTrackSchema, BoardTransactionRecord, BoardValueKind, BoardVec2, BoardVec2Schema, BoardVideoItem, BoardVideoItemSchema, GenerationRunPayload, IDENTITY_MATRIX, ModelFormat, RequestSource, RequestSourceVia, TaskRunStatus, adoptBoardNaturalSize, anchorPoint, applyBoardDelta, applyBoardPatch, applyBoardPatchToDocument, applyMatrix, arrowBindings, autoAnchorSide, bendControl, boardItemPreview, boardItemSchema, boardJsonSchema, boardPatchTouches, boardSchemaOverview, boardTaskSource, clampBoardFontSize, clampBoardStrokeSize, createBoardLayout, createDocumentLayout, createDocumentState, diffBoardDocuments, diffMergePatch, drawPointsBounds, drawSampleRadius, emptyBoardDocument, estimateTextWidth, featuredTaskArtifact, fitBoardMediaSize, 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, rankedTaskArtifacts, resolveBoardProperty, rotateAround, scaleVector, serializeBoardManifest, setBoardTextLayouter, sideAnchor, taskArtifactPreviewUrl, taskArtifacts, taskRunArtifacts, taskRunToBoardTaskSnapshot, trackReferences, withObservedArtifactFacts };
27
+ export { BOARD_ANCHOR_SIDES, BOARD_ARROW_ROUTES, BOARD_BACKGROUND_FITS, BOARD_BACKGROUND_PATTERNS, 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_TASK_SOURCE_PREFIX, BOARD_TEXT_ALIGNS, BoardAnchorSide, BoardAnimation, BoardAnimationHeader, BoardAnimationHeaderSchema, BoardAnimationSchema, BoardApplyOptions, BoardApplyResult, BoardArrowAnchor, BoardArrowAnchorSchema, BoardArrowBinding, BoardArrowBindingSchema, BoardArrowEnd, BoardArrowEndSchema, BoardArrowItem, BoardArrowItemSchema, BoardArrowRoute, BoardAudioItem, BoardAudioItemSchema, BoardBackground, BoardBackgroundFit, BoardBackgroundPattern, 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, BoardItemPreview, BoardItemPreviewSchema, BoardItemType, BoardJsonSchemaResult, BoardKeySchema, BoardKeyframe, BoardKeyframeSchema, BoardLayout, BoardManifest, BoardManifestSchema, BoardMarker, BoardMarkerSchema, BoardMatrix, BoardMediaOrigin, BoardMediaOriginSchema, BoardMediaSnapshot, BoardMediaSnapshotSchema, BoardMediaSource, BoardMediaSourceSchema, BoardPatch, BoardPatchResult, BoardPatchSchema, BoardPlayMode, BoardPlaybackCommand, BoardPlaybackCommandSchema, BoardPlaybackSnapshot, BoardPlaybackStatus, BoardPropertySpec, BoardReadInput, BoardReadInputSchema, BoardReadResult, BoardRect, BoardScript, BoardScriptSchema, BoardSettings, BoardSettingsSchema, BoardShapeGeometry, BoardShapeItem, BoardShapeItemSchema, BoardSize, BoardSizeSchema, BoardState, BoardStyle, BoardStyleSchema, BoardTaskArtifact, BoardTaskArtifactSchema, BoardTaskItem, BoardTaskItemSchema, BoardTaskRunSource, BoardTaskSnapshot, BoardTaskSnapshotSchema, BoardTextFont, BoardTextItem, BoardTextItemSchema, BoardTextLayout, BoardTextLayouter, BoardTextLines, BoardTrack, BoardTrackSchema, BoardTransactionRecord, BoardValueKind, BoardVec2, BoardVec2Schema, BoardVideoItem, BoardVideoItemSchema, GenerationRunPayload, IDENTITY_MATRIX, ModelFormat, RequestSource, RequestSourceVia, TaskRunStatus, adoptBoardNaturalSize, anchorPoint, applyBoardDelta, applyBoardPatch, applyBoardPatchToDocument, applyMatrix, arrowBindings, autoAnchorSide, bendControl, boardItemPreview, boardItemSchema, boardJsonSchema, boardPatchTouches, boardSchemaOverview, boardTaskSource, clampBoardFontSize, clampBoardStrokeSize, createBoardLayout, createDocumentLayout, createDocumentState, diffBoardDocuments, diffMergePatch, drawPointsBounds, drawSampleRadius, emptyBoardDocument, estimateTextWidth, featuredTaskArtifact, fitBoardMediaSize, 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, rankedTaskArtifacts, resolveBoardProperty, rotateAround, scaleVector, serializeBoardManifest, setBoardTextLayouter, sideAnchor, taskArtifactPreviewUrl, taskArtifacts, taskRunArtifacts, taskRunToBoardTaskSnapshot, trackReferences, withObservedArtifactFacts };
@@ -1,4 +1,4 @@
1
- import { u as resolveVoiceInputWebsocketUrl } from "./chunks/environment.js";
1
+ import { d as resolveVoiceInputWebsocketUrl } from "./chunks/environment.js";
2
2
  //#region src/voice-input.ts
3
3
  const TARGET_SAMPLE_RATE = 16e3;
4
4
  const CHUNK_SAMPLES = TARGET_SAMPLE_RATE * 200 / 1e3;
package/dist/websocket.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { C as getSessionTurnPatchStreamKey, S as getRealtimeSpaceRoom, T as normalizeRealtimeRooms, _ as WS_REALTIME_ROOM_CAPABILITY, b as WS_ROOM_SUBSCRIPTION_CAPABILITY, g as WS_COMPACT_STREAM_CAPABILITY, h as WS_BOARD_AWARENESS_CAPABILITY, r as extractBillingPayload, v as WS_REALTIME_ROOM_HISTORY_CAPABILITY, w as isRealtimeDomain } from "./chunks/http-error.js";
2
- import { f as resolveWebsocketUrl } from "./chunks/environment.js";
2
+ import { p as resolveWebsocketUrl } from "./chunks/environment.js";
3
3
  //#region src/websocket.ts
4
4
  const createEventMap = () => ({
5
5
  connecting: /* @__PURE__ */ new Set(),
@@ -109,12 +109,15 @@ var WebsocketClient = class {
109
109
  pongTimeoutMs;
110
110
  debug;
111
111
  getAccessToken;
112
+ anonymous;
112
113
  WebSocketImpl;
113
114
  ws = null;
114
115
  pingTimer = null;
115
116
  reconnectTimer = null;
116
117
  reconnectTimerResolver = null;
117
118
  reconnectAttempt = 0;
119
+ resubscribeTimer = null;
120
+ resubscribeAttempt = 0;
118
121
  authReconnectAttempted = false;
119
122
  forceRefreshOnNextAuth = false;
120
123
  retryAuthClose = false;
@@ -146,6 +149,7 @@ var WebsocketClient = class {
146
149
  this.pongTimeoutMs = normalized.pongTimeoutMs;
147
150
  this.debug = normalized.debug;
148
151
  this.getAccessToken = options.getAccessToken;
152
+ this.anonymous = options.anonymous === true;
149
153
  this.WebSocketImpl = options.WebSocketImpl ?? WebSocket;
150
154
  }
151
155
  on(type, handler) {
@@ -481,6 +485,9 @@ var WebsocketClient = class {
481
485
  });
482
486
  };
483
487
  }
488
+ isRoomLive(room) {
489
+ return this.state === "open" && this.roomSubscriptions.get(room)?.subscribed === true;
490
+ }
484
491
  subscribeRooms(rooms) {
485
492
  return this.retainRooms(rooms);
486
493
  }
@@ -518,11 +525,11 @@ var WebsocketClient = class {
518
525
  const forceRefresh = this.forceRefreshOnNextAuth;
519
526
  this.forceRefreshOnNextAuth = false;
520
527
  const token = this.getAccessToken ? await this.getAccessToken(forceRefresh ? { forceRefresh: true } : void 0) : null;
521
- if (!token) throw new WebsocketAuthError("missing access token");
528
+ if (!token && !this.anonymous) throw new WebsocketAuthError("missing access token");
522
529
  const waiter = this.createAuthWaiter();
523
530
  this.send({
524
531
  type: "auth",
525
- payload: {
532
+ payload: token ? {
526
533
  token,
527
534
  capabilities: [
528
535
  WS_COMPACT_STREAM_CAPABILITY,
@@ -531,6 +538,9 @@ var WebsocketClient = class {
531
538
  WS_REALTIME_ROOM_CAPABILITY,
532
539
  WS_REALTIME_ROOM_HISTORY_CAPABILITY
533
540
  ]
541
+ } : {
542
+ anonymous: true,
543
+ capabilities: [WS_ROOM_SUBSCRIPTION_CAPABILITY]
534
544
  }
535
545
  });
536
546
  await waiter.promise;
@@ -554,6 +564,8 @@ var WebsocketClient = class {
554
564
  this.flushRoomSubscriptions();
555
565
  }
556
566
  resetRoomSubscriptions() {
567
+ if (this.resubscribeTimer) clearTimeout(this.resubscribeTimer);
568
+ this.resubscribeTimer = null;
557
569
  for (const state of this.roomSubscriptions.values()) {
558
570
  state.subscribed = false;
559
571
  state.pending = false;
@@ -633,6 +645,7 @@ var WebsocketClient = class {
633
645
  this.emit("auth", {
634
646
  connectionId,
635
647
  user,
648
+ anonymous: envelope.payload.anonymous === true,
636
649
  capabilities
637
650
  });
638
651
  }
@@ -703,6 +716,7 @@ var WebsocketClient = class {
703
716
  state.pending = false;
704
717
  }
705
718
  }
719
+ if (rooms.length > 0) this.resubscribeAttempt = 0;
706
720
  this.emit("subscribed", {
707
721
  rooms,
708
722
  requestId: envelope.requestId ?? null
@@ -717,11 +731,18 @@ var WebsocketClient = class {
717
731
  code: typeof entry.code === "string" ? entry.code : "UNKNOWN",
718
732
  message: typeof entry.message === "string" ? entry.message : "Subscription failed"
719
733
  })).filter((entry) => entry.room) : [];
734
+ let retry = false;
720
735
  for (const item of rejected) {
721
736
  const room = normalizeRealtimeRooms([item.room])[0];
722
737
  if (!room) continue;
723
- this.roomSubscriptions.delete(room);
738
+ const state = this.roomSubscriptions.get(room);
739
+ if (state && item.code === "UNAVAILABLE") {
740
+ state.subscribed = false;
741
+ state.pending = false;
742
+ retry = true;
743
+ } else this.roomSubscriptions.delete(room);
724
744
  }
745
+ if (retry) this.scheduleResubscribe();
725
746
  this.emit("subscribeError", {
726
747
  rejected,
727
748
  requestId: envelope.requestId ?? null
@@ -900,10 +921,21 @@ var WebsocketClient = class {
900
921
  resolve();
901
922
  }
902
923
  }
924
+ backoff(attempt) {
925
+ return Math.min(this.reconnectBaseDelayMs * 2 ** attempt, this.reconnectMaxDelayMs);
926
+ }
927
+ scheduleResubscribe() {
928
+ if (this.resubscribeTimer) return;
929
+ this.resubscribeTimer = setTimeout(() => {
930
+ this.resubscribeTimer = null;
931
+ this.flushRoomSubscriptions();
932
+ }, this.backoff(this.resubscribeAttempt));
933
+ this.resubscribeAttempt += 1;
934
+ }
903
935
  async scheduleReconnect(code, reason) {
904
936
  this.clearReconnectTimer();
905
937
  const attempt = this.reconnectAttempt + 1;
906
- const delay = Math.min(this.reconnectBaseDelayMs * 2 ** this.reconnectAttempt, this.reconnectMaxDelayMs);
938
+ const delay = this.backoff(this.reconnectAttempt);
907
939
  this.reconnectAttempt = attempt;
908
940
  this.state = "reconnecting";
909
941
  this.log("schedule reconnect", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neta-art/cohub",
3
- "version": "12.5.0",
3
+ "version": "13.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,
@@ -1,18 +0,0 @@
1
- import { BoardSettings } from "../../protocol/dist/board-model.js";
2
- import "../../protocol/dist/index.js";
3
- import { BoardViewport } from "../model/geometry.js";
4
- import { BoardRenderPalette } from "./renderers/board-renderer-registry.js";
5
- import { Application, Container } from "pixi.js";
6
- //#region src/board/render/board-background.d.ts
7
- type BoardBackgroundContext = {
8
- app: Application;
9
- settings: BoardSettings;
10
- viewport: BoardViewport;
11
- colorScheme: "dark" | "light";
12
- palette: BoardRenderPalette;
13
- hasImageBackground?: boolean;
14
- };
15
- declare function createBoardBackground(context: BoardBackgroundContext): Container;
16
- declare function updateBoardBackground(container: Container, context: BoardBackgroundContext): void;
17
- //#endregion
18
- export { BoardBackgroundContext, createBoardBackground, updateBoardBackground };
@@ -1,104 +0,0 @@
1
- import { parseBoardCssColor } from "./css-color.js";
2
- import { Container, Graphics, RenderTexture, TilingSprite } from "pixi.js";
3
- //#region src/board/render/board-background.ts
4
- const partsByContainer = /* @__PURE__ */ new WeakMap();
5
- function wrap(value, period) {
6
- return (value % period + period) % period;
7
- }
8
- function buildGridTexture(context, size, color, opacity, kind) {
9
- const graphics = new Graphics();
10
- if (kind === "grid") graphics.moveTo(0, .5).lineTo(size, .5).moveTo(.5, 0).lineTo(.5, size).stroke({
11
- color,
12
- width: 1,
13
- alpha: opacity
14
- });
15
- else graphics.circle(size / 2, size / 2, 1.1).fill({
16
- color,
17
- alpha: opacity
18
- });
19
- const target = RenderTexture.create({
20
- width: size,
21
- height: size
22
- });
23
- context.app.renderer.render({
24
- container: graphics,
25
- target
26
- });
27
- graphics.destroy();
28
- return target;
29
- }
30
- function sync(parts, context) {
31
- const { app, settings, viewport, palette } = context;
32
- const width = app.screen.width;
33
- const height = app.screen.height;
34
- const declared = settings.background.color;
35
- const cssColor = typeof declared === "object" ? declared[context.colorScheme] : declared;
36
- const bgColor = cssColor ? parseBoardCssColor(cssColor) ?? palette.bg : palette.bg;
37
- const bgAlpha = context.hasImageBackground ? 0 : 1;
38
- if (parts.lastWidth !== width || parts.lastHeight !== height || parts.lastBg !== bgColor || parts.lastBgAlpha !== bgAlpha) {
39
- parts.fill.clear();
40
- parts.fill.rect(0, 0, width, height).fill({
41
- color: bgColor,
42
- alpha: bgAlpha
43
- });
44
- parts.lastWidth = width;
45
- parts.lastHeight = height;
46
- parts.lastBg = bgColor;
47
- parts.lastBgAlpha = bgAlpha;
48
- }
49
- const kind = settings.background.kind === "grid" ? "grid" : "dots";
50
- const visible = settings.grid?.visible === true;
51
- const size = Math.max(4, settings.grid?.size ?? 24);
52
- const color = kind === "grid" ? palette.border : palette.muted;
53
- const opacity = kind === "grid" ? .9 : .4;
54
- const key = `${kind}|${size}|${color}|${opacity}`;
55
- if (!visible) {
56
- if (parts.sprite) parts.sprite.visible = false;
57
- return;
58
- }
59
- if (parts.textureKey !== key || !parts.sprite) {
60
- if (parts.sprite) {
61
- const previousTexture = parts.sprite.texture;
62
- parts.sprite.destroy();
63
- previousTexture.destroy(true);
64
- }
65
- const texture = buildGridTexture(context, size, color, opacity, kind);
66
- parts.sprite = new TilingSprite({
67
- texture,
68
- width,
69
- height
70
- });
71
- parts.textureKey = key;
72
- parts.fill.parent?.addChild(parts.sprite);
73
- }
74
- const sprite = parts.sprite;
75
- if (!sprite) return;
76
- sprite.visible = true;
77
- sprite.width = width;
78
- sprite.height = height;
79
- const step = size * viewport.zoom;
80
- sprite.tileScale.set(viewport.zoom);
81
- sprite.tilePosition.set(wrap(viewport.x, step), wrap(viewport.y, step));
82
- }
83
- function createBoardBackground(context) {
84
- const container = new Container({ label: "board-background" });
85
- const fill = new Graphics();
86
- container.addChild(fill);
87
- partsByContainer.set(container, {
88
- fill,
89
- sprite: null,
90
- textureKey: "",
91
- lastWidth: -1,
92
- lastHeight: -1,
93
- lastBg: NaN,
94
- lastBgAlpha: NaN
95
- });
96
- sync(partsByContainer.get(container), context);
97
- return container;
98
- }
99
- function updateBoardBackground(container, context) {
100
- const parts = partsByContainer.get(container);
101
- if (parts) sync(parts, context);
102
- }
103
- //#endregion
104
- export { createBoardBackground, updateBoardBackground };