@agentshouse/mdruntime 0.1.0-cf6d5f0a5c9c8 → 0.1.0-cfb0d45b48da0

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.
Files changed (158) hide show
  1. package/AGENTS.md +146 -100
  2. package/README.md +11 -1
  3. package/dist/adapter.d.ts +41 -14
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attempt.d.ts +16 -0
  6. package/dist/attempt.d.ts.map +1 -0
  7. package/dist/attempt.js +57 -0
  8. package/dist/binary.d.ts +23 -0
  9. package/dist/binary.d.ts.map +1 -0
  10. package/dist/binary.js +8 -0
  11. package/dist/bootstrap.d.ts.map +1 -1
  12. package/dist/bootstrap.js +5 -8
  13. package/dist/change-set.d.ts.map +1 -1
  14. package/dist/change-set.js +8 -7
  15. package/dist/change.d.ts +15 -0
  16. package/dist/change.d.ts.map +1 -1
  17. package/dist/change.js +26 -1
  18. package/dist/chat/acts.d.ts +34 -0
  19. package/dist/chat/acts.d.ts.map +1 -0
  20. package/dist/chat/acts.js +36 -0
  21. package/dist/chat/context.d.ts +3 -0
  22. package/dist/chat/context.d.ts.map +1 -0
  23. package/dist/chat/context.js +10 -0
  24. package/dist/chat/input.d.ts +9 -0
  25. package/dist/chat/input.d.ts.map +1 -0
  26. package/dist/chat/input.js +99 -0
  27. package/dist/chat/kit.d.ts +60 -0
  28. package/dist/chat/kit.d.ts.map +1 -0
  29. package/dist/chat/kit.js +123 -0
  30. package/dist/chat/lasting.d.ts +6 -0
  31. package/dist/chat/lasting.d.ts.map +1 -0
  32. package/dist/chat/lasting.js +19 -0
  33. package/dist/chat/list.d.ts +20 -0
  34. package/dist/chat/list.d.ts.map +1 -0
  35. package/dist/chat/list.js +59 -0
  36. package/dist/chat/markdown.d.ts +19 -0
  37. package/dist/chat/markdown.d.ts.map +1 -0
  38. package/dist/chat/markdown.js +187 -0
  39. package/dist/chat/message.d.ts +6 -0
  40. package/dist/chat/message.d.ts.map +1 -0
  41. package/dist/chat/message.js +192 -0
  42. package/dist/chat/messages.d.ts +21 -0
  43. package/dist/chat/messages.d.ts.map +1 -0
  44. package/dist/chat/messages.js +151 -0
  45. package/dist/chat/name.d.ts +6 -0
  46. package/dist/chat/name.d.ts.map +1 -0
  47. package/dist/chat/name.js +37 -0
  48. package/dist/chat/opened.d.ts +11 -0
  49. package/dist/chat/opened.d.ts.map +1 -0
  50. package/dist/chat/opened.js +17 -0
  51. package/dist/chat/overlay.d.ts +31 -0
  52. package/dist/chat/overlay.d.ts.map +1 -0
  53. package/dist/chat/overlay.js +97 -0
  54. package/dist/chat/parts.d.ts +57 -0
  55. package/dist/chat/parts.d.ts.map +1 -0
  56. package/dist/chat/parts.js +119 -0
  57. package/dist/chat/process.d.ts +20 -0
  58. package/dist/chat/process.d.ts.map +1 -0
  59. package/dist/chat/process.js +32 -0
  60. package/dist/chat/provider.d.ts +63 -0
  61. package/dist/chat/provider.d.ts.map +1 -0
  62. package/dist/chat/provider.js +645 -0
  63. package/dist/chat/question.d.ts +9 -0
  64. package/dist/chat/question.d.ts.map +1 -0
  65. package/dist/chat/question.js +80 -0
  66. package/dist/chat/questions.d.ts +31 -0
  67. package/dist/chat/questions.d.ts.map +1 -0
  68. package/dist/chat/questions.js +111 -0
  69. package/dist/chat/read.d.ts +5 -0
  70. package/dist/chat/read.d.ts.map +1 -0
  71. package/dist/chat/read.js +13 -0
  72. package/dist/chat/ready.d.ts +33 -0
  73. package/dist/chat/ready.d.ts.map +1 -0
  74. package/dist/chat/ready.js +91 -0
  75. package/dist/chat/style.d.ts +4 -0
  76. package/dist/chat/style.d.ts.map +1 -0
  77. package/dist/chat/style.js +302 -0
  78. package/dist/chat.d.ts +14 -0
  79. package/dist/chat.d.ts.map +1 -0
  80. package/dist/chat.js +8 -0
  81. package/dist/client.d.ts +12 -5
  82. package/dist/client.d.ts.map +1 -1
  83. package/dist/client.js +30 -15
  84. package/dist/connection.d.ts +19 -9
  85. package/dist/connection.d.ts.map +1 -1
  86. package/dist/connection.js +312 -96
  87. package/dist/conversation.d.ts +11 -3
  88. package/dist/conversation.d.ts.map +1 -1
  89. package/dist/conversation.js +47 -7
  90. package/dist/expectation.d.ts +21 -0
  91. package/dist/expectation.d.ts.map +1 -0
  92. package/dist/expectation.js +70 -0
  93. package/dist/failure.d.ts +13 -0
  94. package/dist/failure.d.ts.map +1 -0
  95. package/dist/failure.js +19 -0
  96. package/dist/host.d.ts +2 -2
  97. package/dist/host.d.ts.map +1 -1
  98. package/dist/host.js +12 -12
  99. package/dist/identity.d.ts +2 -0
  100. package/dist/identity.d.ts.map +1 -1
  101. package/dist/identity.js +6 -0
  102. package/dist/index.d.ts +9 -4
  103. package/dist/index.d.ts.map +1 -1
  104. package/dist/index.js +3 -0
  105. package/dist/memory.d.ts +3 -3
  106. package/dist/memory.d.ts.map +1 -1
  107. package/dist/memory.js +47 -16
  108. package/dist/model.d.ts +3 -2
  109. package/dist/model.d.ts.map +1 -1
  110. package/dist/open.d.ts +2 -0
  111. package/dist/open.d.ts.map +1 -0
  112. package/dist/open.js +1 -0
  113. package/dist/outcome.d.ts +28 -3
  114. package/dist/outcome.d.ts.map +1 -1
  115. package/dist/outcome.js +41 -1
  116. package/dist/overlay.d.ts +14 -3
  117. package/dist/overlay.d.ts.map +1 -1
  118. package/dist/overlay.js +75 -37
  119. package/dist/query.d.ts +4 -0
  120. package/dist/query.d.ts.map +1 -1
  121. package/dist/query.js +3 -0
  122. package/dist/reach.d.ts +2 -0
  123. package/dist/reach.d.ts.map +1 -1
  124. package/dist/reach.js +43 -19
  125. package/dist/react.d.ts +4 -2
  126. package/dist/react.d.ts.map +1 -1
  127. package/dist/react.js +3 -2
  128. package/dist/read-side.d.ts.map +1 -1
  129. package/dist/read-side.js +9 -2
  130. package/dist/refresh.d.ts.map +1 -1
  131. package/dist/refresh.js +12 -17
  132. package/dist/replica.d.ts +6 -3
  133. package/dist/replica.d.ts.map +1 -1
  134. package/dist/replica.js +46 -32
  135. package/dist/room-draft.d.ts +26 -9
  136. package/dist/room-draft.d.ts.map +1 -1
  137. package/dist/room-draft.js +131 -22
  138. package/dist/rows.d.ts +3 -1
  139. package/dist/rows.d.ts.map +1 -1
  140. package/dist/rows.js +3 -1
  141. package/dist/save.d.ts +27 -1
  142. package/dist/save.d.ts.map +1 -1
  143. package/dist/save.js +323 -22
  144. package/dist/search.d.ts +3 -2
  145. package/dist/search.d.ts.map +1 -1
  146. package/dist/status.d.ts +2 -2
  147. package/dist/status.d.ts.map +1 -1
  148. package/dist/status.js +0 -8
  149. package/dist/store.d.ts +16 -13
  150. package/dist/store.d.ts.map +1 -1
  151. package/dist/store.js +186 -156
  152. package/dist/wire.d.ts +6 -3
  153. package/dist/wire.d.ts.map +1 -1
  154. package/dist/wire.js +14 -2
  155. package/package.json +22 -14
  156. package/dist/attachment.d.ts +0 -3
  157. package/dist/attachment.d.ts.map +0 -1
  158. package/dist/attachment.js +0 -8
