@agentshouse/mdruntime 0.1.0-cebcd51f70ed1 → 0.1.0-cede5a74284be

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 (166) hide show
  1. package/AGENTS.md +109 -35
  2. package/README.md +13 -3
  3. package/dist/adapter.d.ts +47 -14
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attached-model.d.ts.map +1 -1
  6. package/dist/attached-model.js +15 -2
  7. package/dist/attempt.d.ts +16 -0
  8. package/dist/attempt.d.ts.map +1 -0
  9. package/dist/attempt.js +57 -0
  10. package/dist/binary.d.ts +23 -0
  11. package/dist/binary.d.ts.map +1 -0
  12. package/dist/binary.js +8 -0
  13. package/dist/bootstrap.d.ts +17 -5
  14. package/dist/bootstrap.d.ts.map +1 -1
  15. package/dist/bootstrap.js +88 -38
  16. package/dist/change-set.d.ts.map +1 -1
  17. package/dist/change-set.js +19 -12
  18. package/dist/change.d.ts +15 -0
  19. package/dist/change.d.ts.map +1 -1
  20. package/dist/change.js +26 -1
  21. package/dist/chat/acts.d.ts +34 -0
  22. package/dist/chat/acts.d.ts.map +1 -0
  23. package/dist/chat/acts.js +36 -0
  24. package/dist/chat/context.d.ts +3 -0
  25. package/dist/chat/context.d.ts.map +1 -0
  26. package/dist/chat/context.js +10 -0
  27. package/dist/chat/input.d.ts +9 -0
  28. package/dist/chat/input.d.ts.map +1 -0
  29. package/dist/chat/input.js +99 -0
  30. package/dist/chat/kit.d.ts +60 -0
  31. package/dist/chat/kit.d.ts.map +1 -0
  32. package/dist/chat/kit.js +123 -0
  33. package/dist/chat/lasting.d.ts +6 -0
  34. package/dist/chat/lasting.d.ts.map +1 -0
  35. package/dist/chat/lasting.js +19 -0
  36. package/dist/chat/list.d.ts +20 -0
  37. package/dist/chat/list.d.ts.map +1 -0
  38. package/dist/chat/list.js +59 -0
  39. package/dist/chat/markdown.d.ts +19 -0
  40. package/dist/chat/markdown.d.ts.map +1 -0
  41. package/dist/chat/markdown.js +187 -0
  42. package/dist/chat/message.d.ts +6 -0
  43. package/dist/chat/message.d.ts.map +1 -0
  44. package/dist/chat/message.js +192 -0
  45. package/dist/chat/messages.d.ts +21 -0
  46. package/dist/chat/messages.d.ts.map +1 -0
  47. package/dist/chat/messages.js +151 -0
  48. package/dist/chat/name.d.ts +6 -0
  49. package/dist/chat/name.d.ts.map +1 -0
  50. package/dist/chat/name.js +37 -0
  51. package/dist/chat/opened.d.ts +11 -0
  52. package/dist/chat/opened.d.ts.map +1 -0
  53. package/dist/chat/opened.js +17 -0
  54. package/dist/chat/overlay.d.ts +31 -0
  55. package/dist/chat/overlay.d.ts.map +1 -0
  56. package/dist/chat/overlay.js +97 -0
  57. package/dist/chat/parts.d.ts +57 -0
  58. package/dist/chat/parts.d.ts.map +1 -0
  59. package/dist/chat/parts.js +119 -0
  60. package/dist/chat/process.d.ts +20 -0
  61. package/dist/chat/process.d.ts.map +1 -0
  62. package/dist/chat/process.js +32 -0
  63. package/dist/chat/provider.d.ts +63 -0
  64. package/dist/chat/provider.d.ts.map +1 -0
  65. package/dist/chat/provider.js +645 -0
  66. package/dist/chat/question.d.ts +9 -0
  67. package/dist/chat/question.d.ts.map +1 -0
  68. package/dist/chat/question.js +80 -0
  69. package/dist/chat/questions.d.ts +31 -0
  70. package/dist/chat/questions.d.ts.map +1 -0
  71. package/dist/chat/questions.js +111 -0
  72. package/dist/chat/read.d.ts +5 -0
  73. package/dist/chat/read.d.ts.map +1 -0
  74. package/dist/chat/read.js +13 -0
  75. package/dist/chat/ready.d.ts +33 -0
  76. package/dist/chat/ready.d.ts.map +1 -0
  77. package/dist/chat/ready.js +91 -0
  78. package/dist/chat/style.d.ts +4 -0
  79. package/dist/chat/style.d.ts.map +1 -0
  80. package/dist/chat/style.js +302 -0
  81. package/dist/chat.d.ts +14 -0
  82. package/dist/chat.d.ts.map +1 -0
  83. package/dist/chat.js +8 -0
  84. package/dist/client.d.ts +14 -5
  85. package/dist/client.d.ts.map +1 -1
  86. package/dist/client.js +65 -15
  87. package/dist/collection.d.ts +6 -11
  88. package/dist/collection.d.ts.map +1 -1
  89. package/dist/collection.js +56 -19
  90. package/dist/connection.d.ts +21 -9
  91. package/dist/connection.d.ts.map +1 -1
  92. package/dist/connection.js +470 -142
  93. package/dist/conversation.d.ts +11 -3
  94. package/dist/conversation.d.ts.map +1 -1
  95. package/dist/conversation.js +47 -7
  96. package/dist/expectation.d.ts +21 -0
  97. package/dist/expectation.d.ts.map +1 -0
  98. package/dist/expectation.js +70 -0
  99. package/dist/failure.d.ts +13 -0
  100. package/dist/failure.d.ts.map +1 -0
  101. package/dist/failure.js +19 -0
  102. package/dist/host.d.ts +1 -0
  103. package/dist/host.d.ts.map +1 -1
  104. package/dist/host.js +9 -8
  105. package/dist/identity.d.ts +3 -0
  106. package/dist/identity.d.ts.map +1 -1
  107. package/dist/identity.js +13 -1
  108. package/dist/index.d.ts +9 -4
  109. package/dist/index.d.ts.map +1 -1
  110. package/dist/index.js +3 -0
  111. package/dist/memory.d.ts +4 -3
  112. package/dist/memory.d.ts.map +1 -1
  113. package/dist/memory.js +60 -20
  114. package/dist/model.d.ts +10 -2
  115. package/dist/model.d.ts.map +1 -1
  116. package/dist/model.js +2 -0
  117. package/dist/open.d.ts +2 -0
  118. package/dist/open.d.ts.map +1 -0
  119. package/dist/open.js +1 -0
  120. package/dist/outcome.d.ts +28 -3
  121. package/dist/outcome.d.ts.map +1 -1
  122. package/dist/outcome.js +41 -1
  123. package/dist/overlay.d.ts +14 -3
  124. package/dist/overlay.d.ts.map +1 -1
  125. package/dist/overlay.js +75 -37
  126. package/dist/query.d.ts +4 -0
  127. package/dist/query.d.ts.map +1 -1
  128. package/dist/query.js +5 -31
  129. package/dist/reach.d.ts +2 -0
  130. package/dist/reach.d.ts.map +1 -1
  131. package/dist/reach.js +43 -19
  132. package/dist/react.d.ts +25 -16
  133. package/dist/react.d.ts.map +1 -1
  134. package/dist/react.js +8 -6
  135. package/dist/read-side.d.ts.map +1 -1
  136. package/dist/read-side.js +9 -2
  137. package/dist/refresh.d.ts +10 -0
  138. package/dist/refresh.d.ts.map +1 -1
  139. package/dist/refresh.js +42 -38
  140. package/dist/replica.d.ts +8 -5
  141. package/dist/replica.d.ts.map +1 -1
  142. package/dist/replica.js +76 -56
  143. package/dist/room-draft.d.ts +26 -9
  144. package/dist/room-draft.d.ts.map +1 -1
  145. package/dist/room-draft.js +132 -23
  146. package/dist/rows.d.ts +5 -1
  147. package/dist/rows.d.ts.map +1 -1
  148. package/dist/rows.js +10 -2
  149. package/dist/save.d.ts +27 -1
  150. package/dist/save.d.ts.map +1 -1
  151. package/dist/save.js +340 -33
  152. package/dist/search.d.ts +3 -2
  153. package/dist/search.d.ts.map +1 -1
  154. package/dist/status.d.ts +2 -2
  155. package/dist/status.d.ts.map +1 -1
  156. package/dist/status.js +0 -8
  157. package/dist/store.d.ts +33 -9
  158. package/dist/store.d.ts.map +1 -1
  159. package/dist/store.js +273 -164
  160. package/dist/wire.d.ts +7 -3
  161. package/dist/wire.d.ts.map +1 -1
  162. package/dist/wire.js +15 -2
  163. package/package.json +22 -14
  164. package/dist/attachment.d.ts +0 -3
  165. package/dist/attachment.d.ts.map +0 -1
  166. package/dist/attachment.js +0 -8
