@agentshouse/mdruntime 0.1.0-c3903a68dcbbf → 0.1.0-c3fa75348e547

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 (206) hide show
  1. package/AGENTS.md +270 -181
  2. package/README.md +22 -12
  3. package/dist/acquisition.d.ts +14 -0
  4. package/dist/acquisition.d.ts.map +1 -0
  5. package/dist/acquisition.js +24 -0
  6. package/dist/adapter.d.ts +160 -67
  7. package/dist/adapter.d.ts.map +1 -1
  8. package/dist/adapter.js +1 -9
  9. package/dist/attached-model.d.ts +11 -0
  10. package/dist/attached-model.d.ts.map +1 -0
  11. package/dist/attached-model.js +47 -0
  12. package/dist/attempt.d.ts +16 -0
  13. package/dist/attempt.d.ts.map +1 -0
  14. package/dist/attempt.js +70 -0
  15. package/dist/binary.d.ts +23 -0
  16. package/dist/binary.d.ts.map +1 -0
  17. package/dist/binary.js +8 -0
  18. package/dist/bootstrap.d.ts +21 -6
  19. package/dist/bootstrap.d.ts.map +1 -1
  20. package/dist/bootstrap.js +114 -38
  21. package/dist/change-set.d.ts +2 -0
  22. package/dist/change-set.d.ts.map +1 -1
  23. package/dist/change-set.js +50 -21
  24. package/dist/change.d.ts +15 -0
  25. package/dist/change.d.ts.map +1 -1
  26. package/dist/change.js +26 -1
  27. package/dist/chat/acts.d.ts +33 -0
  28. package/dist/chat/acts.d.ts.map +1 -0
  29. package/dist/chat/acts.js +36 -0
  30. package/dist/chat/context.d.ts +3 -0
  31. package/dist/chat/context.d.ts.map +1 -0
  32. package/dist/chat/context.js +10 -0
  33. package/dist/chat/input.d.ts +9 -0
  34. package/dist/chat/input.d.ts.map +1 -0
  35. package/dist/chat/input.js +99 -0
  36. package/dist/chat/kit.d.ts +61 -0
  37. package/dist/chat/kit.d.ts.map +1 -0
  38. package/dist/chat/kit.js +123 -0
  39. package/dist/chat/lasting.d.ts +6 -0
  40. package/dist/chat/lasting.d.ts.map +1 -0
  41. package/dist/chat/lasting.js +19 -0
  42. package/dist/chat/list.d.ts +27 -0
  43. package/dist/chat/list.d.ts.map +1 -0
  44. package/dist/chat/list.js +63 -0
  45. package/dist/chat/markdown.d.ts +20 -0
  46. package/dist/chat/markdown.d.ts.map +1 -0
  47. package/dist/chat/markdown.js +188 -0
  48. package/dist/chat/message.d.ts +6 -0
  49. package/dist/chat/message.d.ts.map +1 -0
  50. package/dist/chat/message.js +192 -0
  51. package/dist/chat/messages.d.ts +22 -0
  52. package/dist/chat/messages.d.ts.map +1 -0
  53. package/dist/chat/messages.js +155 -0
  54. package/dist/chat/name.d.ts +6 -0
  55. package/dist/chat/name.d.ts.map +1 -0
  56. package/dist/chat/name.js +37 -0
  57. package/dist/chat/opened.d.ts +11 -0
  58. package/dist/chat/opened.d.ts.map +1 -0
  59. package/dist/chat/opened.js +17 -0
  60. package/dist/chat/overlay.d.ts +31 -0
  61. package/dist/chat/overlay.d.ts.map +1 -0
  62. package/dist/chat/overlay.js +97 -0
  63. package/dist/chat/parts.d.ts +57 -0
  64. package/dist/chat/parts.d.ts.map +1 -0
  65. package/dist/chat/parts.js +119 -0
  66. package/dist/chat/process.d.ts +20 -0
  67. package/dist/chat/process.d.ts.map +1 -0
  68. package/dist/chat/process.js +32 -0
  69. package/dist/chat/provider.d.ts +63 -0
  70. package/dist/chat/provider.d.ts.map +1 -0
  71. package/dist/chat/provider.js +629 -0
  72. package/dist/chat/question.d.ts +9 -0
  73. package/dist/chat/question.d.ts.map +1 -0
  74. package/dist/chat/question.js +80 -0
  75. package/dist/chat/questions.d.ts +31 -0
  76. package/dist/chat/questions.d.ts.map +1 -0
  77. package/dist/chat/questions.js +111 -0
  78. package/dist/chat/read.d.ts +5 -0
  79. package/dist/chat/read.d.ts.map +1 -0
  80. package/dist/chat/read.js +13 -0
  81. package/dist/chat/ready.d.ts +34 -0
  82. package/dist/chat/ready.d.ts.map +1 -0
  83. package/dist/chat/ready.js +91 -0
  84. package/dist/chat/style.d.ts +4 -0
  85. package/dist/chat/style.d.ts.map +1 -0
  86. package/dist/chat/style.js +302 -0
  87. package/dist/chat.d.ts +14 -0
  88. package/dist/chat.d.ts.map +1 -0
  89. package/dist/chat.js +8 -0
  90. package/dist/client.d.ts +28 -20
  91. package/dist/client.d.ts.map +1 -1
  92. package/dist/client.js +78 -32
  93. package/dist/collection.d.ts +21 -14
  94. package/dist/collection.d.ts.map +1 -1
  95. package/dist/collection.js +270 -32
  96. package/dist/connection.d.ts +50 -38
  97. package/dist/connection.d.ts.map +1 -1
  98. package/dist/connection.js +2245 -876
  99. package/dist/conversation.d.ts +46 -19
  100. package/dist/conversation.d.ts.map +1 -1
  101. package/dist/conversation.js +632 -221
  102. package/dist/durability.d.ts +7 -1
  103. package/dist/durability.d.ts.map +1 -1
  104. package/dist/entry.d.ts +17 -0
  105. package/dist/entry.d.ts.map +1 -0
  106. package/dist/entry.js +156 -0
  107. package/dist/expectation.d.ts +21 -0
  108. package/dist/expectation.d.ts.map +1 -0
  109. package/dist/expectation.js +70 -0
  110. package/dist/failure.d.ts +13 -0
  111. package/dist/failure.d.ts.map +1 -0
  112. package/dist/failure.js +19 -0
  113. package/dist/fence.d.ts +6 -0
  114. package/dist/fence.d.ts.map +1 -0
  115. package/dist/fence.js +10 -0
  116. package/dist/host.d.ts +24 -3
  117. package/dist/host.d.ts.map +1 -1
  118. package/dist/host.js +128 -70
  119. package/dist/identity.d.ts +5 -0
  120. package/dist/identity.d.ts.map +1 -1
  121. package/dist/identity.js +19 -1
  122. package/dist/index.d.ts +16 -9
  123. package/dist/index.d.ts.map +1 -1
  124. package/dist/index.js +5 -1
  125. package/dist/memory.d.ts +21 -7
  126. package/dist/memory.d.ts.map +1 -1
  127. package/dist/memory.js +164 -47
  128. package/dist/model.d.ts +17 -14
  129. package/dist/model.d.ts.map +1 -1
  130. package/dist/model.js +16 -4
  131. package/dist/observation.d.ts +6 -1
  132. package/dist/observation.d.ts.map +1 -1
  133. package/dist/observation.js +38 -17
  134. package/dist/open.d.ts +2 -0
  135. package/dist/open.d.ts.map +1 -0
  136. package/dist/open.js +1 -0
  137. package/dist/outcome.d.ts +35 -22
  138. package/dist/outcome.d.ts.map +1 -1
  139. package/dist/outcome.js +42 -1
  140. package/dist/overlay.d.ts +16 -3
  141. package/dist/overlay.d.ts.map +1 -1
  142. package/dist/overlay.js +118 -77
  143. package/dist/paths.d.ts +0 -1
  144. package/dist/paths.d.ts.map +1 -1
  145. package/dist/paths.js +0 -16
  146. package/dist/query.d.ts +47 -6
  147. package/dist/query.d.ts.map +1 -1
  148. package/dist/query.js +86 -38
  149. package/dist/reach.d.ts +45 -0
  150. package/dist/reach.d.ts.map +1 -0
  151. package/dist/reach.js +306 -0
  152. package/dist/react.d.ts +44 -0
  153. package/dist/react.d.ts.map +1 -0
  154. package/dist/react.js +66 -0
  155. package/dist/read-side.d.ts +16 -5
  156. package/dist/read-side.d.ts.map +1 -1
  157. package/dist/read-side.js +408 -137
  158. package/dist/readiness.d.ts +53 -0
  159. package/dist/readiness.d.ts.map +1 -0
  160. package/dist/readiness.js +33 -0
  161. package/dist/reads.d.ts +11 -0
  162. package/dist/reads.d.ts.map +1 -0
  163. package/dist/reads.js +98 -0
  164. package/dist/recovery.d.ts +25 -0
  165. package/dist/recovery.d.ts.map +1 -0
  166. package/dist/recovery.js +197 -0
  167. package/dist/refresh.d.ts +13 -2
  168. package/dist/refresh.d.ts.map +1 -1
  169. package/dist/refresh.js +51 -36
  170. package/dist/replica.d.ts +10 -7
  171. package/dist/replica.d.ts.map +1 -1
  172. package/dist/replica.js +131 -79
  173. package/dist/room-draft.d.ts +41 -9
  174. package/dist/room-draft.d.ts.map +1 -1
  175. package/dist/room-draft.js +139 -28
  176. package/dist/rows.d.ts +11 -14
  177. package/dist/rows.d.ts.map +1 -1
  178. package/dist/rows.js +87 -50
  179. package/dist/save.d.ts +32 -3
  180. package/dist/save.d.ts.map +1 -1
  181. package/dist/save.js +465 -93
  182. package/dist/search.d.ts +39 -8
  183. package/dist/search.d.ts.map +1 -1
  184. package/dist/search.js +132 -46
  185. package/dist/seed.d.ts +16 -0
  186. package/dist/seed.d.ts.map +1 -0
  187. package/dist/seed.js +61 -0
  188. package/dist/shared.d.ts +11 -0
  189. package/dist/shared.d.ts.map +1 -0
  190. package/dist/shared.js +368 -0
  191. package/dist/status.d.ts +6 -2
  192. package/dist/status.d.ts.map +1 -1
  193. package/dist/status.js +0 -8
  194. package/dist/store.d.ts +87 -32
  195. package/dist/store.d.ts.map +1 -1
  196. package/dist/store.js +558 -225
  197. package/dist/turn.d.ts +7 -0
  198. package/dist/turn.d.ts.map +1 -0
  199. package/dist/turn.js +45 -0
  200. package/dist/wire.d.ts +162 -19
  201. package/dist/wire.d.ts.map +1 -1
  202. package/dist/wire.js +82 -67
  203. package/package.json +31 -7
  204. package/dist/attachment.d.ts +0 -3
  205. package/dist/attachment.d.ts.map +0 -1
  206. package/dist/attachment.js +0 -8