package/dist/store.js CHANGED
@@ -1,10 +1,9 @@
1
- import { transferIdentity } from './identity.js';
2
- import { sameChange } from './overlay.js';
1
+ import { sameBinary, sameChange } from './overlay.js';
3
2
  const DATABASE = 'mdruntime';
3
+ const AUTHORED = 'mdruntime-authored';
4
4
  const ROOMS = 'rooms';
5
5
  const DOCUMENTS = 'documents';
6
- const BINARY_TARGETS = 'binaryTargets';
7
- const ATTACHMENTS = 'attachments';
6
+ const BINARY_FILES = 'binaryFiles';
8
7
  const TRANSFERS = 'transfers';
9
8
  const PENDING_CHANGES = 'pendingChanges';
10
9
  const DECLARATIONS = 'declarations';
@@ -13,10 +12,21 @@ const PRESENTATION = 'presentation';
13
12
  const CONVERSATIONS = 'conversations';
14
13
  const MESSAGES = 'messages';
15
14
  const CHAT_DRAFTS = 'chatDrafts';
15
+ const QUEUES = 'queues';
16
+ const FACTS = 'facts';
16
17
  const CURRENT = 'current';
17
18
  const MEMBER = 'member';
18
- export const STORE_SCHEMA = 21;
19
- const PATH_KEYED_SCHEMA = 20;
19
+ const GENERATION = 'generation';
20
+ const HOLDER = 'holder';
21
+ export const STORE_SCHEMA = 23;
22
+ export const AUTHORED_SCHEMA = 1;
23
+ const AUTHORED_STORES = [
24
+ [QUEUES, { keyPath: 'locator' }],
25
+ [PENDING_CHANGES, { keyPath: ['locator', 'id'] }],
26
+ [ROOM_DRAFTS, { keyPath: ['locator', 'path'] }],
27
+ [CHAT_DRAFTS, { keyPath: 'conversation' }],
28
+ [FACTS, undefined],
29
+ ];
20
30
  const READ_BATCH = 256;