package/dist/store.js CHANGED
@@ -1,9 +1,10 @@
1
- import { sameChange } from './overlay.js';
1
+ import { sameBinary, sameChange } from './overlay.js';
2
2
  const DATABASE = 'mdruntime';
3
+ const AUTHORED = 'mdruntime-authored';
3
4
  const ROOMS = 'rooms';
4
5
  const DOCUMENTS = 'documents';
5
- const BINARY_TARGETS = 'binaryTargets';
6
- const ATTACHMENTS = 'attachments';
6
+ const BINARY_FILES = 'binaryFiles';
7
+ const TRANSFERS = 'transfers';
7
8
  const PENDING_CHANGES = 'pendingChanges';
8
9
  const DECLARATIONS = 'declarations';
9
10
  const ROOM_DRAFTS = 'roomDrafts';
@@ -11,8 +12,21 @@ const PRESENTATION = 'presentation';
11
12
  const CONVERSATIONS = 'conversations';
12
13
  const MESSAGES = 'messages';
13
14
  const CHAT_DRAFTS = 'chatDrafts';
15
+ const QUEUES = 'queues';
16
+ const FACTS = 'facts';
14
17
  const CURRENT = 'current';
15
- const SCHEMA = 20;
18
+ const MEMBER = 'member';
19
+ const GENERATION = 'generation';
20
+ export const STORE_SCHEMA = 23;
21
+ export const AUTHORED_SCHEMA = 1;
22
+ const AUTHORED_STORES = [
23
+ [QUEUES, { keyPath: 'locator' }],
24
+ [PENDING_CHANGES, { keyPath: ['locator', 'id'] }],
25
+ [ROOM_DRAFTS, { keyPath: ['locator', 'path'] }],
26
+ [CHAT_DRAFTS, { keyPath: 'conversation' }],
27
+ [FACTS, undefined],
28
+ ];
29
+ const READ_BATCH = 256;
16
30
  function settled(request) {
17
31
  return new Promise((resolve, reject) => {
18
32
  request.onsuccess = () => resolve(request.result);
@@ -28,7 +42,6 @@ function completed(transaction) {
28
42
  }
29
43
  const EMPTY_DECLARATIONS = {
30
44
  lastCompleted: null,
31
- generation: null,
32
45
  providerLimits: [],
33
46
  capabilities: [],
34
47
  };
@@ -56,9 +69,102 @@ function amendPending(database, locator, id, amendment) {
56
69
  };
57
70
  return completed(transaction);
58
71
  }
59
- function roomRecord(record, queue) {
60
- const { documents, binaryTargets, revisions, changes, written, attachments, ...room } = record;
61
- return { ...room, order: queue.map((batch) => batch.id) };
72
+ function roomRecord(record) {
73
+ const { documents, binaries, revisions, changes, written, ...room } = record;
74
+ return room;
75
+ }
76
+ function chatDraftRecord(record) {
77
+ return { ...record, revision: record.revision ?? '' };
78
+ }
79
+ function underTransfer(locator, transfer, after) {
80
+ return after === undefined
81
+ ? IDBKeyRange.bound([locator, transfer], [locator, transfer, []])
82
+ : IDBKeyRange.bound([locator, transfer, after], [locator, transfer, []], true);
83
+ }
84
+ function underRoom(locator) {
85
+ return IDBKeyRange.bound([locator], [locator, []]);
86
+ }
87
+ async function readTransfer(store, locator, transfer, receive) {
88
+ let range = underTransfer(locator, transfer);
89
+ for (;;) {
90
+ const batch = await settled(store.getAll(range, READ_BATCH));
91
+ for (const record of batch)
92
+ receive(record);
93
+ if (batch.length < READ_BATCH)
94
+ return;
95
+ range = underTransfer(locator, transfer, batch[batch.length - 1].path);
96
+ }
97
+ }
98
+ function emptyLayer() {
99
+ return { documents: {}, binaries: {}, revisions: {}, changes: {}, written: {} };
100
+ }
101
+ async function readLayer(transaction, locator, transfer) {
102
+ const layer = emptyLayer();
103
+ const head = (held) => {
104
+ if (held.revision !== null)
105
+ layer.revisions[held.path] = held.revision;
106
+ if (held.change !== null)
107
+ layer.changes[held.path] = held.change;
108
+ };
109
+ await readTransfer(transaction.objectStore(DOCUMENTS), locator, transfer, (document) => {
110
+ layer.documents[document.path] = document.content;
111
+ if (document.written !== null)
112
+ layer.written[document.path] = document.written;
113
+ head(document);
114
+ });
115
+ await readTransfer(transaction.objectStore(BINARY_FILES), locator, transfer, (file) => {
116
+ layer.binaries[file.path] = file.binary;
117
+ head(file);
118
+ });
119
+ return layer;
120
+ }
121
+ function documentRecord(locator, transfer, layer, path) {
122
+ return {
123
+ locator,
124
+ transfer,
125
+ path,
126
+ content: layer.documents[path],
127
+ revision: layer.revisions[path] ?? null,
128
+ change: layer.changes[path] ?? null,
129
+ written: layer.written[path] ?? null,
130
+ };
131
+ }
132
+ function binaryFileRecord(locator, transfer, layer, path) {
133
+ return {
134
+ locator,
135
+ transfer,
136
+ path,
137
+ revision: layer.revisions[path] ?? null,
138
+ change: layer.changes[path] ?? null,
139
+ binary: layer.binaries[path],
140
+ };
141
+ }
142
+ function writeLayer(transaction, locator, transfer, next, base) {
143
+ 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
+ const files = transaction.objectStore(BINARY_FILES);
157
+ for (const path of Object.keys(base?.binaries ?? {})) {
158
+ if (next.binaries[path] === undefined)
159
+ files.delete([locator, transfer, path]);
160
+ }
161
+ for (const path of Object.keys(next.binaries)) {
162
+ if (!sameBinary(base?.binaries[path], next.binaries[path]) ||
163
+ base?.revisions[path] !== next.revisions[path] ||
164
+ !sameChange(base?.changes[path], next.changes[path])) {
165
+ files.put(binaryFileRecord(locator, transfer, next, path));
166
+ }
167
+ }
62
168
  }
63
169
  function removeRoomEntries(store, locator) {
64
170
  const keys = store.getAllKeys();
@@ -69,177 +175,121 @@ function removeRoomEntries(store, locator) {
69
175
  }
70
176
  };
71
177
  }
72
- export function removeRuntimeStore() {
178
+ function removeDatabase(name) {
73
179
  return new Promise((resolve, reject) => {
74
- const removal = indexedDB.deleteDatabase(DATABASE);
180
+ const removal = indexedDB.deleteDatabase(name);
75
181
  removal.onsuccess = () => resolve();
76
182
  removal.onerror = () => reject(removal.error);
77
183
  });
78
184
  }
79
- export async function openRuntimeStore() {
80
- const opening = indexedDB.open(DATABASE, SCHEMA);
185
+ export async function removeRuntimeStore() {
186
+ await Promise.all([removeDatabase(DATABASE), removeDatabase(AUTHORED)]);
187
+ }
188
+ function openReplica() {
189
+ const opening = indexedDB.open(DATABASE, STORE_SCHEMA);
81
190
  opening.onupgradeneeded = () => {
82
191
  const database = opening.result;
83
192
  for (const name of [...database.objectStoreNames])
84
193
  database.deleteObjectStore(name);
85
194
  database.createObjectStore(ROOMS, { keyPath: 'locator' });
86
- database.createObjectStore(DOCUMENTS, { keyPath: ['locator', 'path'] });
87
- database.createObjectStore(BINARY_TARGETS, { keyPath: ['locator', 'path'] });
88
- database.createObjectStore(ATTACHMENTS, { keyPath: ['locator', 'reference'] });
89
- database.createObjectStore(PENDING_CHANGES, { keyPath: ['locator', 'id'] });
195
+ database.createObjectStore(DOCUMENTS, { keyPath: ['locator', 'transfer', 'path'] });
196
+ database.createObjectStore(BINARY_FILES, { keyPath: ['locator', 'transfer', 'path'] });
197
+ database.createObjectStore(TRANSFERS, { keyPath: 'locator' });
90
198
  database.createObjectStore(DECLARATIONS);
91
- database.createObjectStore(ROOM_DRAFTS, { keyPath: ['locator', 'path'] });
92
199
  database.createObjectStore(PRESENTATION, { keyPath: 'app' });
93
200
  database.createObjectStore(CONVERSATIONS, { keyPath: 'conversation' });
94
201
  const messages = database.createObjectStore(MESSAGES, {
95
202
  keyPath: ['conversation', 'identity'],
96
203
  });
97
204
  messages.createIndex('conversation', 'conversation');
98
- database.createObjectStore(CHAT_DRAFTS, { keyPath: 'conversation' });
99
205
  };
100
- const database = await settled(opening);
206
+ return settled(opening);
207
+ }
208
+ function openAuthored() {
209
+ const opening = indexedDB.open(AUTHORED, AUTHORED_SCHEMA);
210
+ opening.onupgradeneeded = () => {
211
+ const database = opening.result;
212
+ for (const [name, parameters] of AUTHORED_STORES) {
213
+ if (!database.objectStoreNames.contains(name))
214
+ database.createObjectStore(name, parameters);
215
+ }
216
+ };
217
+ return settled(opening);
218
+ }
219
+ export async function openRuntimeStore() {
220
+ const authored = await openAuthored();
221
+ const database = await openReplica().catch((error) => {
222
+ authored.close();
223
+ throw error;
224
+ });
101
225
  return {
102
226
  async all() {
103
- const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_TARGETS, ATTACHMENTS], 'readonly');
104
- const [rooms, documents, targets, attachments] = await Promise.all([
105
- settled(transaction.objectStore(ROOMS).getAll()),
106
- settled(transaction.objectStore(DOCUMENTS).getAll()),
107
- settled(transaction.objectStore(BINARY_TARGETS).getAll()),
108
- settled(transaction.objectStore(ATTACHMENTS).getAll()),
109
- ]);
110
- const byRoom = new Map();
111
- for (const { order, ...room } of rooms) {
112
- byRoom.set(room.locator, {
113
- ...room,
114
- documents: {},
115
- revisions: {},
116
- changes: {},
117
- written: {},
118
- binaryTargets: [],
119
- attachments: [],
120
- });
121
- }
122
- const head = (room, held) => {
123
- if (held.revision !== null) {
124
- room.revisions[held.path] = held.revision;
125
- }
126
- if (held.change !== null) {
127
- room.changes[held.path] = held.change;
128
- }
129
- };
130
- for (const document of documents) {
131
- const room = byRoom.get(document.locator);
132
- if (room === undefined)
133
- continue;
134
- room.documents[document.path] = document.content;
135
- if (document.written !== null) {
136
- room.written[document.path] = document.written;
137
- }
138
- head(room, document);
139
- }
140
- for (const target of targets) {
141
- const room = byRoom.get(target.locator);
142
- if (room === undefined)
143
- continue;
144
- room.binaryTargets.push(target.path);
145
- head(room, target);
146
- }
147
- for (const { locator, ...attachment } of attachments) {
148
- const room = byRoom.get(locator);
149
- if (room === undefined)
150
- continue;
151
- room.attachments.push(attachment);
152
- }
153
- return [...byRoom.values()];
154
- },
155
- async write({ next, previous, queue, previousQueue, saved, roomDrafts, consumedRoomDrafts }) {
156
- const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_TARGETS, ATTACHMENTS, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
157
- transaction.objectStore(ROOMS).put(roomRecord(next, queue));
158
- const documents = transaction.objectStore(DOCUMENTS);
159
- for (const path of Object.keys(previous?.documents ?? {})) {
160
- if (next.documents[path] === undefined)
161
- documents.delete([next.locator, path]);
162
- }
163
- for (const [path, content] of Object.entries(next.documents)) {
164
- if (previous?.documents[path] === content &&
165
- previous.revisions[path] === next.revisions[path] &&
166
- previous.written[path] === next.written[path] &&
167
- sameChange(previous.changes[path], next.changes[path]))
168
- continue;
169
- documents.put({
170
- locator: next.locator,
171
- path,
172
- content,
173
- revision: next.revisions[path] ?? null,
174
- change: next.changes[path] ?? null,
175
- written: next.written[path] ?? null,
176
- });
177
- }
178
- const targets = transaction.objectStore(BINARY_TARGETS);
179
- const beforeTargets = new Set(previous?.binaryTargets ?? []);
180
- const afterTargets = new Set(next.binaryTargets);
181
- for (const path of beforeTargets) {
182
- if (!afterTargets.has(path))
183
- targets.delete([next.locator, path]);
184
- }
185
- for (const path of afterTargets) {
186
- if (!beforeTargets.has(path) ||
187
- previous?.revisions[path] !== next.revisions[path] ||
188
- !sameChange(previous?.changes[path], next.changes[path])) {
189
- targets.put({
190
- locator: next.locator,
191
- path,
192
- revision: next.revisions[path] ?? null,
193
- change: next.changes[path] ?? null,
194
- });
195
- }
227
+ const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES], 'readonly');
228
+ const rooms = await settled(transaction.objectStore(ROOMS).getAll());
229
+ const records = [];
230
+ for (const room of rooms) {
231
+ records.push({ ...room, ...(await readLayer(transaction, room.locator, room.transfer)) });
196
232
  }
197
- const attachments = transaction.objectStore(ATTACHMENTS);
198
- const held = new Map((previous?.attachments ?? []).map((attachment) => [attachment.reference, attachment]));
199
- const declared = new Set(next.attachments.map((attachment) => attachment.reference));
200
- for (const reference of held.keys()) {
201
- if (!declared.has(reference))
202
- attachments.delete([next.locator, reference]);
203
- }
204
- for (const attachment of next.attachments) {
205
- if (held.get(attachment.reference) === attachment)
206
- continue;
207
- attachments.put({ ...attachment, locator: next.locator });
208
- }
209
- if (previousQueue !== undefined) {
210
- const pending = transaction.objectStore(PENDING_CHANGES);
211
- const before = new Set(previousQueue.map((batch) => batch.id));
233
+ return records;
234
+ },
235
+ async keepAuthored({ locator, queue, saved, roomDrafts, consumedRoomDrafts }) {
236
+ const transaction = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
237
+ const order = transaction.objectStore(QUEUES);
238
+ const pending = transaction.objectStore(PENDING_CHANGES);
239
+ const held = order.get(locator);
240
+ held.onsuccess = () => {
241
+ const before = new Set(held.result?.order ?? []);
212
242
  const after = new Set(queue.map((batch) => batch.id));
243
+ if (queue.length === 0)
244
+ order.delete(locator);
245
+ else
246
+ order.put({ locator, order: [...after] });
213
247
  for (const id of before) {
214
248
  if (!after.has(id))
215
- pending.delete([next.locator, id]);
249
+ pending.delete([locator, id]);
216
250
  }
217
251
  for (const batch of queue) {
218
252
  if (!before.has(batch.id)) {
219
253
  pending.put({
220
- locator: next.locator,
254
+ locator,
221
255
  id: batch.id,
222
256
  batch,
223
- drafts: saved ?? [],
257
+ drafts: saved?.get(batch.id) ?? [],
224
258
  submission: { state: 'waiting' },
225
259
  lost: false,
226
260
  });
227
261
  }
228
262
  }
229
- }
263
+ };
230
264
  const draftStore = transaction.objectStore(ROOM_DRAFTS);
231
265
  for (const path of consumedRoomDrafts ?? [])
232
- draftStore.delete([next.locator, path]);
266
+ draftStore.delete([locator, path]);
233
267
  for (const record of roomDrafts ?? [])
234
268
  draftStore.put(record);
235
269
  await completed(transaction);
236
270
  },
271
+ async write({ next, previous, stored }) {
272
+ if (next === previous)
273
+ return;
274
+ const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
275
+ transaction.objectStore(ROOMS).put(roomRecord(next));
276
+ const moved = previous?.transfer !== next.transfer;
277
+ if (moved && previous !== null) {
278
+ const range = underTransfer(previous.locator, previous.transfer);
279
+ transaction.objectStore(DOCUMENTS).delete(range);
280
+ transaction.objectStore(BINARY_FILES).delete(range);
281
+ }
282
+ if (moved)
283
+ transaction.objectStore(TRANSFERS).delete(next.locator);
284
+ writeLayer(transaction, next.locator, next.transfer, next, moved ? (stored ?? null) : previous);
285
+ await completed(transaction);
286
+ },
237
287
  async revokeModels(records) {
238
288
  const transaction = database.transaction(ROOMS, 'readwrite');
239
289
  const rooms = transaction.objectStore(ROOMS);
240
290
  const revoked = { status: 'unavailable', reason: 'revoked' };
241
- for (const { record, queue } of records) {
242
- rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }, queue));
291
+ for (const record of records) {
292
+ rooms.put(roomRecord({ ...record, model: revoked, selectionModel: revoked }));
243
293
  }
244
294
  await completed(transaction);
245
295
  },
@@ -262,35 +312,45 @@ export async function openRuntimeStore() {
262
312
  capabilities,
263
313
  }));
