@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/memory.js CHANGED
@@ -107,29 +107,30 @@ export function createMemoryAdapter(options = {}) {
107
107
  providerOwnedPaths: room.providerOwnedPaths,
108
108
  };
109
109
  }
110
- function page(room, from) {
110
+ function page(room, after) {
111
111
  const paths = Object.keys(room.documents ?? {}).sort();
112
+ const opening = after === undefined;
113
+ const from = opening ? 0 : paths.filter((path) => path <= after).length;
112
114
  const size = pageSize ?? paths.length;
113
115
  const taken = paths.slice(from, from + size);
114
116
  const next = from + taken.length;
115
- const targets = from === 0 ? (room.binaryTargets ?? []) : [];
117
+ const targets = opening ? Object.keys(room.binaryFiles ?? {}) : [];
116
118
  return {
117
119
  kind: 'bootstrap',
118
120
  roomVersion: room.roomVersion,
119
- ...(from === 0 ? { models: modelsOf(room) } : {}),
121
+ ...(opening ? { models: modelsOf(room) } : {}),
120
122
  documents: named(room.documents ?? {}, taken),
121
- revisions: named(room.revisions ?? {}, taken),
123
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
122
124
  changes: named(room.changes ?? {}, [...taken, ...targets]),
123
- binaryTargets: targets,
124
- ...(from === 0 && room.attachments !== undefined ? { attachments: room.attachments } : {}),
125
- ...(next < paths.length ? { pageToken: String(next) } : {}),
125
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
126
+ ...(next < paths.length ? { pageToken: taken.at(-1) } : {}),
126
127
  };
127
128
  }
128
129
  function advancement(room, from, at) {
129
130
  const current = room.documents ?? {};
130
131
  const previous = from.documents ?? {};
131
- const currentTargets = new Set(room.binaryTargets ?? []);
132
- const previousTargets = new Set(from.binaryTargets ?? []);
132
+ const currentTargets = new Set(Object.keys(room.binaryFiles ?? {}));
133
+ const previousTargets = new Set(Object.keys(from.binaryFiles ?? {}));
133
134
  const headMoved = (path) => room.revisions?.[path] !== from.revisions?.[path] ||
134
135
  !sameChange(room.changes?.[path], from.changes?.[path]);
135
136
  const changed = Object.keys(current)
@@ -145,24 +146,21 @@ export function createMemoryAdapter(options = {}) {
145
146
  const targets = opening
146
147
  ? [...currentTargets].filter((target) => !previousTargets.has(target) || headMoved(target))
147
148
  : [];
148
- const attachments = room.attachments ?? [];
149
- const declared = opening && JSON.stringify(attachments) !== JSON.stringify(from.attachments ?? []);
150
149
  const models = opening ? changedModels(room, from) : undefined;
151
150
  return {
152
151
  kind: 'net-advancement',
153
152
  roomVersion: room.roomVersion,
154
153
  ...(models === undefined ? {} : { models }),
155
154
  documents: named(current, taken),
156
- revisions: named(room.revisions ?? {}, taken),
155
+ revisions: named(room.revisions ?? {}, [...taken, ...targets]),
157
156
  changes: named(room.changes ?? {}, [...taken, ...targets]),
158
- binaryTargets: targets,
157
+ binaryFiles: named(room.binaryFiles ?? {}, targets),
159
158
  removals: opening
160
159
  ? [
161
160
  ...Object.keys(previous).filter((path) => !(path in current) && !currentTargets.has(path)),
162
161
  ...[...previousTargets].filter((target) => !currentTargets.has(target) && !(target in current)),
163
162
  ].sort()
164
163
  : [],
165
- ...(declared ? { attachments } : {}),
166
164
  ...(pageToken === undefined ? {} : { pageToken }),
167
165
  };
168
166
  }
@@ -183,7 +181,7 @@ export function createMemoryAdapter(options = {}) {
183
181
  function historiesOf(input) {
184
182
  const asked = input?.conversations;
185
183
  if (!Array.isArray(asked))
186
- return { kind: 'rejected', code: 'invalid_request', fields: {} };
184
+ return { kind: 'rejected', code: 'invalid_request', fields: {}, retryable: false };
187
185
  const histories = [];
188
186
  for (const entry of asked) {
189
187
  const conversation = typeof entry.conversation === 'string' ? scripted.get(entry.conversation) : undefined;
@@ -211,7 +209,12 @@ export function createMemoryAdapter(options = {}) {
211
209
  const named = typeof input.conversation === 'string' ? input.conversation : '';
212
210
  const conversation = scripted.get(named);
213
211
  if (conversation === undefined) {
214
- return { kind: 'rejected', code: 'unknown-conversation', fields: { conversation: named } };
212
+ return {
213
+ kind: 'rejected',
214
+ code: 'unknown-conversation',
215
+ fields: { conversation: named },
216
+ retryable: false,
217
+ };
215
218
  }
216
219
  const outcome = conversation.outcomes?.[name];
217
220
  if (outcome !== undefined)
@@ -225,7 +228,7 @@ export function createMemoryAdapter(options = {}) {
225
228
  if (name === 'conversation.cancel') {
226
229
  const turn = typeof input.turn === 'string' ? input.turn : '';
227
230
  if (sealed.has(turn) || !unsealed.has(turn)) {
228
- return { kind: 'rejected', code: 'turn-sealed', fields: { turn } };
231
+ return { kind: 'rejected', code: 'turn-sealed', fields: { turn }, retryable: false };
229
232
  }
230
233
  unsealed.delete(turn);
231
234
  return { kind: 'action', result: { turn, cancelled: true } };
@@ -246,6 +249,7 @@ export function createMemoryAdapter(options = {}) {
246
249
  capabilities,
247
250
  providerLimits,
248
251
  retention,
252
+ ...(options.member === undefined ? {} : { member: options.member }),
249
253
  };
250
254
  }
251
255
  return {
@@ -330,6 +334,12 @@ export function createMemoryAdapter(options = {}) {
330
334
  }
331
335
  });
332
336
  },
337
+ reopen() {
338
+ queueMicrotask(() => {
339
+ for (const observer of observers)
340
+ observer({ kind: 'closed', revoked: false });
341
+ });
342
+ },
333
343
  observe(notify) {
334
344
  observers.add(notify);
335
345
  queueMicrotask(() => {
@@ -379,7 +389,7 @@ export function createMemoryAdapter(options = {}) {
379
389
  if (room === undefined) {
380
390
  return { kind: 'room-not-readable', locator: request.locator };
381
391
  }
382
- return page(room, request.pageToken === undefined ? 0 : Number(request.pageToken));
392
+ return page(room, request.pageToken);
383
393
  }, request).then((answer) => note(request.locator, answer));
384
394
  },
385
395
  async refresh(_authorization, request) {
@@ -412,7 +422,13 @@ export function createMemoryAdapter(options = {}) {
412
422
  if (room === undefined) {
413
423
  return { kind: 'room-not-readable', locator: request.locator };
414
424
  }
415
- return { kind: 'rejected', code: 'unscripted-mutation', fields: {}, affected: {} };
425
+ return {
426
+ kind: 'rejected',
427
+ code: 'unscripted-mutation',
428
+ fields: {},
429
+ retryable: false,
430
+ affected: {},
431
+ };
416
432
  }, request).then((answer) => note(request.locator, answer));
417
433
  },
418
434
  async history(_authorization, request) {
@@ -427,11 +443,35 @@ export function createMemoryAdapter(options = {}) {
427
443
  };
428
444
  }, request);
429
445
  },
446
+ async binary(_authorization, request) {
447
+ return resolveScript(scripts.binary, () => {
448
+ if (request.kind === 'reference') {
449
+ return { kind: 'rejected', code: 'unscripted-binary', fields: {}, retryable: false };
450
+ }
451
+ const room = rooms.find((entry) => entry.locator === request.locator);
452
+ if (room === undefined)
453
+ return { kind: 'room-not-readable', locator: request.locator };
454
+ const blob = room.blobs?.[request.path];
455
+ return blob === undefined
456
+ ? { kind: 'rejected', code: 'file_not_found', fields: {}, retryable: false }
457
+ : { kind: 'binary', blob };
458
+ }, request);
459
+ },
460
+ referrerScope(referrer) {
461
+ if (typeof referrer !== 'object' || referrer === null)
462
+ return null;
463
+ const { room, path, message } = referrer;
464
+ if (typeof message === 'string')
465
+ return { kind: 'conversations' };
466
+ if (typeof room !== 'string')
467
+ return null;
468
+ return { kind: 'room', locator: room, ...(typeof path === 'string' ? { path } : {}) };
469
+ },
430
470
  async action(_authorization, request) {
431
471
  return resolveScript(scripts.action, () => {
432
472
  if (request.name.startsWith('conversation.'))
433
473
  return conversationAction(request);
434
- return { kind: 'rejected', code: 'unscripted-action', fields: {} };
474
+ return { kind: 'rejected', code: 'unscripted-action', fields: {}, retryable: false };
435
475
  }, request).then((answer) => {
436
476
  if (answer.kind === 'action' && answer.at !== undefined)
437
477
  note(answer.at.locator, answer.at);
package/dist/model.d.ts CHANGED
@@ -1,12 +1,14 @@
1
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' | '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;
@@ -18,6 +20,8 @@ export type MdType = Definition;
18
20
  export type ModelState = {
19
21
  status: 'unavailable';
20
22
  reason: ModelUnavailableReason;
23
+ schema?: string | null;
24
+ revision?: string | null;
21
25
  } | {
22
26
  status: 'current' | 'cached';
23
27
  snapshot: ModelSnapshot;
@@ -27,17 +31,21 @@ export type ModelState = {
27
31
  export type TypesResult = {
28
32
  status: 'unavailable';
29
33
  reason: ModelUnavailableReason;
34
+ schema?: string | null;
35
+ revision?: string | null;
30
36
  } | {
31
37
  status: 'current' | 'cached';
32
38
  identity: string;
33
39
  version: string;
34
40
  verifiedWith: ModelIdentity;
35
41
  types: readonly MdType[];
42
+ schema: string | null;
43
+ revision: string | null;
36
44
  };
37
45
  export type ValidationReceipt = {
38
46
  identity: string;
39
47
  version: string;
40
- source: 'current' | 'cached';
48
+ source: Open<'current' | 'cached'>;
41
49
  };
42
50
  export declare const NO_MODEL: ModelState;
43
51
  export declare function definitionOf(state: ModelState, type: string | undefined): Definition | undefined;
@@ -1 +1 @@
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;AAElF,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,GAAG,cAAc,GAAG,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC;AAC7F,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;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;AACD,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAErE"}
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,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,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,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAErE"}
package/dist/model.js CHANGED
@@ -12,6 +12,8 @@ export function modelTypes(state) {
12
12
  identity: state.snapshot.identity,
13
13
  version: state.snapshot.version,
14
14
  verifiedWith: { ...state.verifiedWith },
15
+ schema: state.snapshot.schema,
16
+ revision: state.snapshot.revision,
15
17
  types: structuredClone(Object.values(state.types).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0)),
16
18
  };
17
19
  }
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 {};
package/dist/outcome.d.ts CHANGED
@@ -1,8 +1,30 @@
1
- import type { ActionResult } from './adapter.js';
1
+ import type { ActionResult, AdapterFailure, BinaryResult, HistoryResult, ProviderRefusal, RoomVersionAt, ScopedRefusal } from './adapter.js';
2
2
  import type { ChangeBatch } from './change.js';
3
- export type CallResult = ActionResult | {
4
- kind: 'undeclared';
3
+ type Refused<Kind extends string> = ProviderRefusal & {
4
+ kind: Kind;
5
5
  };
6
+ export type Failure = Refused<'transport-uncertainty'> | Refused<'revoked-authorization'> | (Refused<'room-not-readable'> & {
7
+ locator: string;
8
+ }) | ScopedRefusal;
9
+ export type CallResult = {
10
+ kind: 'action';
11
+ result: unknown;
12
+ at?: RoomVersionAt;
13
+ } | Refused<'rejected'> | Refused<'undeclared'> | Failure;
14
+ export type HistoryAnswer = Exclude<HistoryResult, {
15
+ kind: Failure['kind'];
16
+ }> | Failure;
17
+ export type BinaryAnswer = {
18
+ kind: 'binary';
19
+ blob: Blob;
20
+ } | Refused<'rejected'> | Refused<'absent'> | Failure;
21
+ export declare function absentBinary(path: string): BinaryAnswer;
22
+ export declare function binaryAnswer(result: BinaryResult): BinaryAnswer;
23
+ export declare const UNCERTAIN: Failure;
24
+ export declare function undeclared(name: string): CallResult;
25
+ export declare function failure(result: AdapterFailure): Failure;
26
+ export declare function calledResult(result: ActionResult): CallResult;
27
+ export declare function historyAnswer(result: HistoryResult): HistoryAnswer;
6
28
  export type Submission = {
7
29
  readonly state: 'waiting' | 'submitted';
8
30
  } | {
@@ -12,7 +34,10 @@ export type Submission = {
12
34
  export type QueueEntry = {
13
35
  readonly batch: ChangeBatch;
14
36
  } & (Submission | {
37
+ readonly state: 'local';
38
+ } | {
15
39
  readonly state: 'accepted';
16
40
  readonly roomVersion: string;
17
41
  });
42
+ export {};
18
43
  //# sourceMappingURL=outcome.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAE/D,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAAA;CAAE,GAC3C;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,CACvD,UAAU,GACV;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAC/D,CAAC"}
1
+ {"version":3,"file":"outcome.d.ts","sourceRoot":"","sources":["../src/outcome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,aAAa,EACb,eAAe,EACf,aAAa,EACb,aAAa,EACd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,KAAK,OAAO,CAAC,IAAI,SAAS,MAAM,IAAI,eAAe,GAAG;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,CAAC;AAErE,MAAM,MAAM,OAAO,GACf,OAAO,CAAC,uBAAuB,CAAC,GAChC,OAAO,CAAC,uBAAuB,CAAC,GAChC,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,GACpD,aAAa,CAAC;AAElB,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,aAAa,CAAA;CAAE,GACvD,OAAO,CAAC,UAAU,CAAC,GACnB,OAAO,CAAC,YAAY,CAAC,GACrB,OAAO,CAAC;AAEZ,MAAM,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,EAAE;IAAE,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC,GAAG,OAAO,CAAC;AAExF,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC9B,OAAO,CAAC,UAAU,CAAC,GACnB,OAAO,CAAC,QAAQ,CAAC,GACjB,OAAO,CAAC;AAEZ,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,CAEvD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D;AAED,eAAO,MAAM,SAAS,EAAE,OAKvB,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEnD;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAiBvD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,CAE7D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAIlE;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,WAAW,CAAA;CAAE,GAC3C;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExD,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAAG,CACvD,UAAU,GACV;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC3B;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAC/D,CAAC"}
package/dist/outcome.js CHANGED
@@ -1 +1,41 @@
1
- export {};
1
+ export function absentBinary(path) {
2
+ return { kind: 'absent', code: 'binary-file-absent', fields: { path }, retryable: false };
3
+ }
4
+ export function binaryAnswer(result) {
5
+ return result.kind === 'binary' || result.kind === 'rejected' ? result : failure(result);
6
+ }
7
+ export const UNCERTAIN = {
8
+ kind: 'transport-uncertainty',
9
+ code: 'transport-uncertainty',
10
+ fields: {},
11
+ retryable: true,
12
+ };
13
+ export function undeclared(name) {
14
+ return { kind: 'undeclared', code: 'action-undeclared', fields: { name }, retryable: false };
15
+ }
16
+ export function failure(result) {
17
+ switch (result.kind) {
18
+ case 'transport-uncertainty':
19
+ return UNCERTAIN;
20
+ case 'revoked-authorization':
21
+ return { kind: result.kind, code: result.kind, fields: {}, retryable: false };
22
+ case 'room-not-readable':
23
+ return {
24
+ kind: result.kind,
25
+ locator: result.locator,
26
+ code: result.kind,
27
+ fields: {},
28
+ retryable: false,
29
+ };
30
+ case 'scoped-refusal':
31
+ return result;
32
+ }
33
+ }
34
+ export function calledResult(result) {
35
+ return result.kind === 'action' || result.kind === 'rejected' ? result : failure(result);
36
+ }
37
+ export function historyAnswer(result) {
38
+ return result.kind === 'history' || result.kind === 'revision' || result.kind === 'no-history'
39
+ ? result
40
+ : failure(result);
41
+ }
package/dist/overlay.d.ts CHANGED
@@ -1,15 +1,26 @@
1
- import type { HeadChange } from './adapter.js';
1
+ import type { BinaryFile, HeadChange } from './adapter.js';
2
2
  import type { ChangeBatch } from './change.js';
3
3
  export type Heads = {
4
4
  revisions: Readonly<Record<string, string>>;
5
5
  changes: Readonly<Record<string, HeadChange>>;
6
6
  };
7
+ export type HeldBinary = ({
8
+ readonly state: 'accepted';
9
+ } & BinaryFile) | {
10
+ readonly state: 'pending';
11
+ readonly localId: string;
12
+ readonly byteLength: number;
13
+ readonly mediaType: string;
14
+ readonly sha256: string;
15
+ };
7
16
  export type Layer = Heads & {
8
17
  documents: Readonly<Record<string, string>>;
9
- binaryTargets: readonly string[];
18
+ binaries: Readonly<Record<string, HeldBinary>>;
10
19
  };
20
+ export declare function acceptedBinaries(files: Readonly<Record<string, BinaryFile>>): Record<string, HeldBinary>;
21
+ export declare function sameBinary(left: HeldBinary | undefined, right: HeldBinary | undefined): boolean;
11
22
  export declare function sameChange(left: HeadChange | undefined, right: HeadChange | undefined): boolean;
12
- export declare function overlay(base: Layer, queue: readonly ChangeBatch[]): Layer;
23
+ export declare function overlay(base: Layer, queue: readonly ChangeBatch[], unapplied?: () => void): Layer;
13
24
  export declare function sameLayerText(left: Layer, right: Layer): boolean;
14
25
  export declare function overlayChanged(base: Layer, queue: readonly ChangeBatch[], previousBase: Layer, previousQueue: readonly ChangeBatch[], previousVisible: Layer): Layer;
15
26
  //# sourceMappingURL=overlay.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAU,WAAW,EAAgB,MAAM,aAAa,CAAC;AAErE,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG;IAC1B,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;CAClC,CAAC;AAEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAQ/F;AAoJD,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,KAAK,CAiBzE;AAQD,wBAAgB,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAQhE;AAmBD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,YAAY,EAAE,KAAK,EACnB,aAAa,EAAE,SAAS,WAAW,EAAE,EACrC,eAAe,EAAE,KAAK,GACrB,KAAK,CA4FP"}
1
+ {"version":3,"file":"overlay.d.ts","sourceRoot":"","sources":["../src/overlay.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAU,WAAW,EAAgB,MAAM,aAAa,CAAC;AAErE,MAAM,MAAM,KAAK,GAAG;IAClB,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAC/C,CAAC;AAEF,MAAM,MAAM,UAAU,GAClB,CAAC;IAAE,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAAG,UAAU,CAAC,GAC7C;IACE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEN,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG;IAC1B,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CAChD,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,GAC1C,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAI5B;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAW/F;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,SAAS,EAAE,KAAK,EAAE,UAAU,GAAG,SAAS,GAAG,OAAO,CAQ/F;AAoKD,wBAAgB,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,WAAW,EAAE,EAAE,SAAS,CAAC,EAAE,MAAM,IAAI,GAAG,KAAK,CAmBjG;AAQD,wBAAgB,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAOhE;AAiCD,wBAAgB,cAAc,CAC5B,IAAI,EAAE,KAAK,EACX,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,YAAY,EAAE,KAAK,EACnB,aAAa,EAAE,SAAS,WAAW,EAAE,EACrC,eAAe,EAAE,KAAK,GACrB,KAAK,CAyFP"}
package/dist/overlay.js CHANGED
@@ -1,4 +1,18 @@
1
1
  import { apply, parse, serialize } from '@agentshouse/mdmodel';
2
+ export function acceptedBinaries(files) {
3
+ return Object.fromEntries(Object.entries(files).map(([path, file]) => [path, { state: 'accepted', ...file }]));
4
+ }
5
+ export function sameBinary(left, right) {
6
+ if (left === undefined || right === undefined)
7
+ return left === right;
8
+ return (left.state === right.state &&
9
+ left.byteLength === right.byteLength &&
10
+ left.mediaType === right.mediaType &&
11
+ left.sha256 === right.sha256 &&
12
+ (left.state === 'accepted'
13
+ ? right.state === 'accepted' && left.fileRef === right.fileRef
14
+ : right.state === 'pending' && left.localId === right.localId));
15
+ }
2
16
  export function sameChange(left, right) {
3
17
  if (left === undefined || right === undefined)
4
18
  return left === right;
@@ -76,13 +90,15 @@ function edited(document, change, priors) {
76
90
  function edit(staged, change, priors) {
77
91
  const text = staged.documents[change.path];
78
92
  if (text === undefined)
79
- return;
93
+ return false;
80
94
  const parsed = parse(text, change.path);
81
95
  if (!parsed.ok)
82
- return;
96
+ return false;
83
97
  const next = edited(parsed.document, change, priors);
84
- if (next?.outcome === 'applied')
85
- staged.documents[change.path] = serialize(next.document);
98
+ if (next?.outcome !== 'applied')
99
+ return false;
100
+ staged.documents[change.path] = serialize(next.document);
101
+ return true;
86
102
  }
87
103
  function relocate(staged, from, to) {
88
104
  const text = staged.documents[from];
@@ -90,13 +106,15 @@ function relocate(staged, from, to) {
90
106
  delete staged.documents[from];
91
107
  staged.documents[to] = text;
92
108
  }
93
- else if (staged.binaryTargets.delete(from)) {
94
- staged.binaryTargets.add(to);
109
+ else if (staged.binaries[from] !== undefined) {
110
+ staged.binaries[to] = staged.binaries[from];
111
+ delete staged.binaries[from];
95
112
  }
96
113
  else {
97
- return;
114
+ return false;
98
115
  }
99
116
  moveHead(staged, from, to);
117
+ return true;
100
118
  }
101
119
  function moveHead(heads, from, to) {
102
120
  const revision = heads.revisions[from];
@@ -113,46 +131,61 @@ function erase(staged, path) {
113
131
  delete staged.documents[path];
114
132
  delete staged.revisions[path];
115
133
  delete staged.changes[path];
116
- staged.binaryTargets.delete(path);
134
+ delete staged.binaries[path];
117
135
  }
118
136
  function stage(staged, change, priors) {
119
137
  if (change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble') {
120
- edit(staged, change, priors);
121
- return;
138
+ return edit(staged, change, priors);
122
139
  }
123
140
  if (change.kind === 'create') {
124
141
  staged.documents[change.path] =
125
142
  'content' in change ? change.content : compose(change.fields, change.sections);
126
143
  delete staged.changes[change.path];
127
- return;
144
+ return true;
128
145
  }
129
146
  if (change.kind === 'replace') {
130
147
  if (staged.documents[change.path] === undefined)
131
- return;
148
+ return false;
132
149
  staged.documents[change.path] = change.content;
133
- return;
150
+ return true;
151
+ }
152
+ if (change.kind === 'binary') {
153
+ if (staged.documents[change.path] !== undefined)
154
+ return false;
155
+ staged.binaries[change.path] = {
156
+ state: 'pending',
157
+ localId: change.localId,
158
+ byteLength: change.byteLength,
159
+ mediaType: change.mediaType,
160
+ sha256: change.sha256,
161
+ };
162
+ delete staged.revisions[change.path];
163
+ delete staged.changes[change.path];
164
+ return true;
134
165
  }
135
166
  if (change.kind === 'move') {
136
- relocate(staged, change.path, change.to);
137
- return;
167
+ return relocate(staged, change.path, change.to);
138
168
  }
139
169
  erase(staged, change.path);
170
+ return true;
140
171
  }
141
- export function overlay(base, queue) {
172
+ export function overlay(base, queue, unapplied) {
142
173
  const staged = {
143
174
  documents: { ...base.documents },
144
- binaryTargets: new Set(base.binaryTargets),
175
+ binaries: { ...base.binaries },
145
176
  revisions: { ...base.revisions },
146
177
  changes: { ...base.changes },
147
178
  };
148
179
  for (const batch of queue) {
149
180
  const priors = priorsOf(batch.preconditions);
150
- for (const change of batch.changes)
151
- stage(staged, change, priors);
181
+ for (const change of batch.changes) {
182
+ if (!stage(staged, change, priors))
183
+ unapplied?.();
184
+ }
152
185
  }
153
186
  return {
154
187
  documents: staged.documents,
155
- binaryTargets: [...staged.binaryTargets].sort(),
188
+ binaries: staged.binaries,
156
189
  revisions: staged.revisions,
157
190
  changes: staged.changes,
158
191
  };
@@ -164,8 +197,12 @@ export function sameLayerText(left, right) {
164
197
  const paths = Object.keys(left.documents);
165
198
  return (paths.length === Object.keys(right.documents).length &&
166
199
  paths.every((path) => left.documents[path] === right.documents[path]) &&
167
- left.binaryTargets.length === right.binaryTargets.length &&
168
- left.binaryTargets.every((path) => right.binaryTargets.includes(path)));
200
+ sameBinaries(left.binaries, right.binaries));
201
+ }
202
+ function sameBinaries(left, right) {
203
+ const paths = Object.keys(left);
204
+ return (paths.length === Object.keys(right).length &&
205
+ paths.every((path) => sameBinary(left[path], right[path])));
169
206
  }
170
207
  function replayHeads(base, queue) {
171
208
  const heads = { revisions: { ...base.revisions }, changes: { ...base.changes } };
@@ -178,6 +215,10 @@ function replayHeads(base, queue) {
178
215
  else if (change.kind === 'create') {
179
216
  delete heads.changes[change.path];
180
217
  }
218
+ else if (change.kind === 'binary') {
219
+ delete heads.revisions[change.path];
220
+ delete heads.changes[change.path];
221
+ }
181
222
  else if (change.kind === 'move') {
182
223
  moveHead(heads, change.path, change.to);
183
224
  }
@@ -193,7 +234,7 @@ export function overlayChanged(base, queue, previousBase, previousQueue, previou
193
234
  sameLayerText(base, previousBase)) {
194
235
  return {
195
236
  documents: previousVisible.documents,
196
- binaryTargets: previousVisible.binaryTargets,
237
+ binaries: previousVisible.binaries,
197
238
  ...replayHeads(base, queue),
198
239
  };
199
240
  }
@@ -205,14 +246,14 @@ export function overlayChanged(base, queue, previousBase, previousQueue, previou
205
246
  ...Object.keys(previousBase.revisions),
206
247
  ...Object.keys(base.changes),
207
248
  ...Object.keys(previousBase.changes),
208
- ...base.binaryTargets,
209
- ...previousBase.binaryTargets,
249
+ ...Object.keys(base.binaries),
250
+ ...Object.keys(previousBase.binaries),
210
251
  ]);
211
252
  for (const path of paths) {
212
253
  if (base.documents[path] !== previousBase.documents[path] ||
213
254
  base.revisions[path] !== previousBase.revisions[path] ||
214
255
  !sameChange(base.changes[path], previousBase.changes[path]) ||
215
- base.binaryTargets.includes(path) !== previousBase.binaryTargets.includes(path))
256
+ !sameBinary(base.binaries[path], previousBase.binaries[path]))
216
257
  affected.add(path);
217
258
  }
218
259
  const oldIds = new Set(before);
@@ -245,6 +286,7 @@ export function overlayChanged(base, queue, previousBase, previousQueue, previou
245
286
  const documents = {};
246
287
  const revisions = {};
247
288
  const changes = {};
289
+ const binaries = {};
248
290
  for (const path of affected) {
249
291
  if (base.documents[path] !== undefined)
250
292
  documents[path] = base.documents[path];
@@ -252,32 +294,28 @@ export function overlayChanged(base, queue, previousBase, previousQueue, previou
252
294
  revisions[path] = base.revisions[path];
253
295
  if (base.changes[path] !== undefined)
254
296
  changes[path] = base.changes[path];
297
+ if (base.binaries[path] !== undefined)
298
+ binaries[path] = base.binaries[path];
255
299
  }
256
- const staged = overlay({
257
- documents,
258
- revisions,
259
- changes,
260
- binaryTargets: base.binaryTargets.filter((path) => affected.has(path)),
261
- }, queue.filter((batch) => pathsOf(batch).some((path) => affected.has(path))));
300
+ const staged = overlay({ documents, revisions, changes, binaries }, queue.filter((batch) => pathsOf(batch).some((path) => affected.has(path))));
262
301
  const mergedDocuments = { ...previousVisible.documents };
263
302
  const mergedRevisions = { ...previousVisible.revisions };
264
303
  const mergedChanges = { ...previousVisible.changes };
265
- const mergedTargets = new Set(previousVisible.binaryTargets);
304
+ const mergedBinaries = { ...previousVisible.binaries };
266
305
  for (const path of affected) {
267
306
  delete mergedDocuments[path];
268
307
  delete mergedRevisions[path];
269
308
  delete mergedChanges[path];
270
- mergedTargets.delete(path);
309
+ delete mergedBinaries[path];
271
310
  }
272
311
  Object.assign(mergedDocuments, staged.documents);
273
312
  Object.assign(mergedRevisions, staged.revisions);
274
313
  Object.assign(mergedChanges, staged.changes);
275
- for (const path of staged.binaryTargets)
276
- mergedTargets.add(path);
314
+ Object.assign(mergedBinaries, staged.binaries);
277
315
  return {
278
316
  documents: mergedDocuments,
279
317
  revisions: mergedRevisions,
280
318
  changes: mergedChanges,
281
- binaryTargets: [...mergedTargets].sort(),
319
+ binaries: mergedBinaries,
282
320
  };
283
321
  }
package/dist/query.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type Definition } from '@agentshouse/mdmodel';
2
2
  import type { HeadChange } from './adapter.js';
3
+ import type { BinaryFileRecord } from './binary.js';
3
4
  export type Value = string | number | boolean | null;
4
5
  export type Predicate = Value | {
5
6
  $eq: Value;
@@ -93,6 +94,7 @@ export type QueryDocument = {
93
94
  markdown?: string;
94
95
  backlinks?: readonly Backlink[];
95
96
  change?: HeadChange | null;
97
+ binaryFile?: BinaryFileRecord;
96
98
  };
97
99
  export type QueryGroup = {
98
100
  key: readonly unknown[];
@@ -204,6 +206,8 @@ export type Plan = {
204
206
  limit: number | null;
205
207
  };
206
208
  export declare class QueryError extends Error {
209
+ readonly code: QueryErrorCode;
210
+ readonly retryable = false;
207
211
  constructor(code: QueryErrorCode, at: string, problem: string);
208
212
  }
209
213
  type Entries = Readonly<Record<string, unknown>>;