21
31
  function settled(request) {
22
32
  return new Promise((resolve, reject) => {
@@ -33,7 +43,6 @@ function completed(transaction) {
33
43
  }
34
44
  const EMPTY_DECLARATIONS = {
35
45
  lastCompleted: null,
36
- generation: null,
37
46
  providerLimits: [],
38
47
  capabilities: [],
39
48
  };
@@ -61,9 +70,12 @@ function amendPending(database, locator, id, amendment) {
61
70
  };
62
71
  return completed(transaction);
63
72
  }
64
- function roomRecord(record, queue) {
65
- const { documents, binaryTargets, revisions, changes, written, attachments, ...room } = record;
66
- return { ...room, order: queue.map((batch) => batch.id) };
73
+ function roomRecord(record) {
74
+ const { documents, binaries, revisions, changes, written, ...room } = record;
75
+ return room;
76
+ }
77
+ function chatDraftRecord(record) {
78
+ return { ...record, revision: record.revision ?? '' };
67
79
  }
68
80
  function underTransfer(locator, transfer, after) {
69
81
  return after === undefined
@@ -85,7 +97,7 @@ async function readTransfer(store, locator, transfer, receive) {
85
97
  }
86
98
  }
87
99
  function emptyLayer() {
88
- return { documents: {}, binaryTargets: [], revisions: {}, changes: {}, written: {} };
100
+ return { documents: {}, binaries: {}, revisions: {}, changes: {}, written: {} };
89
101
  }
90
102
  async function readLayer(transaction, locator, transfer) {
91
103
  const layer = emptyLayer();
@@ -101,9 +113,9 @@ async function readLayer(transaction, locator, transfer) {
101
113
  layer.written[document.path] = document.written;
102
114
  head(document);
103
115
  });
104
- await readTransfer(transaction.objectStore(BINARY_TARGETS), locator, transfer, (target) => {
105
- layer.binaryTargets.push(target.path);
106
- head(target);
116
+ await readTransfer(transaction.objectStore(BINARY_FILES), locator, transfer, (file) => {
117
+ layer.binaries[file.path] = file.binary;
118
+ head(file);
107
119
  });
108
120
  return layer;
109
121
  }
@@ -118,13 +130,14 @@ function documentRecord(locator, transfer, layer, path) {
118
130
  written: layer.written[path] ?? null,
119
131
  };
120
132
  }
121
- function targetRecord(locator, transfer, layer, path) {
133
+ function binaryFileRecord(locator, transfer, layer, path) {
122
134
  return {
123
135
  locator,
124
136
  transfer,
125
137
  path,
126
138
  revision: layer.revisions[path] ?? null,
127
139
  change: layer.changes[path] ?? null,
140
+ binary: layer.binaries[path],
128
141
  };
129
142
  }
130
143
  function writeLayer(transaction, locator, transfer, next, base) {
@@ -141,18 +154,16 @@ function writeLayer(transaction, locator, transfer, next, base) {
141
154
  continue;
142
155
  documents.put(documentRecord(locator, transfer, next, path));
143
156
  }
144
- const targets = transaction.objectStore(BINARY_TARGETS);
145
- const beforeTargets = new Set(base?.binaryTargets ?? []);
146
- const afterTargets = new Set(next.binaryTargets);
147
- for (const path of beforeTargets) {
148
- if (!afterTargets.has(path))
149
- targets.delete([locator, transfer, path]);
157
+ const files = transaction.objectStore(BINARY_FILES);
158
+ for (const path of Object.keys(base?.binaries ?? {})) {
159
+ if (next.binaries[path] === undefined)
160
+ files.delete([locator, transfer, path]);
150
161
  }
151
- for (const path of afterTargets) {
152
- if (!beforeTargets.has(path) ||
162
+ for (const path of Object.keys(next.binaries)) {
163
+ if (!sameBinary(base?.binaries[path], next.binaries[path]) ||
153
164
  base?.revisions[path] !== next.revisions[path] ||
154
165
  !sameChange(base?.changes[path], next.changes[path])) {
155
- targets.put(targetRecord(locator, transfer, next, path));
166
+ files.put(binaryFileRecord(locator, transfer, next, path));
156
167
  }
157
168
  }
158
169
  }
@@ -165,155 +176,157 @@ function removeRoomEntries(store, locator) {
165
176
  }
166
177
  };
167
178
  }
168
- export function removeRuntimeStore() {
179
+ function removeDatabase(name) {
169
180
  return new Promise((resolve, reject) => {
170
- const removal = indexedDB.deleteDatabase(DATABASE);
181
+ const removal = indexedDB.deleteDatabase(name);
171
182
  removal.onsuccess = () => resolve();
172
183
  removal.onerror = () => reject(removal.error);
173
184
  });
174
185
  }
175
- function keyByTransfer(database, upgrade) {
176
- database.createObjectStore(TRANSFERS, { keyPath: 'locator' });
177
- const moves = [DOCUMENTS, BINARY_TARGETS].map((name) => {
178
- const from = upgrade.objectStore(name);
179
- from.name = `${name}-${PATH_KEYED_SCHEMA}`;
180
- return {
181
- from,
182
- to: database.createObjectStore(name, { keyPath: ['locator', 'transfer', 'path'] }),
186
+ export async function authoredHolder() {
187
+ const authored = await openAuthored();
188
+ try {
189
+ const transaction = authored.transaction(FACTS, 'readonly');
190
+ const held = transaction.objectStore(FACTS).get(HOLDER);
191
+ await completed(transaction);
192
+ return typeof held.result === 'string' ? held.result : null;
193
+ }
194
+ finally {
195
+ authored.close();
196
+ }
197
+ }
198
+ export async function authoredBy(holder) {
199
+ const authored = await openAuthored();
200
+ try {
201
+ const transaction = authored.transaction(FACTS, 'readwrite');
202
+ const facts = transaction.objectStore(FACTS);
203
+ const held = facts.get(HOLDER);
204
+ let owned = true;
205
+ held.onsuccess = () => {
206
+ if (held.result === undefined)
207
+ facts.put(holder, HOLDER);
208
+ else
209
+ owned = held.result === holder;
183
210
  };
184
- });
185
- const transfers = new Map();
186
- const rooms = upgrade.objectStore(ROOMS).openCursor();
187
- rooms.onsuccess = () => {
188
- const room = rooms.result;
189
- if (room !== null) {
190
- const record = room.value;
191
- const transfer = transferIdentity();
192
- transfers.set(record.locator, transfer);
193
- room.update({ ...record, transfer });
194
- room.continue();
195
- return;
196
- }
197
- for (const { from, to } of moves) {
198
- const held = from.openCursor();
199
- held.onsuccess = () => {
200
- const entry = held.result;
201
- if (entry === null) {
202
- database.deleteObjectStore(from.name);
203
- return;
204
- }
205
- const record = entry.value;
206
- const transfer = transfers.get(record.locator);
207
- if (transfer !== undefined)
208
- to.put({ ...record, transfer });
209
- entry.continue();
210
- };
211
- }
212
- };
211
+ await completed(transaction);
212
+ return owned;
213
+ }
214
+ finally {
215
+ authored.close();
216
+ }
213
217
  }
214
- export async function openRuntimeStore() {
218
+ export async function removeRuntimeStore(holder) {
219
+ await removeDatabase(DATABASE);
220
+ if (holder !== undefined && (await authoredBy(holder)))
221
+ return true;
222
+ await removeDatabase(AUTHORED);
223
+ return false;
224
+ }
225
+ function openReplica() {
215
226
  const opening = indexedDB.open(DATABASE, STORE_SCHEMA);
216
- opening.onupgradeneeded = (event) => {
227
+ opening.onupgradeneeded = () => {
217
228
  const database = opening.result;
218
- if (event.oldVersion === PATH_KEYED_SCHEMA && opening.transaction !== null) {
219
- keyByTransfer(database, opening.transaction);
220
- return;
221
- }
222
229
  for (const name of [...database.objectStoreNames])
223
230
  database.deleteObjectStore(name);
224
231
  database.createObjectStore(ROOMS, { keyPath: 'locator' });
225
232
  database.createObjectStore(DOCUMENTS, { keyPath: ['locator', 'transfer', 'path'] });
226
- database.createObjectStore(BINARY_TARGETS, { keyPath: ['locator', 'transfer', 'path'] });
233
+ database.createObjectStore(BINARY_FILES, { keyPath: ['locator', 'transfer', 'path'] });
227
234
  database.createObjectStore(TRANSFERS, { keyPath: 'locator' });
228
- database.createObjectStore(ATTACHMENTS, { keyPath: ['locator', 'reference'] });
229
- database.createObjectStore(PENDING_CHANGES, { keyPath: ['locator', 'id'] });
230
235
  database.createObjectStore(DECLARATIONS);
231
- database.createObjectStore(ROOM_DRAFTS, { keyPath: ['locator', 'path'] });
232
236
  database.createObjectStore(PRESENTATION, { keyPath: 'app' });
233
237
  database.createObjectStore(CONVERSATIONS, { keyPath: 'conversation' });
234
238
  const messages = database.createObjectStore(MESSAGES, {
235
239
  keyPath: ['conversation', 'identity'],
236
240
  });
237
241
  messages.createIndex('conversation', 'conversation');
238
- database.createObjectStore(CHAT_DRAFTS, { keyPath: 'conversation' });
239
242
  };
240
- const database = await settled(opening);
243
+ return settled(opening);
244
+ }
245
+ function openAuthored() {
246
+ const opening = indexedDB.open(AUTHORED, AUTHORED_SCHEMA);
247
+ opening.onupgradeneeded = () => {
248
+ const database = opening.result;
249
+ for (const [name, parameters] of AUTHORED_STORES) {
250
+ if (!database.objectStoreNames.contains(name))
251
+ database.createObjectStore(name, parameters);
252
+ }
253
+ };
254
+ return settled(opening);
255
+ }
256
+ export async function openRuntimeStore() {
257
+ const authored = await openAuthored();
258
+ const database = await openReplica().catch((error) => {
259
+ authored.close();
260
+ throw error;
261
+ });
241
262
  return {
242
263
  async all() {
243
- const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_TARGETS, ATTACHMENTS], 'readonly');
244
- const [rooms, attachments] = await Promise.all([
245
- settled(transaction.objectStore(ROOMS).getAll()),
246
- settled(transaction.objectStore(ATTACHMENTS).getAll()),
247
- ]);
264
+ const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES], 'readonly');
265
+ const rooms = await settled(transaction.objectStore(ROOMS).getAll());
248
266
  const records = [];
249
- for (const { order, ...room } of rooms) {
250
- const layer = await readLayer(transaction, room.locator, room.transfer);
251
- records.push({
252
- ...room,
253
- ...layer,
254
- attachments: attachments.flatMap(({ locator, ...attachment }) => locator === room.locator ? [attachment] : []),
255
- });
267
+ for (const room of rooms) {
268
+ records.push({ ...room, ...(await readLayer(transaction, room.locator, room.transfer)) });
256
269
  }
257
270
  return records;
258
271
  },
259
- async write({ next, previous, stored, queue, previousQueue, saved, roomDrafts, consumedRoomDrafts, }) {
260
- const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_TARGETS, ATTACHMENTS, TRANSFERS, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
261
- transaction.objectStore(ROOMS).put(roomRecord(next, queue));
262
- const moved = previous?.transfer !== next.transfer;
263
- if (moved && previous !== null) {
264
- const range = underTransfer(previous.locator, previous.transfer);
265
- transaction.objectStore(DOCUMENTS).delete(range);
266
- transaction.objectStore(BINARY_TARGETS).delete(range);
267
- }
268
- if (moved)
269
- transaction.objectStore(TRANSFERS).delete(next.locator);
270
- writeLayer(transaction, next.locator, next.transfer, next, moved ? (stored ?? null) : previous);
271
- const attachments = transaction.objectStore(ATTACHMENTS);
272
- const held = new Map((previous?.attachments ?? []).map((attachment) => [attachment.reference, attachment]));
273
- const declared = new Set(next.attachments.map((attachment) => attachment.reference));
274
- for (const reference of held.keys()) {
275
- if (!declared.has(reference))
276
- attachments.delete([next.locator, reference]);
277
- }
278
- for (const attachment of next.attachments) {
279
- if (held.get(attachment.reference) === attachment)
280
- continue;
281
- attachments.put({ ...attachment, locator: next.locator });
282
- }
283
- if (previousQueue !== undefined) {
284
- const pending = transaction.objectStore(PENDING_CHANGES);
285
- const before = new Set(previousQueue.map((batch) => batch.id));
272
+ async keepAuthored({ locator, queue, saved, roomDrafts, consumedRoomDrafts }) {
273
+ const transaction = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
274
+ const order = transaction.objectStore(QUEUES);
275
+ const pending = transaction.objectStore(PENDING_CHANGES);
276
+ const held = order.get(locator);
277
+ held.onsuccess = () => {
278
+ const before = new Set(held.result?.order ?? []);
286
279
  const after = new Set(queue.map((batch) => batch.id));
280
+ if (queue.length === 0)
281
+ order.delete(locator);
282
+ else
283
+ order.put({ locator, order: [...after] });
287
284
  for (const id of before) {
288
285
  if (!after.has(id))
289
- pending.delete([next.locator, id]);
286
+ pending.delete([locator, id]);
290
287
  }
291
288
  for (const batch of queue) {
292
289
  if (!before.has(batch.id)) {
293
290
  pending.put({
294
- locator: next.locator,
291
+ locator,
295
292
  id: batch.id,
296
293
  batch,
297
- drafts: saved ?? [],
294
+ drafts: saved?.get(batch.id) ?? [],
298
295
  submission: { state: 'waiting' },
299
296
  lost: false,
300
297
  });
301
298
  }
302
299
  }
303
- }
300
+ };
304
301
  const draftStore = transaction.objectStore(ROOM_DRAFTS);
305
302
  for (const path of consumedRoomDrafts ?? [])
306
- draftStore.delete([next.locator, path]);
303
+ draftStore.delete([locator, path]);
307
304
  for (const record of roomDrafts ?? [])
308
305
  draftStore.put(record);
309
306
  await completed(transaction);
310
307
  },
308
+ async write({ next, previous, stored }) {
309
+ if (next === previous)
310
+ return;
311
+ const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
312
+ transaction.objectStore(ROOMS).put(roomRecord(next));
313
+ const moved = previous?.transfer !== next.transfer;
314
+ if (moved && previous !== null) {
315
+ const range = underTransfer(previous.locator, previous.transfer);
316
+ transaction.objectStore(DOCUMENTS).delete(range);
317
+ transaction.objectStore(BINARY_FILES).delete(range);
318
+ }
319
+ if (moved)
320
+ transaction.objectStore(TRANSFERS).delete(next.locator);
321
+ writeLayer(transaction, next.locator, next.transfer, next, moved ? (stored ?? null) : previous);
322
+ await completed(transaction);
323
+ },
311
324
  async revokeModels(records) {
312
325
  const transaction = database.transaction(ROOMS, 'readwrite');
313
326
  const rooms = transaction.objectStore(ROOMS);
314
327
  const revoked = { status: 'unavailable', reason: 'revoked' };
315
- for (const { record, queue } of records) {
316
- rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }, queue));
328
+ for (const record of records) {
329
+ rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }));
317
330
  }
318
331
  await completed(transaction);
319
332
  },
@@ -347,34 +360,34 @@ export async function openRuntimeStore() {
347
360
  await completed(transaction);
348
361
  },
349
362
  async queues() {
350
- const transaction = database.transaction([ROOMS, PENDING_CHANGES], 'readonly');
351
- const [rooms, pending] = await Promise.all([
352
- settled(transaction.objectStore(ROOMS).getAll()),
363
+ const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readonly');
364
+ const [queues, pending] = await Promise.all([
365
+ settled(transaction.objectStore(QUEUES).getAll()),
353
366
  settled(transaction.objectStore(PENDING_CHANGES).getAll()),
354
367
  ]);
355
368
  const byId = new Map(pending.map((record) => [`${record.locator}\0${record.id}`, record]));
356
- return rooms.map((room) => ({
357
- locator: room.locator,
358
- pending: room.order.map((id) => {
359
- const record = byId.get(`${room.locator}\0${id}`);
369
+ return queues.map((queue) => ({
370
+ locator: queue.locator,
371
+ pending: queue.order.map((id) => {
372
+ const record = byId.get(`${queue.locator}\0${id}`);
360
373
  if (record === undefined)
361
- throw new Error(`Missing Pending Change ${room.locator}/${id}`);
374
+ throw new Error(`Missing Pending Change ${queue.locator}/${id}`);
362
375
  const { batch, drafts, submission, lost, upload, accepted } = record;
363
376
  return { batch, state: { drafts, submission, lost, upload, accepted } };
364
377
  }),
365
378
  }));
366
379
  },
367
380
  submit(locator, id, submission, lost) {
368
- return amendPending(database, locator, id, { submission, lost });
381
+ return amendPending(authored, locator, id, { submission, lost });
369
382
  },
370
383
  accept(locator, id, roomVersion) {
371
- return amendPending(database, locator, id, { accepted: roomVersion });
384
+ return amendPending(authored, locator, id, { accepted: roomVersion });
372
385
  },
373
386
  keepUpload(locator, id, upload) {
374
- return amendPending(database, locator, id, { upload });
387
+ return amendPending(authored, locator, id, { upload });
375
388
  },
376
389
  async roomDrafts() {
377
- const transaction = database.transaction(ROOM_DRAFTS, 'readonly');
390
+ const transaction = authored.transaction(ROOM_DRAFTS, 'readonly');
378
391
  return settled(transaction.objectStore(ROOM_DRAFTS).getAll());
379
392
  },
380
393
  async presentation() {
@@ -404,7 +417,12 @@ export async function openRuntimeStore() {
404
417
  return [...held.values()];
405
418
  },
406
419
  async keepMessages({ conversation, messages, read, sealed }) {
407
- const transaction = database.transaction([CONVERSATIONS, MESSAGES, CHAT_DRAFTS], 'readwrite');
420
+ if (sealed === true) {
421
+ const sealing = authored.transaction(CHAT_DRAFTS, 'readwrite');
422
+ sealing.objectStore(CHAT_DRAFTS).delete(conversation);
423
+ await completed(sealing);
424
+ }
425
+ const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
408
426
  const stored = transaction.objectStore(MESSAGES);
409
427
  for (const message of messages) {
410
428
  stored.put({ ...message, conversation });
@@ -414,16 +432,17 @@ export async function openRuntimeStore() {
414
432
  .objectStore(CONVERSATIONS)
415
433
  .put({ conversation, read });
416
434
  }
417
- if (sealed === true)
418
- transaction.objectStore(CHAT_DRAFTS).delete(conversation);
419
435
  await completed(transaction);
420
436
  },
421
437
  async dropConversations(conversations) {
422
- const transaction = database.transaction([CONVERSATIONS, MESSAGES, CHAT_DRAFTS], 'readwrite');
438
+ const drafts = authored.transaction(CHAT_DRAFTS, 'readwrite');
439
+ for (const conversation of conversations)
440
+ drafts.objectStore(CHAT_DRAFTS).delete(conversation);
441
+ await completed(drafts);
442
+ const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
423
443
  const messages = transaction.objectStore(MESSAGES);
424
444
  for (const conversation of conversations) {
425
445
  transaction.objectStore(CONVERSATIONS).delete(conversation);
426
- transaction.objectStore(CHAT_DRAFTS).delete(conversation);
427
446
  const keys = messages.index('conversation').getAllKeys(conversation);
428
447
  keys.onsuccess = () => {
429
448
  for (const key of keys.result)
@@ -433,39 +452,45 @@ export async function openRuntimeStore() {
433
452
  await completed(transaction);
434
453
  },
435
454
  async chatDrafts() {
436
- const transaction = database.transaction(CHAT_DRAFTS, 'readonly');
437
- return settled(transaction.objectStore(CHAT_DRAFTS).getAll());
455
+ const transaction = authored.transaction(CHAT_DRAFTS, 'readonly');
456
+ const held = await settled(transaction.objectStore(CHAT_DRAFTS).getAll());
457
+ return held.map(chatDraftRecord);
438
458
  },
439
459
  async keepChatDraft(record) {
440
- const transaction = database.transaction(CHAT_DRAFTS, 'readwrite');
460
+ const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
441
461
  transaction.objectStore(CHAT_DRAFTS).put(record);
442
462
  await completed(transaction);
443
463
  },
444
464
  async dropChatDraft(conversation) {
445
- const transaction = database.transaction(CHAT_DRAFTS, 'readwrite');
465
+ const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
446
466
  transaction.objectStore(CHAT_DRAFTS).delete(conversation);
447
467
  await completed(transaction);
448
468
  },
449
469
  async keepRoomDraft(record) {
450
- const transaction = database.transaction(ROOM_DRAFTS, 'readwrite');
470
+ const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
451
471
  transaction.objectStore(ROOM_DRAFTS).put(record);
452
472
  await completed(transaction);
453
473
  },
454
474
  async discardRoomDraft(locator, path) {
455
- const transaction = database.transaction(ROOM_DRAFTS, 'readwrite');
475
+ const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
456
476
  transaction.objectStore(ROOM_DRAFTS).delete([locator, path]);
457
477
  await completed(transaction);
458
478
  },
459
479
  async dropRooms(locators) {
460
- const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_TARGETS, ATTACHMENTS, TRANSFERS, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
480
+ const work = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
481
+ for (const locator of locators) {
482
+ work.objectStore(QUEUES).delete(locator);
483
+ for (const name of [PENDING_CHANGES, ROOM_DRAFTS]) {
484
+ removeRoomEntries(work.objectStore(name), locator);
485
+ }
486
+ }
487
+ await completed(work);
488
+ const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
461
489
  for (const locator of locators) {
462
490
  transaction.objectStore(ROOMS).delete(locator);
463
491
  transaction.objectStore(TRANSFERS).delete(locator);
464
492
  transaction.objectStore(DOCUMENTS).delete(underRoom(locator));
465
- transaction.objectStore(BINARY_TARGETS).delete(underRoom(locator));
466
- for (const name of [ATTACHMENTS, PENDING_CHANGES, ROOM_DRAFTS]) {
467
- removeRoomEntries(transaction.objectStore(name), locator);
468
- }
493
+ transaction.objectStore(BINARY_FILES).delete(underRoom(locator));
469
494
  }
470
495
  await completed(transaction);
471
496
  },
@@ -474,17 +499,17 @@ export async function openRuntimeStore() {
474
499
  return settled(transaction.objectStore(TRANSFERS).getAll());
475
500
  },
476
501
  staged(record) {
477
- const transaction = database.transaction([DOCUMENTS, BINARY_TARGETS], 'readonly');
502
+ const transaction = database.transaction([DOCUMENTS, BINARY_FILES], 'readonly');
478
503
  return readLayer(transaction, record.locator, record.transfer);
479
504
  },
480
505
  async stage(record, page) {
481
- const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_TARGETS], 'readwrite');
506
+ const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
482
507
  writeLayer(transaction, record.locator, record.transfer, page, null);
483
508
  transaction.objectStore(TRANSFERS).put(record);
484
509
  await completed(transaction);
485
510
  },
486
511
  async abandon(locator) {
487
- const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_TARGETS], 'readwrite');
512
+ const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
488
513
  const transfers = transaction.objectStore(TRANSFERS);
489
514
  const held = transfers.get(locator);
490
515
  held.onsuccess = () => {
@@ -494,17 +519,22 @@ export async function openRuntimeStore() {
494
519
  transfers.delete(locator);
495
520
  const range = underTransfer(locator, record.transfer);
496
521
  transaction.objectStore(DOCUMENTS).delete(range);
497
- transaction.objectStore(BINARY_TARGETS).delete(range);
522
+ transaction.objectStore(BINARY_FILES).delete(range);
498
523
  };
499
524
  await completed(transaction);
500
525
  },
501
526
  async generation() {
502
- return (await declaration(database)).generation;
527
+ const transaction = authored.transaction(FACTS, 'readonly');
528
+ const held = await settled(transaction.objectStore(FACTS).get(GENERATION));
529
+ return held ?? null;
503
530
  },
504
- rememberGeneration(value) {
505
- return updateDeclaration(database, (record) => ({ ...record, generation: value }));
531
+ async rememberGeneration(value) {
532
+ const transaction = authored.transaction(FACTS, 'readwrite');
533
+ transaction.objectStore(FACTS).put(value, GENERATION);
534
+ await completed(transaction);
506
535
  },
507
536
  close() {
537
+ authored.close();
508
538
  database.close();
509
539
  },
510
540
  };
package/dist/wire.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { ConnectionRefusal } from './connection.js';
2
+ import type { Described } from './failure.js';
2
3
  export type RuntimePort = {
3
4
  postMessage(message: unknown): void;
4
5
  addEventListener(type: 'message' | 'close', listener: (event: {
@@ -14,6 +15,8 @@ declare const MEMBERS: {
14
15
  readonly types: 'within';
15
16
  readonly save: 'within';
16
17
  readonly history: 'within';
18
+ readonly 'binaryFile.read': 'within';
19
+ readonly 'binaryFile.readReference': 'within';
17
20
  readonly call: 'actions';
18
21
  readonly reached: 'within';
19
22
  readonly log: 'whole';
@@ -51,6 +54,7 @@ declare const TOPICS: {
51
54
  readonly presentation: 'app';
52
55
  readonly conversation: 'within';
53
56
  readonly conversations: 'within';
57
+ readonly agents: 'within';
54
58
  };
55
59
  export declare const WIRE_REACH: {
56
60
  readonly members: Readonly<Record<string, WireReach>>;
@@ -78,11 +82,10 @@ export type WireAnswer = {
78
82
  kind: 'result';
79
83
  id: number;
80
84
  value: unknown;
81
- } | {
85
+ } | ({
82
86
  kind: 'failure';
83
87
  id: number;
84
- message: string;
85
- } | {
88
+ } & Described) | {
86
89
  kind: 'event';
87
90
  id: number;
88
91
  value: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../src/wire.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,MAAM,MAAM,WAAW,GAAG;IACxB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACpC,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,GAAG,IAAI,CAAC;IACjG,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE3E,QAAA,MAAM,OAAO;oBACJ,QAAQ;oBACR,QAAQ;qBACP,QAAQ;oBACT,QAAQ;mBACT,QAAQ;sBACL,QAAQ;mBACX,SAAS;sBACN,QAAQ;kBACZ,OAAO;0BACC,SAAS;0BACT,SAAS;+BACJ,QAAQ;+BACR,QAAQ;gCACP,QAAQ;kCACN,QAAQ;kCACR,KAAK;mCACJ,KAAK;kCACN,QAAQ;kCACR,QAAQ;oCACN,QAAQ;kCACV,QAAQ;oCACN,QAAQ;uCACL,QAAQ;kCACb,QAAQ;oCACN,QAAQ;oCACR,QAAQ;gCACZ,QAAQ;kCACN,QAAQ;CACyB,CAAC;AAEzD,QAAA,MAAM,MAAM;oBACH,QAAQ;mCACO,SAAS;6BACf,SAAS;iCACL,SAAS;4BACd,QAAQ;6BACP,SAAS;qBACjB,SAAS;oBACV,QAAQ;oBACR,QAAQ;4BACA,QAAQ;2BACT,KAAK;2BACL,QAAQ;4BACP,QAAQ;CAC+B,CAAC;AAEzD,eAAO,MAAM,UAAU,EAAE;IACvB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACf,CAAC;AAEzC,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAC;AAC9C,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,MAAM,CAAC;AAE5C,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,GAC5E;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEtB,eAAO,MAAM,mBAAmB,iCAAiC,CAAC;AAElE,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAQ7C,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,WAAW,GAAG,IAAI,CAiC5D;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAe1D"}
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../src/wire.ts"],"names":[],"mappings":"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"}
package/dist/wire.js CHANGED
@@ -5,6 +5,8 @@ const MEMBERS = {
5
5
  types: 'within',
6
6
  save: 'within',
7
7
  history: 'within',
8
+ 'binaryFile.read': 'within',
9
+ 'binaryFile.readReference': 'within',
8
10
  call: 'actions',
9
11
  reached: 'within',
10
12
  log: 'whole',
@@ -42,6 +44,7 @@ const TOPICS = {
42
44
  presentation: 'app',
43
45
  conversation: 'within',
44
46
  conversations: 'within',
47
+ agents: 'within',
45
48
  };
46
49
  export const WIRE_REACH = { members: MEMBERS, topics: TOPICS };
47
50
  export const AUTHORIZATION_ENDED = 'the host authorization ended';
@@ -103,8 +106,17 @@ export function answer(message) {
103
106
  return { kind: 'result', id: shape.id, value: record.value };
104
107
  if (shape.kind === 'event')
105
108
  return { kind: 'event', id: shape.id, value: record.value };
106
- if (shape.kind === 'failure' && typeof record.message === 'string') {
107
- return { kind: 'failure', id: shape.id, message: record.message };
109
+ if (shape.kind === 'failure' &&
110
+ typeof record.message === 'string' &&
111
+ typeof record.code === 'string' &&
112
+ typeof record.retryable === 'boolean') {
113
+ return {
114
+ kind: 'failure',
115
+ id: shape.id,
116
+ message: record.message,
117
+ code: record.code,
118
+ retryable: record.retryable,
119
+ };
108
120
  }
109
121
  return null;
110
122
  }