@agentshouse/mdruntime 0.1.0-cd507e16e5fc0 → 0.1.0-cd574a610e9c8

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 (269) hide show
  1. package/README.md +21 -19
  2. package/dist/acceptance.d.ts +0 -3
  3. package/dist/acceptance.d.ts.map +1 -1
  4. package/dist/acceptance.js +75 -165
  5. package/dist/act-lanes.d.ts +30 -0
  6. package/dist/act-lanes.d.ts.map +1 -0
  7. package/dist/act-lanes.js +225 -0
  8. package/dist/actions.d.ts +8 -2
  9. package/dist/actions.d.ts.map +1 -1
  10. package/dist/actions.js +118 -67
  11. package/dist/adapter.d.ts +90 -58
  12. package/dist/adapter.d.ts.map +1 -1
  13. package/dist/attached-model.d.ts +0 -1
  14. package/dist/attached-model.d.ts.map +1 -1
  15. package/dist/attached-model.js +0 -5
  16. package/dist/authored.d.ts +88 -0
  17. package/dist/authored.d.ts.map +1 -0
  18. package/dist/authored.js +345 -0
  19. package/dist/bootstrap.d.ts +1 -1
  20. package/dist/bootstrap.d.ts.map +1 -1
  21. package/dist/bootstrap.js +6 -19
  22. package/dist/change-set.d.ts +4 -0
  23. package/dist/change-set.d.ts.map +1 -1
  24. package/dist/change-set.js +6 -0
  25. package/dist/change.d.ts +4 -0
  26. package/dist/change.d.ts.map +1 -1
  27. package/dist/change.js +7 -2
  28. package/dist/chat-types.d.ts +0 -2
  29. package/dist/chat-types.d.ts.map +1 -1
  30. package/dist/chat-types.js +0 -2
  31. package/dist/client.d.ts +13 -20
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +36 -20
  34. package/dist/collection.d.ts +25 -4
  35. package/dist/collection.d.ts.map +1 -1
  36. package/dist/collection.js +19 -2
  37. package/dist/column.d.ts +5 -0
  38. package/dist/column.d.ts.map +1 -0
  39. package/dist/column.js +9 -0
  40. package/dist/compile.d.ts +2 -0
  41. package/dist/compile.d.ts.map +1 -1
  42. package/dist/compile.js +31 -25
  43. package/dist/connection.d.ts.map +1 -1
  44. package/dist/connection.js +31 -24
  45. package/dist/context.d.ts.map +1 -1
  46. package/dist/context.js +1 -1
  47. package/dist/conversation-live.d.ts +26 -12
  48. package/dist/conversation-live.d.ts.map +1 -1
  49. package/dist/conversation-live.js +23 -12
  50. package/dist/conversation-row.d.ts +8 -1
  51. package/dist/conversation-row.d.ts.map +1 -1
  52. package/dist/conversation-row.js +20 -7
  53. package/dist/conversation.d.ts +37 -12
  54. package/dist/conversation.d.ts.map +1 -1
  55. package/dist/conversation.js +320 -234
  56. package/dist/declaration.d.ts +10 -0
  57. package/dist/declaration.d.ts.map +1 -0
  58. package/dist/declaration.js +24 -0
  59. package/dist/discovery.d.ts.map +1 -1
  60. package/dist/discovery.js +19 -44
  61. package/dist/durability.d.ts +4 -0
  62. package/dist/durability.d.ts.map +1 -1
  63. package/dist/durability.js +4 -0
  64. package/dist/entry.js +1 -1
  65. package/dist/expectation.d.ts +26 -13
  66. package/dist/expectation.d.ts.map +1 -1
  67. package/dist/expectation.js +72 -19
  68. package/dist/failure.d.ts +3 -0
  69. package/dist/failure.d.ts.map +1 -1
  70. package/dist/failure.js +6 -0
  71. package/dist/figures.d.ts.map +1 -1
  72. package/dist/figures.js +4 -2
  73. package/dist/file.d.ts +1 -1
  74. package/dist/file.d.ts.map +1 -1
  75. package/dist/file.js +3 -2
  76. package/dist/host.d.ts +18 -2
  77. package/dist/host.d.ts.map +1 -1
  78. package/dist/host.js +59 -15
  79. package/dist/index.d.ts +16 -11
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +12 -7
  82. package/dist/install.d.ts +10 -6
  83. package/dist/install.d.ts.map +1 -1
  84. package/dist/install.js +92 -111
  85. package/dist/lifecycle.d.ts +1 -1
  86. package/dist/lifecycle.d.ts.map +1 -1
  87. package/dist/lifecycle.js +54 -40
  88. package/dist/listing.d.ts +11 -12
  89. package/dist/listing.d.ts.map +1 -1
  90. package/dist/listing.js +48 -72
  91. package/dist/live.d.ts +5 -3
  92. package/dist/live.d.ts.map +1 -1
  93. package/dist/live.js +74 -33
  94. package/dist/loaded.d.ts +5 -0
  95. package/dist/loaded.d.ts.map +1 -0
  96. package/dist/loaded.js +40 -0
  97. package/dist/locks.d.ts +2 -4
  98. package/dist/locks.d.ts.map +1 -1
  99. package/dist/locks.js +10 -39
  100. package/dist/lost.d.ts.map +1 -1
  101. package/dist/lost.js +11 -23
  102. package/dist/media.d.ts +6 -1
  103. package/dist/media.d.ts.map +1 -1
  104. package/dist/media.js +68 -17
  105. package/dist/memory.d.ts +8 -3
  106. package/dist/memory.d.ts.map +1 -1
  107. package/dist/memory.js +92 -33
  108. package/dist/messages.d.ts +12 -6
  109. package/dist/messages.d.ts.map +1 -1
  110. package/dist/messages.js +30 -38
  111. package/dist/model.d.ts +0 -1
  112. package/dist/model.d.ts.map +1 -1
  113. package/dist/model.js +0 -5
  114. package/dist/models.d.ts +4 -8
  115. package/dist/models.d.ts.map +1 -1
  116. package/dist/models.js +97 -139
  117. package/dist/observation.d.ts +27 -12
  118. package/dist/observation.d.ts.map +1 -1
  119. package/dist/observation.js +184 -85
  120. package/dist/opened.d.ts +1 -1
  121. package/dist/opened.d.ts.map +1 -1
  122. package/dist/opened.js +5 -5
  123. package/dist/opening.d.ts.map +1 -1
  124. package/dist/opening.js +5 -9
  125. package/dist/outcome.d.ts +13 -1
  126. package/dist/outcome.d.ts.map +1 -1
  127. package/dist/outcome.js +32 -2
  128. package/dist/overlay.d.ts +6 -2
  129. package/dist/overlay.d.ts.map +1 -1
  130. package/dist/overlay.js +37 -24
  131. package/dist/page-metadata.d.ts +8 -0
  132. package/dist/page-metadata.d.ts.map +1 -0
  133. package/dist/page-metadata.js +19 -0
  134. package/dist/parts.d.ts +3 -58
  135. package/dist/parts.d.ts.map +1 -1
  136. package/dist/parts.js +10 -115
  137. package/dist/preparation.d.ts +27 -6
  138. package/dist/preparation.d.ts.map +1 -1
  139. package/dist/preparation.js +156 -68
  140. package/dist/presence.d.ts +58 -0
  141. package/dist/presence.d.ts.map +1 -0
  142. package/dist/presence.js +231 -0
  143. package/dist/queries.d.ts +2 -2
  144. package/dist/queries.d.ts.map +1 -1
  145. package/dist/queries.js +67 -31
  146. package/dist/query.d.ts +0 -1
  147. package/dist/query.d.ts.map +1 -1
  148. package/dist/questions.d.ts +1 -5
  149. package/dist/questions.d.ts.map +1 -1
  150. package/dist/questions.js +1 -7
  151. package/dist/queue.d.ts +40 -0
  152. package/dist/queue.d.ts.map +1 -0
  153. package/dist/queue.js +480 -0
  154. package/dist/reach.d.ts +2 -3
  155. package/dist/reach.d.ts.map +1 -1
  156. package/dist/reach.js +88 -26
  157. package/dist/react.d.ts +8 -1
  158. package/dist/react.d.ts.map +1 -1
  159. package/dist/react.js +33 -1
  160. package/dist/readiness.d.ts +9 -3
  161. package/dist/readiness.d.ts.map +1 -1
  162. package/dist/readiness.js +3 -5
  163. package/dist/reads.d.ts +4 -2
  164. package/dist/reads.d.ts.map +1 -1
  165. package/dist/reads.js +11 -4
  166. package/dist/recovery.d.ts +3 -1
  167. package/dist/recovery.d.ts.map +1 -1
  168. package/dist/recovery.js +29 -7
  169. package/dist/refresh.js +2 -2
  170. package/dist/refusal.d.ts.map +1 -1
  171. package/dist/refusal.js +5 -6
  172. package/dist/replica.d.ts +5 -11
  173. package/dist/replica.d.ts.map +1 -1
  174. package/dist/replica.js +15 -17
  175. package/dist/retried.d.ts +30 -0
  176. package/dist/retried.d.ts.map +1 -0
  177. package/dist/retried.js +72 -0
  178. package/dist/room-draft.d.ts +31 -8
  179. package/dist/room-draft.d.ts.map +1 -1
  180. package/dist/room-draft.js +273 -66
  181. package/dist/room-drafts.d.ts.map +1 -1
  182. package/dist/room-drafts.js +22 -18
  183. package/dist/room-list.d.ts +10 -0
  184. package/dist/room-list.d.ts.map +1 -0
  185. package/dist/room-list.js +45 -0
  186. package/dist/rows.d.ts +2 -1
  187. package/dist/rows.d.ts.map +1 -1
  188. package/dist/rows.js +9 -10
  189. package/dist/runtime.d.ts +9 -18
  190. package/dist/runtime.d.ts.map +1 -1
  191. package/dist/save.d.ts +42 -90
  192. package/dist/save.d.ts.map +1 -1
  193. package/dist/save.js +327 -229
  194. package/dist/saves.d.ts +4 -40
  195. package/dist/saves.d.ts.map +1 -1
  196. package/dist/saves.js +143 -714
  197. package/dist/seed.d.ts.map +1 -1
  198. package/dist/seed.js +4 -5
  199. package/dist/shared.d.ts +0 -5
  200. package/dist/shared.d.ts.map +1 -1
  201. package/dist/shared.js +4 -90
  202. package/dist/shown.d.ts +7 -5
  203. package/dist/shown.d.ts.map +1 -1
  204. package/dist/shown.js +77 -63
  205. package/dist/socket/lanes.d.ts +12 -4
  206. package/dist/socket/lanes.d.ts.map +1 -1
  207. package/dist/socket/lanes.js +34 -8
  208. package/dist/socket/session.d.ts +0 -1
  209. package/dist/socket/session.d.ts.map +1 -1
  210. package/dist/socket.d.ts +3 -6
  211. package/dist/socket.d.ts.map +1 -1
  212. package/dist/socket.js +5 -16
  213. package/dist/source.d.ts +5 -7
  214. package/dist/source.d.ts.map +1 -1
  215. package/dist/source.js +18 -6
  216. package/dist/store/installs.d.ts +2 -2
  217. package/dist/store/installs.d.ts.map +1 -1
  218. package/dist/store/installs.js +10 -4
  219. package/dist/store/readiness.d.ts +5 -4
  220. package/dist/store/readiness.d.ts.map +1 -1
  221. package/dist/store/readiness.js +28 -12
  222. package/dist/store/records.d.ts +18 -7
  223. package/dist/store/records.d.ts.map +1 -1
  224. package/dist/store/records.js +58 -24
  225. package/dist/store/rooms-shown.d.ts +8 -0
  226. package/dist/store/rooms-shown.d.ts.map +1 -0
  227. package/dist/store/rooms-shown.js +13 -0
  228. package/dist/store/space.d.ts +1 -1
  229. package/dist/store/space.d.ts.map +1 -1
  230. package/dist/store/space.js +0 -2
  231. package/dist/store/watchers.js +1 -2
  232. package/dist/store.d.ts +23 -14
  233. package/dist/store.d.ts.map +1 -1
  234. package/dist/store.js +46 -17
  235. package/dist/stored.d.ts +25 -14
  236. package/dist/stored.d.ts.map +1 -1
  237. package/dist/stored.js +83 -32
  238. package/dist/surface.d.ts +5 -3
  239. package/dist/surface.d.ts.map +1 -1
  240. package/dist/surface.js +25 -23
  241. package/dist/sync.d.ts +1 -1
  242. package/dist/sync.d.ts.map +1 -1
  243. package/dist/sync.js +96 -92
  244. package/dist/tables.d.ts +16 -57
  245. package/dist/tables.d.ts.map +1 -1
  246. package/dist/tables.js +91 -332
  247. package/dist/tallies.d.ts.map +1 -1
  248. package/dist/tallies.js +6 -7
  249. package/dist/validation.d.ts.map +1 -1
  250. package/dist/validation.js +4 -10
  251. package/dist/wire.d.ts +53 -7
  252. package/dist/wire.d.ts.map +1 -1
  253. package/dist/wire.js +17 -4
  254. package/package.json +3 -2
  255. package/dist/attempt.d.ts +0 -16
  256. package/dist/attempt.d.ts.map +0 -1
  257. package/dist/attempt.js +0 -70
  258. package/dist/job.d.ts +0 -33
  259. package/dist/job.d.ts.map +0 -1
  260. package/dist/job.js +0 -54
  261. package/dist/log.d.ts +0 -6
  262. package/dist/log.d.ts.map +0 -1
  263. package/dist/log.js +0 -14
  264. package/dist/socket/rooms.d.ts +0 -44
  265. package/dist/socket/rooms.d.ts.map +0 -1
  266. package/dist/socket/rooms.js +0 -90
  267. package/dist/store/fences.d.ts +0 -16
  268. package/dist/store/fences.d.ts.map +0 -1
  269. package/dist/store/fences.js +0 -26
