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