@agentshouse/mdruntime 0.1.0-cdf82f77fae68 → 0.1.0-ceb97106cc2fd
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 +259 -272
- 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/attempt.d.ts.map +1 -1
- package/dist/attempt.js +14 -1
- package/dist/bootstrap.d.ts +2 -2
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +32 -6
- 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 +8 -1
- package/dist/chat/list.d.ts.map +1 -1
- package/dist/chat/list.js +10 -6
- 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 +51 -67
- 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 +3 -3
- 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 +24 -7
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +1340 -318
- 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 +17 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +156 -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 +18 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +89 -12
- 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 +34 -3
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +7 -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 +6 -2
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +42 -18
- package/dist/search.d.ts +34 -6
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +116 -45
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +61 -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 +45 -12
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +315 -85
- 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 +12 -8
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,17 +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
|
-
|
|
21
|
-
|
|
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;
|
|
22
30
|
const AUTHORED_STORES = [
|
|
23
31
|
[QUEUES, { keyPath: 'locator' }],
|
|
24
32
|
[PENDING_CHANGES, { keyPath: ['locator', 'id'] }],
|
|
25
33
|
[ROOM_DRAFTS, { keyPath: ['locator', 'path'] }],
|
|
26
34
|
[CHAT_DRAFTS, { keyPath: 'conversation' }],
|
|
27
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'] }],
|
|
28
49
|
];
|
|
29
50
|
const READ_BATCH = 256;
|
|
51
|
+
const MESSAGE_INDEXES = [
|
|
52
|
+
['conversation', 'conversation'],
|
|
53
|
+
['position', ['conversation', 'position']],
|
|
54
|
+
['turn', ['conversation', 'turn']],
|
|
55
|
+
];
|
|
30
56
|
function settled(request) {
|
|
31
57
|
return new Promise((resolve, reject) => {
|
|
32
58
|
request.onsuccess = () => resolve(request.result);
|
|
@@ -69,8 +95,11 @@ function amendPending(database, locator, id, amendment) {
|
|
|
69
95
|
};
|
|
70
96
|
return completed(transaction);
|
|
71
97
|
}
|
|
98
|
+
function accepted({ conversation: _held, ...message }) {
|
|
99
|
+
return message;
|
|
100
|
+
}
|
|
72
101
|
function roomRecord(record) {
|
|
73
|
-
const { documents, binaries, revisions, changes, written, ...room } = record;
|
|
102
|
+
const { documents, binaries, revisions, fileIds, changes, written, ...room } = record;
|
|
74
103
|
return room;
|
|
75
104
|
}
|
|
76
105
|
function chatDraftRecord(record) {
|
|
@@ -96,13 +125,15 @@ async function readTransfer(store, locator, transfer, receive) {
|
|
|
96
125
|
}
|
|
97
126
|
}
|
|
98
127
|
function emptyLayer() {
|
|
99
|
-
return { documents: {}, binaries: {}, revisions: {}, changes: {}, written: {} };
|
|
128
|
+
return { documents: {}, binaries: {}, revisions: {}, fileIds: {}, changes: {}, written: {} };
|
|
100
129
|
}
|
|
101
130
|
async function readLayer(transaction, locator, transfer) {
|
|
102
131
|
const layer = emptyLayer();
|
|
103
132
|
const head = (held) => {
|
|
104
133
|
if (held.revision !== null)
|
|
105
134
|
layer.revisions[held.path] = held.revision;
|
|
135
|
+
if (held.fileId !== null)
|
|
136
|
+
layer.fileIds[held.path] = held.fileId;
|
|
106
137
|
if (held.change !== null)
|
|
107
138
|
layer.changes[held.path] = held.change;
|
|
108
139
|
};
|
|
@@ -125,6 +156,7 @@ function documentRecord(locator, transfer, layer, path) {
|
|
|
125
156
|
path,
|
|
126
157
|
content: layer.documents[path],
|
|
127
158
|
revision: layer.revisions[path] ?? null,
|
|
159
|
+
fileId: layer.fileIds[path] ?? null,
|
|
128
160
|
change: layer.changes[path] ?? null,
|
|
129
161
|
written: layer.written[path] ?? null,
|
|
130
162
|
};
|
|
@@ -135,35 +167,37 @@ function binaryFileRecord(locator, transfer, layer, path) {
|
|
|
135
167
|
transfer,
|
|
136
168
|
path,
|
|
137
169
|
revision: layer.revisions[path] ?? null,
|
|
170
|
+
fileId: layer.fileIds[path] ?? null,
|
|
138
171
|
change: layer.changes[path] ?? null,
|
|
139
172
|
binary: layer.binaries[path],
|
|
140
173
|
};
|
|
141
174
|
}
|
|
142
175
|
function writeLayer(transaction, locator, transfer, next, base) {
|
|
143
176
|
const documents = transaction.objectStore(DOCUMENTS);
|
|
144
|
-
for (const path of Object.keys(base?.documents ?? {})) {
|
|
145
|
-
if (next.documents[path] === undefined)
|
|
146
|
-
documents.delete([locator, transfer, path]);
|
|
147
|
-
}
|
|
148
|
-
for (const [path, content] of Object.entries(next.documents)) {
|
|
149
|
-
if (base?.documents[path] === content &&
|
|
150
|
-
base.revisions[path] === next.revisions[path] &&
|
|
151
|
-
base.written[path] === next.written[path] &&
|
|
152
|
-
sameChange(base.changes[path], next.changes[path]))
|
|
153
|
-
continue;
|
|
154
|
-
documents.put(documentRecord(locator, transfer, next, path));
|
|
155
|
-
}
|
|
156
177
|
const files = transaction.objectStore(BINARY_FILES);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
base
|
|
164
|
-
|
|
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) {
|
|
165
196
|
files.put(binaryFileRecord(locator, transfer, next, path));
|
|
166
197
|
}
|
|
198
|
+
else if (base?.binaries[path] !== undefined) {
|
|
199
|
+
files.delete([locator, transfer, path]);
|
|
200
|
+
}
|
|
167
201
|
}
|
|
168
202
|
}
|
|
169
203
|
function removeRoomEntries(store, locator) {
|
|
@@ -182,41 +216,113 @@ function removeDatabase(name) {
|
|
|
182
216
|
removal.onerror = () => reject(removal.error);
|
|
183
217
|
});
|
|
184
218
|
}
|
|
185
|
-
export async function
|
|
186
|
-
await
|
|
219
|
+
export async function authoredHolder() {
|
|
220
|
+
const authored = await openAuthored();
|
|
221
|
+
try {
|
|
222
|
+
const transaction = authored.transaction(FACTS, 'readonly');
|
|
223
|
+
const held = transaction.objectStore(FACTS).get(HOLDER);
|
|
224
|
+
await completed(transaction);
|
|
225
|
+
return typeof held.result === 'string' ? held.result : null;
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
authored.close();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
export async function authoredBy(holder) {
|
|
232
|
+
const authored = await openAuthored();
|
|
233
|
+
try {
|
|
234
|
+
const transaction = authored.transaction(FACTS, 'readwrite');
|
|
235
|
+
const facts = transaction.objectStore(FACTS);
|
|
236
|
+
const held = facts.get(HOLDER);
|
|
237
|
+
let owned = true;
|
|
238
|
+
held.onsuccess = () => {
|
|
239
|
+
if (held.result === undefined)
|
|
240
|
+
facts.put(holder, HOLDER);
|
|
241
|
+
else
|
|
242
|
+
owned = held.result === holder;
|
|
243
|
+
};
|
|
244
|
+
await completed(transaction);
|
|
245
|
+
return owned;
|
|
246
|
+
}
|
|
247
|
+
finally {
|
|
248
|
+
authored.close();
|
|
249
|
+
}
|
|
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
|
+
}
|
|
274
|
+
export async function removeRuntimeStore(holder) {
|
|
275
|
+
await removeDatabase(DATABASE);
|
|
276
|
+
if (holder !== undefined && (await authoredBy(holder)))
|
|
277
|
+
return true;
|
|
278
|
+
await removeDatabase(AUTHORED);
|
|
279
|
+
return false;
|
|
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
|
+
});
|
|
187
296
|
}
|
|
188
297
|
function openReplica() {
|
|
189
|
-
|
|
190
|
-
opening.onupgradeneeded = () => {
|
|
298
|
+
return openDatabase(DATABASE, STORE_SCHEMA, (opening, oldVersion) => {
|
|
191
299
|
const database = opening.result;
|
|
192
|
-
|
|
193
|
-
database.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const messages =
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
+
});
|
|
207
315
|
}
|
|
208
316
|
function openAuthored() {
|
|
209
|
-
|
|
210
|
-
opening.onupgradeneeded = () => {
|
|
317
|
+
return openDatabase(AUTHORED, AUTHORED_SCHEMA, (opening) => {
|
|
211
318
|
const database = opening.result;
|
|
212
319
|
for (const [name, parameters] of AUTHORED_STORES) {
|
|
213
320
|
if (!database.objectStoreNames.contains(name))
|
|
214
321
|
database.createObjectStore(name, parameters);
|
|
215
322
|
}
|
|
216
|
-
};
|
|
217
|
-
return settled(opening);
|
|
323
|
+
});
|
|
218
324
|
}
|
|
219
|
-
export async function openRuntimeStore() {
|
|
325
|
+
export async function openRuntimeStore(fenced) {
|
|
220
326
|
const authored = await openAuthored();
|
|
221
327
|
const database = await openReplica().catch((error) => {
|
|
222
328
|
authored.close();
|
|
@@ -227,12 +333,14 @@ export async function openRuntimeStore() {
|
|
|
227
333
|
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES], 'readonly');
|
|
228
334
|
const rooms = await settled(transaction.objectStore(ROOMS).getAll());
|
|
229
335
|
const records = [];
|
|
230
|
-
for (const room of rooms) {
|
|
336
|
+
for (const room of rooms.filter((held) => !fenced(held.locator))) {
|
|
231
337
|
records.push({ ...room, ...(await readLayer(transaction, room.locator, room.transfer)) });
|
|
232
338
|
}
|
|
233
339
|
return records;
|
|
234
340
|
},
|
|
235
341
|
async keepAuthored({ locator, queue, saved, roomDrafts, consumedRoomDrafts }) {
|
|
342
|
+
if (fenced(locator))
|
|
343
|
+
return;
|
|
236
344
|
const transaction = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
|
|
237
345
|
const order = transaction.objectStore(QUEUES);
|
|
238
346
|
const pending = transaction.objectStore(PENDING_CHANGES);
|
|
@@ -269,7 +377,7 @@ export async function openRuntimeStore() {
|
|
|
269
377
|
await completed(transaction);
|
|
270
378
|
},
|
|
271
379
|
async write({ next, previous, stored }) {
|
|
272
|
-
if (next === previous)
|
|
380
|
+
if (next === previous || fenced(next.locator))
|
|
273
381
|
return;
|
|
274
382
|
const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
|
|
275
383
|
transaction.objectStore(ROOMS).put(roomRecord(next));
|
|
@@ -289,6 +397,8 @@ export async function openRuntimeStore() {
|
|
|
289
397
|
const rooms = transaction.objectStore(ROOMS);
|
|
290
398
|
const revoked = { status: 'unavailable', reason: 'revoked' };
|
|
291
399
|
for (const record of records) {
|
|
400
|
+
if (fenced(record.locator))
|
|
401
|
+
continue;
|
|
292
402
|
rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }));
|
|
293
403
|
}
|
|
294
404
|
await completed(transaction);
|
|
@@ -322,6 +432,16 @@ export async function openRuntimeStore() {
|
|
|
322
432
|
transaction.objectStore(DECLARATIONS).put(member, MEMBER);
|
|
323
433
|
await completed(transaction);
|
|
324
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
|
+
},
|
|
325
445
|
async queues() {
|
|
326
446
|
const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readonly');
|
|
327
447
|
const [queues, pending] = await Promise.all([
|
|
@@ -329,7 +449,9 @@ export async function openRuntimeStore() {
|
|
|
329
449
|
settled(transaction.objectStore(PENDING_CHANGES).getAll()),
|
|
330
450
|
]);
|
|
331
451
|
const byId = new Map(pending.map((record) => [`${record.locator}\0${record.id}`, record]));
|
|
332
|
-
return queues
|
|
452
|
+
return queues
|
|
453
|
+
.filter((queue) => !fenced(queue.locator))
|
|
454
|
+
.map((queue) => ({
|
|
333
455
|
locator: queue.locator,
|
|
334
456
|
pending: queue.order.map((id) => {
|
|
335
457
|
const record = byId.get(`${queue.locator}\0${id}`);
|
|
@@ -340,18 +462,22 @@ export async function openRuntimeStore() {
|
|
|
340
462
|
}),
|
|
341
463
|
}));
|
|
342
464
|
},
|
|
343
|
-
submit(locator, id, submission, lost) {
|
|
344
|
-
|
|
465
|
+
async submit(locator, id, submission, lost) {
|
|
466
|
+
if (!fenced(locator))
|
|
467
|
+
await amendPending(authored, locator, id, { submission, lost });
|
|
345
468
|
},
|
|
346
|
-
accept(locator, id, roomVersion) {
|
|
347
|
-
|
|
469
|
+
async accept(locator, id, roomVersion) {
|
|
470
|
+
if (!fenced(locator))
|
|
471
|
+
await amendPending(authored, locator, id, { accepted: roomVersion });
|
|
348
472
|
},
|
|
349
|
-
keepUpload(locator, id, upload) {
|
|
350
|
-
|
|
473
|
+
async keepUpload(locator, id, upload) {
|
|
474
|
+
if (!fenced(locator))
|
|
475
|
+
await amendPending(authored, locator, id, { upload });
|
|
351
476
|
},
|
|
352
477
|
async roomDrafts() {
|
|
353
478
|
const transaction = authored.transaction(ROOM_DRAFTS, 'readonly');
|
|
354
|
-
|
|
479
|
+
const held = await settled(transaction.objectStore(ROOM_DRAFTS).getAll());
|
|
480
|
+
return held.filter((record) => !fenced(record.locator));
|
|
355
481
|
},
|
|
356
482
|
async presentation() {
|
|
357
483
|
const transaction = database.transaction(PRESENTATION, 'readonly');
|
|
@@ -364,39 +490,91 @@ export async function openRuntimeStore() {
|
|
|
364
490
|
},
|
|
365
491
|
async conversations() {
|
|
366
492
|
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readonly');
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
+
});
|
|
380
515
|
return [...held.values()];
|
|
381
516
|
},
|
|
382
|
-
async keepMessages({ conversation, messages, read
|
|
383
|
-
if (sealed === true) {
|
|
384
|
-
const sealing = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
385
|
-
sealing.objectStore(CHAT_DRAFTS).delete(conversation);
|
|
386
|
-
await completed(sealing);
|
|
387
|
-
}
|
|
517
|
+
async keepMessages({ conversation, messages, read }) {
|
|
388
518
|
const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
|
|
389
519
|
const stored = transaction.objectStore(MESSAGES);
|
|
390
520
|
for (const message of messages) {
|
|
391
521
|
stored.put({ ...message, conversation });
|
|
392
522
|
}
|
|
393
523
|
if (read !== undefined) {
|
|
394
|
-
transaction
|
|
395
|
-
|
|
396
|
-
.
|
|
524
|
+
transaction.objectStore(CONVERSATIONS).put({
|
|
525
|
+
conversation,
|
|
526
|
+
read: read.at,
|
|
527
|
+
...(read.partial ? { partial: true } : {}),
|
|
528
|
+
});
|
|
397
529
|
}
|
|
398
530
|
await completed(transaction);
|
|
399
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
|
+
},
|
|
400
578
|
async dropConversations(conversations) {
|
|
401
579
|
const drafts = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
402
580
|
for (const conversation of conversations)
|
|
@@ -419,9 +597,10 @@ export async function openRuntimeStore() {
|
|
|
419
597
|
const held = await settled(transaction.objectStore(CHAT_DRAFTS).getAll());
|
|
420
598
|
return held.map(chatDraftRecord);
|
|
421
599
|
},
|
|
422
|
-
async
|
|
600
|
+
async keepChatDrafts(records) {
|
|
423
601
|
const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
|
|
424
|
-
|
|
602
|
+
for (const record of records)
|
|
603
|
+
transaction.objectStore(CHAT_DRAFTS).put(record);
|
|
425
604
|
await completed(transaction);
|
|
426
605
|
},
|
|
427
606
|
async dropChatDraft(conversation) {
|
|
@@ -430,18 +609,28 @@ export async function openRuntimeStore() {
|
|
|
430
609
|
await completed(transaction);
|
|
431
610
|
},
|
|
432
611
|
async keepRoomDraft(record) {
|
|
612
|
+
if (fenced(record.locator))
|
|
613
|
+
return;
|
|
433
614
|
const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
|
|
434
615
|
transaction.objectStore(ROOM_DRAFTS).put(record);
|
|
435
616
|
await completed(transaction);
|
|
436
617
|
},
|
|
437
618
|
async discardRoomDraft(locator, path) {
|
|
619
|
+
if (fenced(locator))
|
|
620
|
+
return;
|
|
438
621
|
const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
|
|
439
622
|
transaction.objectStore(ROOM_DRAFTS).delete([locator, path]);
|
|
440
623
|
await completed(transaction);
|
|
441
624
|
},
|
|
442
|
-
async
|
|
443
|
-
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');
|
|
444
632
|
for (const locator of locators) {
|
|
633
|
+
work.objectStore(FENCES).put({ locator });
|
|
445
634
|
work.objectStore(QUEUES).delete(locator);
|
|
446
635
|
for (const name of [PENDING_CHANGES, ROOM_DRAFTS]) {
|
|
447
636
|
removeRoomEntries(work.objectStore(name), locator);
|
|
@@ -456,22 +645,37 @@ export async function openRuntimeStore() {
|
|
|
456
645
|
transaction.objectStore(BINARY_FILES).delete(underRoom(locator));
|
|
457
646
|
}
|
|
458
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);
|
|
459
658
|
},
|
|
460
659
|
async transfers() {
|
|
461
660
|
const transaction = database.transaction(TRANSFERS, 'readonly');
|
|
462
|
-
|
|
661
|
+
const held = await settled(transaction.objectStore(TRANSFERS).getAll());
|
|
662
|
+
return held.filter((record) => !fenced(record.locator));
|
|
463
663
|
},
|
|
464
664
|
staged(record) {
|
|
465
665
|
const transaction = database.transaction([DOCUMENTS, BINARY_FILES], 'readonly');
|
|
466
666
|
return readLayer(transaction, record.locator, record.transfer);
|
|
467
667
|
},
|
|
468
668
|
async stage(record, page) {
|
|
669
|
+
if (fenced(record.locator))
|
|
670
|
+
return;
|
|
469
671
|
const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
|
|
470
672
|
writeLayer(transaction, record.locator, record.transfer, page, null);
|
|
471
673
|
transaction.objectStore(TRANSFERS).put(record);
|
|
472
674
|
await completed(transaction);
|
|
473
675
|
},
|
|
474
676
|
async abandon(locator) {
|
|
677
|
+
if (fenced(locator))
|
|
678
|
+
return;
|
|
475
679
|
const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
|
|
476
680
|
const transfers = transaction.objectStore(TRANSFERS);
|
|
477
681
|
const held = transfers.get(locator);
|
|
@@ -486,6 +690,32 @@ export async function openRuntimeStore() {
|
|
|
486
690
|
};
|
|
487
691
|
await completed(transaction);
|
|
488
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
|
+
},
|
|
489
719
|
async generation() {
|
|
490
720
|
const transaction = authored.transaction(FACTS, 'readonly');
|
|
491
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
|
+
}
|