package/README.md CHANGED
@@ -12,14 +12,14 @@ npm install @agentshouse/mdruntime
12
12
 
13
13
  ## Entries
14
14
 
15
- | Entry | For |
16
- | ------------------------------- | ----------------------------------------------------------------------------------- |
17
- | `@agentshouse/mdruntime/client` | The host's client: `connectMdRuntime(port)` |
18
- | `@agentshouse/mdruntime/host` | The host that serves a Runtime: `serveMdRuntime` |
19
- | `@agentshouse/mdruntime` | Shared types |
20
- | `@agentshouse/mdruntime/memory` | Tests: `createMemoryAdapter`, an in-memory Adapter |
21
- | `@agentshouse/mdruntime/tables` | The host's database: the Authored store's and opened files' tables, `answerRuntime` |
22
- | `@agentshouse/mdruntime/react` | React over the client: `useObserve`, `useSave` |
15
+ | Entry | For |
16
+ | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
17
+ | `@agentshouse/mdruntime/client` | The host's client: `connectMdRuntime(port)` |
18
+ | `@agentshouse/mdruntime/host` | The host that serves a Runtime: `serveMdRuntime` |
19
+ | `@agentshouse/mdruntime` | Shared types |
20
+ | `@agentshouse/mdruntime/memory` | Tests: `createMemoryAdapter`, an in-memory Adapter |
21
+ | `@agentshouse/mdruntime/tables` | The host's database: `formatted` lays it out for a device format, keeping the Authored store's tables and creating any it lacks, and `answerRuntime` answers it |
22
+ | `@agentshouse/mdruntime/react` | React over the client: `useObserve`, `useSave`; `useExpected`, a reader of an expectation store; `useLane`, a reader of an act lane |
23
23
 
