@agentshouse/mdruntime 0.1.0-cec6690d5712e → 0.1.0-cedb03eaa48b6
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/AGENTS.md +277 -271
- package/README.md +8 -8
- package/dist/adapter.d.ts +85 -20
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attempt.d.ts.map +1 -1
- package/dist/attempt.js +14 -1
- package/dist/binary.d.ts +23 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +8 -0
- package/dist/bootstrap.d.ts +3 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +37 -14
- package/dist/change-set.d.ts +2 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +40 -13
- package/dist/change.d.ts +11 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +26 -1
- package/dist/chat/acts.d.ts +3 -4
- package/dist/chat/acts.d.ts.map +1 -1
- package/dist/chat/acts.js +10 -10
- package/dist/chat/earlier.d.ts +10 -0
- package/dist/chat/earlier.d.ts.map +1 -0
- package/dist/chat/earlier.js +54 -0
- package/dist/chat/kit.d.ts +2 -1
- package/dist/chat/kit.d.ts.map +1 -1
- package/dist/chat/kit.js +3 -3
- package/dist/chat/list.d.ts +8 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +48 -8
- package/dist/chat/markdown.d.ts +2 -1
- package/dist/chat/markdown.d.ts.map +1 -1
- package/dist/chat/markdown.js +7 -6
- package/dist/chat/message.d.ts.map +1 -1
- package/dist/chat/message.js +2 -2
- package/dist/chat/messages.d.ts +1 -0
- package/dist/chat/messages.d.ts.map +1 -1
- package/dist/chat/messages.js +4 -0
- package/dist/chat/provider.d.ts +1 -1
- package/dist/chat/provider.d.ts.map +1 -1
- package/dist/chat/provider.js +62 -79
- package/dist/chat/question.d.ts +1 -1
- package/dist/chat/question.d.ts.map +1 -1
- package/dist/chat/question.js +7 -18
- package/dist/chat/ready.d.ts +1 -0
- package/dist/chat/ready.d.ts.map +1 -1
- package/dist/chat/ready.js +4 -4
- package/dist/chat/style.js +5 -5
- package/dist/client.d.ts +22 -9
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +23 -6
- package/dist/collection.d.ts +17 -3
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +260 -19
- package/dist/connection.d.ts +39 -12
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1769 -385
- package/dist/conversation.d.ts +20 -7
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +474 -163
- package/dist/durability.d.ts +7 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +17 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +157 -0
- package/dist/fence.d.ts +6 -0
- package/dist/fence.d.ts.map +1 -0
- package/dist/fence.js +10 -0
- package/dist/host.d.ts +15 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +98 -12
- package/dist/identity.d.ts +3 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +9 -0
- package/dist/index.d.ts +12 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/memory.d.ts +10 -4
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +64 -17
- package/dist/model.d.ts +4 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +10 -1
- package/dist/observation.d.ts +7 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +29 -12
- package/dist/outcome.d.ts +17 -1
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +10 -0
- package/dist/overlay.d.ts +15 -2
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +99 -62
- package/dist/query.d.ts +58 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +36 -7
- package/dist/reach.d.ts +8 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +53 -6
- package/dist/react.d.ts +8 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -17
- package/dist/read-side.d.ts +16 -7
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +493 -102
- package/dist/readiness.d.ts +53 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/reads.d.ts +11 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +98 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +197 -0
- package/dist/refresh.d.ts +4 -4
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +27 -25
- package/dist/replica.d.ts +11 -4
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +106 -48
- package/dist/room-draft.d.ts +32 -3
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +121 -3
- package/dist/rows.d.ts +8 -13
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +12 -13
- package/dist/save.d.ts +29 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +358 -30
- package/dist/search.d.ts +49 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +192 -47
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +75 -0
- package/dist/shared.d.ts +11 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +368 -0
- package/dist/status.d.ts +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +68 -21
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +463 -206
- package/dist/turn.d.ts +7 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +51 -0
- package/dist/windows.d.ts +26 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +93 -0
- package/dist/wire.d.ts +152 -30
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +52 -29
- package/package.json +12 -8
- package/dist/attachment.d.ts +0 -3
- package/dist/attachment.d.ts.map +0 -1
- package/dist/attachment.js +0 -8
package/dist/store.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { sameBinary, sameChange } from './overlay.js';
|
|
2
|
+
import { differing } from './shared.js';
|
|
3
|
+
import { precedes } from './windows.js';
|
|
3
4
|
const DATABASE = 'mdruntime';
|
|
5
|
+
const AUTHORED = 'mdruntime-authored';
|
|
6
|
+
const FENCES = 'fences';
|
|
4
7
|
const ROOMS = 'rooms';
|
|
5
8
|
const DOCUMENTS = 'documents';
|
|
6
|
-
const
|
|
7
|
-
const ATTACHMENTS = 'attachments';
|
|
9
|
+
const BINARY_FILES = 'binaryFiles';
|
|
8
10
|
const TRANSFERS = 'transfers';
|
|
11
|
+
const RECEIVED = 'received';
|
|
12
|
+
const RECEIVED_PARTS = 'receivedParts';
|
|
9
13
|
const PENDING_CHANGES = 'pendingChanges';
|
|
10
14
|
const DECLARATIONS = 'declarations';
|
|
11
15
|
const ROOM_DRAFTS = 'roomDrafts';
|
|
@@ -13,11 +17,45 @@ const PRESENTATION = 'presentation';
|
|
|
13
17
|
const CONVERSATIONS = 'conversations';
|
|
14
18
|
const MESSAGES = 'messages';
|
|
15
19
|
const CHAT_DRAFTS = 'chatDrafts';
|
|
20
|
+
const CALLS = 'calls';
|
|
21
|
+
const QUEUES = 'queues';
|
|
22
|
+
const FACTS = 'facts';
|
|
16
23
|
const CURRENT = 'current';
|
|
17
24
|
const MEMBER = 'member';
|
|
18
|
-
|
|
19
|
-
const
|
|
25
|
+
const TARGETS = 'targets';
|
|
26
|
+
const GENERATION = 'generation';
|
|
27
|
+
const HOLDER = 'holder';
|
|
28
|
+
const BINDING = 'binding';
|
|
29
|
+
export const STORE_SCHEMA = 25;
|
|
30
|
+
const REPLICA_SHAPE = 23;
|
|
31
|
+
export const AUTHORED_SCHEMA = 3;
|
|
32
|
+
const AUTHORED_STORES = [
|
|
33
|
+
[QUEUES, { keyPath: 'locator' }],
|
|
34
|
+
[PENDING_CHANGES, { keyPath: ['locator', 'id'] }],
|
|
35
|
+
[ROOM_DRAFTS, { keyPath: ['locator', 'path'] }],
|
|
36
|
+
[CHAT_DRAFTS, { keyPath: 'conversation' }],
|
|
37
|
+
[CALLS, { keyPath: 'operation' }],
|
|
38
|
+
[FACTS, undefined],
|
|
39
|
+
[FENCES, { keyPath: 'locator' }],
|
|
40
|
+
];
|
|
41
|
+
const REPLICA_STORES = [
|
|
42
|
+
[ROOMS, { keyPath: 'locator' }],
|
|
43
|
+
[DOCUMENTS, { keyPath: ['locator', 'transfer', 'path'] }],
|
|
44
|
+
[BINARY_FILES, { keyPath: ['locator', 'transfer', 'path'] }],
|
|
45
|
+
[TRANSFERS, { keyPath: 'locator' }],
|
|
46
|
+
[RECEIVED, { keyPath: 'key' }],
|
|
47
|
+
[RECEIVED_PARTS, { keyPath: ['key', 'index'] }],
|
|
48
|
+
[DECLARATIONS, undefined],
|
|
49
|
+
[PRESENTATION, { keyPath: 'app' }],
|
|
50
|
+
[CONVERSATIONS, { keyPath: 'conversation' }],
|
|
51
|
+
[MESSAGES, { keyPath: ['conversation', 'identity'] }],
|
|
52
|
+
];
|
|
20
53
|
const READ_BATCH = 256;
|
|
54
|
+
const MESSAGE_INDEXES = [
|
|
55
|
+
['conversation', 'conversation'],
|
|
56
|
+
['position', ['conversation', 'position']],
|
|
57
|
+
['turn', ['conversation', 'turn']],
|
|
58
|
+
];
|
|
21
59
|
function settled(request) {
|
|
22
60
|
return new Promise((resolve, reject) => {
|
|
23
61
|
request.onsuccess = () => resolve(request.result);
|
|
@@ -33,7 +71,6 @@ function completed(transaction) {
|
|
|
33
71
|
}
|
|
34
72
|
const EMPTY_DECLARATIONS = {
|
|
35
73
|
lastCompleted: null,
|
|
36
|
-
generation: null,
|
|
37
74
|
providerLimits: [],
|
|
38
75
|
capabilities: [],
|
|
39
76
|
};
|
|
@@ -61,9 +98,15 @@ function amendPending(database, locator, id, amendment) {
|
|
|
61
98
|
};
|
|
62
99
|
return completed(transaction);
|
|
63
100
|
}
|
|
64
|
-
function
|
|
65
|
-
|
|
66
|
-
|
|
101
|
+
function accepted({ conversation: _held, ...message }) {
|
|
102
|
+
return message;
|
|
103
|
+
}
|
|
104
|
+
function roomRecord(record) {
|
|
105
|
+
const { documents, binaries, revisions, fileIds, changes, written, ...room } = record;
|
|
106
|
+
return room;
|
|
107
|
+
}
|
|
108
|
+
function chatDraftRecord(record) {
|
|
109
|
+
return { ...record, revision: record.revision ?? '' };
|
|
67
110
|
}
|
|
68
111
|
function underTransfer(locator, transfer, after) {
|
|
69
112
|
return after === undefined
|
|
@@ -85,13 +128,15 @@ async function readTransfer(store, locator, transfer, receive) {
|
|
|
85
128
|
}
|
|
86
129
|
}
|
|
87
130
|
function emptyLayer() {
|
|
88
|
-
return { documents: {},
|
|
131
|
+
return { documents: {}, binaries: {}, revisions: {}, fileIds: {}, changes: {}, written: {} };
|
|
89
132
|
}
|
|
90
133
|
async function readLayer(transaction, locator, transfer) {
|
|
91
134
|
const layer = emptyLayer();
|
|
92
135
|
const head = (held) => {
|
|
93
136
|
if (held.revision !== null)
|
|
94
137
|
layer.revisions[held.path] = held.revision;
|
|
138
|
+
if (held.fileId !== null)
|
|
139
|
+
layer.fileIds[held.path] = held.fileId;
|
|
95
140
|
if (held.change !== null)
|
|
96
141
|
layer.changes[held.path] = held.change;
|
|
97
142
|
};
|
|
@@ -101,9 +146,9 @@ async function readLayer(transaction, locator, transfer) {
|
|
|
101
146
|
layer.written[document.path] = document.written;
|
|
102
147
|
head(document);
|
|
103
148
|
});
|
|
104
|
-
await readTransfer(transaction.objectStore(
|
|
105
|
-
layer.
|
|
106
|
-
head(
|
|
149
|
+
await readTransfer(transaction.objectStore(BINARY_FILES), locator, transfer, (file) => {
|
|
150
|
+
layer.binaries[file.path] = file.binary;
|
|
151
|
+
head(file);
|
|
107
152
|
});
|
|
108
153
|
return layer;
|
|
109
154
|
}
|
|
@@ -114,45 +159,47 @@ function documentRecord(locator, transfer, layer, path) {
|
|
|
114
159
|
path,
|
|
115
160
|
content: layer.documents[path],
|
|
116
161
|
revision: layer.revisions[path] ?? null,
|
|
162
|
+
fileId: layer.fileIds[path] ?? null,
|
|
117
163
|
change: layer.changes[path] ?? null,
|
|
118
164
|
written: layer.written[path] ?? null,
|
|
119
165
|
};
|
|
120
166
|
}
|
|
121
|
-
function
|
|
167
|
+
function binaryFileRecord(locator, transfer, layer, path) {
|
|
122
168
|
return {
|
|
123
169
|
locator,
|
|
124
170
|
transfer,
|
|
125
171
|
path,
|
|
126
172
|
revision: layer.revisions[path] ?? null,
|
|
173
|
+
fileId: layer.fileIds[path] ?? null,
|
|
127
174
|
change: layer.changes[path] ?? null,
|
|
175
|
+
binary: layer.binaries[path],
|
|
128
176
|
};
|
|
129
177
|
}
|
|
130
178
|
function writeLayer(transaction, locator, transfer, next, base) {
|
|
131
179
|
const documents = transaction.objectStore(DOCUMENTS);
|
|
132
|
-
|
|
133
|
-
|
|
180
|
+
const files = transaction.objectStore(BINARY_FILES);
|
|
181
|
+
const paths = base === null
|
|
182
|
+
? new Set([...Object.keys(next.documents), ...Object.keys(next.binaries)])
|
|
183
|
+
: new Set([
|
|
184
|
+
...differing(base.documents, next.documents),
|
|
185
|
+
...differing(base.revisions, next.revisions),
|
|
186
|
+
...differing(base.fileIds, next.fileIds),
|
|
187
|
+
...differing(base.written, next.written),
|
|
188
|
+
...differing(base.changes, next.changes, sameChange),
|
|
189
|
+
...differing(base.binaries, next.binaries, sameBinary),
|
|
190
|
+
]);
|
|
191
|
+
for (const path of paths) {
|
|
192
|
+
if (next.documents[path] !== undefined) {
|
|
193
|
+
documents.put(documentRecord(locator, transfer, next, path));
|
|
194
|
+
}
|
|
195
|
+
else if (base?.documents[path] !== undefined) {
|
|
134
196
|
documents.delete([locator, transfer, path]);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
continue;
|
|
142
|
-
documents.put(documentRecord(locator, transfer, next, path));
|
|
143
|
-
}
|
|
144
|
-
const targets = transaction.objectStore(BINARY_TARGETS);
|
|
145
|
-
const beforeTargets = new Set(base?.binaryTargets ?? []);
|
|
146
|
-
const afterTargets = new Set(next.binaryTargets);
|
|
147
|
-
for (const path of beforeTargets) {
|
|
148
|
-
if (!afterTargets.has(path))
|
|
149
|
-
targets.delete([locator, transfer, path]);
|
|
150
|
-
}
|
|
151
|
-
for (const path of afterTargets) {
|
|
152
|
-
if (!beforeTargets.has(path) ||
|
|
153
|
-
base?.revisions[path] !== next.revisions[path] ||
|
|
154
|
-
!sameChange(base?.changes[path], next.changes[path])) {
|
|
155
|
-
targets.put(targetRecord(locator, transfer, next, path));
|
|
197
|
+
}
|
|
198
|
+
if (next.binaries[path] !== undefined) {
|
|
199
|
+
files.put(binaryFileRecord(locator, transfer, next, path));
|
|
200
|
+
}
|
|
201
|
+
else if (base?.binaries[path] !== undefined) {
|
|
202
|
+
files.delete([locator, transfer, path]);
|
|
156
203
|
}
|
|
157
204
|
}
|
|
158
205
|
}
|
|
@@ -165,155 +212,207 @@ function removeRoomEntries(store, locator) {
|
|
|
165
212
|
}
|
|
166
213
|
};
|
|
167
214
|
}
|
|
168
|
-
|
|
215
|
+
function removeDatabase(name) {
|
|
169
216
|
return new Promise((resolve, reject) => {
|
|
170
|
-
const removal = indexedDB.deleteDatabase(
|
|
217
|
+
const removal = indexedDB.deleteDatabase(name);
|
|
171
218
|
removal.onsuccess = () => resolve();
|
|
172
219
|
removal.onerror = () => reject(removal.error);
|
|
173
220
|
});
|
|
174
221
|
}
|
|
175
|
-
function
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
222
|
+
export async function authoredHolder() {
|
|
223
|
+
const authored = await openAuthored();
|
|
224
|
+
try {
|
|
225
|
+
const transaction = authored.transaction(FACTS, 'readonly');
|
|
226
|
+
const held = transaction.objectStore(FACTS).get(HOLDER);
|
|
227
|
+
await completed(transaction);
|
|
228
|
+
return typeof held.result === 'string' ? held.result : null;
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
authored.close();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export async function authoredBy(holder) {
|
|
235
|
+
const authored = await openAuthored();
|
|
236
|
+
try {
|
|
237
|
+
const transaction = authored.transaction(FACTS, 'readwrite');
|
|
238
|
+
const facts = transaction.objectStore(FACTS);
|
|
239
|
+
const held = facts.get(HOLDER);
|
|
240
|
+
let owned = true;
|
|
241
|
+
held.onsuccess = () => {
|
|
242
|
+
if (held.result === undefined)
|
|
243
|
+
facts.put(holder, HOLDER);
|
|
244
|
+
else
|
|
245
|
+
owned = held.result === holder;
|
|
246
|
+
};
|
|
247
|
+
await completed(transaction);
|
|
248
|
+
return owned;
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
authored.close();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
export async function authoredBinding() {
|
|
255
|
+
const authored = await openAuthored();
|
|
256
|
+
try {
|
|
257
|
+
const transaction = authored.transaction(FACTS, 'readonly');
|
|
258
|
+
const held = transaction.objectStore(FACTS).get(BINDING);
|
|
259
|
+
await completed(transaction);
|
|
260
|
+
return typeof held.result === 'string' ? held.result : null;
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
authored.close();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
export async function bindAuthored(binding) {
|
|
267
|
+
const authored = await openAuthored();
|
|
268
|
+
try {
|
|
269
|
+
const transaction = authored.transaction(FACTS, 'readwrite');
|
|
270
|
+
transaction.objectStore(FACTS).put(binding, BINDING);
|
|
271
|
+
await completed(transaction);
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
authored.close();
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
export async function removeRuntimeStore(holder) {
|
|
278
|
+
await removeDatabase(DATABASE);
|
|
279
|
+
if (holder !== undefined && (await authoredBy(holder)))
|
|
280
|
+
return true;
|
|
281
|
+
await removeDatabase(AUTHORED);
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
export function openDatabase(name, version, upgrade) {
|
|
285
|
+
return new Promise((resolve, reject) => {
|
|
286
|
+
const opening = indexedDB.open(name, version);
|
|
287
|
+
opening.onupgradeneeded = (event) => upgrade(opening, event.oldVersion);
|
|
288
|
+
opening.onsuccess = () => resolve(opening.result);
|
|
289
|
+
opening.onerror = () => {
|
|
290
|
+
if (opening.error?.name !== 'VersionError') {
|
|
291
|
+
reject(opening.error);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
removeDatabase(name)
|
|
295
|
+
.then(() => openDatabase(name, version, upgrade))
|
|
296
|
+
.then(resolve, reject);
|
|
183
297
|
};
|
|
184
298
|
});
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
const
|
|
189
|
-
if (
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
transfers.set(record.locator, transfer);
|
|
193
|
-
room.update({ ...record, transfer });
|
|
194
|
-
room.continue();
|
|
195
|
-
return;
|
|
299
|
+
}
|
|
300
|
+
function openReplica() {
|
|
301
|
+
return openDatabase(DATABASE, STORE_SCHEMA, (opening, oldVersion) => {
|
|
302
|
+
const database = opening.result;
|
|
303
|
+
if (oldVersion < REPLICA_SHAPE) {
|
|
304
|
+
for (const name of [...database.objectStoreNames])
|
|
305
|
+
database.deleteObjectStore(name);
|
|
196
306
|
}
|
|
197
|
-
for (const
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
if (entry === null) {
|
|
202
|
-
database.deleteObjectStore(from.name);
|
|
203
|
-
return;
|
|
204
|
-
}
|
|
205
|
-
const record = entry.value;
|
|
206
|
-
const transfer = transfers.get(record.locator);
|
|
207
|
-
if (transfer !== undefined)
|
|
208
|
-
to.put({ ...record, transfer });
|
|
209
|
-
entry.continue();
|
|
210
|
-
};
|
|
307
|
+
for (const [name, parameters] of REPLICA_STORES) {
|
|
308
|
+
if (database.objectStoreNames.contains(name))
|
|
309
|
+
continue;
|
|
310
|
+
database.createObjectStore(name, parameters);
|
|
211
311
|
}
|
|
212
|
-
|
|
312
|
+
const messages = opening.transaction.objectStore(MESSAGES);
|
|
313
|
+
for (const [name, keyPath] of MESSAGE_INDEXES) {
|
|
314
|
+
if (!messages.indexNames.contains(name))
|
|
315
|
+
messages.createIndex(name, keyPath);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
213
318
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
opening.onupgradeneeded = (event) => {
|
|
319
|
+
function openAuthored() {
|
|
320
|
+
return openDatabase(AUTHORED, AUTHORED_SCHEMA, (opening) => {
|
|
217
321
|
const database = opening.result;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
322
|
+
for (const [name, parameters] of AUTHORED_STORES) {
|
|
323
|
+
if (!database.objectStoreNames.contains(name))
|
|
324
|
+
database.createObjectStore(name, parameters);
|
|
221
325
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
database.createObjectStore(DECLARATIONS);
|
|
231
|
-
database.createObjectStore(ROOM_DRAFTS, { keyPath: ['locator', 'path'] });
|
|
232
|
-
database.createObjectStore(PRESENTATION, { keyPath: 'app' });
|
|
233
|
-
database.createObjectStore(CONVERSATIONS, { keyPath: 'conversation' });
|
|
234
|
-
const messages = database.createObjectStore(MESSAGES, {
|
|
235
|
-
keyPath: ['conversation', 'identity'],
|
|
236
|
-
});
|
|
237
|
-
messages.createIndex('conversation', 'conversation');
|
|
238
|
-
database.createObjectStore(CHAT_DRAFTS, { keyPath: 'conversation' });
|
|
239
|
-
};
|
|
240
|
-
const database = await settled(opening);
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
export async function openRuntimeStore(fenced) {
|
|
329
|
+
const authored = await openAuthored();
|
|
330
|
+
const database = await openReplica().catch((error) => {
|
|
331
|
+
authored.close();
|
|
332
|
+
throw error;
|
|
333
|
+
});
|
|
241
334
|
return {
|
|
242
335
|
async all() {
|
|
243
|
-
const transaction = database.transaction([ROOMS, DOCUMENTS,
|
|
244
|
-
const
|
|
245
|
-
settled(transaction.objectStore(ROOMS).getAll()),
|
|
246
|
-
settled(transaction.objectStore(ATTACHMENTS).getAll()),
|
|
247
|
-
]);
|
|
336
|
+
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES], 'readonly');
|
|
337
|
+
const rooms = await settled(transaction.objectStore(ROOMS).getAll());
|
|
248
338
|
const records = [];
|
|
249
|
-
for (const
|
|
250
|
-
|
|
251
|
-
records.push({
|
|
252
|
-
...room,
|
|
253
|
-
...layer,
|
|
254
|
-
attachments: attachments.flatMap(({ locator, ...attachment }) => locator === room.locator ? [attachment] : []),
|
|
255
|
-
});
|
|
339
|
+
for (const room of rooms.filter((held) => !fenced(held.locator))) {
|
|
340
|
+
records.push({ ...room, ...(await readLayer(transaction, room.locator, room.transfer)) });
|
|
256
341
|
}
|
|
257
342
|
return records;
|
|
258
343
|
},
|
|
259
|
-
async
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
if (moved)
|
|
269
|
-
transaction.objectStore(TRANSFERS).delete(next.locator);
|
|
270
|
-
writeLayer(transaction, next.locator, next.transfer, next, moved ? (stored ?? null) : previous);
|
|
271
|
-
const attachments = transaction.objectStore(ATTACHMENTS);
|
|
272
|
-
const held = new Map((previous?.attachments ?? []).map((attachment) => [attachment.reference, attachment]));
|
|
273
|
-
const declared = new Set(next.attachments.map((attachment) => attachment.reference));
|
|
274
|
-
for (const reference of held.keys()) {
|
|
275
|
-
if (!declared.has(reference))
|
|
276
|
-
attachments.delete([next.locator, reference]);
|
|
277
|
-
}
|
|
278
|
-
for (const attachment of next.attachments) {
|
|
279
|
-
if (held.get(attachment.reference) === attachment)
|
|
280
|
-
continue;
|
|
281
|
-
attachments.put({ ...attachment, locator: next.locator });
|
|
282
|
-
}
|
|
283
|
-
if (previousQueue !== undefined) {
|
|
284
|
-
const pending = transaction.objectStore(PENDING_CHANGES);
|
|
285
|
-
const before = new Set(previousQueue.map((batch) => batch.id));
|
|
344
|
+
async keepAuthored({ locator, queue, founded, saved, roomDrafts, consumedRoomDrafts }) {
|
|
345
|
+
if (fenced(locator))
|
|
346
|
+
return;
|
|
347
|
+
const transaction = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
|
|
348
|
+
const order = transaction.objectStore(QUEUES);
|
|
349
|
+
const pending = transaction.objectStore(PENDING_CHANGES);
|
|
350
|
+
const held = order.get(locator);
|
|
351
|
+
held.onsuccess = () => {
|
|
352
|
+
const before = new Set(held.result?.order ?? []);
|
|
286
353
|
const after = new Set(queue.map((batch) => batch.id));
|
|
354
|
+
if (queue.length === 0)
|
|
355
|
+
order.delete(locator);
|
|
356
|
+
else
|
|
357
|
+
order.put({ locator, order: [...after] });
|
|
287
358
|
for (const id of before) {
|
|
288
359
|
if (!after.has(id))
|
|
289
|
-
pending.delete([
|
|
360
|
+
pending.delete([locator, id]);
|
|
290
361
|
}
|
|
291
362
|
for (const batch of queue) {
|
|
292
363
|
if (!before.has(batch.id)) {
|
|
293
364
|
pending.put({
|
|
294
|
-
locator
|
|
365
|
+
locator,
|
|
295
366
|
id: batch.id,
|
|
296
367
|
batch,
|
|
297
|
-
drafts: saved ?? [],
|
|
368
|
+
drafts: saved?.get(batch.id) ?? [],
|
|
298
369
|
submission: { state: 'waiting' },
|
|
299
370
|
lost: false,
|
|
300
371
|
});
|
|
301
372
|
}
|
|
302
373
|
}
|
|
303
|
-
|
|
374
|
+
for (const batch of founded ?? []) {
|
|
375
|
+
if (!before.has(batch.id))
|
|
376
|
+
continue;
|
|
377
|
+
const stored = pending.get([locator, batch.id]);
|
|
378
|
+
stored.onsuccess = () => {
|
|
379
|
+
const record = stored.result;
|
|
380
|
+
if (record !== undefined)
|
|
381
|
+
pending.put({ ...record, batch });
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
};
|
|
304
385
|
const draftStore = transaction.objectStore(ROOM_DRAFTS);
|
|
305
386
|
for (const path of consumedRoomDrafts ?? [])
|
|
306
|
-
draftStore.delete([
|
|
387
|
+
draftStore.delete([locator, path]);
|
|
307
388
|
for (const record of roomDrafts ?? [])
|
|
308
389
|
draftStore.put(record);
|
|
309
390
|
await completed(transaction);
|
|
310
391
|
},
|
|
392
|
+
async write({ next, previous, stored }) {
|
|
393
|
+
if (next === previous || fenced(next.locator))
|
|
394
|
+
return;
|
|
395
|
+
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
|
|
396
|
+
transaction.objectStore(ROOMS).put(roomRecord(next));
|
|
397
|
+
const moved = previous?.transfer !== next.transfer;
|
|
398
|
+
if (moved && previous !== null) {
|
|
399
|
+
const range = underTransfer(previous.locator, previous.transfer);
|
|
400
|
+
transaction.objectStore(DOCUMENTS).delete(range);
|
|
401
|
+
transaction.objectStore(BINARY_FILES).delete(range);
|
|
402
|
+
}
|
|
403
|
+
if (moved)
|
|
404
|
+
transaction.objectStore(TRANSFERS).delete(next.locator);
|
|
405
|
+
writeLayer(transaction, next.locator, next.transfer, next, moved ? (stored ?? null) : previous);
|
|
406
|
+
await completed(transaction);
|
|
407
|
+
},
|
|
311
408
|
async revokeModels(records) {
|
|
312
409
|
const transaction = database.transaction(ROOMS, 'readwrite');
|
|
313
410
|
const rooms = transaction.objectStore(ROOMS);
|
|
314
411
|
const revoked = { status: 'unavailable', reason: 'revoked' };
|
|
315
|
-
for (const
|
|
316
|
-
|
|
412
|
+
for (const record of records) {
|
|
413
|
+
if (fenced(record.locator))
|
|
414
|
+
continue;
|
|
415
|
+
rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }));
|
|
317
416
|
}
|
|
318
417
|
await completed(transaction);
|
|
319
418
|
},
|
|
@@ -346,36 +445,52 @@ export async function openRuntimeStore() {
|
|
|
346
445
|
transaction.objectStore(DECLARATIONS).put(member, MEMBER);
|
|
347
446
|
await completed(transaction);
|
|
348
447
|
},
|
|
448
|
+
async targets() {
|
|
449
|
+
const transaction = database.transaction(DECLARATIONS, 'readonly');
|
|
450
|
+
const held = await settled(transaction.objectStore(DECLARATIONS).get(TARGETS));
|
|
451
|
+
return held ?? {};
|
|
452
|
+
},
|
|
453
|
+
async keepTargets(targets) {
|
|
454
|
+
const transaction = database.transaction(DECLARATIONS, 'readwrite');
|
|
455
|
+
transaction.objectStore(DECLARATIONS).put(targets, TARGETS);
|
|
456
|
+
await completed(transaction);
|
|
457
|
+
},
|
|
349
458
|
async queues() {
|
|
350
|
-
const transaction =
|
|
351
|
-
const [
|
|
352
|
-
settled(transaction.objectStore(
|
|
459
|
+
const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readonly');
|
|
460
|
+
const [queues, pending] = await Promise.all([
|
|
461
|
+
settled(transaction.objectStore(QUEUES).getAll()),
|
|
353
462
|
settled(transaction.objectStore(PENDING_CHANGES).getAll()),
|
|
354
463
|
]);
|
|
355
464
|
const byId = new Map(pending.map((record) => [`${record.locator}\0${record.id}`, record]));
|
|
356
|
-
return
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
465
|
+
return queues
|
|
466
|
+
.filter((queue) => !fenced(queue.locator))
|
|
467
|
+
.map((queue) => ({
|
|
468
|
+
locator: queue.locator,
|
|
469
|
+
pending: queue.order.map((id) => {
|
|
470
|
+
const record = byId.get(`${queue.locator}\0${id}`);
|
|
360
471
|
if (record === undefined)
|
|
361
|
-
throw new Error(`Missing Pending Change ${
|
|
472
|
+
throw new Error(`Missing Pending Change ${queue.locator}/${id}`);
|
|
362
473
|
const { batch, drafts, submission, lost, upload, accepted } = record;
|
|
363
474
|
return { batch, state: { drafts, submission, lost, upload, accepted } };
|
|
364
475
|
}),
|
|
365
476
|
}));
|
|
366
477
|
},
|
|
367
|
-
submit(locator, id, submission, lost) {
|
|
368
|
-
|
|
478
|
+
async submit(locator, id, submission, lost) {
|
|
479
|
+
if (!fenced(locator))
|
|
480
|
+
await amendPending(authored, locator, id, { submission, lost });
|
|
369
481
|
},
|
|
370
|
-
accept(locator, id, roomVersion) {
|
|
371
|
-
|
|
482
|
+
async accept(locator, id, roomVersion) {
|
|
483
|
+
if (!fenced(locator))
|
|
484
|
+
await amendPending(authored, locator, id, { accepted: roomVersion });
|
|
372
485
|
},
|
|
373
|
-
keepUpload(locator, id, upload) {
|
|
374
|
-
|
|
486
|
+
async keepUpload(locator, id, upload) {
|
|
487
|
+
if (!fenced(locator))
|
|
488
|
+
await amendPending(authored, locator, id, { upload });
|
|
375
489
|
},
|
|
376
490
|
async roomDrafts() {
|
|
377
|
-
const transaction =
|
|
378
|
-
|
|
491
|
+
const transaction = authored.transaction(ROOM_DRAFTS, 'readonly');
|
|
492
|
+
const held = await settled(transaction.objectStore(ROOM_DRAFTS).getAll());
|
|
493
|
+
return held.filter((record) => !fenced(record.locator));
|
|
379
494
|
},
|
|
380
495
|
async presentation() {
|
|
381
496
|
const transaction = database.transaction(PRESENTATION, 'readonly');
|
|
@@ -388,42 +503,107 @@ export async function openRuntimeStore() {
|
|
|
388
503
|
},
|
|
389
504
|
async conversations() {
|
|
390
505
|
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readonly');
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
506
|
+
const records = await settled(transaction.objectStore(CONVERSATIONS).getAll());
|
|
507
|
+
const held = new Map(records.map(({ conversation, read, partial }) => [
|
|
508
|
+
conversation,
|
|
509
|
+
{ conversation, read, partial: partial === true },
|
|
510
|
+
]));
|
|
511
|
+
const keys = transaction.objectStore(MESSAGES).index('conversation');
|
|
512
|
+
await new Promise((resolve, reject) => {
|
|
513
|
+
const cursor = keys.openKeyCursor(null, 'nextunique');
|
|
514
|
+
cursor.onerror = () => reject(cursor.error);
|
|
515
|
+
cursor.onsuccess = () => {
|
|
516
|
+
const at = cursor.result;
|
|
517
|
+
if (at === null) {
|
|
518
|
+
resolve();
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const conversation = at.key;
|
|
522
|
+
if (!held.has(conversation)) {
|
|
523
|
+
held.set(conversation, { conversation, read: undefined, partial: true });
|
|
524
|
+
}
|
|
525
|
+
at.continue();
|
|
526
|
+
};
|
|
527
|
+
});
|
|
404
528
|
return [...held.values()];
|
|
405
529
|
},
|
|
406
|
-
async keepMessages({ conversation, messages, read
|
|
407
|
-
const transaction = database.transaction([CONVERSATIONS, MESSAGES
|
|
530
|
+
async keepMessages({ conversation, messages, read }) {
|
|
531
|
+
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
|
|
408
532
|
const stored = transaction.objectStore(MESSAGES);
|
|
409
533
|
for (const message of messages) {
|
|
410
534
|
stored.put({ ...message, conversation });
|
|
411
535
|
}
|
|
412
536
|
if (read !== undefined) {
|
|
413
|
-
transaction
|
|
414
|
-
|
|
415
|
-
.
|
|
537
|
+
transaction.objectStore(CONVERSATIONS).put({
|
|
538
|
+
conversation,
|
|
539
|
+
read: read.at,
|
|
540
|
+
...(read.partial ? { partial: true } : {}),
|
|
541
|
+
});
|
|
416
542
|
}
|
|
417
|
-
if (sealed === true)
|
|
418
|
-
transaction.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
419
543
|
await completed(transaction);
|
|
420
544
|
},
|
|
545
|
+
async messageWindow(conversation, limit, before) {
|
|
546
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
547
|
+
const index = transaction.objectStore(MESSAGES).index('position');
|
|
548
|
+
const range = IDBKeyRange.bound([conversation], [conversation, before?.[0] ?? []]);
|
|
549
|
+
const latest = [];
|
|
550
|
+
let more = false;
|
|
551
|
+
await new Promise((resolve, reject) => {
|
|
552
|
+
const cursor = index.openCursor(range, 'prev');
|
|
553
|
+
cursor.onerror = () => reject(cursor.error);
|
|
554
|
+
cursor.onsuccess = () => {
|
|
555
|
+
const at = cursor.result;
|
|
556
|
+
if (at === null) {
|
|
557
|
+
resolve();
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
const record = at.value;
|
|
561
|
+
if (!precedes(record, before)) {
|
|
562
|
+
at.continue();
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
if (latest.length === limit) {
|
|
566
|
+
more = true;
|
|
567
|
+
resolve();
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
latest.push(accepted(record));
|
|
571
|
+
at.continue();
|
|
572
|
+
};
|
|
573
|
+
});
|
|
574
|
+
return { messages: latest.reverse(), more };
|
|
575
|
+
},
|
|
576
|
+
async messageCount(conversation) {
|
|
577
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
578
|
+
return settled(transaction.objectStore(MESSAGES).index('conversation').count(conversation));
|
|
579
|
+
},
|
|
580
|
+
async messagesAfter(conversation, identity) {
|
|
581
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
582
|
+
const range = identity === null
|
|
583
|
+
? IDBKeyRange.bound([conversation], [conversation, []])
|
|
584
|
+
: IDBKeyRange.bound([conversation, identity], [conversation, []], true);
|
|
585
|
+
const held = await settled(transaction.objectStore(MESSAGES).getAll(range, READ_BATCH));
|
|
586
|
+
return held.map(accepted);
|
|
587
|
+
},
|
|
588
|
+
async messageIdentities(conversation) {
|
|
589
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
590
|
+
const keys = await settled(transaction.objectStore(MESSAGES).index('conversation').getAllKeys(conversation));
|
|
591
|
+
return keys.map((key) => key[1]);
|
|
592
|
+
},
|
|
593
|
+
async turnArrived(conversation, turn) {
|
|
594
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
595
|
+
const held = await settled(transaction.objectStore(MESSAGES).index('turn').count([conversation, turn]));
|
|
596
|
+
return held > 0;
|
|
597
|
+
},
|
|
421
598
|
async dropConversations(conversations) {
|
|
422
|
-
const
|
|
599
|
+
const drafts = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
600
|
+
for (const conversation of conversations)
|
|
601
|
+
drafts.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
602
|
+
await completed(drafts);
|
|
603
|
+
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
|
|
423
604
|
const messages = transaction.objectStore(MESSAGES);
|
|
424
605
|
for (const conversation of conversations) {
|
|
425
606
|
transaction.objectStore(CONVERSATIONS).delete(conversation);
|
|
426
|
-
transaction.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
427
607
|
const keys = messages.index('conversation').getAllKeys(conversation);
|
|
428
608
|
keys.onsuccess = () => {
|
|
429
609
|
for (const key of keys.result)
|
|
@@ -433,58 +613,104 @@ export async function openRuntimeStore() {
|
|
|
433
613
|
await completed(transaction);
|
|
434
614
|
},
|
|
435
615
|
async chatDrafts() {
|
|
436
|
-
const transaction =
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
transaction.
|
|
616
|
+
const transaction = authored.transaction(CHAT_DRAFTS, 'readonly');
|
|
617
|
+
const held = await settled(transaction.objectStore(CHAT_DRAFTS).getAll());
|
|
618
|
+
return held.map(chatDraftRecord);
|
|
619
|
+
},
|
|
620
|
+
async keepChatDrafts(records) {
|
|
621
|
+
const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
622
|
+
for (const record of records)
|
|
623
|
+
transaction.objectStore(CHAT_DRAFTS).put(record);
|
|
442
624
|
await completed(transaction);
|
|
443
625
|
},
|
|
444
626
|
async dropChatDraft(conversation) {
|
|
445
|
-
const transaction =
|
|
627
|
+
const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
446
628
|
transaction.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
447
629
|
await completed(transaction);
|
|
448
630
|
},
|
|
631
|
+
async calls() {
|
|
632
|
+
const transaction = authored.transaction(CALLS, 'readonly');
|
|
633
|
+
return settled(transaction.objectStore(CALLS).getAll());
|
|
634
|
+
},
|
|
635
|
+
async keepCall(record) {
|
|
636
|
+
const transaction = authored.transaction(CALLS, 'readwrite');
|
|
637
|
+
transaction.objectStore(CALLS).put(record);
|
|
638
|
+
await completed(transaction);
|
|
639
|
+
},
|
|
640
|
+
async dropCall(operation) {
|
|
641
|
+
const transaction = authored.transaction(CALLS, 'readwrite');
|
|
642
|
+
transaction.objectStore(CALLS).delete(operation);
|
|
643
|
+
await completed(transaction);
|
|
644
|
+
},
|
|
449
645
|
async keepRoomDraft(record) {
|
|
450
|
-
|
|
646
|
+
if (fenced(record.locator))
|
|
647
|
+
return;
|
|
648
|
+
const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
|
|
451
649
|
transaction.objectStore(ROOM_DRAFTS).put(record);
|
|
452
650
|
await completed(transaction);
|
|
453
651
|
},
|
|
454
652
|
async discardRoomDraft(locator, path) {
|
|
455
|
-
|
|
653
|
+
if (fenced(locator))
|
|
654
|
+
return;
|
|
655
|
+
const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
|
|
456
656
|
transaction.objectStore(ROOM_DRAFTS).delete([locator, path]);
|
|
457
657
|
await completed(transaction);
|
|
458
658
|
},
|
|
459
|
-
async
|
|
460
|
-
const transaction =
|
|
659
|
+
async fences() {
|
|
660
|
+
const transaction = authored.transaction(FENCES, 'readonly');
|
|
661
|
+
const held = await settled(transaction.objectStore(FENCES).getAll());
|
|
662
|
+
return held.map((fence) => fence.locator);
|
|
663
|
+
},
|
|
664
|
+
async erase(locators) {
|
|
665
|
+
const work = authored.transaction([FENCES, QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
|
|
666
|
+
for (const locator of locators) {
|
|
667
|
+
work.objectStore(FENCES).put({ locator });
|
|
668
|
+
work.objectStore(QUEUES).delete(locator);
|
|
669
|
+
for (const name of [PENDING_CHANGES, ROOM_DRAFTS]) {
|
|
670
|
+
removeRoomEntries(work.objectStore(name), locator);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
await completed(work);
|
|
674
|
+
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
|
|
461
675
|
for (const locator of locators) {
|
|
462
676
|
transaction.objectStore(ROOMS).delete(locator);
|
|
463
677
|
transaction.objectStore(TRANSFERS).delete(locator);
|
|
464
678
|
transaction.objectStore(DOCUMENTS).delete(underRoom(locator));
|
|
465
|
-
transaction.objectStore(
|
|
466
|
-
for (const name of [ATTACHMENTS, PENDING_CHANGES, ROOM_DRAFTS]) {
|
|
467
|
-
removeRoomEntries(transaction.objectStore(name), locator);
|
|
468
|
-
}
|
|
679
|
+
transaction.objectStore(BINARY_FILES).delete(underRoom(locator));
|
|
469
680
|
}
|
|
470
681
|
await completed(transaction);
|
|
682
|
+
const fences = authored.transaction(FENCES, 'readwrite');
|
|
683
|
+
for (const locator of locators)
|
|
684
|
+
fences.objectStore(FENCES).delete(locator);
|
|
685
|
+
await completed(fences);
|
|
686
|
+
},
|
|
687
|
+
async discard(locator) {
|
|
688
|
+
const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readwrite');
|
|
689
|
+
transaction.objectStore(QUEUES).delete(locator);
|
|
690
|
+
removeRoomEntries(transaction.objectStore(PENDING_CHANGES), locator);
|
|
691
|
+
await completed(transaction);
|
|
471
692
|
},
|
|
472
693
|
async transfers() {
|
|
473
694
|
const transaction = database.transaction(TRANSFERS, 'readonly');
|
|
474
|
-
|
|
695
|
+
const held = await settled(transaction.objectStore(TRANSFERS).getAll());
|
|
696
|
+
return held.filter((record) => !fenced(record.locator));
|
|
475
697
|
},
|
|
476
698
|
staged(record) {
|
|
477
|
-
const transaction = database.transaction([DOCUMENTS,
|
|
699
|
+
const transaction = database.transaction([DOCUMENTS, BINARY_FILES], 'readonly');
|
|
478
700
|
return readLayer(transaction, record.locator, record.transfer);
|
|
479
701
|
},
|
|
480
702
|
async stage(record, page) {
|
|
481
|
-
|
|
703
|
+
if (fenced(record.locator))
|
|
704
|
+
return;
|
|
705
|
+
const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
|
|
482
706
|
writeLayer(transaction, record.locator, record.transfer, page, null);
|
|
483
707
|
transaction.objectStore(TRANSFERS).put(record);
|
|
484
708
|
await completed(transaction);
|
|
485
709
|
},
|
|
486
710
|
async abandon(locator) {
|
|
487
|
-
|
|
711
|
+
if (fenced(locator))
|
|
712
|
+
return;
|
|
713
|
+
const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
|
|
488
714
|
const transfers = transaction.objectStore(TRANSFERS);
|
|
489
715
|
const held = transfers.get(locator);
|
|
490
716
|
held.onsuccess = () => {
|
|
@@ -494,17 +720,48 @@ export async function openRuntimeStore() {
|
|
|
494
720
|
transfers.delete(locator);
|
|
495
721
|
const range = underTransfer(locator, record.transfer);
|
|
496
722
|
transaction.objectStore(DOCUMENTS).delete(range);
|
|
497
|
-
transaction.objectStore(
|
|
723
|
+
transaction.objectStore(BINARY_FILES).delete(range);
|
|
498
724
|
};
|
|
499
725
|
await completed(transaction);
|
|
500
726
|
},
|
|
727
|
+
async receivedHeads() {
|
|
728
|
+
const transaction = database.transaction(RECEIVED, 'readonly');
|
|
729
|
+
return settled(transaction.objectStore(RECEIVED).getAll());
|
|
730
|
+
},
|
|
731
|
+
async receivedParts(key, count) {
|
|
732
|
+
const transaction = database.transaction(RECEIVED_PARTS, 'readonly');
|
|
733
|
+
const kept = await settled(transaction
|
|
734
|
+
.objectStore(RECEIVED_PARTS)
|
|
735
|
+
.getAll(IDBKeyRange.bound([key, 0], [key, count], false, true)));
|
|
736
|
+
return kept.map((part) => part.value);
|
|
737
|
+
},
|
|
738
|
+
async keepReceived(key, head, part) {
|
|
739
|
+
const transaction = database.transaction([RECEIVED, RECEIVED_PARTS], 'readwrite');
|
|
740
|
+
transaction.objectStore(RECEIVED).put({ key, head });
|
|
741
|
+
if (part !== undefined)
|
|
742
|
+
transaction.objectStore(RECEIVED_PARTS).put({ key, ...part });
|
|
743
|
+
await completed(transaction);
|
|
744
|
+
},
|
|
745
|
+
async dropReceived(keys) {
|
|
746
|
+
const transaction = database.transaction([RECEIVED, RECEIVED_PARTS], 'readwrite');
|
|
747
|
+
for (const key of keys) {
|
|
748
|
+
transaction.objectStore(RECEIVED).delete(key);
|
|
749
|
+
transaction.objectStore(RECEIVED_PARTS).delete(IDBKeyRange.bound([key], [key, []]));
|
|
750
|
+
}
|
|
751
|
+
await completed(transaction);
|
|
752
|
+
},
|
|
501
753
|
async generation() {
|
|
502
|
-
|
|
754
|
+
const transaction = authored.transaction(FACTS, 'readonly');
|
|
755
|
+
const held = await settled(transaction.objectStore(FACTS).get(GENERATION));
|
|
756
|
+
return held ?? null;
|
|
503
757
|
},
|
|
504
|
-
rememberGeneration(value) {
|
|
505
|
-
|
|
758
|
+
async rememberGeneration(value) {
|
|
759
|
+
const transaction = authored.transaction(FACTS, 'readwrite');
|
|
760
|
+
transaction.objectStore(FACTS).put(value, GENERATION);
|
|
761
|
+
await completed(transaction);
|
|
506
762
|
},
|
|
507
763
|
close() {
|
|
764
|
+
authored.close();
|
|
508
765
|
database.close();
|
|
509
766
|
},
|
|
510
767
|
};
|