264
314
  },
315
+ async member() {
316
+ const transaction = database.transaction(DECLARATIONS, 'readonly');
317
+ const held = await settled(transaction.objectStore(DECLARATIONS).get(MEMBER));
318
+ return held ?? null;
319
+ },
320
+ async keepMember(member) {
321
+ const transaction = database.transaction(DECLARATIONS, 'readwrite');
322
+ transaction.objectStore(DECLARATIONS).put(member, MEMBER);
323
+ await completed(transaction);
324
+ },
265
325
  async queues() {
266
- const transaction = database.transaction([ROOMS, PENDING_CHANGES], 'readonly');
267
- const [rooms, pending] = await Promise.all([
268
- settled(transaction.objectStore(ROOMS).getAll()),
326
+ const transaction = authored.transaction([QUEUES, PENDING_CHANGES], 'readonly');
327
+ const [queues, pending] = await Promise.all([
328
+ settled(transaction.objectStore(QUEUES).getAll()),
269
329
  settled(transaction.objectStore(PENDING_CHANGES).getAll()),
270
330
  ]);
271
331
  const byId = new Map(pending.map((record) => [`${record.locator}\0${record.id}`, record]));
272
- return rooms.map((room) => ({
273
- locator: room.locator,
274
- pending: room.order.map((id) => {
275
- const record = byId.get(`${room.locator}\0${id}`);
332
+ return queues.map((queue) => ({
333
+ locator: queue.locator,
334
+ pending: queue.order.map((id) => {
335
+ const record = byId.get(`${queue.locator}\0${id}`);
276
336
  if (record === undefined)
277
- throw new Error(`Missing Pending Change ${room.locator}/${id}`);
337
+ throw new Error(`Missing Pending Change ${queue.locator}/${id}`);
278
338
  const { batch, drafts, submission, lost, upload, accepted } = record;
279
339
  return { batch, state: { drafts, submission, lost, upload, accepted } };
280
340
  }),
281
341
  }));
282
342
  },
283
343
  submit(locator, id, submission, lost) {
284
- return amendPending(database, locator, id, { submission, lost });
344
+ return amendPending(authored, locator, id, { submission, lost });
285
345
  },
286
346
  accept(locator, id, roomVersion) {
287
- return amendPending(database, locator, id, { accepted: roomVersion });
347
+ return amendPending(authored, locator, id, { accepted: roomVersion });
288
348
  },
289
349
  keepUpload(locator, id, upload) {
290
- return amendPending(database, locator, id, { upload });
350
+ return amendPending(authored, locator, id, { upload });
291
351
  },
292
352
  async roomDrafts() {
293
- const transaction = database.transaction(ROOM_DRAFTS, 'readonly');
353
+ const transaction = authored.transaction(ROOM_DRAFTS, 'readonly');
294
354
  return settled(transaction.objectStore(ROOM_DRAFTS).getAll());
295
355
  },
296
356
  async presentation() {
@@ -320,7 +380,12 @@ export async function openRuntimeStore() {
320
380
  return [...held.values()];
321
381
  },
322
382
  async keepMessages({ conversation, messages, read, sealed }) {
323
- const transaction = database.transaction([CONVERSATIONS, MESSAGES, CHAT_DRAFTS], 'readwrite');
383
+ if (sealed === true) {
384
+ const sealing = authored.transaction(CHAT_DRAFTS, 'readwrite');
385
+ sealing.objectStore(CHAT_DRAFTS).delete(conversation);
386
+ await completed(sealing);
387
+ }
388
+ const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
324
389
  const stored = transaction.objectStore(MESSAGES);
325
390
  for (const message of messages) {
326
391
  stored.put({ ...message, conversation });
@@ -330,16 +395,17 @@ export async function openRuntimeStore() {
330
395
  .objectStore(CONVERSATIONS)
331
396
  .put({ conversation, read });
332
397
  }
333
- if (sealed === true)
334
- transaction.objectStore(CHAT_DRAFTS).delete(conversation);
335
398
  await completed(transaction);
336
399
  },
337
400
  async dropConversations(conversations) {
338
- const transaction = database.transaction([CONVERSATIONS, MESSAGES, CHAT_DRAFTS], 'readwrite');
401
+ const drafts = authored.transaction(CHAT_DRAFTS, 'readwrite');
402
+ for (const conversation of conversations)
403
+ drafts.objectStore(CHAT_DRAFTS).delete(conversation);
404
+ await completed(drafts);
405
+ const transaction = database.transaction([CONVERSATIONS, MESSAGES], 'readwrite');
339
406
  const messages = transaction.objectStore(MESSAGES);
340
407
  for (const conversation of conversations) {
341
408
  transaction.objectStore(CONVERSATIONS).delete(conversation);
342
- transaction.objectStore(CHAT_DRAFTS).delete(conversation);
343
409
  const keys = messages.index('conversation').getAllKeys(conversation);
344
410
  keys.onsuccess = () => {
345
411
  for (const key of keys.result)
@@ -349,46 +415,89 @@ export async function openRuntimeStore() {
349
415
  await completed(transaction);
350
416
  },
351
417
  async chatDrafts() {
352
- const transaction = database.transaction(CHAT_DRAFTS, 'readonly');
353
- return settled(transaction.objectStore(CHAT_DRAFTS).getAll());
418
+ const transaction = authored.transaction(CHAT_DRAFTS, 'readonly');
419
+ const held = await settled(transaction.objectStore(CHAT_DRAFTS).getAll());
420
+ return held.map(chatDraftRecord);
354
421
  },
355
422
  async keepChatDraft(record) {
356
- const transaction = database.transaction(CHAT_DRAFTS, 'readwrite');
423
+ const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
357
424
  transaction.objectStore(CHAT_DRAFTS).put(record);
358
425
  await completed(transaction);
359
426
  },
360
427
  async dropChatDraft(conversation) {
361
- const transaction = database.transaction(CHAT_DRAFTS, 'readwrite');
428
+ const transaction = authored.transaction(CHAT_DRAFTS, 'readwrite');
362
429
  transaction.objectStore(CHAT_DRAFTS).delete(conversation);
363
430
  await completed(transaction);
364
431
  },
365
432
  async keepRoomDraft(record) {
366
- const transaction = database.transaction(ROOM_DRAFTS, 'readwrite');
433
+ const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
367
434
  transaction.objectStore(ROOM_DRAFTS).put(record);
368
435
  await completed(transaction);
369
436
  },
370
437
  async discardRoomDraft(locator, path) {
371
- const transaction = database.transaction(ROOM_DRAFTS, 'readwrite');
438
+ const transaction = authored.transaction(ROOM_DRAFTS, 'readwrite');
372
439
  transaction.objectStore(ROOM_DRAFTS).delete([locator, path]);
373
440
  await completed(transaction);
374
441
  },
375
442
  async dropRooms(locators) {
376
- const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_TARGETS, ATTACHMENTS, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
443
+ const work = authored.transaction([QUEUES, PENDING_CHANGES, ROOM_DRAFTS], 'readwrite');
377
444
  for (const locator of locators) {
378
- transaction.objectStore(ROOMS).delete(locator);
379
- for (const name of [DOCUMENTS, BINARY_TARGETS, ATTACHMENTS, PENDING_CHANGES, ROOM_DRAFTS]) {
380
- removeRoomEntries(transaction.objectStore(name), locator);
445
+ work.objectStore(QUEUES).delete(locator);
446
+ for (const name of [PENDING_CHANGES, ROOM_DRAFTS]) {
447
+ removeRoomEntries(work.objectStore(name), locator);
381
448
  }
382
449
  }
450
+ await completed(work);
451
+ const transaction = database.transaction([ROOMS, DOCUMENTS, BINARY_FILES, TRANSFERS], 'readwrite');
452
+ for (const locator of locators) {
453
+ transaction.objectStore(ROOMS).delete(locator);
454
+ transaction.objectStore(TRANSFERS).delete(locator);
455
+ transaction.objectStore(DOCUMENTS).delete(underRoom(locator));
456
+ transaction.objectStore(BINARY_FILES).delete(underRoom(locator));
457
+ }
458
+ await completed(transaction);
459
+ },
460
+ async transfers() {
461
+ const transaction = database.transaction(TRANSFERS, 'readonly');
462
+ return settled(transaction.objectStore(TRANSFERS).getAll());
463
+ },
464
+ staged(record) {
465
+ const transaction = database.transaction([DOCUMENTS, BINARY_FILES], 'readonly');
466
+ return readLayer(transaction, record.locator, record.transfer);
467
+ },
468
+ async stage(record, page) {
469
+ const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
470
+ writeLayer(transaction, record.locator, record.transfer, page, null);
471
+ transaction.objectStore(TRANSFERS).put(record);
472
+ await completed(transaction);
473
+ },
474
+ async abandon(locator) {
475
+ const transaction = database.transaction([TRANSFERS, DOCUMENTS, BINARY_FILES], 'readwrite');
476
+ const transfers = transaction.objectStore(TRANSFERS);
477
+ const held = transfers.get(locator);
478
+ held.onsuccess = () => {
479
+ const record = held.result;
480
+ if (record === undefined)
481
+ return;
482
+ transfers.delete(locator);
483
+ const range = underTransfer(locator, record.transfer);
484
+ transaction.objectStore(DOCUMENTS).delete(range);
485
+ transaction.objectStore(BINARY_FILES).delete(range);
486
+ };
383
487
  await completed(transaction);
384
488
  },
385
489
  async generation() {
386
- return (await declaration(database)).generation;
490
+ const transaction = authored.transaction(FACTS, 'readonly');
491
+ const held = await settled(transaction.objectStore(FACTS).get(GENERATION));
492
+ return held ?? null;
387
493
  },
388
- rememberGeneration(value) {
389
- return updateDeclaration(database, (record) => ({ ...record, generation: value }));
494
+ async rememberGeneration(value) {
495
+ const transaction = authored.transaction(FACTS, 'readwrite');
496
+ transaction.objectStore(FACTS).put(value, GENERATION);
497
+ await completed(transaction);
390
498
  },
391
499
  close() {
500
+ authored.close();
392
501
  database.close();
393
502
  },
394
503
  };
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';
@@ -44,12 +47,14 @@ declare const TOPICS: {
44
47
  readonly 'deployment-facts': 'runtime';
45
48
  readonly 'sync-status': 'within';
46
49
  readonly 'service-mode': 'runtime';
50
+ readonly member: 'runtime';
47
51
  readonly query: 'within';
48
52
  readonly queue: 'within';
49
53
  readonly 'room-drafts': 'within';
50
54
  readonly presentation: 'app';
51
55
  readonly conversation: 'within';
52
56
  readonly conversations: 'within';
57
+ readonly agents: 'within';
53
58
  };
54
59
  export declare const WIRE_REACH: {
55
60
  readonly members: Readonly<Record<string, WireReach>>;
@@ -77,11 +82,10 @@ export type WireAnswer = {
77
82
  kind: 'result';
78
83
  id: number;
79
84
  value: unknown;
80
- } | {
85
+ } | ({
81
86
  kind: 'failure';
82
87
  id: number;
83
- message: string;
84
- } | {
88
+ } & Described) | {
85
89
  kind: 'event';
86
90
  id: number;
87
91
  value: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../src/wire.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"wire.d.ts","sourceRoot":"","sources":["../src/wire.ts"],"names":[],"mappings":"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"}