24
24
  ## Usage
25
25
 
@@ -33,24 +33,26 @@ const rooms = await runtime.rooms();
33
33
  const notes = await runtime.query({ types: ['note'], select: 'all', limit: 20 });
34
34
  ```
35
35
 
36
- `observe('storage-loss')` reports `null` or the stable code
37
- `storage-loss` when unsynchronized Room Drafts and Pending Changes were lost.
38
- The host supplies the user-facing wording.
36
+ `observe('storage-loss')` reports `null`, the stable code `storage-loss` when
37
+ unsynchronized Room Drafts and Pending Changes were lost, or `visit` while the host holds
38
+ the database in memory, which ends with the visit; the readiness `persistence` answer is then
39
+ `memory`. The host supplies the user-facing wording.
39
40
 
40
41
  In House the bridge object the page holds as `window.houseBridge` places the Chat, which
41
- House serves with the page: install and bundle nothing for it. Mount it in an element,
42
- themed by CSS custom properties on that element, docked at a third of the window:
42
+ House serves with the page: install and bundle nothing for it. Mount it in an element it
43
+ fills, where it lays out the User's chats by the element's width, themed by CSS custom
44
+ properties on that element, or as the Chat button, House's dot that opens it in a sheet:
43
45
 
44
46
  ```ts