package/dist/memory.js CHANGED
@@ -1,9 +1,7 @@
1
- import { ROOM_CONTRACT_VERSION, } from './adapter.js';
2
- import { MD_MODEL } from './collection.js';
3
1
  import { sameChange } from './overlay.js';
4
2
  const FIXTURE_RETENTION = {
5
3
  history: { kind: 'duration', seconds: 1 },
6
- outcome: 1,
4
+ outcome: 604_800,
7
5
  refreshHorizon: 1,
8
6
  };
9
7
  function declaredRetention(value) {
@@ -15,6 +13,19 @@ function declaredRetention(value) {
15
13
  }
16
14
  throw new Error('history retention duration must be a finite positive number of seconds');
17
15
  }
16
+ const MODEL_ABSENT = { kind: 'model-unavailable', reason: 'not-readable' };
17
+ function modelsOf(room) {
18
+ return {
19
+ collection: room.model ?? MODEL_ABSENT,
20
+ ...(room.typedSelection === undefined
21
+ ? {}
22
+ : { selection: room.selectionModel ?? MODEL_ABSENT }),
23
+ };
24
+ }
25
+ function changedModels(room, from) {
26
+ const now = modelsOf(room);
27
+ return JSON.stringify(now) === JSON.stringify(modelsOf(from)) ? undefined : now;
28
+ }
18
29
  function named(source, paths) {
19
30
  const taken = {};
20
31
  for (const path of paths) {
@@ -31,8 +42,6 @@ async function resolveScript(answer, fallback, request) {
31
42
  }
32
43
  export function createMemoryAdapter(options = {}) {
33
44
  let rooms = options.rooms === undefined ? [] : [...options.rooms];
34
- const mdModel = options.mdModel ?? MD_MODEL;
35
- const supportedVersions = options.supportedVersions ?? [ROOM_CONTRACT_VERSION];
36
45
  const capabilities = options.capabilities ?? [];
37
46
  const providerLimits = options.providerLimits ?? [];
38
47
  const retention = declaredRetention(options.retention);
@@ -46,8 +55,11 @@ export function createMemoryAdapter(options = {}) {
46
55
  const scripted = new Map();
47
56
  const unsealed = new Map();
48
57
  const sealed = new Set();
58
+ const sentTurns = new Map();
49
59
  const historyPageSize = options.historyPageSize;
50
- let selected = [];
60
+ let held = [];
61
+ let heldDemand = null;
62
+ let expiring = [];
51
63
  let replicated = [];
52
64
  let issued = 0;
53
65
  function scriptConversations(entries) {
@@ -89,38 +101,43 @@ export function createMemoryAdapter(options = {}) {
89
101
  return {
90
102
  name: room.name,
91
103
  locator: room.locator,
104
+ handle: room.handle,
92
105
  roomVersion: room.roomVersion,
93
106
  operations: room.operations,
94
107
  replica: room.replica,
95
- attachedModel: room.attachedModel,
96
108
  ...(room.typedSelection === undefined ? {} : { typedSelection: room.typedSelection }),
97
- ...(room.untypedFolders === undefined ? {} : { untypedFolders: room.untypedFolders }),
98
109
  providerOwnedPaths: room.providerOwnedPaths,
99
110
  };
100
111
  }
101
- function page(room, from) {
112
+ function page(room, after) {
102
113
  const paths = Object.keys(room.documents ?? {}).sort();
114
+ const opening = after === undefined;
115
+ const from = opening ? 0 : paths.filter((path) => path <= after).length;
103
116
  const size = pageSize ?? paths.length;
104
117
  const taken = paths.slice(from, from + size);
105
118
  const next = from + taken.length;
106
- const targets = from === 0 ? (room.binaryTargets ?? []) : [];
119
+ const targets = opening ? Object.keys(room.binaryFiles ?? {}) : [];
107
120
  return {
108
121
  kind: 'bootstrap',
109
122
  roomVersion: room.roomVersion,
123
+ ...(opening ? { models: modelsOf(room) } : {}),
110
124
  documents: named(room.documents ?? {}, taken),
111
- revisions: named(room.revisions ?? {}, taken),
125
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
126
+ ...(room.fileIds === undefined
127
+ ? {}
128
+ : { fileIds: named(room.fileIds, [...taken, ...targets]) }),
112
129
  changes: named(room.changes ?? {}, [...taken, ...targets]),
113
- binaryTargets: targets,
114
- ...(from === 0 && room.attachments !== undefined ? { attachments: room.attachments } : {}),
115
- ...(next < paths.length ? { pageToken: String(next) } : {}),
130
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
131
+ ...(next < paths.length ? { pageToken: taken.at(-1) } : {}),
116
132
  };
117
133
  }
118
134
  function advancement(room, from, at) {
119
135
  const current = room.documents ?? {};
120
136
  const previous = from.documents ?? {};
121
- const currentTargets = new Set(room.binaryTargets ?? []);
122
- const previousTargets = new Set(from.binaryTargets ?? []);
137
+ const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
138
+ const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
123
139
  const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
140
+ room.fileIds?.[path] !== from.fileIds?.[path] ||
124
141
  !sameChange(room.changes?.[path], from.changes?.[path]);
125
142
  const changed = Object.keys(current)
126
143
  .filter((path) => current[path] !== previous[path] || headMoved(path))
@@ -135,22 +152,24 @@ export function createMemoryAdapter(options = {}) {
135
152
  const targets = opening
136
153
  ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
137
154
  : [];
138
- const attachments = room.attachments ?? [];
139
- const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
155
+ const models = opening ? changedModels(room, from) : undefined;
140
156
  return {
141
157
  kind: 'net-advancement',
142
158
  roomVersion: room.roomVersion,
159
+ ...(models === undefined ? {} : { models }),
143
160
  documents: named(current, taken),
144
- revisions: named(room.revisions ?? {}, taken),
161
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
162
+ ...(room.fileIds === undefined
163
+ ? {}
164
+ : { fileIds: named(room.fileIds, [...taken, ...targets]) }),
145
165
  changes: named(room.changes ?? {}, [...taken, ...targets]),
146
- binaryTargets: targets,
166
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
147
167
  removals: opening
148
168
  ? [
149
169
  ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
150
170
  ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
151
171
  ].sort()
152
172
  : [],
153
- ...(declared ? { attachments } : {}),
154
173
  ...(pageToken === undefined ? {} : { pageToken }),
155
174
  };
156
175
  }
@@ -171,7 +190,7 @@ export function createMemoryAdapter(options = {}) {
171
190
  function historiesOf(input) {
172
191
  const asked = input?.conversations;
173
192
  if (!Array.isArray(asked))
174
- return { kind: 'rejected', code: 'invalid_request', fields: {} };
193
+ return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
175
194
  const histories = [];
176
195
  for (const entry of asked) {
177
196
  const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
@@ -199,21 +218,32 @@ export function createMemoryAdapter(options = {}) {
199
218
  const named = typeof input.conversation === 'string' ? input.conversation : '';
200
219
  const conversation = scripted.get(named);
201
220
  if (conversation === undefined) {
202
- return { kind: 'rejected', code: 'unknown-conversation', fields: { conversation: named } };
221
+ return {
222
+ kind: 'rejected',
223
+ code: 'unknown-conversation',
224
+ fields: { conversation: named },
225
+ retryable: false,
226
+ };
203
227
  }
204
228
  const outcome = conversation.outcomes?.[name];
205
229
  if (outcome !== undefined)
206
230
  return outcome;
207
231
  if (name === 'conversation.send') {
232
+ const operation = typeof input.operation_id === 'string' ? input.operation_id : null;
233
+ const answered = operation === null ? undefined : sentTurns.get(operation);
234
+ if (answered !== undefined)
235
+ return { kind: 'action', result: { turn: answered } };
208
236
  issued += 1;
209
237
  const turn = `turn-${issued}`;
210
238
  unsealed.set(turn, named);
239
+ if (operation !== null)
240
+ sentTurns.set(operation, turn);
211
241
  return { kind: 'action', result: { turn } };
212
242
  }
213
243
  if (name === 'conversation.cancel') {
214
244
  const turn = typeof input.turn === 'string' ? input.turn : '';
215
245
  if (sealed.has(turn) || !unsealed.has(turn)) {
216
- return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
246
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
217
247
  }
218
248
  unsealed.delete(turn);
219
249
  return { kind: 'action', result: { turn, cancelled: true } };
@@ -222,18 +252,23 @@ export function createMemoryAdapter(options = {}) {
222
252
  scripted.delete(named);
223
253
  return { kind: 'action', result: { conversation: named } };
224
254
  }
255
+ function announceList() {
256
+ const entries = [...scripted.values()].flatMap(({ conversation, listed }) => listed === undefined ? [] : [{ conversation, ...listed }]);
257
+ for (const listener of listeners)
258
+ listener({ kind: 'list', entries });
259
+ }
225
260
  function discovery() {
226
261
  return {
227
262
  kind: 'discovery',
228
- supportedVersions,
229
- mdModel,
230
263
  rooms: rooms.map(declared),
231
264
  capabilities,
232
265
  providerLimits,
233
266
  retention,
267
+ ...(options.member === undefined ? {} : { member: options.member }),
234
268
  };
235
269
  }
236
270
  return {
271
+ ...(options.exhaustiveDiscovery === undefined ? {} : { exhaustiveDiscovery: true }),
237
272
  setRooms(next) {
238
273
  rooms = [...next];
239
274
  retain(rooms);
@@ -241,9 +276,25 @@ export function createMemoryAdapter(options = {}) {
241
276
  setConversations(next) {
242
277
  scriptConversations(next);
243
278
  },
244
- notifyRoomVersion(notification) {
279
+ open() {
280
+ announceList();
281
+ for (const observer of observers)
282
+ observer({ kind: 'opened' });
283
+ },
284
+ close({ revoked = false, lost = !revoked } = {}) {
285
+ for (const observer of observers)
286
+ observer({ kind: 'closed', revoked, lost });
287
+ },
288
+ expire(locators) {
289
+ expiring = [...locators];
290
+ },
291
+ notifyRoomVersion({ locator, roomVersion }) {
292
+ for (const observer of observers)
293
+ observer({ kind: 'room-version', locator, roomVersion });
294
+ },
295
+ notifyAuthorityChanged() {
245
296
  for (const observer of observers)
246
- observer(notification);
297
+ observer({ kind: 'authority-changed' });
247
298
  },
248
299
  notifyConversation(event) {
249
300
  if (event.kind === 'accepted-message') {
@@ -257,8 +308,11 @@ export function createMemoryAdapter(options = {}) {
257
308
  for (const observer of modeObservers)
258
309
  observer(mode);
259
310
  },
260
- selectedRooms() {
261
- return selected;
311
+ heldRooms() {
312
+ return held;
313
+ },
314
+ heldDemand() {
315
+ return heldDemand;
262
316
  },
263
317
  replicatedConversations() {
264
318
  return replicated;
@@ -282,12 +336,48 @@ export function createMemoryAdapter(options = {}) {
282
336
  };
283
337
  },
284
338
  },
285
- roomVersions: {
286
- select(locators) {
287
- selected = [...locators];
339
+ roomStream: {
340
+ hold(asked, demand) {
341
+ held = asked.map((room) => room.locator);
342
+ heldDemand = demand;
343
+ const expired = expiring.filter((locator) => held.includes(locator));
344
+ expiring = [];
345
+ const moved = asked.flatMap((room) => {
346
+ const current = rooms.find((entry) => entry.locator === room.locator);
347
+ return current === undefined ||
348
+ expired.includes(room.locator) ||
349
+ current.roomVersion === room.roomVersion
350
+ ? []
351
+ : [{ locator: room.locator, roomVersion: current.roomVersion }];
352
+ });
353
+ queueMicrotask(() => {
354
+ for (const observer of observers) {
355
+ for (const room of moved)
356
+ observer({ kind: 'room-version', ...room });
357
+ observer({ kind: 'opening', expired });
358
+ }
359
+ });
360
+ },
361
+ reopen() {
362
+ queueMicrotask(() => {
363
+ for (const observer of observers) {
364
+ observer({ kind: 'closed', revoked: false, lost: false });
365
+ }
366
+ });
288
367
  },
368
+ published() { },
289
369
  observe(notify) {
290
370
  observers.add(notify);
371
+ queueMicrotask(() => {
372
+ if (!observers.has(notify))
373
+ return;
374
+ if (options.unopened === true) {
375
+ notify({ kind: 'closed', revoked: false, lost: true });
376
+ return;
377
+ }
378
+ announceList();
379
+ notify({ kind: 'opened' });
380
+ });
291
381
  return () => {
292
382
  observers.delete(notify);
293
383
  };
@@ -299,13 +389,6 @@ export function createMemoryAdapter(options = {}) {
299
389
  else
300
390
  scripts[operation] = answer;
301
391
  },
302
- async model(_authorization, request) {
303
- return resolveScript(scripts.model, () => {
304
- const room = rooms.find((entry) => entry.locator === request.locator);
305
- const answer = request.attached === 'collection' ? room?.model : room?.selectionModel;
306
- return answer ?? { kind: 'model-unavailable', reason: 'not-readable' };
307
- }, request);
308
- },
309
392
  async authorize() {
310
393
  return resolveScript(scripts.authorize, () => ({}), undefined);
311
394
  },
@@ -318,13 +401,21 @@ export function createMemoryAdapter(options = {}) {
318
401
  });
319
402
  },
320
403
  reached,
404
+ follows(locator, roomVersion, next) {
405
+ const scripted = scripts.follows;
406
+ if (typeof scripted === 'boolean')
407
+ return scripted;
408
+ if (scripted !== undefined)
409
+ return scripted(locator, roomVersion, next);
410
+ return true;
411
+ },
321
412
  async bootstrap(_authorization, request) {
322
413
  return resolveScript(scripts.bootstrap, () => {
323
414
  const room = rooms.find((entry) => entry.locator === request.locator);
324
415
  if (room === undefined) {
325
416
  return { kind: 'room-not-readable', locator: request.locator };
326
417
  }
327
- return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
418
+ return page(room, request.pageToken);
328
419
  }, request).then((answer) => note(request.locator, answer));
329
420
  },
330
421
  async refresh(_authorization, request) {
@@ -342,10 +433,6 @@ export function createMemoryAdapter(options = {}) {
342
433
  }
343
434
  return advancement(continuation.room, continuation.from, continuation.at);
344
435
  }
345
- if (request.minPosition !== undefined &&
346
- !reached(room.locator, room.roomVersion, request.minPosition)) {
347
- return { kind: 'retryable-refusal', code: 'replica_behind', fields: {} };
348
- }
349
436
  if (request.fromRoomVersion === room.roomVersion) {
350
437
  return { kind: 'still-current' };
351
438
  }
@@ -361,7 +448,13 @@ export function createMemoryAdapter(options = {}) {
361
448
  if (room === undefined) {
362
449
  return { kind: 'room-not-readable', locator: request.locator };
363
450
  }
364
- return { kind: 'rejected', code: 'unscripted-mutation', fields: {}, affected: {} };
451
+ return {
452
+ kind: 'rejected',
453
+ code: 'unscripted-mutation',
454
+ fields: {},
455
+ retryable: false,
456
+ affected: {},
457
+ };
365
458
  }, request).then((answer) => note(request.locator, answer));
366
459
  },
367
460
  async history(_authorization, request) {
@@ -376,11 +469,35 @@ export function createMemoryAdapter(options = {}) {
376
469
  };
377
470
  }, request);
378
471
  },
472
+ async binary(_authorization, request) {
473
+ return resolveScript(scripts.binary, () => {
474
+ if (request.kind === 'reference') {
475
+ return { kind: 'rejected', code: 'unscripted-binary', fields: {}, retryable: false };
476
+ }
477
+ const room = rooms.find((entry) => entry.locator === request.locator);
478
+ if (room === undefined)
479
+ return { kind: 'room-not-readable', locator: request.locator };
480
+ const blob = room.blobs?.[request.path];
481
+ return blob === undefined
482
+ ? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
483
+ : { kind: 'binary', blob };
484
+ }, request);
485
+ },
486
+ referrerScope(referrer) {
487
+ if (typeof referrer !== 'object' || referrer === null)
488
+ return null;
489
+ const { room, path, message } = referrer;
490
+ if (typeof message === 'string')
491
+ return { kind: 'conversations' };
492
+ if (typeof room !== 'string')
493
+ return null;
494
+ return { kind: 'room', locator: room, ...(typeof path === 'string' ? { path } : {}) };
495
+ },
379
496
  async action(_authorization, request) {
380
497
  return resolveScript(scripts.action, () => {
381
498
  if (request.name.startsWith('conversation.'))
382
499
  return conversationAction(request);
383
- return { kind: 'rejected', code: 'unscripted-action', fields: {} };
500
+ return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
384
501
  }, request).then((answer) => {
385
502
  if (answer.kind === 'action' && answer.at !== undefined)
386
503
  note(answer.at.locator, answer.at);
package/dist/model.d.ts CHANGED
@@ -1,31 +1,27 @@
1
- import type { Definition, FieldSpec, SectionSpec, VerifiedModel } from '@agentshouse/mdmodel';
1
+ import type { Definition, ValueFacts, VerifiedModel } from '@agentshouse/mdmodel';
2
+ import type { Open } from './open.js';
2
3
  export type ModelIdentity = {
3
4
  identity: string;
4
5
  version: string;
5
6
  };
6
7
  export type ModelSnapshot = ModelIdentity & {
7
8
  schema: string | null;
9
+ revision: string | null;
8
10
  };
9
- export type ModelUnavailableReason = 'not-readable' | 'revoked' | 'not-acquired' | 'version-changed' | 'invalid';
11
+ export type ModelUnavailableReason = Open<'not-readable' | 'revoked' | 'not-acquired' | 'invalid'>;
10
12
  export type ModelResult = {
11
13
  kind: 'model';
12
14
  snapshot: ModelSnapshot;
13
15
  } | {
14
16
  kind: 'model-unavailable';
15
17
  reason: ModelUnavailableReason;
16
- } | {
17
- kind: 'transport-uncertainty';
18
- } | {
19
- kind: 'revoked-authorization';
20
- };
21
- export type MdType = {
22
- name: string;
23
- fields: Readonly<Record<string, FieldSpec>>;
24
- sections: Readonly<Record<string, SectionSpec>>;
25
18
  };
19
+ export type MdType = Definition;
26
20
  export type ModelState = {
27
21
  status: 'unavailable';
28
22
  reason: ModelUnavailableReason;
23
+ schema?: string | null;
24
+ revision?: string | null;
29
25
  } | {
30
26
  status: 'current' | 'cached';
31
27
  snapshot: ModelSnapshot;
@@ -33,23 +29,30 @@ export type ModelState = {
33
29
  types: VerifiedModel['types'];
34
30
  };
35
31
  export type TypesResult = {
36
- status: 'unavailable';
32
+ status: Open<'unavailable'>;
37
33
  reason: ModelUnavailableReason;
34
+ types: null;
35
+ schema?: string | null;
36
+ revision?: string | null;
38
37
  } | {
39
- status: 'current' | 'cached';
38
+ status: Open<'current' | 'cached'>;
40
39
  identity: string;
41
40
  version: string;
42
41
  verifiedWith: ModelIdentity;
43
42
  types: readonly MdType[];
43
+ schema: string | null;
44
+ revision: string | null;
44
45
  };
45
46
  export type ValidationReceipt = {
46
47
  identity: string;
47
48
  version: string;
48
- source: 'current' | 'cached';
49
+ source: Open<'current' | 'cached'>;
49
50
  };
50
51
  export declare const NO_MODEL: ModelState;
51
52
  export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
52
53
  export declare function modelTypes(state: ModelState): TypesResult;
53
54
  export declare function cached(state: ModelState): ModelState;
54
55
  export declare function sameModel(left: ModelIdentity, right: ModelIdentity): boolean;
56
+ export declare function sameTyping(left: ModelState, right: ModelState): boolean;
57
+ export declare function referenceField(facts: ValueFacts | undefined): boolean;
55
58
  //# sourceMappingURL=model.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE9F,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AACtE,MAAM,MAAM,sBAAsB,GAC9B,cAAc,GACd,SAAS,GACT,cAAc,GACd,iBAAiB,GACjB,SAAS,CAAC;AACd,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,uBAAuB,CAAA;CAAE,CAAC;AACtC,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;CACjD,CAAC;AACF,MAAM,MAAM,UAAU,GAClB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,GACzD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CAC1B,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;CAAE,CAAC;AACpG,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAGhG;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAczD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E"}
1
+ {"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../src/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAC/F,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,cAAc,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC,CAAC;AACnG,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,mBAAmB,CAAC;IAAC,MAAM,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAClE,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAChC,MAAM,MAAM,UAAU,GAClB;IACE,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CAC/B,CAAC;AACN,MAAM,MAAM,WAAW,GACnB;IACE,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;IAC5B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,IAAI,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GACD;IACE,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,aAAa,CAAC;IAC5B,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB,CAAC;AACN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,IAAI,CAAC,SAAS,GAAG,QAAQ,CAAC,CAAC;CACpC,CAAC;AACF,eAAO,MAAM,QAAQ,EAAE,UAA8D,CAAC;AACtF,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,CAGhG;AACD,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,WAAW,CAgBzD;AACD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAEpD;AACD,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAE5E;AACD,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CASvE;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAErE"}
package/dist/model.js CHANGED
@@ -6,15 +6,15 @@ export function definitionOf(state, type) {
6
6
  }
7
7
  export function modelTypes(state) {
8
8
  return state.status === 'unavailable'
9
- ? { ...state }
9
+ ? { ...state, types: null }
10
10
  : {
11
11
  status: state.status,
12
12
  identity: state.snapshot.identity,
13
13
  version: state.snapshot.version,
14
14
  verifiedWith: { ...state.verifiedWith },
15
- types: structuredClone(Object.values(state.types)
16
- .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0))
17
- .map(({ name, fields, sections }) => ({ name, fields, sections }))),
15
+ schema: state.snapshot.schema,
16
+ revision: state.snapshot.revision,
17
+ types: structuredClone(Object.values(state.types).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)),
18
18
  };
19
19
  }
20
20
  export function cached(state) {
@@ -23,3 +23,15 @@ export function cached(state) {
23
23
  export function sameModel(left, right) {
24
24
  return left.identity === right.identity && left.version === right.version;
25
25
  }
26
+ export function sameTyping(left, right) {
27
+ if (left === right)
28
+ return true;
29
+ if (left.status === 'unavailable' || right.status === 'unavailable') {
30
+ return left.status === right.status;
31
+ }
32
+ return (left.snapshot.schema === right.snapshot.schema &&
33
+ sameModel(left.verifiedWith, right.verifiedWith));
34
+ }
35
+ export function referenceField(facts) {
36
+ return facts?.reference !== undefined || facts?.items?.reference !== undefined;
37
+ }
@@ -1,4 +1,4 @@
1
- import type { QueryDocument, QueryGroup, QueryResult } from './query.js';
1
+ import type { QueryCoverage, QueryDocument, QueryGroup, QueryResult } from './query.js';
2
2
  export type Observation<T> = {
3
3
  current(): T;
4
4
  subscribe(listener: (value: T) => void): () => void;
@@ -13,13 +13,18 @@ export type QueryChange = {
13
13
  changed: readonly (readonly [RowKey, QueryDocument | QueryGroup])[];
14
14
  removed: readonly RowKey[];
15
15
  order: readonly RowKey[] | null;
16
+ coverage?: QueryCoverage;
16
17
  };
18
+ export type QueryMessage = KeyedResult | QueryChange;
17
19
  export type Observed = {
18
20
  observation: Observation<unknown>;
19
21
  receive(message: unknown): void;
20
22
  end(): void;
21
23
  };
22
24
  export declare function rowsOf(result: QueryResult): readonly (QueryDocument | QueryGroup)[];
25
+ export declare function whole(message: QueryMessage): message is KeyedResult;
26
+ export declare function applied(keyed: KeyedResult, message: QueryMessage): KeyedResult;
23
27
  export declare function observed(first: unknown, stop: () => void, keyed: boolean): Observed;
24
28
  export declare function opened(watch: (deliver: (message: unknown) => void) => () => void, keyed: boolean): Promise<Observation<unknown>>;
29
+ export declare function observing<Topic extends string>(watch: (topic: Topic, input: readonly unknown[], deliver: (message: unknown) => void) => () => void): (topic: Topic, ...input: unknown[]) => Promise<Observation<unknown>>;
25
30
  //# sourceMappingURL=observation.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzE,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,OAAO,IAAI,CAAC,CAAC;IACb,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACpD,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC;IACpE,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,GAAG,IAAI,IAAI,CAAC;CACb,CAAC;AAEF,wBAAgB,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,aAAa,GAAG,UAAU,CAAC,EAAE,CAEnF;AA0BD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAkCnF;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,MAAM,IAAI,EAC1D,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAiB/B"}
1
+ {"version":3,"file":"observation.d.ts","sourceRoot":"","sources":["../src/observation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,OAAO,IAAI,CAAC,CAAC;IACb,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IACpD,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErC,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC;IACpE,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;AAErD,MAAM,MAAM,QAAQ,GAAG;IACrB,WAAW,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,GAAG,IAAI,IAAI,CAAC;CACb,CAAC;AAEF,wBAAgB,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC,aAAa,GAAG,UAAU,CAAC,EAAE,CAGnF;AAED,wBAAgB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,IAAI,WAAW,CAEnE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,CAkB9E;AAiBD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAkCnF;AAED,wBAAgB,MAAM,CACpB,KAAK,EAAE,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,MAAM,IAAI,EAC1D,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAiB/B;AAED,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAC5C,KAAK,EAAE,CACL,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,SAAS,OAAO,EAAE,EACzB,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAChC,MAAM,IAAI,WAEA,KAAK,YAAY,OAAO,EAAE,KAAG,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,CAQ1E"}
@@ -1,32 +1,48 @@
1
1
  export function rowsOf(result) {
2
- return 'groups' in result ? result.groups : result.documents;
2
+ if ('groups' in result)
3
+ return result.groups;
4
+ return 'documents' in result ? result.documents : [];
5
+ }
6
+ export function whole(message) {
7
+ return 'result' in message;
8
+ }
9
+ export function applied(keyed, message) {
10
+ if (whole(message))
11
+ return message;
12
+ const result = keyed.result;
13
+ if ('pending' in result)
14
+ return keyed;
15
+ const rows = rowsOf(result);
16
+ const byKey = new Map(keyed.keys.map((key, index) => [key, rows[index]]));
17
+ for (const key of message.removed)
18
+ byKey.delete(key);
19
+ for (const [key, row] of message.changed)
20
+ byKey.set(key, row);
21
+ const keys = message.order ?? keyed.keys.filter((key) => byKey.has(key));
22
+ const next = keys.map((key) => byKey.get(key));
23
+ const coverage = message.coverage ?? result.coverage;
24
+ return {
25
+ result: 'groups' in result
26
+ ? { groups: next, coverage }
27
+ : { documents: next, coverage },
28
+ keys,
29
+ };
3
30
  }
4
31
  function keyedResult(first) {
5
- const grouped = 'groups' in first.result;
6
- const rows = rowsOf(first.result);
7
- const byKey = new Map(first.keys.map((key, index) => [key, rows[index]]));
8
- let keys = first.keys;
32
+ let keyed = first;
9
33
  return {
10
34
  value: first.result,
11
35
  next(message) {
12
- const change = message;
13
- for (const key of change.removed)
14
- byKey.delete(key);
15
- for (const [key, row] of change.changed)
16
- byKey.set(key, row);
17
- keys = change.order ?? keys.filter((key) => byKey.has(key));
18
- const next = keys.map((key) => byKey.get(key));
19
- return grouped
20
- ? { groups: next }
21
- : { documents: next };
36
+ keyed = applied(keyed, message);
37
+ return keyed.result;
22
38
  },
23
39
  };
24
40
  }
25
- function whole(first) {
41
+ function replaced(first) {
26
42
  return { value: first, next: (message) => message };
27
43
  }
28
44
  export function observed(first, stop, keyed) {
29
- const reducer = keyed ? keyedResult(first) : whole(first);
45
+ const reducer = keyed ? keyedResult(first) : replaced(first);
30
46
  let value = reducer.value;
31
47
  let open = true;
32
48
  const listeners = new Set();
@@ -83,3 +99,8 @@ export function opened(watch, keyed) {
83
99
  }
84
100
  });
85
101
  }
102
+ export function observing(watch) {
103
+ return (topic, ...input) => opened((deliver) => watch(topic, input, (message) => {
104
+ deliver(structuredClone(message));
105
+ }), topic === 'query');
106
+ }
package/dist/open.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export type Open<Value extends string> = Value | (string & {});
2
+ //# sourceMappingURL=open.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../src/open.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,IAAI,CAAC,KAAK,SAAS,MAAM,IAAI,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC"}
package/dist/open.js ADDED
@@ -0,0 +1 @@
1
+ export {};