@agentshouse/mdruntime 0.1.0-cf08ada271a7f → 0.1.0-cf0c43fc48aad
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 +12 -12
- package/dist/acceptance.d.ts.map +1 -1
- package/dist/acceptance.js +25 -35
- package/dist/act-lanes.d.ts +30 -0
- package/dist/act-lanes.d.ts.map +1 -0
- package/dist/act-lanes.js +225 -0
- package/dist/actions.d.ts +8 -2
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +116 -65
- package/dist/adapter.d.ts +11 -4
- package/dist/adapter.d.ts.map +1 -1
- package/dist/client.d.ts +6 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +26 -11
- package/dist/compile.d.ts +2 -0
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +17 -4
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +15 -10
- package/dist/conversation-live.d.ts +7 -2
- package/dist/conversation-live.d.ts.map +1 -1
- package/dist/conversation-live.js +6 -3
- package/dist/conversation.d.ts +25 -5
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +157 -76
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +18 -45
- package/dist/durability.d.ts +3 -0
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.js +1 -1
- package/dist/expectation.d.ts +25 -14
- package/dist/expectation.d.ts.map +1 -1
- package/dist/expectation.js +51 -20
- package/dist/failure.d.ts +2 -0
- package/dist/failure.d.ts.map +1 -1
- package/dist/failure.js +3 -0
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +29 -7
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -5
- package/dist/install.d.ts +2 -3
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +9 -22
- package/dist/lifecycle.d.ts +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +32 -26
- package/dist/listing.d.ts +4 -9
- package/dist/listing.d.ts.map +1 -1
- package/dist/listing.js +21 -51
- package/dist/locks.d.ts +2 -4
- package/dist/locks.d.ts.map +1 -1
- package/dist/locks.js +8 -38
- package/dist/lost.d.ts.map +1 -1
- package/dist/lost.js +7 -19
- package/dist/media.js +1 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +36 -17
- package/dist/messages.d.ts +9 -2
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +20 -10
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +15 -32
- package/dist/opened.d.ts +1 -1
- package/dist/opened.d.ts.map +1 -1
- package/dist/opened.js +2 -2
- package/dist/opening.d.ts.map +1 -1
- package/dist/opening.js +3 -9
- package/dist/outcome.d.ts +3 -0
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +15 -0
- package/dist/overlay.d.ts +3 -0
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +8 -4
- package/dist/page-metadata.d.ts +8 -0
- package/dist/page-metadata.d.ts.map +1 -0
- package/dist/page-metadata.js +19 -0
- package/dist/parts.d.ts +2 -9
- package/dist/parts.d.ts.map +1 -1
- package/dist/parts.js +6 -14
- package/dist/preparation.d.ts.map +1 -1
- package/dist/preparation.js +15 -21
- package/dist/presence.d.ts +52 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +220 -0
- package/dist/queries.d.ts +1 -1
- package/dist/queries.d.ts.map +1 -1
- package/dist/queries.js +23 -13
- package/dist/questions.d.ts +0 -5
- package/dist/questions.d.ts.map +1 -1
- package/dist/questions.js +0 -7
- package/dist/queue.d.ts +2 -1
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +26 -31
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +62 -18
- package/dist/react.d.ts +5 -4
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +28 -5
- package/dist/reads.d.ts +3 -1
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +5 -1
- package/dist/recovery.d.ts +3 -1
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +29 -7
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +2 -4
- package/dist/retried.d.ts +30 -0
- package/dist/retried.d.ts.map +1 -0
- package/dist/retried.js +72 -0
- package/dist/room-draft.d.ts +2 -2
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +24 -19
- package/dist/runtime.d.ts +4 -2
- package/dist/runtime.d.ts.map +1 -1
- package/dist/save.d.ts +1 -0
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +105 -55
- package/dist/saves.d.ts.map +1 -1
- package/dist/saves.js +8 -11
- package/dist/seed.js +2 -2
- package/dist/shown.d.ts +2 -2
- package/dist/shown.d.ts.map +1 -1
- package/dist/shown.js +14 -23
- package/dist/socket/lanes.d.ts +12 -4
- package/dist/socket/lanes.d.ts.map +1 -1
- package/dist/socket/lanes.js +34 -8
- package/dist/socket.d.ts +3 -5
- package/dist/socket.d.ts.map +1 -1
- package/dist/socket.js +3 -14
- package/dist/source.d.ts +0 -7
- package/dist/source.d.ts.map +1 -1
- package/dist/store/records.d.ts +7 -3
- package/dist/store/records.d.ts.map +1 -1
- package/dist/store/records.js +12 -2
- package/dist/store.d.ts +10 -5
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +37 -12
- package/dist/stored.d.ts +1 -0
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +5 -5
- package/dist/surface.d.ts +1 -1
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js +9 -13
- package/dist/sync.d.ts.map +1 -1
- package/dist/sync.js +63 -58
- package/dist/tables.d.ts +6 -3
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +34 -10
- package/dist/wire.d.ts +47 -3
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +12 -1
- package/package.json +3 -3
- package/dist/attempt.d.ts +0 -16
- package/dist/attempt.d.ts.map +0 -1
- package/dist/attempt.js +0 -70
- package/dist/job.d.ts +0 -5
- package/dist/job.d.ts.map +0 -1
- package/dist/job.js +0 -7
- package/dist/log.d.ts +0 -6
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js +0 -14
- package/dist/socket/rooms.d.ts +0 -41
- package/dist/socket/rooms.d.ts.map +0 -1
- package/dist/socket/rooms.js +0 -90
- package/dist/store/fences.d.ts +0 -16
- package/dist/store/fences.d.ts.map +0 -1
- 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: the Authored store's and opened files' tables, `answerRuntime` |
|
|
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
|
|
|
@@ -38,13 +38,13 @@ const notes = await runtime.query({ types: ['note'], select: 'all', limit: 20 })
|
|
|
38
38
|
The host supplies the user-facing wording.
|
|
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
|
|
41
|
+
House serves with the page: install and bundle nothing for it. Mount it in an element it
|
|
42
|
+
fills, on one chat, themed by CSS custom properties on that element:
|
|
43
43
|
|
|
44
44
|
```ts
|
|
45
|
-
const chat = await window.houseBridge.chat.mount(element, {
|
|
45
|
+
const chat = await window.houseBridge.chat.mount(element, { conversation });
|
|
46
46
|
element.style.setProperty('--chat-accent', '#2a6cf0');
|
|
47
|
-
chat.update({
|
|
47
|
+
chat.update({ conversation: null, agent });
|
|
48
48
|
chat.unmount();
|
|
49
49
|
```
|
|
50
50
|
|
package/dist/acceptance.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"acceptance.d.ts","sourceRoot":"","sources":["../src/acceptance.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
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"}
|
package/dist/acceptance.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { refusalError } from './failure.js';
|
|
1
2
|
import { changeSet } from './change-set.js';
|
|
2
3
|
import { declared } from './declaration.js';
|
|
3
4
|
import { leaving as leavingIn, partnerOf } from './change.js';
|
|
4
5
|
import { olderThan, showing } from './install.js';
|
|
5
|
-
import { readable } from './listing.js';
|
|
6
6
|
import { scoped } from './models.js';
|
|
7
7
|
import { answered, settle } from './queue.js';
|
|
8
8
|
import { refuse } from './refusal.js';
|
|
@@ -13,7 +13,7 @@ import { advanced, withhold } from './sync.js';
|
|
|
13
13
|
import { unconfirmed } from './transfer.js';
|
|
14
14
|
import { stepped } from './turn.js';
|
|
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,27 +23,22 @@ 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 (
|
|
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({
|
|
33
|
+
async function keepUpload({ socket, presence }, local, locator, identifier, upload) {
|
|
34
34
|
if (!socket.continuing())
|
|
35
35
|
throw new Error();
|
|
36
36
|
await local.keepUpload(locator, identifier, upload);
|
|
37
|
-
if (
|
|
37
|
+
if (presence.lost(locator))
|
|
38
38
|
throw new Error();
|
|
39
39
|
if (!socket.continuing())
|
|
40
40
|
throw new Error();
|
|
41
41
|
}
|
|
42
|
-
function logAccepted({ journal }, locator, submitted, accepted) {
|
|
43
|
-
journal.record(`outcome ${locator} ${submitted.id} accepted ${accepted.roomVersion}` +
|
|
44
|
-
(accepted.author === undefined ? '' : ` author ${accepted.author}`) +
|
|
45
|
-
(accepted.time === undefined ? '' : ` time ${accepted.time}`));
|
|
46
|
-
}
|
|
47
42
|
function restands(adoptions) {
|
|
48
43
|
return adoptions.flatMap((one) => (one === null || !('record' in one) ? [] : [one]));
|
|
49
44
|
}
|
|
@@ -55,7 +50,6 @@ async function adoption(runtime, room, current, local, submitted, accepted) {
|
|
|
55
50
|
return null;
|
|
56
51
|
}
|
|
57
52
|
const held = current.record.roomVersion;
|
|
58
|
-
logAccepted(runtime, room.locator, submitted, accepted);
|
|
59
53
|
let record = current.record;
|
|
60
54
|
let adopted;
|
|
61
55
|
if (!socket.reads.reached(room.locator, held, accepted.roomVersion) &&
|
|
@@ -78,7 +72,7 @@ async function adoption(runtime, room, current, local, submitted, accepted) {
|
|
|
78
72
|
...(adopted === undefined ? {} : { adopted }),
|
|
79
73
|
after() {
|
|
80
74
|
showing(runtime, room.locator, accepted.roomVersion, reached);
|
|
81
|
-
readable(
|
|
75
|
+
runtime.presence.readable(room.locator);
|
|
82
76
|
},
|
|
83
77
|
};
|
|
84
78
|
}
|
|
@@ -92,7 +86,7 @@ async function adopted(runtime, room, local, submitted, accepted) {
|
|
|
92
86
|
return kept;
|
|
93
87
|
}
|
|
94
88
|
async function adoptedMove(runtime, room, partner, local, submitted, accepted) {
|
|
95
|
-
const other = runtime.
|
|
89
|
+
const other = runtime.presence.room(partner);
|
|
96
90
|
let kept = true;
|
|
97
91
|
await settle(runtime, [room.locator, partner], async (held) => {
|
|
98
92
|
const left = await adoption(runtime, room, held.get(room.locator)?.replica, local, submitted, accepted);
|
|
@@ -119,7 +113,7 @@ async function behindIn({ store }, locator, batch) {
|
|
|
119
113
|
return room ? order.indexOf(batch.id) > 0 : order.length > 0;
|
|
120
114
|
}
|
|
121
115
|
async function submitRoom(runtime, room, local, authorized, progress, signal) {
|
|
122
|
-
const { store, socket,
|
|
116
|
+
const { store, socket, presence } = runtime;
|
|
123
117
|
while (socket.continuing() &&
|
|
124
118
|
socket.session.now().authorization !== undefined &&
|
|
125
119
|
!signal.aborted) {
|
|
@@ -152,21 +146,18 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
|
|
|
152
146
|
}
|
|
153
147
|
if (socket.writesHeld()) {
|
|
154
148
|
progress.complete = false;
|
|
155
|
-
journal.record(`submission ${room.locator} ${head.id} held`);
|
|
156
149
|
return 'done';
|
|
157
150
|
}
|
|
158
151
|
const lost = earlier || submission.state === 'submitted';
|
|
159
152
|
let result;
|
|
160
|
-
journal.record(`submission ${room.locator} ${head.id}`);
|
|
161
153
|
await store.exclusive(() => mark(runtime, local, room.locator, head, { state: 'submitted' }, lost));
|
|
162
|
-
if (socket.session.now().paused ||
|
|
154
|
+
if (socket.session.now().paused || presence.lost(room.locator))
|
|
163
155
|
return 'done';
|
|
164
156
|
if (signal.aborted || socket.writesHeld()) {
|
|
165
157
|
await store.exclusive(() => mark(runtime, local, room.locator, head, submission, earlier));
|
|
166
158
|
if (signal.aborted)
|
|
167
159
|
return 'done';
|
|
168
160
|
progress.complete = false;
|
|
169
|
-
journal.record(`submission ${room.locator} ${head.id} held`);
|
|
170
161
|
return 'done';
|
|
171
162
|
}
|
|
172
163
|
const opensBefore = socket.session.now().openSignals;
|
|
@@ -184,7 +175,8 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
|
|
|
184
175
|
...(state?.upload === undefined ? {} : { upload: state.upload }),
|
|
185
176
|
}, (upload) => store.exclusive(() => keepUpload(runtime, local, room.locator, head.id, upload)));
|
|
186
177
|
}
|
|
187
|
-
catch {
|
|
178
|
+
catch (error) {
|
|
179
|
+
runtime.retries.failed('sending', submitting(room.locator), error);
|
|
188
180
|
heard();
|
|
189
181
|
progress.complete = false;
|
|
190
182
|
if (socket.continuing())
|
|
@@ -199,14 +191,17 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
|
|
|
199
191
|
heard();
|
|
200
192
|
if (!socket.continuing())
|
|
201
193
|
return 'done';
|
|
194
|
+
if (result.kind === 'accepted')
|
|
195
|
+
runtime.retries.succeeded('sending', submitting(room.locator));
|
|
202
196
|
if (result.kind === 'transport-uncertainty') {
|
|
197
|
+
runtime.retries.uncertain('sending', submitting(room.locator), result);
|
|
203
198
|
progress.complete = false;
|
|
204
199
|
progress.reachable = false;
|
|
205
200
|
return 'again';
|
|
206
201
|
}
|
|
207
202
|
if (result.kind === 'room-not-readable') {
|
|
208
203
|
progress.complete = false;
|
|
209
|
-
roomUnreadable(runtime,
|
|
204
|
+
roomUnreadable(runtime, (presence.room(result.locator) ?? room).locator);
|
|
210
205
|
return 'done';
|
|
211
206
|
}
|
|
212
207
|
if (result.kind === 'revoked-authorization') {
|
|
@@ -219,24 +214,15 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
|
|
|
219
214
|
return 'done';
|
|
220
215
|
}
|
|
221
216
|
if (result.kind === 'write-halted') {
|
|
222
|
-
journal.record(`outcome ${room.locator} ${head.id} write-halted`);
|
|
223
217
|
await store.exclusive(() => mark(runtime, local, room.locator, head, { state: 'waiting' }, lost));
|
|
224
218
|
if (!socket.haltedSince(opensBefore))
|
|
225
219
|
continue;
|
|
226
220
|
progress.complete = false;
|
|
227
221
|
return 'done';
|
|
228
222
|
}
|
|
229
|
-
const other = partner === null ? undefined :
|
|
230
|
-
if (result.kind === 'conflicted' ||
|
|
231
|
-
result.kind === 'rejected' ||
|
|
232
|
-
result.kind === 'retryable-refusal') {
|
|
233
|
-
journal.record(`outcome ${room.locator} ${head.id} ${result.kind}` +
|
|
234
|
-
(result.kind === 'conflicted' && result.roomVersion !== undefined
|
|
235
|
-
? ` ${result.roomVersion}`
|
|
236
|
-
: ''));
|
|
237
|
-
journal.record(`refusal ${result.kind} ${result.code}`);
|
|
238
|
-
}
|
|
223
|
+
const other = partner === null ? undefined : presence.room(partner);
|
|
239
224
|
if (result.kind === 'retryable-refusal') {
|
|
225
|
+
runtime.retries.failed('sending', submitting(room.locator), refusalError(result));
|
|
240
226
|
const reset = result.reset;
|
|
241
227
|
progress.complete = false;
|
|
242
228
|
await store.exclusive(() => mark(runtime, local, room.locator, head, reset === undefined ? { state: 'waiting' } : { state: 'reset', reset }, lost));
|
|
@@ -278,14 +264,17 @@ async function submitRoom(runtime, room, local, authorized, progress, signal) {
|
|
|
278
264
|
}
|
|
279
265
|
return 'done';
|
|
280
266
|
}
|
|
267
|
+
function submitting(locator) {
|
|
268
|
+
return `submit ${locator}`;
|
|
269
|
+
}
|
|
281
270
|
export function submitLater(runtime, locator) {
|
|
282
271
|
if (runtime.localSaves)
|
|
283
272
|
return;
|
|
284
|
-
void runtime.recovery.attempt(
|
|
273
|
+
void runtime.recovery.attempt(submitting(locator), (signal) => submitPass(runtime, locator, signal));
|
|
285
274
|
}
|
|
286
275
|
async function submitPass(runtime, locator, signal) {
|
|
287
|
-
const { store, socket } = runtime;
|
|
288
|
-
const room =
|
|
276
|
+
const { store, socket, presence } = runtime;
|
|
277
|
+
const room = presence.room(locator);
|
|
289
278
|
if (!socket.continuing() || socket.stopping() || room === undefined) {
|
|
290
279
|
return 'done';
|
|
291
280
|
}
|
|
@@ -298,7 +287,8 @@ async function submitPass(runtime, locator, signal) {
|
|
|
298
287
|
return 'done';
|
|
299
288
|
next = await submitRoom(runtime, room, await store.open(), authorization, progress, signal);
|
|
300
289
|
}
|
|
301
|
-
catch {
|
|
290
|
+
catch (error) {
|
|
291
|
+
runtime.retries.failed('sending', submitting(locator), error);
|
|
302
292
|
progress.reachable = false;
|
|
303
293
|
next = 'again';
|
|
304
294
|
}
|
|
@@ -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"}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { expectedList } from './expectation.js';
|
|
2
|
+
import { changeBatchIdentity } from './identity.js';
|
|
3
|
+
const IDLE = { busy: false, drawn: false, ended: null };
|
|
4
|
+
export function acting(rules) {
|
|
5
|
+
const { store, uncertain, ending, settles } = rules;
|
|
6
|
+
const mint = rules.mint ?? (() => changeBatchIdentity());
|
|
7
|
+
const identities = new Map();
|
|
8
|
+
const waiting = new Map();
|
|
9
|
+
const settling = new Map();
|
|
10
|
+
const blobs = new WeakMap();
|
|
11
|
+
let counted = 0;
|
|
12
|
+
let touches = 0;
|
|
13
|
+
const requestOf = (name, input) => {
|
|
14
|
+
const carried = [];
|
|
15
|
+
const json = JSON.stringify(input, (_key, value) => {
|
|
16
|
+
if (!(value instanceof Blob))
|
|
17
|
+
return value;
|
|
18
|
+
let one = blobs.get(value);
|
|
19
|
+
if (one === undefined) {
|
|
20
|
+
counted += 1;
|
|
21
|
+
one = counted;
|
|
22
|
+
blobs.set(value, one);
|
|
23
|
+
}
|
|
24
|
+
carried.push(one);
|
|
25
|
+
return null;
|
|
26
|
+
});
|
|
27
|
+
return `${name}\u0000${json}\u0000${carried.join(',')}`;
|
|
28
|
+
};
|
|
29
|
+
const identityOf = (request) => {
|
|
30
|
+
const held = identities.get(request);
|
|
31
|
+
if (held !== undefined)
|
|
32
|
+
return held;
|
|
33
|
+
const fresh = { operation: mint(), touched: 0, flying: 0 };
|
|
34
|
+
identities.set(request, fresh);
|
|
35
|
+
return fresh;
|
|
36
|
+
};
|
|
37
|
+
const settled = (act, ended, calls) => {
|
|
38
|
+
const released = new Map();
|
|
39
|
+
for (const { request, identity, ended: answered } of calls) {
|
|
40
|
+
const heard = answered === 'accepted' || answered === 'refused';
|
|
41
|
+
if (ended === 'accepted' && heard)
|
|
42
|
+
released.set(request, identity.touched);
|
|
43
|
+
else {
|
|
44
|
+
touches += 1;
|
|
45
|
+
identity.touched = touches;
|
|
46
|
+
identities.set(request, identity);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (ended === 'refused' || ended === 'unsent')
|
|
50
|
+
store.drop(act);
|
|
51
|
+
for (const { request, ended: answered } of calls) {
|
|
52
|
+
const earlier = waiting.get(request);
|
|
53
|
+
if (answered === 'unsent' && earlier !== undefined)
|
|
54
|
+
continue;
|
|
55
|
+
if (earlier !== undefined && earlier !== act)
|
|
56
|
+
store.drop(earlier);
|
|
57
|
+
if (ended === 'unanswered')
|
|
58
|
+
waiting.set(request, act);
|
|
59
|
+
else
|
|
60
|
+
waiting.delete(request);
|
|
61
|
+
}
|
|
62
|
+
if (ended === 'accepted' || calls.some((one) => one.ended === 'accepted'))
|
|
63
|
+
rules.acted?.();
|
|
64
|
+
return released;
|
|
65
|
+
};
|
|
66
|
+
const release = (released) => {
|
|
67
|
+
for (const [request, touched] of released) {
|
|
68
|
+
const held = identities.get(request);
|
|
69
|
+
if (held !== undefined && held.touched === touched && held.flying === 0) {
|
|
70
|
+
identities.delete(request);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
return {
|
|
75
|
+
open() {
|
|
76
|
+
const listeners = new Set();
|
|
77
|
+
const releasing = new Map();
|
|
78
|
+
let tail = Promise.resolve();
|
|
79
|
+
let pressed = 0;
|
|
80
|
+
let drawing = 0;
|
|
81
|
+
let ended = null;
|
|
82
|
+
let held = null;
|
|
83
|
+
let presses = 0;
|
|
84
|
+
let shown = IDLE;
|
|
85
|
+
const show = () => {
|
|
86
|
+
const busy = pressed > 0;
|
|
87
|
+
const drawn = drawing > 0;
|
|
88
|
+
if (shown.busy === busy && shown.drawn === drawn && shown.ended === ended)
|
|
89
|
+
return;
|
|
90
|
+
shown = { busy, drawn, ended };
|
|
91
|
+
for (const listener of listeners)
|
|
92
|
+
listener();
|
|
93
|
+
};
|
|
94
|
+
const awaiting = (outcome, operations, heard, again) => new Promise((resolve) => {
|
|
95
|
+
const forgotten = () => {
|
|
96
|
+
for (const operation of operations)
|
|
97
|
+
if (settling.get(operation) === record)
|
|
98
|
+
settling.delete(operation);
|
|
99
|
+
};
|
|
100
|
+
const record = {
|
|
101
|
+
supersede() {
|
|
102
|
+
if (held !== record)
|
|
103
|
+
return;
|
|
104
|
+
held = null;
|
|
105
|
+
forgotten();
|
|
106
|
+
resolve(outcome);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
held = record;
|
|
110
|
+
for (const operation of operations)
|
|
111
|
+
settling.set(operation, record);
|
|
112
|
+
const answers = operations.map((operation) => heard(operation).then((answered) => {
|
|
113
|
+
if (!answered)
|
|
114
|
+
record.supersede();
|
|
115
|
+
return answered;
|
|
116
|
+
}));
|
|
117
|
+
void Promise.all(answers).then(() => {
|
|
118
|
+
if (held !== record)
|
|
119
|
+
return;
|
|
120
|
+
held = null;
|
|
121
|
+
forgotten();
|
|
122
|
+
resolve(again());
|
|
123
|
+
}, () => record.supersede());
|
|
124
|
+
});
|
|
125
|
+
const attempt = (steps, expected, press) => {
|
|
126
|
+
const act = store.begin();
|
|
127
|
+
let drew = false;
|
|
128
|
+
const expect = (more) => {
|
|
129
|
+
if (expectedList(more).length === 0)
|
|
130
|
+
return;
|
|
131
|
+
store.expect(act, more);
|
|
132
|
+
if (drew)
|
|
133
|
+
return;
|
|
134
|
+
drew = true;
|
|
135
|
+
drawing += 1;
|
|
136
|
+
show();
|
|
137
|
+
};
|
|
138
|
+
pressed += 1;
|
|
139
|
+
expect(expected);
|
|
140
|
+
show();
|
|
141
|
+
const calls = [];
|
|
142
|
+
const send = Object.assign(async (name, input, sending) => {
|
|
143
|
+
const request = requestOf(name, input);
|
|
144
|
+
const identity = identityOf(request);
|
|
145
|
+
settling.get(identity.operation)?.supersede();
|
|
146
|
+
const called = { request, identity, ended: null };
|
|
147
|
+
calls.push(called);
|
|
148
|
+
touches += 1;
|
|
149
|
+
identity.touched = touches;
|
|
150
|
+
identity.flying += 1;
|
|
151
|
+
let outcome;
|
|
152
|
+
try {
|
|
153
|
+
outcome = await sending(identity.operation);
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
outcome = uncertain;
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
identity.flying -= 1;
|
|
160
|
+
}
|
|
161
|
+
called.ended = ending(outcome);
|
|
162
|
+
return outcome;
|
|
163
|
+
}, { expect });
|
|
164
|
+
const end = (outcome, how) => {
|
|
165
|
+
for (const [request, touched] of settled(act, how, calls))
|
|
166
|
+
releasing.set(request, touched);
|
|
167
|
+
pressed -= 1;
|
|
168
|
+
if (drew)
|
|
169
|
+
drawing -= 1;
|
|
170
|
+
ended = outcome;
|
|
171
|
+
if (pressed === 0) {
|
|
172
|
+
release(releasing);
|
|
173
|
+
releasing.clear();
|
|
174
|
+
}
|
|
175
|
+
show();
|
|
176
|
+
};
|
|
177
|
+
const turn = tail.then(async () => {
|
|
178
|
+
ended = null;
|
|
179
|
+
show();
|
|
180
|
+
let outcome;
|
|
181
|
+
try {
|
|
182
|
+
outcome = await steps(send);
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
end(uncertain, 'unanswered');
|
|
186
|
+
throw error;
|
|
187
|
+
}
|
|
188
|
+
const how = ending(outcome);
|
|
189
|
+
end(outcome, how);
|
|
190
|
+
return { outcome, how };
|
|
191
|
+
});
|
|
192
|
+
tail = turn.catch(() => undefined);
|
|
193
|
+
return turn.then(({ outcome, how }) => {
|
|
194
|
+
const lost = calls.flatMap(({ identity, ended: answered }) => answered === 'unanswered' ? [identity.operation] : []);
|
|
195
|
+
if (how !== 'unanswered' || lost.length === 0 || settles === undefined)
|
|
196
|
+
return outcome;
|
|
197
|
+
if (press !== presses)
|
|
198
|
+
return outcome;
|
|
199
|
+
return awaiting(outcome, lost, settles, () => attempt(steps, expected, press));
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
const run = (steps, expected = null) => {
|
|
203
|
+
held?.supersede();
|
|
204
|
+
presses += 1;
|
|
205
|
+
return attempt(steps, expected, presses);
|
|
206
|
+
};
|
|
207
|
+
return {
|
|
208
|
+
run,
|
|
209
|
+
shown: () => shown,
|
|
210
|
+
subscribe(listener) {
|
|
211
|
+
listeners.add(listener);
|
|
212
|
+
return () => {
|
|
213
|
+
listeners.delete(listener);
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
forget() {
|
|
217
|
+
if (pressed > 0 || ended === null)
|
|
218
|
+
return;
|
|
219
|
+
ended = null;
|
|
220
|
+
show();
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
package/dist/actions.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ConversationHistoryRequest } from './adapter.js';
|
|
2
2
|
import { type CallResult, type HistoryAnswer, type Resolution } from './outcome.js';
|
|
3
3
|
import type { Attempted } from './recovery.js';
|
|
4
|
+
import type { Attempt } from './retried.js';
|
|
4
5
|
import type { Runtime } from './runtime.js';
|
|
5
6
|
export type HistoryQuery = {
|
|
6
7
|
revision?: string;
|
|
@@ -12,9 +13,14 @@ export declare function located(runtime: Runtime, room: string, path: string, de
|
|
|
12
13
|
path: string;
|
|
13
14
|
} | null>;
|
|
14
15
|
export declare function resolveReference(runtime: Runtime, room: string, path: string, destination: string): Promise<Resolution>;
|
|
15
|
-
export
|
|
16
|
+
export type Invoked = {
|
|
17
|
+
readonly dispatching?: () => Promise<void>;
|
|
18
|
+
readonly attempt?: Attempt;
|
|
19
|
+
};
|
|
20
|
+
export declare function invokeAction(runtime: Runtime, name: string, input: unknown, { dispatching, attempt }?: Invoked): Promise<CallResult>;
|
|
16
21
|
export declare function readConversationHistory(runtime: Runtime, request: ConversationHistoryRequest): Promise<CallResult>;
|
|
17
|
-
export declare function called(runtime: Runtime, name: string, input: unknown): Promise<CallResult>;
|
|
22
|
+
export declare function called(runtime: Runtime, name: string, input: unknown, attempt?: Attempt): Promise<CallResult>;
|
|
23
|
+
export declare function answeredCall(runtime: Runtime, operation: string): Promise<boolean>;
|
|
18
24
|
export declare function resendCalls(runtime: Runtime, signal: AbortSignal): Promise<Attempted>;
|
|
19
25
|
export declare function resendLater(runtime: Runtime): void;
|
|
20
26
|
//# sourceMappingURL=actions.d.ts.map
|
package/dist/actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../src/actions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAC;AAM/D,OAAO,EAWL,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAG5C,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAOF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,YAAiB,GACvB,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAED,wBAAsB,OAAO,CAC3B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAShD;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,UAAU,CAAC,CAuBrB;AAwBD,MAAM,MAAM,OAAO,GAAG;IACpB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,wBAAsB,YAAY,CAChC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,EAAE,WAAW,EAAE,OAAO,EAAE,GAAE,OAAY,GACrC,OAAO,CAAC,UAAU,CAAC,CA6BrB;AAED,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,UAAU,CAAC,CAerB;AA4GD,wBAAsB,MAAM,CAC1B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,UAAU,CAAC,CAKrB;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAaxF;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,CAAC,CAe3F;AAiBD,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,QAG3C"}
|