45
- const chat = await window.houseBridge.chat.mount(element, { width: '1/3', showChats: true });
47
+ const chat = await window.houseBridge.chat.mount(element, { conversation });
46
48
  element.style.setProperty('--chat-accent', '#2a6cf0');
47
- chat.update({ width: 'full', showChats: true });
48
- chat.unmount();
49
+ chat.update({ conversation: null, agent });
50
+ const button = await window.houseBridge.chat.mountButton({});
51
+ button.open({ agent });
49
52
  ```
50
53
 
51
- The rules an App's agent follows, including Local Query, search, Room
52
- Draft, Save and the Chat, are the `apps/` pages of House's Guide, which House's
53
- `guide/open` opens.
54
+ The rules an App's agent follows, including Local Query, search, Room Draft, Save and the
55
+ Chat, are the `apps/` pages of House's Guide, which House's `guide/open` opens.
54
56
 
55
57
  ## License
56
58
 
@@ -1,6 +1,3 @@
1
1
  import type { Runtime } from './runtime.js';
2
- import type { RuntimeStore } from './store.js';
3
- export declare function unpair(runtime: Runtime, local: RuntimeStore): Promise<void>;
4
2
  export declare function submitLater(runtime: Runtime, locator: string): void;
5
- export declare function submitAll(runtime: Runtime): Promise<void>;
6
3
  //# sourceMappingURL=acceptance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AAkO5D,wBAAsB,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF;AAoOD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,QAK5D;AA4BD,wBAAsB,SAAS,CAAC,OAAO,EAAE,OAAO,iBAM/C"}
1
+ {"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AA0V5C,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,QAK5D"}
@@ -1,19 +1,19 @@
1
+ import { refusalError } from './failure.js';
1
2
  import { changeSet } from './change-set.js';
3
+ import { declared } from './declaration.js';
2
4
  import { leaving as leavingIn, partnerOf } from './change.js';
3
- import { runtimeError } from './failure.js';
4
5
  import { olderThan, showing } from './install.js';
5
- import { readable } from './listing.js';
6
+ import { scoped } from './models.js';
7
+ import { answered, settle } from './queue.js';
6
8
  import { refuse } from './refusal.js';
7
- import { landed, returnedPaths, returning, slicing, touchedBy } from './replica.js';
8
- import { batchFile, landedWhole, settle, settlement, sliceAt, together, unpairing, withdrawable, } from './saves.js';
9
+ import { returnedPaths, returning, slicing } from './replica.js';
10
+ import { batchFile } from './saves.js';
9
11
  import { rest, roomUnreadable, statusShown } from './shown.js';
12
+ import { advanced, withhold } from './sync.js';
10
13
  import { unconfirmed } from './transfer.js';
11
14
  import { stepped } from './turn.js';
12
- function pendingKey(locator, id) {
13
- return `${locator}\u0000${id}`;
14
- }
15
15
  async function mark(runtime, local, locator, batch, submission, lost) {
16
- const { store, socket } = runtime;
16
+ const { store, socket, presence } = runtime;
17
17
  const partner = partnerOf(batch, locator);
18
18
  for (const held of partner === null ? [locator] : [locator, partner]) {
19
19
  const { state, room } = await local.pending(held, batch.id);
@@ -23,116 +23,86 @@ async function mark(runtime, local, locator, batch, submission, lost) {
23
23
  continue;
24
24
  }
25
25
  await local.submit(held, batch.id, submission, lost);
26
- if (store.fences.has(held))
26
+ if (presence.lost(held))
27
27
  continue;
28
28
  if (room)
29
29
  store.changed(changeSet(held, { queue: true }));
30
30
  }
31
31
  statusShown(runtime);
32
32
  }
33
- async function keepUpload({ store, socket }, local, locator, identifier, upload) {
33
+ async function keepUpload({ socket, presence }, local, locator, identifier, upload) {
34
34
  if (!socket.continuing())
35
- throw new Error('connection refused');
35
+ throw new Error();
36
36
  await local.keepUpload(locator, identifier, upload);
37
- if (store.fences.has(locator))
38
- throw runtimeError('unknown-room', `Unknown Room ${locator}`);
37
+ if (presence.lost(locator))
38
+ throw new Error();
39
39
  if (!socket.continuing())
40
- throw new Error('connection refused');
41
- }
42
- function leaving(batch, result) {
43
- return {
44
- batch,
45
- returned: {
46
- kind: result.kind,
47
- code: result.code,
48
- fields: result.fields,
49
- retryable: result.retryable,
50
- },
51
- };
52
- }
53
- function logAccepted({ journal }, locator, submitted, accepted) {
54
- journal.record(`outcome ${locator} ${submitted.id} accepted ${accepted.roomVersion}` +
55
- (accepted.author === undefined ? '' : ` author ${accepted.author}`) +
56
- (accepted.time === undefined ? '' : ` time ${accepted.time}`));
57
- }
58
- function settling(acceptance) {
59
- return acceptance !== null && 'apply' in acceptance;
40
+ throw new Error();
60
41
  }
61
- function failureOf(acceptance) {
62
- return settling(acceptance) ? null : acceptance;
42
+ function restands(adoptions) {
43
+ return adoptions.flatMap((one) => (one === null || !('record' in one) ? [] : [one]));
63
44
  }
64
- async function acceptance(runtime, room, local, submitted, accepted) {
45
+ async function adoption(runtime, room, current, local, submitted, accepted) {
65
46
  const { store, socket } = runtime;
66
47
  if (!socket.continuing())
67
48
  return unconfirmed;
68
- const work = await store.work(room.locator);
69
- const current = work.replica;
70
49
  if (current === undefined || !current.queue.some((batch) => batch.id === submitted.id)) {
71
50
  return null;
72
51
  }
73
52
  const held = current.record.roomVersion;
74
- logAccepted(runtime, room.locator, submitted, accepted);
75
53
  let record = current.record;
76
- let changes;
54
+ let adopted;
77
55
  if (!socket.reads.reached(room.locator, held, accepted.roomVersion) &&
78
56
  !olderThan(runtime, room.locator, accepted.roomVersion, held)) {
79
57
  const paths = [...returnedPaths(submitted, accepted)];
80
58
  const confirmedLayer = await stepped(slicing(await local.entries(record.key, 'confirmed', paths), paths));
81
- const back = await stepped(returning(confirmedLayer, submitted, accepted, accepted.roomVersion, store.composed(record)));
59
+ adopted = await stepped(returning(confirmedLayer, submitted, accepted, accepted.roomVersion, store.composed(record)));
82
60
  record = {
83
61
  ...record,
84
62
  roomVersion: socket.follows(room.locator, held, accepted.roomVersion)
85
63
  ? accepted.roomVersion
86
64
  : held,
87
65
  };
88
- changes = back;
89
66
  }
90
- const settled = await settlement(runtime, local, room.locator, work, record, current.queue.filter((batch) => batch.id !== submitted.id), { room: true, ...(changes === undefined ? {} : { changes }) });
91
67
  const reached = record.roomVersion;
92
68
  return {
93
- ...settled,
94
- apply(answer) {
95
- const set = settled.apply(answer);
69
+ locator: room.locator,
70
+ record,
71
+ accepted: submitted.id,
72
+ ...(adopted === undefined ? {} : { adopted }),
73
+ after() {
96
74
  showing(runtime, room.locator, accepted.roomVersion, reached);
97
- readable(runtime, room);
98
- return set;
75
+ runtime.presence.readable(room.locator);
99
76
  },
100
77
  };
101
78
  }
102
- async function adoptedTogether(runtime, local, acceptances) {
103
- const settlements = acceptances.filter(settling);
104
- if (settlements.length > 0) {
105
- const set = await together(runtime, local, settlements);
106
- void statusShown(runtime);
107
- void runtime.store.changed(set);
108
- }
109
- await unpair(runtime, local);
110
- }
111
79
  async function adopted(runtime, room, local, submitted, accepted) {
112
- const failed = await runtime.store.exclusive(async () => {
113
- const adopting = await acceptance(runtime, room, local, submitted, accepted);
114
- await adoptedTogether(runtime, local, [adopting]);
115
- return failureOf(adopting);
80
+ let kept = true;
81
+ await settle(runtime, [room.locator], async (held) => {
82
+ const adopting = await adoption(runtime, room, held.get(room.locator)?.replica, local, submitted, accepted);
83
+ kept = adopting !== unconfirmed;
84
+ return restands([adopting]);
116
85
  });
117
- return failed === null;
86
+ return kept;
118
87
  }
119
88
  async function adoptedMove(runtime, room, partner, local, submitted, accepted) {
120
- const { store, socket } = runtime;
121
- const other = socket.rooms.discovered(partner);
122
- const failed = await store.exclusive(async () => {
123
- const left = await acceptance(runtime, room, local, submitted, accepted);
124
- const arriving = (await store.replica(partner))?.queue.find((batch) => batch.id === submitted.id);
89
+ const other = runtime.presence.room(partner);
90
+ let kept = true;
91
+ await settle(runtime, [room.locator, partner], async (held) => {
92
+ const left = await adoption(runtime, room, held.get(room.locator)?.replica, local, submitted, accepted);
93
+ const there = held.get(partner)?.replica;
94
+ const arriving = there?.queue.find((batch) => batch.id === submitted.id);
125
95
  const arrived = other === undefined || arriving === undefined || accepted.destination === undefined
126
96
  ? null
127
- : await acceptance(runtime, other, local, arriving, {
97
+ : await adoption(runtime, other, there, local, arriving, {
128
98
  kind: 'accepted',
129
99
  ...accepted.destination,
130
100
  });
131
- await adoptedTogether(runtime, local, [left, arrived]);
132
- return failureOf(left);
101
+ kept = left !== unconfirmed;
102
+ return restands([left, arrived]);
133
103
  });
134
104
  submitLater(runtime, partner);
135
- return failed === null;
105
+ return kept;
136
106
  }
137
107
  async function behindIn({ store }, locator, batch) {
138
108
  const local = await store.open();
@@ -142,38 +112,12 @@ async function behindIn({ store }, locator, batch) {
142
112
  ]);
143
113
  return room ? order.indexOf(batch.id) > 0 : order.length > 0;
144
114
  }
145
- async function unpaired(local, skipped) {
146
- const { queued, moving } = await local.moving();
147
- for (const { locator, batch, state } of moving) {
148
- const partner = partnerOf(batch, locator);
149
- if (partner === null || skipped.has(pendingKey(locator, batch.id)))
150
- continue;
151
- if (queued.get(partner)?.includes(batch.id) === true)
152
- continue;
153
- if (!leavingIn(batch, locator) || withdrawable(new Map([[batch.id, state]]))(batch)) {
154
- return { locator, batch };
155
- }
156
- }
157
- return null;
158
- }
159
- export async function unpair(runtime, local) {
160
- const { store, socket } = runtime;
161
- const handled = new Set();
162
- for (let held = await unpaired(local, handled); held !== null && socket.continuing(); held = await unpaired(local, handled)) {
163
- const { locator, batch } = held;
164
- handled.add(pendingKey(locator, batch.id));
165
- store.changed(await together(runtime, local, [await unpairing(runtime, local, locator, [batch])]));
166
- }
167
- if (handled.size === 0)
168
- return;
169
- statusShown(runtime);
170
- }
171
115
  async function submitRoom(runtime, room, local, authorized, progress, signal) {
172
- const { store, socket, journal, advanced, withhold } = runtime;
116
+ const { store, socket, presence } = runtime;
173
117
  while (socket.continuing() &&
174
118
  socket.session.now().authorization !== undefined &&
175
119
  !signal.aborted) {
176
- const headId = (await local.order(room.locator)).find((id) => store.landed.of(room.locator, id) === undefined);
120
+ const headId = (await local.order(room.locator)).find((id) => store.conflicted.of(room.locator, id) === undefined);
177
121
  if (headId === undefined)
178
122
  return 'done';
179
123
  const [head, pending] = await Promise.all([
@@ -202,27 +146,24 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
202
146
  }
203
147
  if (socket.writesHeld()) {
204
148
  progress.complete = false;
205
- journal.record(`submission ${room.locator} ${head.id} held`);
206
149
  return 'done';
207
150
  }
208
151
  const lost = earlier || submission.state === 'submitted';
209
152
  let result;
210
- journal.record(`submission ${room.locator} ${head.id}`);
211
153
  await store.exclusive(() => mark(runtime, local, room.locator, head, { state: 'submitted' }, lost));
212
- if (socket.session.now().paused || store.fences.has(room.locator))
154
+ if (socket.session.now().paused || presence.lost(room.locator))
213
155
  return 'done';
214
156
  if (signal.aborted || socket.writesHeld()) {
215
157
  await store.exclusive(() => mark(runtime, local, room.locator, head, submission, earlier));
216
158
  if (signal.aborted)
217
159
  return 'done';
218
160
  progress.complete = false;
219
- journal.record(`submission ${room.locator} ${head.id} held`);
220
161
  return 'done';
221
162
  }
222
163
  const opensBefore = socket.session.now().openSignals;
223
164
  const answeredHere = socket.awaitingAnswer(room.locator);
224
165
  const answeredThere = partner === null ? () => { } : socket.awaitingAnswer(partner);
225
- const answered = () => {
166
+ const heard = () => {
226
167
  answeredHere();
227
168
  answeredThere();
228
169
  };
@@ -234,29 +175,33 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
234
175
  ...(state?.upload === undefined ? {} : { upload: state.upload }),
235
176
  }, (upload) => store.exclusive(() => keepUpload(runtime, local, room.locator, head.id, upload)));
236
177
  }
237
- catch {
238
- answered();
178
+ catch (error) {
179
+ runtime.retries.failed('sending', submitting(room.locator), error);
180
+ heard();
239
181
  progress.complete = false;
240
182
  if (socket.continuing())
241
183
  progress.reachable = false;
242
184
  return 'again';
243
185
  }
244
186
  if (signal.aborted) {
245
- answered();
187
+ heard();
246
188
  return 'done';
247
189
  }
248
190
  if (result.kind !== 'accepted' || !socket.continuing())
249
- answered();
191
+ heard();
250
192
  if (!socket.continuing())
251
193
  return 'done';
194
+ if (result.kind === 'accepted')
195
+ runtime.retries.succeeded('sending', submitting(room.locator));
252
196
  if (result.kind === 'transport-uncertainty') {
197
+ runtime.retries.uncertain('sending', submitting(room.locator), result);
253
198
  progress.complete = false;
254
199
  progress.reachable = false;
255
200
  return 'again';
256
201
  }
257
202
  if (result.kind === 'room-not-readable') {
258
203
  progress.complete = false;
259
- roomUnreadable(runtime, socket.rooms.discovered(result.locator) ?? room);
204
+ roomUnreadable(runtime, (presence.room(result.locator) ?? room).locator);
260
205
  return 'done';
261
206
  }
262
207
  if (result.kind === 'revoked-authorization') {
@@ -264,84 +209,54 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
264
209
  return 'done';
265
210
  }
266
211
  if (result.kind === 'scoped-refusal') {
267
- await runtime.scoped(result, room, local);
212
+ await scoped(runtime, result, room.locator, declared(room));
268
213
  progress.complete = false;
269
214
  return 'done';
270
215
  }
271
216
  if (result.kind === 'write-halted') {
272
- journal.record(`outcome ${room.locator} ${head.id} write-halted`);
273
217
  await store.exclusive(() => mark(runtime, local, room.locator, head, { state: 'waiting' }, lost));
274
218
  if (!socket.haltedSince(opensBefore))
275
219
  continue;
276
220
  progress.complete = false;
277
221
  return 'done';
278
222
  }
279
- const other = partner === null ? undefined : socket.rooms.discovered(partner);
280
- if (result.kind === 'conflicted' ||
281
- result.kind === 'rejected' ||
282
- result.kind === 'retryable-refusal') {
283
- journal.record(`outcome ${room.locator} ${head.id} ${result.kind}` +
284
- (result.kind === 'conflicted' && result.roomVersion !== undefined
285
- ? ` ${result.roomVersion}`
286
- : ''));
287
- journal.record(`refusal ${result.kind} ${result.code}`);
288
- }
223
+ const other = partner === null ? undefined : presence.room(partner);
289
224
  if (result.kind === 'retryable-refusal') {
225
+ runtime.retries.failed('sending', submitting(room.locator), refusalError(result));
290
226
  const reset = result.reset;
291
227
  progress.complete = false;
292
228
  await store.exclusive(() => mark(runtime, local, room.locator, head, reset === undefined ? { state: 'waiting' } : { state: 'reset', reset }, lost));
293
229
  return reset === undefined ? 'again' : { at: Date.parse(reset) };
294
230
  }
295
231
  if (result.kind === 'conflicted' || result.kind === 'rejected') {
296
- const left = leaving(head, result);
297
232
  const refreshed = async () => ({
298
- there: other === undefined ? null : await advanced(other, local, authorized),
299
- here: await advanced(room, local, authorized),
233
+ there: other === undefined ? null : await advanced(runtime, other, local, authorized),
234
+ here: await advanced(runtime, room, local, authorized),
300
235
  });
301
236
  const judged = result.kind === 'conflicted' && other !== undefined ? await refreshed() : null;
302
237
  if (judged !== null && (judged.there !== null || judged.here !== null)) {
303
238
  await store.exclusive(() => mark(runtime, local, room.locator, head, { state: 'waiting' }, lost));
304
239
  if (other !== undefined && judged.there !== null) {
305
- await withhold(judged.there, other, local, progress);
240
+ await withhold(runtime, judged.there, other, local, progress);
306
241
  }
307
242
  if (judged.here !== null)
308
- await withhold(judged.here, room, local, progress);
243
+ await withhold(runtime, judged.here, room, local, progress);
309
244
  return 'done';
310
245
  }
311
- await store.exclusive(async () => {
312
- if (!socket.continuing())
313
- return;
314
- const work = await store.work(room.locator);
315
- const current = work.replica;
316
- if (current === undefined || !current.queue.some((batch) => batch.id === head.id)) {
317
- return;
318
- }
319
- const confirmedLayer = await sliceAt(store, current.record, 'confirmed', [head]);
320
- const held = result.kind === 'conflicted' &&
321
- (await landedWhole(store, room.locator, head, confirmedLayer, result.affected));
322
- if (held &&
323
- result.kind === 'conflicted' &&
324
- partner === null &&
325
- !landed(head, confirmedLayer)) {
326
- store.landed.hold(room.locator, head.id, Object.fromEntries([...touchedBy([head])].map((path) => [path, confirmedLayer.revisions[path]])));
327
- return;
328
- }
329
- store.changed(await settle(runtime, local, room.locator, work, current.record, current.queue.filter((batch) => batch.id !== head.id), { leaving: [held ? { ...left, returned: null } : left] }));
330
- await unpair(runtime, local);
331
- statusShown(runtime);
332
- });
246
+ await answered(runtime, room.locator, head, result);
333
247
  const { there, here } = judged ?? (await refreshed());
334
- if (other !== undefined && there !== null)
335
- await withhold(there, other, local, progress);
248
+ if (other !== undefined && there !== null) {
249
+ await withhold(runtime, there, other, local, progress);
250
+ }
336
251
  if (here !== null) {
337
- await withhold(here, room, local, progress);
252
+ await withhold(runtime, here, room, local, progress);
338
253
  return 'done';
339
254
  }
340
255
  continue;
341
256
  }
342
257
  const kept = await (partner === null
343
258
  ? adopted(runtime, room, local, head, result)
344
- : adoptedMove(runtime, room, partner, local, head, result)).finally(answered);
259
+ : adoptedMove(runtime, room, partner, local, head, result)).finally(heard);
345
260
  if (!kept) {
346
261
  progress.complete = false;
347
262
  return 'done';
@@ -349,14 +264,17 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
349
264
  }
350
265
  return 'done';
351
266
  }
267
+ function submitting(locator) {
268
+ return `submit ${locator}`;
269
+ }
352
270
  export function submitLater(runtime, locator) {
353
271
  if (runtime.localSaves)
354
272
  return;
355
- void runtime.recovery.attempt(`submit ${locator}`, (signal) => submitPass(runtime, locator, signal));
273
+ void runtime.recovery.attempt(submitting(locator), (signal) => submitPass(runtime, locator, signal));
356
274
  }
357
275
  async function submitPass(runtime, locator, signal) {
358
- const { store, socket } = runtime;
359
- const room = socket.rooms.discovered(locator);
276
+ const { store, socket, presence } = runtime;
277
+ const room = presence.room(locator);
360
278
  if (!socket.continuing() || socket.stopping() || room === undefined) {
361
279
  return 'done';
362
280
  }
@@ -369,7 +287,8 @@ async function submitPass(runtime, locator, signal) {
369
287
  return 'done';
370
288
  next = await submitRoom(runtime, room, await store.open(), authorization, progress, signal);
371
289
  }
372
- catch {
290
+ catch (error) {
291
+ runtime.retries.failed('sending', submitting(locator), error);
373
292
  progress.reachable = false;
374
293
  next = 'again';
375
294
  }
@@ -378,12 +297,3 @@ async function submitPass(runtime, locator, signal) {
378
297
  await rest(runtime, progress);
379
298
  return next === 'again' && !socket.isOpen() ? 'done' : next;
380
299
  }
381
- export async function submitAll(runtime) {
382
- const { store } = runtime;
383
- if (runtime.localSaves)
384
- return;
385
- for (const locator of await (await store.open()).queued()) {
386
- if (!store.fences.has(locator))
387
- submitLater(runtime, locator);
388
- }
389
- }
@@ -0,0 +1,30 @@
1
+ import { type Expected, type Expecting } from './expectation.js';
2
+ export type Ended = 'accepted' | 'refused' | 'unanswered' | 'unsent';
3
+ export type Send<O> = {
4
+ (name: string, input: unknown, sending: (operation: string) => Promise<O>): Promise<O>;
5
+ expect(expected: Expected): void;
6
+ };
7
+ export type LaneShown<O> = {
8
+ readonly busy: boolean;
9
+ readonly drawn: boolean;
10
+ readonly ended: O | null;
11
+ };
12
+ export type Lane<O> = {
13
+ run(steps: (send: Send<O>) => Promise<O>, expected?: Expected): Promise<O>;
14
+ shown(): LaneShown<O>;
15
+ subscribe(listener: () => void): () => void;
16
+ forget(): void;
17
+ };
18
+ export type Acting<O> = {
19
+ open(): Lane<O>;
20
+ };
21
+ export type ActingRules<O> = {
22
+ readonly store: Pick<Expecting, 'begin' | 'expect' | 'drop'>;
23
+ readonly uncertain: O;
24
+ ending(outcome: O): Ended;
25
+ acted?(): void;
26
+ mint?(): string;
27
+ settles?(operation: string): Promise<boolean>;
28
+ };
29
+ export declare function acting<O>(rules: ActingRules<O>): Acting<O>;
30
+ //# sourceMappingURL=act-lanes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"act-lanes.d.ts","sourceRoot":"","sources":["../src/act-lanes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAG/E,MAAM,MAAM,KAAK,GAAG,UAAU,GAAG,SAAS,GAAG,YAAY,GAAG,QAAQ,CAAC;AAErE,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI;IACpB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACvF,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,IAAI,CAAC,CAAC,IAAI;IACpB,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC3E,KAAK,IAAI,SAAS,CAAC,CAAC,CAAC,CAAC;IACtB,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAC5C,MAAM,IAAI,IAAI,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI;IACtB,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC,CAAC;IAC7D,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC;IACtB,MAAM,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC;IAC1B,KAAK,CAAC,IAAI,IAAI,CAAC;IACf,IAAI,CAAC,IAAI,MAAM,CAAC;IAChB,OAAO,CAAC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC/C,CAAC;AAUF,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CA6N1D"}