@agentshouse/mdruntime 0.1.0-ce531b51ff088 → 0.1.0-ce6bc9239a3ee
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.
- package/README.md +25 -12
- package/dist/acceptance.d.ts +26 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +384 -0
- package/dist/adapter.d.ts +218 -62
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +1 -9
- package/dist/attached-model.d.ts +8 -0
- package/dist/attached-model.d.ts.map +1 -0
- package/dist/attached-model.js +46 -0
- package/dist/attempt.d.ts +16 -0
- package/dist/attempt.d.ts.map +1 -0
- package/dist/attempt.js +70 -0
- package/dist/binary.d.ts +18 -0
- package/dist/binary.d.ts.map +1 -0
- package/dist/binary.js +8 -0
- package/dist/bootstrap.d.ts +40 -6
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +336 -51
- package/dist/chain.d.ts +12 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +9 -14
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -56
- package/dist/change.d.ts +46 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +34 -0
- package/dist/chat-types.d.ts +3 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +2 -0
- package/dist/client.d.ts +50 -18
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +162 -30
- package/dist/collection.d.ts +13 -14
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +52 -56
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +717 -0
- package/dist/connection.d.ts +63 -48
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +2487 -1575
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +47 -0
- package/dist/conversation.d.ts +72 -22
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +1008 -273
- package/dist/digest.d.ts +7 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +113 -0
- package/dist/durability.d.ts +10 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +20 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +161 -0
- package/dist/expectation.d.ts +21 -0
- package/dist/expectation.d.ts.map +1 -0
- package/dist/expectation.js +70 -0
- package/dist/failure.d.ts +13 -0
- package/dist/failure.d.ts.map +1 -0
- package/dist/failure.js +19 -0
- package/dist/figures.d.ts +48 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/file.d.ts +2 -19
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +7 -122
- package/dist/host.d.ts +18 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +164 -50
- package/dist/identity.d.ts +3 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +13 -1
- package/dist/index.d.ts +31 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/install.d.ts +86 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +537 -0
- package/dist/job.d.ts +33 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +54 -0
- package/dist/live.d.ts +23 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +165 -0
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/media.d.ts +8 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +218 -0
- package/dist/memory.d.ts +30 -9
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +337 -86
- package/dist/messages.d.ts +52 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +168 -0
- package/dist/model.d.ts +17 -16
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +9 -9
- package/dist/name.d.ts +4 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +122 -0
- package/dist/observation.d.ts +22 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +133 -17
- package/dist/open.d.ts +2 -0
- package/dist/open.d.ts.map +1 -0
- package/dist/open.js +1 -0
- package/dist/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -0
- package/dist/outcome.d.ts +73 -5
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +84 -1
- package/dist/overlay.d.ts +16 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +147 -180
- package/dist/parts.d.ts +59 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +118 -0
- package/dist/paths.d.ts +1 -1
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -16
- package/dist/query.d.ts +56 -180
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -422
- package/dist/questions.d.ts +32 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +118 -0
- package/dist/reach.d.ts +54 -0
- package/dist/reach.d.ts.map +1 -0
- package/dist/reach.js +494 -0
- package/dist/react.d.ts +46 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +54 -0
- package/dist/read.d.ts +7 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +17 -0
- package/dist/readiness.d.ts +50 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +27 -0
- package/dist/reads.d.ts +36 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +136 -0
- package/dist/recovery.d.ts +26 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +232 -0
- package/dist/refresh.d.ts +21 -7
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +155 -55
- package/dist/replica.d.ts +58 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +355 -158
- package/dist/room-draft.d.ts +62 -11
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +281 -83
- package/dist/room-drafts.d.ts +29 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +216 -0
- package/dist/rows.d.ts +32 -34
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +65 -87
- package/dist/save.d.ts +74 -6
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +902 -182
- package/dist/saves.d.ts +96 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +999 -0
- package/dist/search.d.ts +15 -54
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -121
- package/dist/seed.d.ts +30 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +141 -0
- package/dist/shared.d.ts +15 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +421 -0
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket.d.ts +43 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +96 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +81 -0
- package/dist/status.d.ts +7 -4
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -15
- package/dist/store/fences.d.ts +16 -0
- package/dist/store/fences.d.ts.map +1 -0
- package/dist/store/fences.js +26 -0
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/records.d.ts +212 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +408 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/watchers.d.ts +15 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +36 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +77 -94
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +118 -389
- package/dist/stored.d.ts +156 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +637 -0
- package/dist/tables.d.ts +407 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +724 -0
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/turn.d.ts +9 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +75 -0
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +104 -0
- package/dist/windows.d.ts +11 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +16 -0
- package/dist/wire.d.ts +205 -19
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +95 -61
- package/package.json +33 -10
- package/AGENTS.md +0 -207
- package/dist/attachment.d.ts +0 -3
- package/dist/attachment.d.ts.map +0 -1
- package/dist/attachment.js +0 -8
- package/dist/read-side.d.ts +0 -14
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -371
package/README.md
CHANGED
|
@@ -12,22 +12,23 @@ npm install @agentshouse/mdruntime
|
|
|
12
12
|
|
|
13
13
|
## Entries
|
|
14
14
|
|
|
15
|
-
| Entry | For
|
|
16
|
-
| ------------------------------- |
|
|
17
|
-
| `@agentshouse/mdruntime/client` |
|
|
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
|
|
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` |
|
|
21
23
|
|
|
22
24
|
## Usage
|
|
23
25
|
|
|
24
|
-
App code
|
|
25
|
-
it:
|
|
26
|
+
App code takes the client its host hands it; in House the App bridge hands it:
|
|
26
27
|
|
|
27
28
|
```ts
|
|
28
|
-
import {
|
|
29
|
+
import { houseBridge } from '@agentshouse/app-bridge';
|
|
29
30
|
|
|
30
|
-
const runtime =
|
|
31
|
+
const runtime = await houseBridge().runtime;
|
|
31
32
|
const rooms = await runtime.rooms();
|
|
32
33
|
const notes = await runtime.query({ types: ['note'], select: 'all', limit: 20 });
|
|
33
34
|
```
|
|
@@ -36,8 +37,20 @@ const notes = await runtime.query({ types: ['note'], select: 'all', limit: 20 })
|
|
|
36
37
|
`storage-loss` when unsynchronized Room Drafts and Pending Changes were lost.
|
|
37
38
|
The host supplies the user-facing wording.
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
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:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const chat = await window.houseBridge.chat.mount(element, { width: '1/3', showChats: true });
|
|
46
|
+
element.style.setProperty('--chat-accent', '#2a6cf0');
|
|
47
|
+
chat.update({ width: 'full', showChats: true });
|
|
48
|
+
chat.unmount();
|
|
49
|
+
```
|
|
50
|
+
|
|
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.
|
|
41
54
|
|
|
42
55
|
## License
|
|
43
56
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Authorization, DiscoveredRoom } from './adapter.js';
|
|
2
|
+
import { type Withheld } from './install.js';
|
|
3
|
+
import type { Recovery } from './recovery.js';
|
|
4
|
+
import { type Saver } from './saves.js';
|
|
5
|
+
import type { CycleProgress } from './status.js';
|
|
6
|
+
import type { RuntimeStore } from './store.js';
|
|
7
|
+
export type Accepting = Saver & {
|
|
8
|
+
readonly recovery: Recovery;
|
|
9
|
+
stopping(): boolean;
|
|
10
|
+
paused(): boolean;
|
|
11
|
+
continuing(): boolean;
|
|
12
|
+
discovered(locator: string): DiscoveredRoom | undefined;
|
|
13
|
+
readable(room: DiscoveredRoom): void;
|
|
14
|
+
unreadable(room: DiscoveredRoom): void;
|
|
15
|
+
advanced(room: DiscoveredRoom, local: RuntimeStore, authorized: Authorization): Promise<Withheld | null>;
|
|
16
|
+
withhold(withheld: Withheld, room: DiscoveredRoom, local: RuntimeStore, progress: CycleProgress): Promise<void>;
|
|
17
|
+
writesHeld(): boolean;
|
|
18
|
+
openSignals(): number;
|
|
19
|
+
haltedSince(opens: number): boolean;
|
|
20
|
+
rest(progress: CycleProgress): Promise<void>;
|
|
21
|
+
statusShown(): Promise<void>;
|
|
22
|
+
};
|
|
23
|
+
export declare function unpair(accepting: Accepting, local: RuntimeStore): Promise<void>;
|
|
24
|
+
export declare function submitLater(accepting: Accepting, locator: string): void;
|
|
25
|
+
export declare function submitAll(accepting: Accepting): Promise<void>;
|
|
26
|
+
//# sourceMappingURL=acceptance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAkB,MAAM,cAAc,CAAC;AAIlF,OAAO,EAAsB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEjE,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzD,OAAO,EAUL,KAAK,KAAK,EAEX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,YAAY,CAAC;AAI5D,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,IAAI,OAAO,CAAC;IACpB,MAAM,IAAI,OAAO,CAAC;IAClB,UAAU,IAAI,OAAO,CAAC;IACtB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACrC,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAAC;IACvC,QAAQ,CACN,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,YAAY,EACnB,UAAU,EAAE,aAAa,GACxB,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAC5B,QAAQ,CACN,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,YAAY,EACnB,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,UAAU,IAAI,OAAO,CAAC;IACtB,WAAW,IAAI,MAAM,CAAC;IACtB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,IAAI,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B,CAAC;AAoOF,wBAAsB,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrF;AAgOD,wBAAgB,WAAW,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,QAKhE;AA4BD,wBAAsB,SAAS,CAAC,SAAS,EAAE,SAAS,iBAMnD"}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { changeSet } from './change-set.js';
|
|
2
|
+
import { leaving as leavingIn, partnerOf } from './change.js';
|
|
3
|
+
import { runtimeError } from './failure.js';
|
|
4
|
+
import { olderThan, showing } from './install.js';
|
|
5
|
+
import { landed, returnedPaths, returning, slicing, touchedBy } from './replica.js';
|
|
6
|
+
import { batchFile, landedWhole, settle, settlement, sliceAt, together, unpairing, withdrawable, } from './saves.js';
|
|
7
|
+
import { unconfirmed } from './transfer.js';
|
|
8
|
+
import { stepped } from './turn.js';
|
|
9
|
+
function pendingKey(locator, id) {
|
|
10
|
+
return `${locator}\u0000${id}`;
|
|
11
|
+
}
|
|
12
|
+
async function mark(accepting, local, locator, batch, submission, lost) {
|
|
13
|
+
const { store, continuing, publishChangeSet, statusShown } = accepting;
|
|
14
|
+
const partner = partnerOf(batch, locator);
|
|
15
|
+
for (const held of partner === null ? [locator] : [locator, partner]) {
|
|
16
|
+
const { state, room } = await local.pending(held, batch.id);
|
|
17
|
+
if (!continuing() ||
|
|
18
|
+
state === undefined ||
|
|
19
|
+
(JSON.stringify(state.submission) === JSON.stringify(submission) && state.lost === lost)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
await local.submit(held, batch.id, submission, lost);
|
|
23
|
+
if (store.fences.has(held))
|
|
24
|
+
continue;
|
|
25
|
+
if (room)
|
|
26
|
+
publishChangeSet(changeSet(held, { queue: true }));
|
|
27
|
+
}
|
|
28
|
+
statusShown();
|
|
29
|
+
}
|
|
30
|
+
async function keepUpload({ store, continuing }, local, locator, identifier, upload) {
|
|
31
|
+
if (!continuing())
|
|
32
|
+
throw new Error('connection refused');
|
|
33
|
+
await local.keepUpload(locator, identifier, upload);
|
|
34
|
+
if (store.fences.has(locator))
|
|
35
|
+
throw runtimeError('unknown-room', `Unknown Room ${locator}`);
|
|
36
|
+
if (!continuing())
|
|
37
|
+
throw new Error('connection refused');
|
|
38
|
+
}
|
|
39
|
+
function leaving(batch, result) {
|
|
40
|
+
return {
|
|
41
|
+
batch,
|
|
42
|
+
returned: {
|
|
43
|
+
kind: result.kind,
|
|
44
|
+
code: result.code,
|
|
45
|
+
fields: result.fields,
|
|
46
|
+
retryable: result.retryable,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function logAccepted({ journal }, locator, submitted, accepted) {
|
|
51
|
+
journal.record(`outcome ${locator} ${submitted.id} accepted ${accepted.roomVersion}` +
|
|
52
|
+
(accepted.author === undefined ? '' : ` author ${accepted.author}`) +
|
|
53
|
+
(accepted.time === undefined ? '' : ` time ${accepted.time}`));
|
|
54
|
+
}
|
|
55
|
+
function settling(acceptance) {
|
|
56
|
+
return acceptance !== null && 'apply' in acceptance;
|
|
57
|
+
}
|
|
58
|
+
function failureOf(acceptance) {
|
|
59
|
+
return settling(acceptance) ? null : acceptance;
|
|
60
|
+
}
|
|
61
|
+
async function acceptance(accepting, room, local, submitted, accepted) {
|
|
62
|
+
const { store, socket } = accepting;
|
|
63
|
+
if (!accepting.continuing())
|
|
64
|
+
return unconfirmed;
|
|
65
|
+
const work = await store.work(room.locator);
|
|
66
|
+
const current = work.replica;
|
|
67
|
+
if (current === undefined || !current.queue.some((batch) => batch.id === submitted.id)) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const held = current.record.roomVersion;
|
|
71
|
+
logAccepted(accepting, room.locator, submitted, accepted);
|
|
72
|
+
let record = current.record;
|
|
73
|
+
let changes;
|
|
74
|
+
if (!socket.reads.reached(room.locator, held, accepted.roomVersion) &&
|
|
75
|
+
!olderThan(accepting, room.locator, accepted.roomVersion, held)) {
|
|
76
|
+
const paths = [...returnedPaths(submitted, accepted)];
|
|
77
|
+
const confirmedLayer = await stepped(slicing(await local.entries(record.key, 'confirmed', paths), paths));
|
|
78
|
+
const back = await stepped(returning(confirmedLayer, submitted, accepted, accepted.roomVersion, store.composed(record)));
|
|
79
|
+
record = {
|
|
80
|
+
...record,
|
|
81
|
+
roomVersion: socket.follows(room.locator, held, accepted.roomVersion)
|
|
82
|
+
? accepted.roomVersion
|
|
83
|
+
: held,
|
|
84
|
+
};
|
|
85
|
+
changes = back;
|
|
86
|
+
}
|
|
87
|
+
const settled = await settlement(accepting, local, room.locator, work, record, current.queue.filter((batch) => batch.id !== submitted.id), { room: true, ...(changes === undefined ? {} : { changes }) });
|
|
88
|
+
const reached = record.roomVersion;
|
|
89
|
+
return {
|
|
90
|
+
...settled,
|
|
91
|
+
apply(answer) {
|
|
92
|
+
const set = settled.apply(answer);
|
|
93
|
+
showing(accepting, room.locator, accepted.roomVersion, reached);
|
|
94
|
+
accepting.readable(room);
|
|
95
|
+
return set;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
async function adoptedTogether(accepting, local, acceptances) {
|
|
100
|
+
const settlements = acceptances.filter(settling);
|
|
101
|
+
if (settlements.length > 0) {
|
|
102
|
+
const set = await together(accepting, local, settlements);
|
|
103
|
+
void accepting.statusShown();
|
|
104
|
+
void accepting.publishChangeSet(set);
|
|
105
|
+
}
|
|
106
|
+
await unpair(accepting, local);
|
|
107
|
+
}
|
|
108
|
+
async function adopted(accepting, room, local, submitted, accepted) {
|
|
109
|
+
const failed = await accepting.store.exclusive(async () => {
|
|
110
|
+
const adopting = await acceptance(accepting, room, local, submitted, accepted);
|
|
111
|
+
await adoptedTogether(accepting, local, [adopting]);
|
|
112
|
+
return failureOf(adopting);
|
|
113
|
+
});
|
|
114
|
+
return failed === null;
|
|
115
|
+
}
|
|
116
|
+
async function adoptedMove(accepting, room, partner, local, submitted, accepted) {
|
|
117
|
+
const { store } = accepting;
|
|
118
|
+
const other = accepting.discovered(partner);
|
|
119
|
+
const failed = await store.exclusive(async () => {
|
|
120
|
+
const left = await acceptance(accepting, room, local, submitted, accepted);
|
|
121
|
+
const arriving = (await store.replica(partner))?.queue.find((batch) => batch.id === submitted.id);
|
|
122
|
+
const arrived = other === undefined || arriving === undefined || accepted.destination === undefined
|
|
123
|
+
? null
|
|
124
|
+
: await acceptance(accepting, other, local, arriving, {
|
|
125
|
+
kind: 'accepted',
|
|
126
|
+
...accepted.destination,
|
|
127
|
+
});
|
|
128
|
+
await adoptedTogether(accepting, local, [left, arrived]);
|
|
129
|
+
return failureOf(left);
|
|
130
|
+
});
|
|
131
|
+
submitLater(accepting, partner);
|
|
132
|
+
return failed === null;
|
|
133
|
+
}
|
|
134
|
+
async function behindIn({ store }, locator, batch) {
|
|
135
|
+
const local = await store.open();
|
|
136
|
+
const [order, { room }] = await Promise.all([
|
|
137
|
+
local.order(locator),
|
|
138
|
+
local.pending(locator, batch.id),
|
|
139
|
+
]);
|
|
140
|
+
return room ? order.indexOf(batch.id) > 0 : order.length > 0;
|
|
141
|
+
}
|
|
142
|
+
async function unpaired(local, skipped) {
|
|
143
|
+
const { queued, moving } = await local.moving();
|
|
144
|
+
for (const { locator, batch, state } of moving) {
|
|
145
|
+
const partner = partnerOf(batch, locator);
|
|
146
|
+
if (partner === null || skipped.has(pendingKey(locator, batch.id)))
|
|
147
|
+
continue;
|
|
148
|
+
if (queued.get(partner)?.includes(batch.id) === true)
|
|
149
|
+
continue;
|
|
150
|
+
if (!leavingIn(batch, locator) || withdrawable(new Map([[batch.id, state]]))(batch)) {
|
|
151
|
+
return { locator, batch };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
export async function unpair(accepting, local) {
|
|
157
|
+
const { continuing, publishChangeSet } = accepting;
|
|
158
|
+
const handled = new Set();
|
|
159
|
+
for (let held = await unpaired(local, handled); held !== null && continuing(); held = await unpaired(local, handled)) {
|
|
160
|
+
const { locator, batch } = held;
|
|
161
|
+
handled.add(pendingKey(locator, batch.id));
|
|
162
|
+
publishChangeSet(await together(accepting, local, [await unpairing(accepting, local, locator, [batch])]));
|
|
163
|
+
}
|
|
164
|
+
if (handled.size === 0)
|
|
165
|
+
return;
|
|
166
|
+
accepting.statusShown();
|
|
167
|
+
}
|
|
168
|
+
async function submitRoom(accepting, room, local, authorized, progress, signal) {
|
|
169
|
+
const { store, socket, journal, continuing, writesHeld, advanced, withhold } = accepting;
|
|
170
|
+
while (continuing() && accepting.authorized() !== undefined && !signal.aborted) {
|
|
171
|
+
const headId = (await local.order(room.locator)).find((id) => store.landed.of(room.locator, id) === undefined);
|
|
172
|
+
if (headId === undefined)
|
|
173
|
+
return 'done';
|
|
174
|
+
const [head, pending] = await Promise.all([
|
|
175
|
+
local.batch(room.locator, headId),
|
|
176
|
+
local.pending(room.locator, headId),
|
|
177
|
+
]);
|
|
178
|
+
if (head === null || !pending.room)
|
|
179
|
+
return 'done';
|
|
180
|
+
const { state } = pending;
|
|
181
|
+
const partner = partnerOf(head, room.locator);
|
|
182
|
+
if (partner !== null && !leavingIn(head, room.locator)) {
|
|
183
|
+
submitLater(accepting, partner);
|
|
184
|
+
return 'done';
|
|
185
|
+
}
|
|
186
|
+
if (partner !== null && (await behindIn(accepting, partner, head))) {
|
|
187
|
+
progress.complete = false;
|
|
188
|
+
return 'done';
|
|
189
|
+
}
|
|
190
|
+
const { submission, lost: earlier } = state ?? {
|
|
191
|
+
submission: { state: 'waiting' },
|
|
192
|
+
lost: false,
|
|
193
|
+
};
|
|
194
|
+
if (submission.state === 'reset' && Date.now() < Date.parse(submission.reset)) {
|
|
195
|
+
progress.complete = false;
|
|
196
|
+
return { at: Date.parse(submission.reset) };
|
|
197
|
+
}
|
|
198
|
+
if (writesHeld()) {
|
|
199
|
+
progress.complete = false;
|
|
200
|
+
journal.record(`submission ${room.locator} ${head.id} held`);
|
|
201
|
+
return 'done';
|
|
202
|
+
}
|
|
203
|
+
const lost = earlier || submission.state === 'submitted';
|
|
204
|
+
let result;
|
|
205
|
+
journal.record(`submission ${room.locator} ${head.id}`);
|
|
206
|
+
await store.exclusive(() => mark(accepting, local, room.locator, head, { state: 'submitted' }, lost));
|
|
207
|
+
if (accepting.paused() || store.fences.has(room.locator))
|
|
208
|
+
return 'done';
|
|
209
|
+
if (signal.aborted || writesHeld()) {
|
|
210
|
+
await store.exclusive(() => mark(accepting, local, room.locator, head, submission, earlier));
|
|
211
|
+
if (signal.aborted)
|
|
212
|
+
return 'done';
|
|
213
|
+
progress.complete = false;
|
|
214
|
+
journal.record(`submission ${room.locator} ${head.id} held`);
|
|
215
|
+
return 'done';
|
|
216
|
+
}
|
|
217
|
+
const opensBefore = accepting.openSignals();
|
|
218
|
+
const answeredHere = socket.awaitingAnswer(room.locator);
|
|
219
|
+
const answeredThere = partner === null ? () => { } : socket.awaitingAnswer(partner);
|
|
220
|
+
const answered = () => {
|
|
221
|
+
answeredHere();
|
|
222
|
+
answeredThere();
|
|
223
|
+
};
|
|
224
|
+
try {
|
|
225
|
+
result = await socket.mutate(authorized, {
|
|
226
|
+
locator: room.locator,
|
|
227
|
+
changeBatch: head,
|
|
228
|
+
file: batchFile(store, head),
|
|
229
|
+
...(state?.upload === undefined ? {} : { upload: state.upload }),
|
|
230
|
+
}, (upload) => store.exclusive(() => keepUpload(accepting, local, room.locator, head.id, upload)));
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
answered();
|
|
234
|
+
progress.complete = false;
|
|
235
|
+
if (continuing())
|
|
236
|
+
progress.reachable = false;
|
|
237
|
+
return 'again';
|
|
238
|
+
}
|
|
239
|
+
if (signal.aborted) {
|
|
240
|
+
answered();
|
|
241
|
+
return 'done';
|
|
242
|
+
}
|
|
243
|
+
if (result.kind !== 'accepted' || !continuing())
|
|
244
|
+
answered();
|
|
245
|
+
if (!continuing())
|
|
246
|
+
return 'done';
|
|
247
|
+
if (result.kind === 'transport-uncertainty') {
|
|
248
|
+
progress.complete = false;
|
|
249
|
+
progress.reachable = false;
|
|
250
|
+
return 'again';
|
|
251
|
+
}
|
|
252
|
+
if (result.kind === 'room-not-readable') {
|
|
253
|
+
progress.complete = false;
|
|
254
|
+
accepting.unreadable(accepting.discovered(result.locator) ?? room);
|
|
255
|
+
return 'done';
|
|
256
|
+
}
|
|
257
|
+
if (result.kind === 'revoked-authorization') {
|
|
258
|
+
await accepting.refuse('revoked-authorization');
|
|
259
|
+
return 'done';
|
|
260
|
+
}
|
|
261
|
+
if (result.kind === 'scoped-refusal') {
|
|
262
|
+
await accepting.scoped(result, room, local);
|
|
263
|
+
progress.complete = false;
|
|
264
|
+
return 'done';
|
|
265
|
+
}
|
|
266
|
+
if (result.kind === 'write-halted') {
|
|
267
|
+
journal.record(`outcome ${room.locator} ${head.id} write-halted`);
|
|
268
|
+
await store.exclusive(() => mark(accepting, local, room.locator, head, { state: 'waiting' }, lost));
|
|
269
|
+
if (!accepting.haltedSince(opensBefore))
|
|
270
|
+
continue;
|
|
271
|
+
progress.complete = false;
|
|
272
|
+
return 'done';
|
|
273
|
+
}
|
|
274
|
+
const other = partner === null ? undefined : accepting.discovered(partner);
|
|
275
|
+
if (result.kind === 'conflicted' ||
|
|
276
|
+
result.kind === 'rejected' ||
|
|
277
|
+
result.kind === 'retryable-refusal') {
|
|
278
|
+
journal.record(`outcome ${room.locator} ${head.id} ${result.kind}` +
|
|
279
|
+
(result.kind === 'conflicted' && result.roomVersion !== undefined
|
|
280
|
+
? ` ${result.roomVersion}`
|
|
281
|
+
: ''));
|
|
282
|
+
journal.record(`refusal ${result.kind} ${result.code}`);
|
|
283
|
+
}
|
|
284
|
+
if (result.kind === 'retryable-refusal') {
|
|
285
|
+
const reset = result.reset;
|
|
286
|
+
progress.complete = false;
|
|
287
|
+
await store.exclusive(() => mark(accepting, local, room.locator, head, reset === undefined ? { state: 'waiting' } : { state: 'reset', reset }, lost));
|
|
288
|
+
return reset === undefined ? 'again' : { at: Date.parse(reset) };
|
|
289
|
+
}
|
|
290
|
+
if (result.kind === 'conflicted' || result.kind === 'rejected') {
|
|
291
|
+
const left = leaving(head, result);
|
|
292
|
+
const refreshed = async () => ({
|
|
293
|
+
there: other === undefined ? null : await advanced(other, local, authorized),
|
|
294
|
+
here: await advanced(room, local, authorized),
|
|
295
|
+
});
|
|
296
|
+
const judged = result.kind === 'conflicted' && other !== undefined ? await refreshed() : null;
|
|
297
|
+
if (judged !== null && (judged.there !== null || judged.here !== null)) {
|
|
298
|
+
await store.exclusive(() => mark(accepting, local, room.locator, head, { state: 'waiting' }, lost));
|
|
299
|
+
if (other !== undefined && judged.there !== null) {
|
|
300
|
+
await withhold(judged.there, other, local, progress);
|
|
301
|
+
}
|
|
302
|
+
if (judged.here !== null)
|
|
303
|
+
await withhold(judged.here, room, local, progress);
|
|
304
|
+
return 'done';
|
|
305
|
+
}
|
|
306
|
+
await store.exclusive(async () => {
|
|
307
|
+
if (!continuing())
|
|
308
|
+
return;
|
|
309
|
+
const work = await store.work(room.locator);
|
|
310
|
+
const current = work.replica;
|
|
311
|
+
if (current === undefined || !current.queue.some((batch) => batch.id === head.id)) {
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const confirmedLayer = await sliceAt(store, current.record, 'confirmed', [head]);
|
|
315
|
+
const held = result.kind === 'conflicted' &&
|
|
316
|
+
(await landedWhole(store, room.locator, head, confirmedLayer, result.affected));
|
|
317
|
+
if (held &&
|
|
318
|
+
result.kind === 'conflicted' &&
|
|
319
|
+
partner === null &&
|
|
320
|
+
!landed(head, confirmedLayer)) {
|
|
321
|
+
store.landed.hold(room.locator, head.id, Object.fromEntries([...touchedBy([head])].map((path) => [path, confirmedLayer.revisions[path]])));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
accepting.publishChangeSet(await settle(accepting, local, room.locator, work, current.record, current.queue.filter((batch) => batch.id !== head.id), { leaving: [held ? { ...left, returned: null } : left] }));
|
|
325
|
+
await unpair(accepting, local);
|
|
326
|
+
accepting.statusShown();
|
|
327
|
+
});
|
|
328
|
+
const { there, here } = judged ?? (await refreshed());
|
|
329
|
+
if (other !== undefined && there !== null)
|
|
330
|
+
await withhold(there, other, local, progress);
|
|
331
|
+
if (here !== null) {
|
|
332
|
+
await withhold(here, room, local, progress);
|
|
333
|
+
return 'done';
|
|
334
|
+
}
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
const kept = await (partner === null
|
|
338
|
+
? adopted(accepting, room, local, head, result)
|
|
339
|
+
: adoptedMove(accepting, room, partner, local, head, result)).finally(answered);
|
|
340
|
+
if (!kept) {
|
|
341
|
+
progress.complete = false;
|
|
342
|
+
return 'done';
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return 'done';
|
|
346
|
+
}
|
|
347
|
+
export function submitLater(accepting, locator) {
|
|
348
|
+
if (accepting.localSaves)
|
|
349
|
+
return;
|
|
350
|
+
void accepting.recovery.attempt(`submit ${locator}`, (signal) => submitPass(accepting, locator, signal));
|
|
351
|
+
}
|
|
352
|
+
async function submitPass(accepting, locator, signal) {
|
|
353
|
+
const { store, socket } = accepting;
|
|
354
|
+
const room = accepting.discovered(locator);
|
|
355
|
+
if (accepting.closed() || accepting.stopping() || accepting.paused() || room === undefined) {
|
|
356
|
+
return 'done';
|
|
357
|
+
}
|
|
358
|
+
const progress = { complete: true, reachable: true };
|
|
359
|
+
let next;
|
|
360
|
+
try {
|
|
361
|
+
await accepting.ensureAuthorization();
|
|
362
|
+
const authorization = accepting.authorized();
|
|
363
|
+
if (authorization === undefined)
|
|
364
|
+
return 'done';
|
|
365
|
+
next = await submitRoom(accepting, room, await store.open(), authorization, progress, signal);
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
progress.reachable = false;
|
|
369
|
+
next = 'again';
|
|
370
|
+
}
|
|
371
|
+
if (signal.aborted)
|
|
372
|
+
return 'done';
|
|
373
|
+
await accepting.rest(progress);
|
|
374
|
+
return next === 'again' && !socket.isOpen() ? 'done' : next;
|
|
375
|
+
}
|
|
376
|
+
export async function submitAll(accepting) {
|
|
377
|
+
const { store } = accepting;
|
|
378
|
+
if (accepting.localSaves)
|
|
379
|
+
return;
|
|
380
|
+
for (const locator of await (await store.open()).queued()) {
|
|
381
|
+
if (!store.fences.has(locator))
|
|
382
|
+
submitLater(accepting, locator);
|
|
383
|
+
}
|
|
384
|
+
}
|