@agentshouse/mdruntime 0.1.0-c56daf494ecb4 → 0.1.0-c5d09b1c896fb
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 +261 -261
- 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 +37 -9
- package/dist/adapter.d.ts.map +1 -1
- package/dist/bootstrap.d.ts +2 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +26 -4
- package/dist/change-set.d.ts +2 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +36 -10
- 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/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 +2 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +4 -3
- 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 +51 -67
- package/dist/chat/ready.d.ts +1 -0
- package/dist/chat/ready.d.ts.map +1 -1
- package/dist/chat/ready.js +2 -2
- package/dist/client.d.ts +12 -8
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +3 -1
- package/dist/collection.d.ts +17 -3
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +230 -19
- package/dist/connection.d.ts +22 -7
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1253 -309
- package/dist/conversation.d.ts +14 -7
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +328 -137
- package/dist/durability.d.ts +7 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +3 -3
- 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 +49 -7
- package/dist/identity.d.ts +2 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +6 -0
- package/dist/index.d.ts +9 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/memory.d.ts +4 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +23 -2
- 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 +5 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +22 -11
- package/dist/outcome.d.ts +4 -0
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +1 -0
- package/dist/overlay.d.ts +2 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +58 -55
- package/dist/query.d.ts +32 -3
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -1
- package/dist/reach.d.ts +6 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +17 -5
- package/dist/react.d.ts +7 -4
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +6 -4
- package/dist/read-side.d.ts +13 -6
- package/dist/read-side.d.ts.map +1 -1
- package/dist/read-side.js +285 -83
- 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.map +1 -1
- package/dist/refresh.js +17 -10
- package/dist/replica.d.ts +1 -1
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +57 -20
- package/dist/room-draft.d.ts +13 -1
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +2 -2
- package/dist/rows.d.ts +5 -13
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +5 -13
- package/dist/save.d.ts +5 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +36 -13
- package/dist/search.d.ts +34 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +116 -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 +4 -0
- package/dist/status.d.ts.map +1 -1
- package/dist/store.d.ts +42 -11
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +276 -83
- 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 +136 -32
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +48 -31
- package/package.json +2 -2
package/dist/store.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { sameBinary, sameChange } from './overlay.js';
|
|
2
|
+
import { differing } from './shared.js';
|
|
2
3
|
const DATABASE = 'mdruntime';
|
|
3
4
|
const AUTHORED = 'mdruntime-authored';
|
|
5
|
+
const FENCES = 'fences';
|
|
4
6
|
const ROOMS = 'rooms';
|
|
5
7
|
const DOCUMENTS = 'documents';
|
|
6
8
|
const BINARY_FILES = 'binaryFiles';
|
|
7
9
|
const TRANSFERS = 'transfers';
|
|
10
|
+
const RECEIVED = 'received';
|
|
11
|
+
const RECEIVED_PARTS = 'receivedParts';
|
|
8
12
|
const PENDING_CHANGES = 'pendingChanges';
|
|
9
13
|
const DECLARATIONS = 'declarations';
|
|
10
14
|
const ROOM_DRAFTS = 'roomDrafts';
|
|
@@ -16,18 +20,39 @@ const QUEUES = 'queues';
|
|
|
16
20
|
const FACTS = 'facts';
|
|
17
21
|
const CURRENT = 'current';
|
|
18
22
|
const MEMBER = 'member';
|
|
23
|
+
const TARGETS = 'targets';
|
|
19
24
|
const GENERATION = 'generation';
|
|
20
25
|
const HOLDER = 'holder';
|
|
21
|
-
|
|
22
|
-
export const
|
|
26
|
+
const BINDING = 'binding';
|
|
27
|
+
export const STORE_SCHEMA = 25;
|
|
28
|
+
const REPLICA_SHAPE = 23;
|
|
29
|
+
export const AUTHORED_SCHEMA = 2;
|
|
23
30
|
const AUTHORED_STORES = [
|
|
24
31
|
[QUEUES, { keyPath: 'locator' }],
|
|
25
32
|
[PENDING_CHANGES, { keyPath: ['locator', 'id'] }],
|
|
26
33
|
[ROOM_DRAFTS, { keyPath: ['locator', 'path'] }],
|
|
27
34
|
[CHAT_DRAFTS, { keyPath: 'conversation' }],
|
|
28
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'] }],
|
|
29
49
|
];
|
|
30
50
|
const READ_BATCH = 256;
|
|
51
|
+
const MESSAGE_INDEXES = [
|
|
52
|
+
['conversation', 'conversation'],
|
|
53
|
+
['position', ['conversation', 'position']],
|
|
54
|
+
['turn', ['conversation', 'turn']],
|
|
55
|
+
];
|
|
31
56
|
function settled(request) {
|
|
32
57
|
return new Promise((resolve, reject) => {
|
|
33
58
|
request.onsuccess = () => resolve(request.result);
|
|
@@ -70,8 +95,11 @@ function amendPending(database, locator, id, amendment) {
|
|
|
70
95
|
};
|
|
71
96
|
return completed(transaction);
|
|
72
97
|
}
|
|
98
|
+
function accepted({ conversation: _held, ...message }) {
|
|
99
|
+
return message;
|
|
100
|
+
}
|
|
73
101
|
function roomRecord(record) {
|
|
74
|
-
const { documents, binaries, revisions, changes, written, ...room } = record;
|
|
102
|
+
const { documents, binaries, revisions, fileIds, changes, written, ...room } = record;
|
|
75
103
|
return room;
|
|
76
104
|
}
|
|
77
105
|
function chatDraftRecord(record) {
|
|
@@ -97,13 +125,15 @@ async function readTransfer(store, locator, transfer, receive) {
|
|
|
97
125
|
}
|
|
98
126
|
}
|
|
99
127
|
function emptyLayer() {
|
|
100
|
-
return { documents: {}, binaries: {}, revisions: {}, changes: {}, written: {} };
|
|
128
|
+
return { documents: {}, binaries: {}, revisions: {}, fileIds: {}, changes: {}, written: {} };
|
|
101
129
|
}
|
|
102
130
|
async function readLayer(transaction, locator, transfer) {
|
|
103
131
|
const layer = emptyLayer();
|
|
104
132
|
const head = (held) => {
|
|
105
133
|
if (held.revision !== null)
|
|
106
134
|
layer.revisions[held.path] = held.revision;
|
|
135
|
+
if (held.fileId !== null)
|
|
136
|
+
layer.fileIds[held.path] = held.fileId;
|
|
107
137
|
if (held.change !== null)
|
|
108
138
|
layer.changes[held.path] = held.change;
|
|
109
139
|
};
|
|
@@ -126,6 +156,7 @@ function documentRecord(locator, transfer, layer, path) {
|
|
|
126
156
|
path,
|
|
127
157
|
content: layer.documents[path],
|
|
128
158
|
revision: layer.revisions[path] ?? null,
|
|
159
|
+
fileId: layer.fileIds[path] ?? null,
|
|
129
160
|
change: layer.changes[path] ?? null,
|
|
130
161
|
written: layer.written[path] ?? null,
|
|
131
162
|
};
|
|
@@ -136,35 +167,37 @@ function binaryFileRecord(locator, transfer, layer, path) {
|
|
|
136
167
|
transfer,
|
|
137
168
|
path,
|
|
138
169
|
revision: layer.revisions[path] ?? null,
|
|
170
|
+
fileId: layer.fileIds[path] ?? null,
|
|
139
171
|
change: layer.changes[path] ?? null,
|
|
140
172
|
binary: layer.binaries[path],
|
|
141
173
|
};
|
|
142
174
|
}
|
|
143
175
|
function writeLayer(transaction, locator, transfer, next, base) {
|
|
144
176
|
const documents = transaction.objectStore(DOCUMENTS);
|
|
145
|
-
for (const path of Object.keys(base?.documents ?? {})) {
|
|
146
|
-
if (next.documents[path] === undefined)
|
|
147
|
-
documents.delete([locator, transfer, path]);
|
|
148
|
-
}
|
|
149
|
-
for (const [path, content] of Object.entries(next.documents)) {
|
|
150
|
-
if (base?.documents[path] === content &&
|
|
151
|
-
base.revisions[path] === next.revisions[path] &&
|
|
152
|
-
base.written[path] === next.written[path] &&
|
|
153
|
-
sameChange(base.changes[path], next.changes[path]))
|
|
154
|
-
continue;
|
|
155
|
-
documents.put(documentRecord(locator, transfer, next, path));
|
|
156
|
-
}
|
|
157
177
|
const files = transaction.objectStore(BINARY_FILES);
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
base
|
|
165
|
-
|
|
178
|
+
const paths = base === null
|
|
179
|
+
? new Set([...Object.keys(next.documents), ...Object.keys(next.binaries)])
|
|
180
|
+
: new Set([
|
|
181
|
+
...differing(base.documents, next.documents),
|
|
182
|
+
...differing(base.revisions, next.revisions),
|
|
183
|
+
...differing(base.fileIds, next.fileIds),
|
|
184
|
+
...differing(base.written, next.written),
|
|
185
|
+
...differing(base.changes, next.changes, sameChange),
|
|
186
|
+
...differing(base.binaries, next.binaries, sameBinary),
|
|
187
|
+
]);
|
|
188
|
+
for (const path of paths) {
|
|
189
|
+
if (next.documents[path] !== undefined) {
|
|
190
|
+
documents.put(documentRecord(locator, transfer, next, path));
|
|
191
|
+
}
|
|
192
|
+
else if (base?.documents[path] !== undefined) {
|
|
193
|
+
documents.delete([locator, transfer, path]);
|
|
194
|
+
}
|
|
195
|
+
if (next.binaries[path] !== undefined) {
|
|
166
196
|
files.put(binaryFileRecord(locator, transfer, next, path));
|
|
167
197
|
}
|
|
198
|
+
else if (base?.binaries[path] !== undefined) {
|
|
199
|
+
files.delete([locator, transfer, path]);
|
|
200
|
+
}
|
|
168
201
|
}
|
|
169
202
|
}
|
|
170
203
|
function removeRoomEntries(store, locator) {
|
|
@@ -215,6 +248,29 @@ export async function authoredBy(holder) {
|
|
|
215
248
|
authored.close();
|
|
216
249
|
}
|
|
217
250
|
}
|
|
251
|
+
export async function authoredBinding() {
|
|
252
|
+
const authored = await openAuthored();
|
|
253
|
+
try {
|
|
254
|
+
const transaction = authored.transaction(FACTS, 'readonly');
|
|
255
|
+
const held = transaction.objectStore(FACTS).get(BINDING);
|
|
256
|
+
await completed(transaction);
|
|
257
|
+
return typeof held.result === 'string' ? held.result : null;
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
authored.close();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
export async function bindAuthored(binding) {
|
|
264
|
+
const authored = await openAuthored();
|
|
265
|
+
try {
|
|
266
|
+
const transaction = authored.transaction(FACTS, 'readwrite');
|
|
267
|
+
transaction.objectStore(FACTS).put(binding, BINDING);
|
|
268
|
+
await completed(transaction);
|
|
269
|
+
}
|
|
270
|
+
finally {
|
|
271
|
+
authored.close();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
218
274
|
export async function removeRuntimeStore(holder) {
|
|
219
275
|
await removeDatabase(DATABASE);
|
|
220
276
|
if (holder !== undefined && (await authoredBy(holder)))
|
|
@@ -222,38 +278,51 @@ export async function removeRuntimeStore(holder) {
|
|
|
222
278
|
await removeDatabase(AUTHORED);
|
|
223
279
|
return false;
|
|
224
280
|
}
|
|
281
|
+
export function openDatabase(name, version, upgrade) {
|
|
282
|
+
return new Promise((resolve, reject) => {
|
|
283
|
+
const opening = indexedDB.open(name, version);
|
|
284
|
+
opening.onupgradeneeded = (event) => upgrade(opening, event.oldVersion);
|
|
285
|
+
opening.onsuccess = () => resolve(opening.result);
|
|
286
|
+
opening.onerror = () => {
|
|
287
|
+
if (opening.error?.name !== 'VersionError') {
|
|
288
|
+
reject(opening.error);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
removeDatabase(name)
|
|
292
|
+
.then(() => openDatabase(name, version, upgrade))
|
|
293
|
+
.then(resolve, reject);
|
|
294
|
+
};
|
|
295
|
+
});
|
|
296
|
+
}
|
|
225
297
|
function openReplica() {
|
|
226
|
-
|
|
227
|
-
opening.onupgradeneeded = () => {
|
|
298
|
+
return openDatabase(DATABASE, STORE_SCHEMA, (opening, oldVersion) => {
|
|
228
299
|
const database = opening.result;
|
|
229
|
-
|
|
230
|
-
database.
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
const messages =
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
300
|
+
if (oldVersion < REPLICA_SHAPE) {
|
|
301
|
+
for (const name of [...database.objectStoreNames])
|
|
302
|
+
database.deleteObjectStore(name);
|
|
303
|
+
}
|
|
304
|
+
for (const [name, parameters] of REPLICA_STORES) {
|
|
305
|
+
if (database.objectStoreNames.contains(name))
|
|
306
|
+
continue;
|
|
307
|
+
database.createObjectStore(name, parameters);
|
|
308
|
+
}
|
|
309
|
+
const messages = opening.transaction.objectStore(MESSAGES);
|
|
310
|
+
for (const [name, keyPath] of MESSAGE_INDEXES) {
|
|
311
|
+
if (!messages.indexNames.contains(name))
|
|
312
|
+
messages.createIndex(name, keyPath);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
244
315
|
}
|
|
245
316
|
function openAuthored() {
|
|
246
|
-
|
|
247
|
-
opening.onupgradeneeded = () => {
|
|
317
|
+
return openDatabase(AUTHORED, AUTHORED_SCHEMA, (opening) => {
|
|
248
318
|
const database = opening.result;
|
|
249
319
|
for (const [name, parameters] of AUTHORED_STORES) {
|
|
250
320
|
if (!database.objectStoreNames.contains(name))
|
|
251
321
|
database.createObjectStore(name, parameters);
|
|
252
322
|
}
|
|
253
|
-
};
|
|
254
|
-
return settled(opening);
|
|
323
|
+
});
|
|
255
324
|
}
|
|
256
|
-
export async function openRuntimeStore() {
|
|
325
|
+
export async function openRuntimeStore(fenced) {
|
|
257
326
|
const authored = await openAuthored();
|
|
258
327
|
const database = await openReplica().catch((error) => {
|
|
259
328
|
authored.close();
|
|
@@ -264,12 +333,14 @@ export async function openRuntimeStore() {
|
|
|
264
333
|
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES], 'readonly');
|
|
265
334
|
const rooms = await settled(transaction.objectStore(ROOMS).getAll());
|
|
266
335
|
const records = [];
|
|
267
|
-
for (const room of rooms) {
|
|
336
|
+
for (const room of rooms.filter((held) => !fenced(held.locator))) {
|
|
268
337
|
records.push({ ...room, ...(await readLayer(transaction, room.locator, room.transfer)) });
|
|
269
338
|
}
|
|
270
339
|
return records;
|
|
271
340
|
},
|
|
272
341
|
async keepAuthored({ locator, queue, saved, roomDrafts, consumedRoomDrafts }) {
|
|
342
|
+
if (fenced(locator))
|
|
343
|
+
return;
|
|
273
344
|
const transaction = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
|
|
274
345
|
const order = transaction.objectStore(QUEUES);
|
|
275
346
|
const pending = transaction.objectStore(PENDING_CHANGES);
|
|
@@ -306,7 +377,7 @@ export async function openRuntimeStore() {
|
|
|
306
377
|
await completed(transaction);
|
|
307
378
|
},
|
|
308
379
|
async write({ next, previous, stored }) {
|
|
309
|
-
if (next === previous)
|
|
380
|
+
if (next === previous || fenced(next.locator))
|
|
310
381
|
return;
|
|
311
382
|
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
|
|
312
383
|
transaction.objectStore(ROOMS).put(roomRecord(next));
|
|
@@ -326,6 +397,8 @@ export async function openRuntimeStore() {
|
|
|
326
397
|
const rooms = transaction.objectStore(ROOMS);
|
|
327
398
|
const revoked = { status: 'unavailable', reason: 'revoked' };
|
|
328
399
|
for (const record of records) {
|
|
400
|
+
if (fenced(record.locator))
|
|
401
|
+
continue;
|
|
329
402
|
rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }));
|
|
330
403
|
}
|
|
331
404
|
await completed(transaction);
|
|
@@ -359,6 +432,16 @@ export async function openRuntimeStore() {
|
|
|
359
432
|
transaction.objectStore(DECLARATIONS).put(member, MEMBER);
|
|
360
433
|
await completed(transaction);
|
|
361
434
|
},
|
|
435
|
+
async targets() {
|
|
436
|
+
const transaction = database.transaction(DECLARATIONS, 'readonly');
|
|
437
|
+
const held = await settled(transaction.objectStore(DECLARATIONS).get(TARGETS));
|
|
438
|
+
return held ?? {};
|
|
439
|
+
},
|
|
440
|
+
async keepTargets(targets) {
|
|
441
|
+
const transaction = database.transaction(DECLARATIONS, 'readwrite');
|
|
442
|
+
transaction.objectStore(DECLARATIONS).put(targets, TARGETS);
|
|
443
|
+
await completed(transaction);
|
|
444
|
+
},
|
|
362
445
|
async queues() {
|
|
363
446
|
const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readonly');
|
|
364
447
|
const [queues, pending] = await Promise.all([
|
|
@@ -366,7 +449,9 @@ export async function openRuntimeStore() {
|
|
|
366
449
|
settled(transaction.objectStore(PENDING_CHANGES).getAll()),
|
|
367
450
|
]);
|
|
368
451
|
const byId = new Map(pending.map((record) => [`${record.locator}\0${record.id}`, record]));
|
|
369
|
-
return queues
|
|
452
|
+
return queues
|
|
453
|
+
.filter((queue) => !fenced(queue.locator))
|
|
454
|
+
.map((queue) => ({
|
|
370
455
|
locator: queue.locator,
|
|
371
456
|
pending: queue.order.map((id) => {
|
|
372
457
|
const record = byId.get(`${queue.locator}\0${id}`);
|
|
@@ -377,18 +462,22 @@ export async function openRuntimeStore() {
|
|
|
377
462
|
}),
|
|
378
463
|
}));
|
|
379
464
|
},
|
|
380
|
-
submit(locator, id, submission, lost) {
|
|
381
|
-
|
|
465
|
+
async submit(locator, id, submission, lost) {
|
|
466
|
+
if (!fenced(locator))
|
|
467
|
+
await amendPending(authored, locator, id, { submission, lost });
|
|
382
468
|
},
|
|
383
|
-
accept(locator, id, roomVersion) {
|
|
384
|
-
|
|
469
|
+
async accept(locator, id, roomVersion) {
|
|
470
|
+
if (!fenced(locator))
|
|
471
|
+
await amendPending(authored, locator, id, { accepted: roomVersion });
|
|
385
472
|
},
|
|
386
|
-
keepUpload(locator, id, upload) {
|
|
387
|
-
|
|
473
|
+
async keepUpload(locator, id, upload) {
|
|
474
|
+
if (!fenced(locator))
|
|
475
|
+
await amendPending(authored, locator, id, { upload });
|
|
388
476
|
},
|
|
389
477
|
async roomDrafts() {
|
|
390
478
|
const transaction = authored.transaction(ROOM_DRAFTS, 'readonly');
|
|
391
|
-
|
|
479
|
+
const held = await settled(transaction.objectStore(ROOM_DRAFTS).getAll());
|
|
480
|
+
return held.filter((record) => !fenced(record.locator));
|
|
392
481
|
},
|
|
393
482
|
async presentation() {
|
|
394
483
|
const transaction = database.transaction(PRESENTATION, 'readonly');
|
|
@@ -401,39 +490,91 @@ export async function openRuntimeStore() {
|
|
|
401
490
|
},
|
|
402
491
|
async conversations() {
|
|
403
492
|
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readonly');
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
493
|
+
const records = await settled(transaction.objectStore(CONVERSATIONS).getAll());
|
|
494
|
+
const held = new Map(records.map(({ conversation, read, partial }) => [
|
|
495
|
+
conversation,
|
|
496
|
+
{ conversation, read, partial: partial === true },
|
|
497
|
+
]));
|
|
498
|
+
const keys = transaction.objectStore(MESSAGES).index('conversation');
|
|
499
|
+
await new Promise((resolve, reject) => {
|
|
500
|
+
const cursor = keys.openKeyCursor(null, 'nextunique');
|
|
501
|
+
cursor.onerror = () => reject(cursor.error);
|
|
502
|
+
cursor.onsuccess = () => {
|
|
503
|
+
const at = cursor.result;
|
|
504
|
+
if (at === null) {
|
|
505
|
+
resolve();
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const conversation = at.key;
|
|
509
|
+
if (!held.has(conversation)) {
|
|
510
|
+
held.set(conversation, { conversation, read: undefined, partial: true });
|
|
511
|
+
}
|
|
512
|
+
at.continue();
|
|
513
|
+
};
|
|
514
|
+
});
|
|
417
515
|
return [...held.values()];
|
|
418
516
|
},
|
|
419
|
-
async keepMessages({ conversation, messages, read
|
|
420
|
-
if (sealed === true) {
|
|
421
|
-
const sealing = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
422
|
-
sealing.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
423
|
-
await completed(sealing);
|
|
424
|
-
}
|
|
517
|
+
async keepMessages({ conversation, messages, read }) {
|
|
425
518
|
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
|
|
426
519
|
const stored = transaction.objectStore(MESSAGES);
|
|
427
520
|
for (const message of messages) {
|
|
428
521
|
stored.put({ ...message, conversation });
|
|
429
522
|
}
|
|
430
523
|
if (read !== undefined) {
|
|
431
|
-
transaction
|
|
432
|
-
|
|
433
|
-
.
|
|
524
|
+
transaction.objectStore(CONVERSATIONS).put({
|
|
525
|
+
conversation,
|
|
526
|
+
read: read.at,
|
|
527
|
+
...(read.partial ? { partial: true } : {}),
|
|
528
|
+
});
|
|
434
529
|
}
|
|
435
530
|
await completed(transaction);
|
|
436
531
|
},
|
|
532
|
+
async messageWindow(conversation, limit) {
|
|
533
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
534
|
+
const index = transaction.objectStore(MESSAGES).index('position');
|
|
535
|
+
const range = IDBKeyRange.bound([conversation], [conversation, []]);
|
|
536
|
+
if (limit === undefined) {
|
|
537
|
+
return (await settled(index.getAll(range))).map(accepted);
|
|
538
|
+
}
|
|
539
|
+
const latest = [];
|
|
540
|
+
if (limit === 0)
|
|
541
|
+
return latest;
|
|
542
|
+
await new Promise((resolve, reject) => {
|
|
543
|
+
const cursor = index.openCursor(range, 'prev');
|
|
544
|
+
cursor.onerror = () => reject(cursor.error);
|
|
545
|
+
cursor.onsuccess = () => {
|
|
546
|
+
const at = cursor.result;
|
|
547
|
+
if (at === null) {
|
|
548
|
+
resolve();
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
latest.push(accepted(at.value));
|
|
552
|
+
if (latest.length === limit)
|
|
553
|
+
resolve();
|
|
554
|
+
else
|
|
555
|
+
at.continue();
|
|
556
|
+
};
|
|
557
|
+
});
|
|
558
|
+
return latest.reverse();
|
|
559
|
+
},
|
|
560
|
+
async messagesAfter(conversation, identity) {
|
|
561
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
562
|
+
const range = identity === null
|
|
563
|
+
? IDBKeyRange.bound([conversation], [conversation, []])
|
|
564
|
+
: IDBKeyRange.bound([conversation, identity], [conversation, []], true);
|
|
565
|
+
const held = await settled(transaction.objectStore(MESSAGES).getAll(range, READ_BATCH));
|
|
566
|
+
return held.map(accepted);
|
|
567
|
+
},
|
|
568
|
+
async messageIdentities(conversation) {
|
|
569
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
570
|
+
const keys = await settled(transaction.objectStore(MESSAGES).index('conversation').getAllKeys(conversation));
|
|
571
|
+
return keys.map((key) => key[1]);
|
|
572
|
+
},
|
|
573
|
+
async turnArrived(conversation, turn) {
|
|
574
|
+
const transaction = database.transaction(MESSAGES, 'readonly');
|
|
575
|
+
const held = await settled(transaction.objectStore(MESSAGES).index('turn').count([conversation, turn]));
|
|
576
|
+
return held > 0;
|
|
577
|
+
},
|
|
437
578
|
async dropConversations(conversations) {
|
|
438
579
|
const drafts = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
439
580
|
for (const conversation of conversations)
|
|
@@ -456,9 +597,10 @@ export async function openRuntimeStore() {
|
|
|
456
597
|
const held = await settled(transaction.objectStore(CHAT_DRAFTS).getAll());
|
|
457
598
|
return held.map(chatDraftRecord);
|
|
458
599
|
},
|
|
459
|
-
async
|
|
600
|
+
async keepChatDrafts(records) {
|
|
460
601
|
const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
461
|
-
|
|
602
|
+
for (const record of records)
|
|
603
|
+
transaction.objectStore(CHAT_DRAFTS).put(record);
|
|
462
604
|
await completed(transaction);
|
|
463
605
|
},
|
|
464
606
|
async dropChatDraft(conversation) {
|
|
@@ -467,18 +609,28 @@ export async function openRuntimeStore() {
|
|
|
467
609
|
await completed(transaction);
|
|
468
610
|
},
|
|
469
611
|
async keepRoomDraft(record) {
|
|
612
|
+
if (fenced(record.locator))
|
|
613
|
+
return;
|
|
470
614
|
const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
|
|
471
615
|
transaction.objectStore(ROOM_DRAFTS).put(record);
|
|
472
616
|
await completed(transaction);
|
|
473
617
|
},
|
|
474
618
|
async discardRoomDraft(locator, path) {
|
|
619
|
+
if (fenced(locator))
|
|
620
|
+
return;
|
|
475
621
|
const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
|
|
476
622
|
transaction.objectStore(ROOM_DRAFTS).delete([locator, path]);
|
|
477
623
|
await completed(transaction);
|
|
478
624
|
},
|
|
479
|
-
async
|
|
480
|
-
const
|
|
625
|
+
async fences() {
|
|
626
|
+
const transaction = authored.transaction(FENCES, 'readonly');
|
|
627
|
+
const held = await settled(transaction.objectStore(FENCES).getAll());
|
|
628
|
+
return held.map((fence) => fence.locator);
|
|
629
|
+
},
|
|
630
|
+
async erase(locators) {
|
|
631
|
+
const work = authored.transaction([FENCES, QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
|
|
481
632
|
for (const locator of locators) {
|
|
633
|
+
work.objectStore(FENCES).put({ locator });
|
|
482
634
|
work.objectStore(QUEUES).delete(locator);
|
|
483
635
|
for (const name of [PENDING_CHANGES, ROOM_DRAFTS]) {
|
|
484
636
|
removeRoomEntries(work.objectStore(name), locator);
|
|
@@ -493,22 +645,37 @@ export async function openRuntimeStore() {
|
|
|
493
645
|
transaction.objectStore(BINARY_FILES).delete(underRoom(locator));
|
|
494
646
|
}
|
|
495
647
|
await completed(transaction);
|
|
648
|
+
const fences = authored.transaction(FENCES, 'readwrite');
|
|
649
|
+
for (const locator of locators)
|
|
650
|
+
fences.objectStore(FENCES).delete(locator);
|
|
651
|
+
await completed(fences);
|
|
652
|
+
},
|
|
653
|
+
async discard(locator) {
|
|
654
|
+
const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readwrite');
|
|
655
|
+
transaction.objectStore(QUEUES).delete(locator);
|
|
656
|
+
removeRoomEntries(transaction.objectStore(PENDING_CHANGES), locator);
|
|
657
|
+
await completed(transaction);
|
|
496
658
|
},
|
|
497
659
|
async transfers() {
|
|
498
660
|
const transaction = database.transaction(TRANSFERS, 'readonly');
|
|
499
|
-
|
|
661
|
+
const held = await settled(transaction.objectStore(TRANSFERS).getAll());
|
|
662
|
+
return held.filter((record) => !fenced(record.locator));
|
|
500
663
|
},
|
|
501
664
|
staged(record) {
|
|
502
665
|
const transaction = database.transaction([DOCUMENTS, BINARY_FILES], 'readonly');
|
|
503
666
|
return readLayer(transaction, record.locator, record.transfer);
|
|
504
667
|
},
|
|
505
668
|
async stage(record, page) {
|
|
669
|
+
if (fenced(record.locator))
|
|
670
|
+
return;
|
|
506
671
|
const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
|
|
507
672
|
writeLayer(transaction, record.locator, record.transfer, page, null);
|
|
508
673
|
transaction.objectStore(TRANSFERS).put(record);
|
|
509
674
|
await completed(transaction);
|
|
510
675
|
},
|
|
511
676
|
async abandon(locator) {
|
|
677
|
+
if (fenced(locator))
|
|
678
|
+
return;
|
|
512
679
|
const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
|
|
513
680
|
const transfers = transaction.objectStore(TRANSFERS);
|
|
514
681
|
const held = transfers.get(locator);
|
|
@@ -523,6 +690,32 @@ export async function openRuntimeStore() {
|
|
|
523
690
|
};
|
|
524
691
|
await completed(transaction);
|
|
525
692
|
},
|
|
693
|
+
async receivedHeads() {
|
|
694
|
+
const transaction = database.transaction(RECEIVED, 'readonly');
|
|
695
|
+
return settled(transaction.objectStore(RECEIVED).getAll());
|
|
696
|
+
},
|
|
697
|
+
async receivedParts(key, count) {
|
|
698
|
+
const transaction = database.transaction(RECEIVED_PARTS, 'readonly');
|
|
699
|
+
const kept = await settled(transaction
|
|
700
|
+
.objectStore(RECEIVED_PARTS)
|
|
701
|
+
.getAll(IDBKeyRange.bound([key, 0], [key, count], false, true)));
|
|
702
|
+
return kept.map((part) => part.value);
|
|
703
|
+
},
|
|
704
|
+
async keepReceived(key, head, part) {
|
|
705
|
+
const transaction = database.transaction([RECEIVED, RECEIVED_PARTS], 'readwrite');
|
|
706
|
+
transaction.objectStore(RECEIVED).put({ key, head });
|
|
707
|
+
if (part !== undefined)
|
|
708
|
+
transaction.objectStore(RECEIVED_PARTS).put({ key, ...part });
|
|
709
|
+
await completed(transaction);
|
|
710
|
+
},
|
|
711
|
+
async dropReceived(keys) {
|
|
712
|
+
const transaction = database.transaction([RECEIVED, RECEIVED_PARTS], 'readwrite');
|
|
713
|
+
for (const key of keys) {
|
|
714
|
+
transaction.objectStore(RECEIVED).delete(key);
|
|
715
|
+
transaction.objectStore(RECEIVED_PARTS).delete(IDBKeyRange.bound([key], [key, []]));
|
|
716
|
+
}
|
|
717
|
+
await completed(transaction);
|
|
718
|
+
},
|
|
526
719
|
async generation() {
|
|
527
720
|
const transaction = authored.transaction(FACTS, 'readonly');
|
|
528
721
|
const held = await settled(transaction.objectStore(FACTS).get(GENERATION));
|
package/dist/turn.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function yielded(): Promise<void>;
|
|
2
|
+
export declare const ROW_WEIGHT = 256;
|
|
3
|
+
export type Later<T> = T | Promise<T>;
|
|
4
|
+
export declare function after<T, R>(value: Later<T>, next: (value: T) => R): Later<R>;
|
|
5
|
+
export declare function inUnits<T>(items: Iterable<T>, each: (item: T) => number): Later<void>;
|
|
6
|
+
export declare function inChunks<T>(items: readonly T[], weigh: (item: T) => number, each: (chunk: readonly T[]) => void): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=turn.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../src/turn.ts"],"names":[],"mappings":"AAAA,wBAAgB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CASvC;AAID,eAAO,MAAM,UAAU,MAAM,CAAC;AAE9B,MAAM,MAAM,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEtC,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAE5E;AAaD,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAOrF;AAED,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAC1B,IAAI,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI,GAClC,OAAO,CAAC,IAAI,CAAC,CAUf"}
|
package/dist/turn.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function yielded() {
|
|
2
|
+
return new Promise((resolve) => {
|
|
3
|
+
const channel = new MessageChannel();
|
|
4
|
+
channel.port1.onmessage = () => {
|
|
5
|
+
channel.port1.close();
|
|
6
|
+
resolve();
|
|
7
|
+
};
|
|
8
|
+
channel.port2.postMessage(null);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
const UNIT = 1 << 20;
|
|
12
|
+
export const ROW_WEIGHT = 256;
|
|
13
|
+
export function after(value, next) {
|
|
14
|
+
return value instanceof Promise ? value.then(next) : next(value);
|
|
15
|
+
}
|
|
16
|
+
async function resumed(iterator, each) {
|
|
17
|
+
let spent = UNIT;
|
|
18
|
+
for (let next = iterator.next(); next.done !== true; next = iterator.next()) {
|
|
19
|
+
if (spent >= UNIT) {
|
|
20
|
+
await yielded();
|
|
21
|
+
spent = 0;
|
|
22
|
+
}
|
|
23
|
+
spent += each(next.value);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function inUnits(items, each) {
|
|
27
|
+
const iterator = items[Symbol.iterator]();
|
|
28
|
+
let spent = 0;
|
|
29
|
+
for (let next = iterator.next(); next.done !== true; next = iterator.next()) {
|
|
30
|
+
spent += each(next.value);
|
|
31
|
+
if (spent >= UNIT)
|
|
32
|
+
return resumed(iterator, each);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function inChunks(items, weigh, each) {
|
|
36
|
+
for (let at = 0; at < items.length;) {
|
|
37
|
+
await yielded();
|
|
38
|
+
const chunk = [];
|
|
39
|
+
for (let spent = 0; at < items.length && spent < UNIT; at += 1) {
|
|
40
|
+
chunk.push(items[at]);
|
|
41
|
+
spent += weigh(items[at]);
|
|
42
|
+
}
|
|
43
|
+
each(chunk);
|
|
44
|
+
}
|
|
45
|
+
}
|