@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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BOARD_FONT_STACK, BOARD_MONO_FONT_STACK } from "../../../protocol/dist/board-constants.js";
|
|
2
2
|
import { featuredTaskArtifact } from "../../../protocol/dist/board-task.js";
|
|
3
|
-
import {
|
|
3
|
+
import { drawAudioWaveform } from "../audio-waveform.js";
|
|
4
4
|
import { fitTextToLines, fitTextToWidth } from "../text-fit.js";
|
|
5
5
|
import { syncTextResolution } from "../text-resolution.js";
|
|
6
6
|
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
7
|
-
import {
|
|
7
|
+
import { boardCardDetailed } from "../lod.js";
|
|
8
8
|
import { cardElevation, containRect, drawCardSurface, traceCardOutline } from "../surface.js";
|
|
9
9
|
import { positionShell } from "./base-card-renderer.js";
|
|
10
10
|
import { drawFarPlate, farPictureTone } from "./far-plate.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { estimateTextWidth, layoutBoardText } from "../../../protocol/dist/board-layout.js";
|
|
2
|
-
import { itemAlpha, itemColor } from "../palette.js";
|
|
3
2
|
import { boardTextStyle, canvasFont, cssBaselineShift, layoutTextLines } from "../text-measurement.js";
|
|
4
|
-
import { boardTextSize } from "../lod.js";
|
|
5
3
|
import { syncTextResolution } from "../text-resolution.js";
|
|
4
|
+
import { itemAlpha, itemColor } from "../palette.js";
|
|
5
|
+
import { boardTextSize } from "../lod.js";
|
|
6
6
|
import { positionShell } from "./base-card-renderer.js";
|
|
7
7
|
import { drawFarBars } from "./far-plate.js";
|
|
8
8
|
import { Container, Graphics, Text } from "pixi.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getMediaResourceTitle } from "../../model/media.js";
|
|
2
|
-
import { boardCardDetailed } from "../lod.js";
|
|
3
2
|
import { createCardTag, formatBoardDuration, syncCardTag, zoomCardTag } from "../card-tag.js";
|
|
3
|
+
import { boardCardDetailed } from "../lod.js";
|
|
4
4
|
import { cardElevation, containRect, drawCardSurface, fillCardPicture } from "../surface.js";
|
|
5
5
|
import { positionShell } from "./base-card-renderer.js";
|
|
6
6
|
import { drawFarPlate, farPictureTone } from "./far-plate.js";
|
|
@@ -2,12 +2,14 @@ import { BoardShapeColors } from "../model/palette.js";
|
|
|
2
2
|
import { BoardThemeId } from "../model/themes.js";
|
|
3
3
|
import { BoardRenderStyle } from "./style.js";
|
|
4
4
|
import { BoardRenderPalette } from "./renderers/board-renderer-registry.js";
|
|
5
|
+
import { BoardThemeBackdrop } from "./backdrop.js";
|
|
5
6
|
//#region src/board/render/theme.d.ts
|
|
6
7
|
type BoardRenderTheme = {
|
|
7
8
|
colorScheme: "dark" | "light";
|
|
8
9
|
palette: BoardRenderPalette;
|
|
9
10
|
colors: BoardShapeColors;
|
|
10
11
|
style: BoardRenderStyle;
|
|
12
|
+
backdrop?: BoardThemeBackdrop;
|
|
11
13
|
};
|
|
12
14
|
/** A built-in Cohub theme as the app draws it; spread it into export or sampler options. */
|
|
13
15
|
declare function boardRenderTheme(id: BoardThemeId): BoardRenderTheme;
|
|
@@ -3,12 +3,14 @@ import { resolveBoardRenderStyle } from "./style.js";
|
|
|
3
3
|
//#region src/board/render/theme.ts
|
|
4
4
|
/** A built-in Cohub theme as the app draws it; spread it into export or sampler options. */
|
|
5
5
|
function boardRenderTheme(id) {
|
|
6
|
-
const
|
|
6
|
+
const data = BOARD_THEME_DATA[id];
|
|
7
|
+
const { colorScheme, palette, colors, style } = data;
|
|
7
8
|
return {
|
|
8
9
|
colorScheme,
|
|
9
10
|
palette: { ...palette },
|
|
10
11
|
colors: Object.fromEntries(Object.entries(colors).map(([key, value]) => [key, { ...value }])),
|
|
11
|
-
style: resolveBoardRenderStyle(colorScheme, style)
|
|
12
|
+
style: resolveBoardRenderStyle(colorScheme, style),
|
|
13
|
+
..."backdrop" in data ? { backdrop: structuredClone(data.backdrop) } : {}
|
|
12
14
|
};
|
|
13
15
|
}
|
|
14
16
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BoardDelta, BoardDocument, BoardPatch } from "../../protocol/dist/board-model.js";
|
|
2
|
-
import { BoardApplyResult, BoardPlaybackSnapshot, BoardReadResult } from "../../protocol/dist/board.js";
|
|
2
|
+
import { BoardApplyResult, BoardPlaybackSnapshot, BoardReadInput, BoardReadResult } from "../../protocol/dist/board.js";
|
|
3
3
|
import "../../protocol/dist/index.js";
|
|
4
4
|
import { BoardReplicaDatabaseOptions, BoardReplicaScope, clearBoardReplicaStorage, createIndexedDbBoardReplicaStorage } from "./indexeddb.js";
|
|
5
5
|
//#region src/board/replica/index.d.ts
|
|
@@ -14,7 +14,8 @@ type BoardChangedPayload = {
|
|
|
14
14
|
after?: BoardDelta;
|
|
15
15
|
};
|
|
16
16
|
type BoardRemote = {
|
|
17
|
-
|
|
17
|
+
/** `since` asks only for the changes after that version; remotes may return the full Board. */
|
|
18
|
+
get(read?: Pick<BoardReadInput, "since">): Promise<BoardReadResult>;
|
|
18
19
|
apply(patch: BoardPatch, options: {
|
|
19
20
|
mutationId: string;
|
|
20
21
|
clientId?: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { applyBoardDelta, applyBoardPatchToDocument, parseBoardDocument } from "../../protocol/dist/board-patch.js";
|
|
2
2
|
import { createBoardEntityId } from "../model/items/id.js";
|
|
3
|
-
import {
|
|
3
|
+
import { readBoardDocument } from "../model/read.js";
|
|
4
4
|
import { clearBoardReplicaStorage, createIndexedDbBoardReplicaStorage } from "./indexeddb.js";
|
|
5
5
|
//#region src/board/replica/index.ts
|
|
6
6
|
function memoryStorage() {
|
|
@@ -15,6 +15,7 @@ function memoryStorage() {
|
|
|
15
15
|
const RETRY_BASE_MS = 1e3;
|
|
16
16
|
const RETRY_MAX_MS = 3e4;
|
|
17
17
|
const PERSIST_INTERVAL_MS = 500;
|
|
18
|
+
const CACHE_WAIT_MS = 250;
|
|
18
19
|
function isRejection(error) {
|
|
19
20
|
const status = error.status;
|
|
20
21
|
return typeof status === "number" && status >= 400 && status < 500 && ![
|
|
@@ -34,6 +35,7 @@ function createBoardReplica(options) {
|
|
|
34
35
|
let unsubscribeRemote = null;
|
|
35
36
|
let server = null;
|
|
36
37
|
let version = 0;
|
|
38
|
+
let sent = [];
|
|
37
39
|
let title = null;
|
|
38
40
|
let playback = null;
|
|
39
41
|
let playbackRevision = 0;
|
|
@@ -69,7 +71,7 @@ function createBoardReplica(options) {
|
|
|
69
71
|
return;
|
|
70
72
|
}
|
|
71
73
|
let next = server;
|
|
72
|
-
for (const entry of pending) {
|
|
74
|
+
for (const entry of [...sent, ...pending]) {
|
|
73
75
|
const result = applyBoardPatchToDocument(next, entry.patch);
|
|
74
76
|
if (result.ok) next = result.document;
|
|
75
77
|
}
|
|
@@ -95,6 +97,7 @@ function createBoardReplica(options) {
|
|
|
95
97
|
function adoptServer(next, nextVersion, persist) {
|
|
96
98
|
server = next;
|
|
97
99
|
version = nextVersion;
|
|
100
|
+
sent = sent.filter((entry) => entry.version > nextVersion);
|
|
98
101
|
recompute();
|
|
99
102
|
if (persist) schedulePersist(nextVersion, next);
|
|
100
103
|
}
|
|
@@ -112,21 +115,16 @@ function createBoardReplica(options) {
|
|
|
112
115
|
unpersisted = null;
|
|
113
116
|
if (entry) storage.writeDocument(entry.version, entry.document).catch(() => void 0);
|
|
114
117
|
}
|
|
115
|
-
function adoptRead(result, readPlaybackRevision) {
|
|
116
|
-
const
|
|
117
|
-
board: result.board,
|
|
118
|
-
items: result.items ?? {},
|
|
119
|
-
animations: result.animations ?? {}
|
|
120
|
-
});
|
|
121
|
-
if (!parsed.ok) throw new Error(`Board ${result.id} could not be read.`);
|
|
118
|
+
function adoptRead(result, base, readPlaybackRevision) {
|
|
119
|
+
const next = readBoardDocument(result, result.changes ? base : server);
|
|
122
120
|
title = result.title;
|
|
123
121
|
if (readPlaybackRevision === playbackRevision) playback = result.playback;
|
|
124
122
|
loaded = true;
|
|
125
|
-
const next = shareBoardDocument(server, parsed.document);
|
|
126
123
|
if (next === server && result.version === version) return;
|
|
127
124
|
adoptServer(next, result.version, true);
|
|
128
125
|
}
|
|
129
126
|
function refresh() {
|
|
127
|
+
if (disposed) return Promise.resolve();
|
|
130
128
|
if (refreshing) {
|
|
131
129
|
refreshAgain = true;
|
|
132
130
|
return refreshing;
|
|
@@ -136,9 +134,10 @@ function createBoardReplica(options) {
|
|
|
136
134
|
do {
|
|
137
135
|
refreshAgain = false;
|
|
138
136
|
const readPlaybackRevision = playbackRevision;
|
|
139
|
-
const
|
|
137
|
+
const base = server;
|
|
138
|
+
const result = await remote.get(base ? { since: version } : void 0);
|
|
140
139
|
if (disposed) return;
|
|
141
|
-
if (result.version >= version || !loaded) adoptRead(result, readPlaybackRevision);
|
|
140
|
+
if (result.version >= version || !loaded) adoptRead(result, base, readPlaybackRevision);
|
|
142
141
|
readError = null;
|
|
143
142
|
emit();
|
|
144
143
|
} while (refreshAgain && !disposed);
|
|
@@ -162,6 +161,7 @@ function createBoardReplica(options) {
|
|
|
162
161
|
async function flush() {
|
|
163
162
|
if (sending || disposed || !loaded || !restored) return;
|
|
164
163
|
sending = true;
|
|
164
|
+
let latest = 0;
|
|
165
165
|
try {
|
|
166
166
|
while (pending.length && !disposed) {
|
|
167
167
|
const entry = pending[0];
|
|
@@ -173,12 +173,12 @@ function createBoardReplica(options) {
|
|
|
173
173
|
const stillPending = pending.some((item) => item.mutationId === entry.mutationId);
|
|
174
174
|
pending = pending.filter((item) => item.mutationId !== entry.mutationId);
|
|
175
175
|
storage.deletePending(entry.mutationId).catch(() => void 0);
|
|
176
|
-
if (stillPending &&
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
176
|
+
if (stillPending && result.status === "applied" && result.version > version) sent = [...sent, {
|
|
177
|
+
version: result.version,
|
|
178
|
+
patch: entry.patch
|
|
179
|
+
}];
|
|
180
|
+
latest = Math.max(latest, result.version);
|
|
181
|
+
recompute();
|
|
182
182
|
retryDelay = RETRY_BASE_MS;
|
|
183
183
|
writeError = null;
|
|
184
184
|
emit();
|
|
@@ -198,6 +198,7 @@ function createBoardReplica(options) {
|
|
|
198
198
|
return;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
|
+
if (latest > version && !disposed) refresh();
|
|
201
202
|
} finally {
|
|
202
203
|
sending = false;
|
|
203
204
|
}
|
|
@@ -233,15 +234,19 @@ function createBoardReplica(options) {
|
|
|
233
234
|
function onOnline() {
|
|
234
235
|
if (pending.length || readError || writeError) retry();
|
|
235
236
|
}
|
|
236
|
-
async function
|
|
237
|
-
const
|
|
237
|
+
async function restoreDocument() {
|
|
238
|
+
const cached = await storage.readDocument().catch(() => null);
|
|
239
|
+
if (disposed || server || !cached) return;
|
|
240
|
+
const parsed = parseBoardDocument(cached.document);
|
|
241
|
+
if (parsed.ok) adoptServer(parsed.document, cached.version, false);
|
|
242
|
+
}
|
|
243
|
+
async function restore(document) {
|
|
244
|
+
const [, stored] = await Promise.all([document, storage.listPending().catch(() => [])]);
|
|
238
245
|
if (disposed) return;
|
|
239
246
|
const known = new Set(stored.map((entry) => entry.mutationId));
|
|
240
247
|
pending = [...stored, ...pending.filter((entry) => !known.has(entry.mutationId))];
|
|
241
248
|
restored = true;
|
|
242
|
-
|
|
243
|
-
if (cached && parsed?.ok) adoptServer(parsed.document, cached.version, false);
|
|
244
|
-
else recompute();
|
|
249
|
+
recompute();
|
|
245
250
|
emit();
|
|
246
251
|
}
|
|
247
252
|
function receivePlayback(next) {
|
|
@@ -260,7 +265,12 @@ function createBoardReplica(options) {
|
|
|
260
265
|
async start() {
|
|
261
266
|
unsubscribeRemote ??= subscribeRemote();
|
|
262
267
|
globalThis.addEventListener?.("online", onOnline);
|
|
263
|
-
|
|
268
|
+
const document = restoreDocument();
|
|
269
|
+
const cacheWait = new Promise((resolve) => {
|
|
270
|
+
const timer = setTimeout(resolve, CACHE_WAIT_MS);
|
|
271
|
+
document.then(() => clearTimeout(timer));
|
|
272
|
+
});
|
|
273
|
+
await Promise.all([restore(document), Promise.race([document, cacheWait]).then(refresh)]);
|
|
264
274
|
await flush();
|
|
265
275
|
},
|
|
266
276
|
apply(patch) {
|
|
@@ -1,102 +1,31 @@
|
|
|
1
|
+
import { deleteByIndex, indexedDb } from "../../indexeddb.js";
|
|
1
2
|
//#region src/board/replica/indexeddb.ts
|
|
2
3
|
const DATABASE = "cohub-board";
|
|
3
4
|
const VERSION = 1;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const opening = new Promise((resolve, reject) => {
|
|
10
|
-
const factory = globalThis.indexedDB;
|
|
11
|
-
if (!factory) {
|
|
12
|
-
reject(/* @__PURE__ */ new Error("IndexedDB is unavailable."));
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
let late = false;
|
|
16
|
-
const timer = setTimeout(() => {
|
|
17
|
-
late = true;
|
|
18
|
-
reject(/* @__PURE__ */ new Error("IndexedDB did not open in time."));
|
|
19
|
-
}, OPEN_TIMEOUT_MS);
|
|
20
|
-
const request = factory.open(name, VERSION);
|
|
21
|
-
request.onupgradeneeded = () => {
|
|
22
|
-
const db = request.result;
|
|
23
|
-
db.createObjectStore("documents", { keyPath: "board" }).createIndex("user", "userKey");
|
|
24
|
-
const pending = db.createObjectStore("pending", { keyPath: ["board", "mutationId"] });
|
|
25
|
-
pending.createIndex("board", "board");
|
|
26
|
-
pending.createIndex("user", "userKey");
|
|
27
|
-
};
|
|
28
|
-
request.onsuccess = () => {
|
|
29
|
-
clearTimeout(timer);
|
|
30
|
-
const db = request.result;
|
|
31
|
-
if (late) {
|
|
32
|
-
db.close();
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
const forget = () => {
|
|
36
|
-
if (connections.get(name) === opening) connections.delete(name);
|
|
37
|
-
};
|
|
38
|
-
db.onversionchange = () => {
|
|
39
|
-
db.close();
|
|
40
|
-
forget();
|
|
41
|
-
};
|
|
42
|
-
db.onclose = forget;
|
|
43
|
-
resolve(db);
|
|
44
|
-
};
|
|
45
|
-
request.onerror = () => {
|
|
46
|
-
clearTimeout(timer);
|
|
47
|
-
reject(request.error ?? /* @__PURE__ */ new Error("IndexedDB failed to open."));
|
|
48
|
-
};
|
|
49
|
-
});
|
|
50
|
-
connections.set(name, opening);
|
|
51
|
-
opening.catch(() => {
|
|
52
|
-
if (connections.get(name) === opening) connections.delete(name);
|
|
53
|
-
});
|
|
54
|
-
return opening;
|
|
55
|
-
}
|
|
56
|
-
async function transact(name, stores, mode, work, retry = true) {
|
|
57
|
-
const db = await open(name);
|
|
58
|
-
let tx;
|
|
59
|
-
try {
|
|
60
|
-
tx = db.transaction(stores, mode);
|
|
61
|
-
} catch (error) {
|
|
62
|
-
if (!retry) throw error;
|
|
63
|
-
db.close();
|
|
64
|
-
connections.delete(name);
|
|
65
|
-
return transact(name, stores, mode, work, false);
|
|
66
|
-
}
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
68
|
-
const result = work(tx);
|
|
69
|
-
tx.oncomplete = () => resolve(result());
|
|
70
|
-
tx.onerror = () => reject(tx.error ?? /* @__PURE__ */ new Error("IndexedDB transaction failed."));
|
|
71
|
-
tx.onabort = () => reject(tx.error ?? /* @__PURE__ */ new Error("IndexedDB transaction aborted."));
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
function deleteByIndex(store, index, key) {
|
|
75
|
-
const request = store.index(index).openKeyCursor(IDBKeyRange.only(key));
|
|
76
|
-
request.onsuccess = () => {
|
|
77
|
-
const cursor = request.result;
|
|
78
|
-
if (!cursor) return;
|
|
79
|
-
store.delete(cursor.primaryKey);
|
|
80
|
-
cursor.continue();
|
|
81
|
-
};
|
|
5
|
+
function upgrade(db) {
|
|
6
|
+
db.createObjectStore("documents", { keyPath: "board" }).createIndex("user", "userKey");
|
|
7
|
+
const pending = db.createObjectStore("pending", { keyPath: ["board", "mutationId"] });
|
|
8
|
+
pending.createIndex("board", "board");
|
|
9
|
+
pending.createIndex("user", "userKey");
|
|
82
10
|
}
|
|
11
|
+
const database = (name) => indexedDb(name, VERSION, upgrade);
|
|
83
12
|
let lastOrder = 0;
|
|
84
13
|
function createIndexedDbBoardReplicaStorage(scope, options = {}) {
|
|
85
|
-
const
|
|
14
|
+
const { transact } = database(options.database ?? DATABASE);
|
|
86
15
|
const board = JSON.stringify([
|
|
87
16
|
scope.userKey,
|
|
88
17
|
scope.spaceId,
|
|
89
18
|
scope.boardId
|
|
90
19
|
]);
|
|
91
20
|
return {
|
|
92
|
-
listPending: () => transact(
|
|
21
|
+
listPending: () => transact(["pending"], "readonly", (tx) => {
|
|
93
22
|
const request = tx.objectStore("pending").index("board").getAll(IDBKeyRange.only(board));
|
|
94
23
|
return () => request.result.sort((a, b) => a.order - b.order).map(({ mutationId, patch }) => ({
|
|
95
24
|
mutationId,
|
|
96
25
|
patch
|
|
97
26
|
}));
|
|
98
27
|
}),
|
|
99
|
-
putPending: ({ mutationId, patch }) => transact(
|
|
28
|
+
putPending: ({ mutationId, patch }) => transact(["pending"], "readwrite", (tx) => {
|
|
100
29
|
lastOrder = Math.max(Date.now(), lastOrder + 1);
|
|
101
30
|
const record = {
|
|
102
31
|
board,
|
|
@@ -108,11 +37,11 @@ function createIndexedDbBoardReplicaStorage(scope, options = {}) {
|
|
|
108
37
|
tx.objectStore("pending").put(record);
|
|
109
38
|
return () => void 0;
|
|
110
39
|
}),
|
|
111
|
-
deletePending: (mutationId) => transact(
|
|
40
|
+
deletePending: (mutationId) => transact(["pending"], "readwrite", (tx) => {
|
|
112
41
|
tx.objectStore("pending").delete([board, mutationId]);
|
|
113
42
|
return () => void 0;
|
|
114
43
|
}),
|
|
115
|
-
readDocument: () => transact(
|
|
44
|
+
readDocument: () => transact(["documents"], "readonly", (tx) => {
|
|
116
45
|
const request = tx.objectStore("documents").get(board);
|
|
117
46
|
return () => {
|
|
118
47
|
const record = request.result;
|
|
@@ -122,7 +51,7 @@ function createIndexedDbBoardReplicaStorage(scope, options = {}) {
|
|
|
122
51
|
} : null;
|
|
123
52
|
};
|
|
124
53
|
}),
|
|
125
|
-
writeDocument: (version, document) => transact(
|
|
54
|
+
writeDocument: (version, document) => transact(["documents"], "readwrite", (tx) => {
|
|
126
55
|
const store = tx.objectStore("documents");
|
|
127
56
|
const request = store.get(board);
|
|
128
57
|
request.onsuccess = () => {
|
|
@@ -142,7 +71,7 @@ function createIndexedDbBoardReplicaStorage(scope, options = {}) {
|
|
|
142
71
|
}
|
|
143
72
|
async function clearBoardReplicaStorage(options = {}) {
|
|
144
73
|
const { userKey } = options;
|
|
145
|
-
await
|
|
74
|
+
await database(options.database ?? DATABASE).transact(["documents", "pending"], "readwrite", (tx) => {
|
|
146
75
|
for (const name of ["documents", "pending"]) {
|
|
147
76
|
const store = tx.objectStore(name);
|
|
148
77
|
if (userKey === void 0) store.clear();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ModelFormat } from "../../protocol/dist/fs/mime.js";
|
|
2
2
|
import { BoardSceneItem } from "../model/scene.js";
|
|
3
3
|
import { BoardAssetMedia, BoardAssetRef } from "../model/asset-key.js";
|
|
4
|
-
import {
|
|
4
|
+
import { BoardAssetSource } from "../model/media-playback.js";
|
|
5
5
|
import "../model/index.js";
|
|
6
6
|
import { LruBudget } from "./lru.js";
|
|
7
7
|
import { BoardImageTexturePool } from "./texture-pool.js";
|
|
@@ -25,7 +25,7 @@ type BoardModelPreviews = {
|
|
|
25
25
|
type BoardAssetManager = {
|
|
26
26
|
assetKey: (item: BoardSceneItem) => string | null;
|
|
27
27
|
invalidatePath: (path: string) => void;
|
|
28
|
-
invalidateItemAssets: () => void;
|
|
28
|
+
invalidateItemAssets: (ids?: Iterable<string>) => void;
|
|
29
29
|
requestItem: (item: BoardSceneItem, edge?: number) => void;
|
|
30
30
|
/** World point used to prioritize queued loads. */
|
|
31
31
|
focus: (point: {
|
|
@@ -60,7 +60,8 @@ type BoardAssetPrefetch = {
|
|
|
60
60
|
type BoardAssetChange = "texture" | "tone";
|
|
61
61
|
type BoardAssetManagerOptions = {
|
|
62
62
|
/** Resolve a Space file path to a URL a texture can load from; null when unavailable. */
|
|
63
|
-
|
|
63
|
+
resolveFile: BoardAssetSource["resolveFile"];
|
|
64
|
+
subscribe?: BoardAssetSource["subscribe"];
|
|
64
65
|
/** undefined keeps the built-in rule, null shows none; cached until `invalidateItemAssets`. */
|
|
65
66
|
itemAsset?: (item: BoardSceneItem) => BoardAssetRef | null | undefined;
|
|
66
67
|
concurrency?: number;
|