@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.
- package/README.md +35 -13
- package/dist/board/editor/editor.d.ts +7 -5
- package/dist/board/editor/index.js +1 -1
- package/dist/board/editor/interaction.js +1 -1
- package/dist/board/export/index.d.ts +1 -6
- package/dist/board/export/index.js +16 -10
- package/dist/board/export/node/index.d.ts +2 -7
- package/dist/board/export/node/index.js +2 -5
- package/dist/board/export/scene.d.ts +3 -7
- package/dist/board/export/scene.js +22 -26
- package/dist/board/model/asset-key.d.ts +5 -2
- package/dist/board/model/asset-key.js +13 -5
- package/dist/board/model/index.d.ts +5 -4
- package/dist/board/model/index.js +4 -3
- package/dist/board/model/media-playback.d.ts +4 -6
- package/dist/board/model/media-playback.js +4 -4
- package/dist/board/model/read.d.ts +7 -0
- package/dist/board/model/read.js +18 -0
- package/dist/board/model/themes.d.ts +50 -0
- package/dist/board/model/themes.js +44 -6
- package/dist/board/render/backdrop-layer.d.ts +21 -0
- package/dist/board/render/backdrop-layer.js +227 -0
- package/dist/board/render/backdrop.d.ts +45 -0
- package/dist/board/render/backdrop.js +62 -0
- package/dist/board/render/index.d.ts +3 -2
- package/dist/board/render/index.js +7 -6
- package/dist/board/render/renderers/arrow-card-renderer.js +1 -1
- package/dist/board/render/renderers/audio-card-renderer.js +2 -2
- package/dist/board/render/renderers/file-card-renderer.js +1 -1
- package/dist/board/render/renderers/frame-card-renderer.js +1 -1
- package/dist/board/render/renderers/model-card-renderer.js +1 -1
- package/dist/board/render/renderers/shape-card-renderer.js +1 -1
- package/dist/board/render/renderers/task-card-renderer.js +2 -2
- package/dist/board/render/renderers/text-card-renderer.js +2 -2
- package/dist/board/render/renderers/video-card-renderer.js +1 -1
- package/dist/board/render/theme.d.ts +2 -0
- package/dist/board/render/theme.js +4 -2
- package/dist/board/replica/index.d.ts +3 -2
- package/dist/board/replica/index.js +34 -24
- package/dist/board/replica/indexeddb.js +14 -85
- package/dist/board/stage/assets.d.ts +4 -3
- package/dist/board/stage/assets.js +186 -83
- package/dist/board/stage/backdrop.d.ts +25 -0
- package/dist/board/stage/backdrop.js +104 -0
- package/dist/board/stage/index.d.ts +2 -1
- package/dist/board/stage/scene.js +12 -5
- package/dist/board/stage/stage.d.ts +7 -2
- package/dist/board/stage/stage.js +44 -24
- package/dist/board/stage/texture-pool.d.ts +1 -1
- package/dist/board/stage/texture-pool.js +4 -5
- package/dist/chunks/app-realtime.js +1 -1
- package/dist/chunks/environment.d.ts +34 -21
- package/dist/chunks/environment.js +4 -3
- package/dist/chunks/http-error.js +28 -5
- package/dist/chunks/http.d.ts +87 -18
- package/dist/chunks/http.js +1855 -59
- package/dist/chunks/websocket.d.ts +9 -1
- package/dist/http.d.ts +2 -2
- package/dist/http.js +1 -1
- package/dist/index.d.ts +9 -3
- package/dist/index.js +6 -1080
- package/dist/indexeddb.js +79 -0
- package/dist/media.d.ts +18 -32
- package/dist/media.js +81 -67
- package/dist/protocol/dist/board-model.d.ts +33 -26
- package/dist/protocol/dist/board-model.js +21 -18
- package/dist/protocol/dist/board.d.ts +21 -1
- package/dist/protocol/dist/board.js +5 -1
- package/dist/protocol/dist/core/media.d.ts +32 -9
- package/dist/protocol/dist/core/media.js +203 -48
- package/dist/protocol/dist/index.d.ts +3 -3
- package/dist/voice-input.js +1 -1
- package/dist/websocket.js +37 -5
- package/package.json +1 -1
- package/dist/board/render/board-background.d.ts +0 -18
- 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", {
|
|
8
|
+
["public.cohub.live", {
|
|
9
|
+
transform: "oss",
|
|
10
|
+
metaHeaders: true
|
|
11
|
+
}],
|
|
9
12
|
["public.cohub.run", { transform: "oss" }],
|
|
10
|
-
["sessions.cohub.live", {
|
|
11
|
-
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
94
|
-
const
|
|
95
|
-
if (!
|
|
96
|
-
const
|
|
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
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
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 =
|
|
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 &&
|
|
297
|
+
while (reader && size === void 0) {
|
|
141
298
|
const { done, value } = await reader.read();
|
|
142
299
|
if (done) break;
|
|
143
|
-
|
|
144
|
-
|
|
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 (
|
|
148
|
-
|
|
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 {
|
|
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 };
|
package/dist/voice-input.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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.
|
|
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 =
|
|
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,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 };
|