@agentshouse/mdruntime 0.1.0-cc5745cd9af96 → 0.1.0-ccbb89b0ca151
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 +18 -15
- package/dist/adapter.d.ts +56 -32
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +5 -1
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +21 -4
- package/dist/binary.d.ts +0 -5
- package/dist/binary.d.ts.map +1 -1
- package/dist/binary.js +1 -1
- package/dist/bootstrap.d.ts +30 -8
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +186 -85
- package/dist/chain.d.ts +11 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +6 -16
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -94
- package/dist/change.d.ts +31 -1
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +10 -1
- package/dist/client.d.ts +9 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +80 -6
- package/dist/collection.d.ts +6 -20
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +31 -354
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +765 -0
- package/dist/connection.d.ts +16 -9
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +2399 -952
- package/dist/conversation.d.ts +3 -3
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +80 -68
- 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 +3 -5
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +3 -1
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +18 -24
- package/dist/file.d.ts +2 -19
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +7 -122
- package/dist/fulltext.d.ts +27 -0
- package/dist/fulltext.d.ts.map +1 -0
- package/dist/fulltext.js +368 -0
- package/dist/host.d.ts +4 -4
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +45 -15
- package/dist/identity.d.ts +0 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -3
- package/dist/index.d.ts +11 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/live.d.ts +22 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +124 -0
- package/dist/media.d.ts +8 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +195 -0
- package/dist/memory.d.ts +2 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +63 -22
- package/dist/messages.d.ts +28 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +90 -0
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +1 -1
- 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 +12 -0
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +84 -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 +40 -5
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +36 -2
- package/dist/overlay.d.ts +1 -4
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +22 -148
- package/dist/query.d.ts +11 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +13 -1
- package/dist/reach.d.ts +11 -3
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +198 -69
- package/dist/readiness.d.ts +20 -9
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +6 -6
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +4 -2
- package/dist/recovery.d.ts +2 -2
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +8 -7
- package/dist/refresh.d.ts +15 -14
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +113 -75
- package/dist/replica.d.ts +56 -39
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +277 -197
- package/dist/room-draft.d.ts +4 -1
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +54 -13
- package/dist/rows.d.ts +38 -31
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +173 -101
- package/dist/save.d.ts +49 -14
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +352 -98
- package/dist/search.d.ts +11 -43
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +0 -213
- package/dist/shared.d.ts +4 -3
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +67 -34
- package/dist/store.d.ts +83 -95
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +317 -720
- package/dist/stored.d.ts +152 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +607 -0
- package/dist/tables.d.ts +352 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +624 -0
- package/dist/turn.d.ts +1 -1
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +31 -20
- package/dist/validation.d.ts +30 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +162 -0
- package/dist/windows.d.ts +2 -6
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +30 -34
- package/dist/wire.d.ts +17 -1
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +5 -1
- package/dist/words.d.ts +19 -0
- package/dist/words.d.ts.map +1 -0
- package/dist/words.js +150 -0
- package/package.json +18 -19
- package/AGENTS.md +0 -299
- package/dist/chat/acts.d.ts +0 -33
- package/dist/chat/acts.d.ts.map +0 -1
- package/dist/chat/acts.js +0 -36
- package/dist/chat/context.d.ts +0 -3
- package/dist/chat/context.d.ts.map +0 -1
- package/dist/chat/context.js +0 -10
- package/dist/chat/earlier.d.ts +0 -10
- package/dist/chat/earlier.d.ts.map +0 -1
- package/dist/chat/earlier.js +0 -54
- package/dist/chat/input.d.ts +0 -9
- package/dist/chat/input.d.ts.map +0 -1
- package/dist/chat/input.js +0 -99
- package/dist/chat/kit.d.ts +0 -61
- package/dist/chat/kit.d.ts.map +0 -1
- package/dist/chat/kit.js +0 -123
- package/dist/chat/lasting.d.ts +0 -6
- package/dist/chat/lasting.d.ts.map +0 -1
- package/dist/chat/lasting.js +0 -19
- package/dist/chat/list.d.ts +0 -28
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -103
- package/dist/chat/markdown.d.ts +0 -21
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -246
- package/dist/chat/message.d.ts +0 -7
- package/dist/chat/message.d.ts.map +0 -1
- package/dist/chat/message.js +0 -202
- package/dist/chat/messages.d.ts +0 -24
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -187
- package/dist/chat/name.d.ts +0 -6
- package/dist/chat/name.d.ts.map +0 -1
- package/dist/chat/name.js +0 -37
- package/dist/chat/opened.d.ts +0 -11
- package/dist/chat/opened.d.ts.map +0 -1
- package/dist/chat/opened.js +0 -17
- package/dist/chat/overlay.d.ts +0 -32
- package/dist/chat/overlay.d.ts.map +0 -1
- package/dist/chat/overlay.js +0 -107
- package/dist/chat/parts.d.ts +0 -57
- package/dist/chat/parts.d.ts.map +0 -1
- package/dist/chat/parts.js +0 -119
- package/dist/chat/pieces.d.ts +0 -62
- package/dist/chat/pieces.d.ts.map +0 -1
- package/dist/chat/pieces.js +0 -1110
- package/dist/chat/process.d.ts +0 -20
- package/dist/chat/process.d.ts.map +0 -1
- package/dist/chat/process.js +0 -32
- package/dist/chat/provider.d.ts +0 -64
- package/dist/chat/provider.d.ts.map +0 -1
- package/dist/chat/provider.js +0 -638
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -69
- package/dist/chat/questions.d.ts +0 -31
- package/dist/chat/questions.d.ts.map +0 -1
- package/dist/chat/questions.js +0 -111
- package/dist/chat/read.d.ts +0 -5
- package/dist/chat/read.d.ts.map +0 -1
- package/dist/chat/read.js +0 -13
- package/dist/chat/ready.d.ts +0 -34
- package/dist/chat/ready.d.ts.map +0 -1
- package/dist/chat/ready.js +0 -91
- package/dist/chat/steady.d.ts +0 -3
- package/dist/chat/steady.d.ts.map +0 -1
- package/dist/chat/steady.js +0 -26
- package/dist/chat/style.d.ts +0 -4
- package/dist/chat/style.d.ts.map +0 -1
- package/dist/chat/style.js +0 -302
- package/dist/chat.d.ts +0 -14
- package/dist/chat.d.ts.map +0 -1
- package/dist/chat.js +0 -8
- package/dist/read-side.d.ts +0 -27
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -826
package/dist/reach.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { unheldView } from './conversation.js';
|
|
2
2
|
import { modelTypes, NO_MODEL } from './model.js';
|
|
3
|
-
import {
|
|
3
|
+
import { changeOf, digestApplied, digestOf, observing, } from './observation.js';
|
|
4
4
|
import { runtimeError } from './failure.js';
|
|
5
|
-
import { failure, undeclared, } from './outcome.js';
|
|
5
|
+
import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
|
|
6
6
|
import { beneath } from './paths.js';
|
|
7
|
-
import { reconciled } from './read-side.js';
|
|
8
7
|
import { moveTarget, readParts, staleWrite, } from './room-draft.js';
|
|
9
8
|
import { documentKey } from './rows.js';
|
|
10
9
|
import { undeclaredSearch } from './search.js';
|
|
@@ -28,10 +27,20 @@ const NO_CHAT_DRAFT = {
|
|
|
28
27
|
prepend: () => Promise.resolve(),
|
|
29
28
|
discard: () => Promise.resolve(),
|
|
30
29
|
};
|
|
30
|
+
function areasOf(reach) {
|
|
31
|
+
return reach.areas ?? [];
|
|
32
|
+
}
|
|
33
|
+
function typedAreas(reach, room) {
|
|
34
|
+
return areasOf(reach).filter((area) => area.room === room && area.types.length > 0);
|
|
35
|
+
}
|
|
36
|
+
function fenced(reach, room, path) {
|
|
37
|
+
return areasOf(reach).some((area) => area.room === room && beneath(area.path, path));
|
|
38
|
+
}
|
|
31
39
|
export function holds(reach, room) {
|
|
32
40
|
return (reach === null ||
|
|
33
41
|
reach.rooms.includes(room) ||
|
|
34
|
-
reach.documents.some((document) => document.room === room)
|
|
42
|
+
reach.documents.some((document) => document.room === room) ||
|
|
43
|
+
typedAreas(reach, room).length > 0);
|
|
35
44
|
}
|
|
36
45
|
function wholly(reach, room) {
|
|
37
46
|
return reach === null || reach.rooms.includes(room);
|
|
@@ -41,33 +50,23 @@ export function governs(reach, room) {
|
|
|
41
50
|
return { collection: true, selection: room.typedSelection !== null };
|
|
42
51
|
}
|
|
43
52
|
const selected = (path) => room.typedSelection?.roots.some((root) => beneath(root, path)) ?? false;
|
|
44
|
-
const paths =
|
|
45
|
-
.
|
|
46
|
-
|
|
53
|
+
const paths = [
|
|
54
|
+
...reach.documents
|
|
55
|
+
.filter((document) => document.room === room.locator)
|
|
56
|
+
.map(({ path }) => path),
|
|
57
|
+
...typedAreas(reach, room.locator).map(({ path }) => path),
|
|
58
|
+
];
|
|
47
59
|
return { collection: paths.some((path) => !selected(path)), selection: paths.some(selected) };
|
|
48
60
|
}
|
|
49
61
|
function covers(reach, room, path) {
|
|
50
62
|
return (reach === null ||
|
|
51
|
-
reach
|
|
52
|
-
|
|
63
|
+
(!fenced(reach, room, path) &&
|
|
64
|
+
(reach.rooms.includes(room) ||
|
|
65
|
+
reach.documents.some((document) => document.room === room && document.path === path))));
|
|
53
66
|
}
|
|
54
67
|
function conversing(reach) {
|
|
55
68
|
return reach === null || reach.conversations;
|
|
56
69
|
}
|
|
57
|
-
function refers(reach, scope) {
|
|
58
|
-
if (reach === null)
|
|
59
|
-
return true;
|
|
60
|
-
if (scope === null)
|
|
61
|
-
return false;
|
|
62
|
-
if (scope.kind === 'conversations')
|
|
63
|
-
return reach.conversations;
|
|
64
|
-
return scope.path === undefined
|
|
65
|
-
? wholly(reach, scope.locator)
|
|
66
|
-
: covers(reach, scope.locator, scope.path);
|
|
67
|
-
}
|
|
68
|
-
function unreachedReference(fileRef) {
|
|
69
|
-
return { kind: 'absent', code: 'binary-file-absent', fields: { fileRef }, retryable: false };
|
|
70
|
-
}
|
|
71
70
|
export function planReach(reach) {
|
|
72
71
|
return reach === null
|
|
73
72
|
? null
|
|
@@ -76,6 +75,9 @@ export function planReach(reach) {
|
|
|
76
75
|
documents: [
|
|
77
76
|
...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
|
|
78
77
|
].sort(),
|
|
78
|
+
areas: areasOf(reach)
|
|
79
|
+
.map(({ room, path, types }) => ({ room, path, types: [...new Set(types)].sort() }))
|
|
80
|
+
.sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
|
|
79
81
|
};
|
|
80
82
|
}
|
|
81
83
|
function roomsWithin(reach, rooms) {
|
|
@@ -91,7 +93,7 @@ function typesWithin(reach, room, types) {
|
|
|
91
93
|
};
|
|
92
94
|
}
|
|
93
95
|
function moves(reach, room, move) {
|
|
94
|
-
return move === undefined || covers(reach, room, moveTarget(move));
|
|
96
|
+
return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
|
|
95
97
|
}
|
|
96
98
|
function draftWithin(reach, draft) {
|
|
97
99
|
return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
|
|
@@ -128,29 +130,61 @@ function statusWithin(reach, status) {
|
|
|
128
130
|
};
|
|
129
131
|
}
|
|
130
132
|
function queueWithin(reach, room, entries) {
|
|
131
|
-
return entries
|
|
132
|
-
(
|
|
133
|
+
return entries
|
|
134
|
+
.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
|
|
135
|
+
(change.kind !== 'move' || covers(reach, room, change.to))))
|
|
136
|
+
.map((entry) => {
|
|
137
|
+
const { between, ...batch } = entry.batch;
|
|
138
|
+
if (between === undefined)
|
|
139
|
+
return entry;
|
|
140
|
+
return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
|
|
141
|
+
? entry
|
|
142
|
+
: { ...entry, batch };
|
|
143
|
+
});
|
|
133
144
|
}
|
|
134
145
|
function unreached(room) {
|
|
135
146
|
return runtimeError('room-not-held', `No Local Replica for ${room}`);
|
|
136
147
|
}
|
|
148
|
+
function lockedError(room) {
|
|
149
|
+
return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
|
|
150
|
+
}
|
|
151
|
+
function deviceUnreached() {
|
|
152
|
+
return runtimeError('device-unreached', 'Only the panel cleans up this device');
|
|
153
|
+
}
|
|
154
|
+
const ATTACH_REQUIRED = 'attach-required';
|
|
155
|
+
function attachRequired() {
|
|
156
|
+
return runtimeError(ATTACH_REQUIRED, 'App code takes a file in with binaryFile.attach');
|
|
157
|
+
}
|
|
158
|
+
function carriesFile(parts) {
|
|
159
|
+
return parts !== null && typeof parts === 'object' && Object.hasOwn(parts, 'file');
|
|
160
|
+
}
|
|
137
161
|
export function narrowed(runtime, given, told) {
|
|
138
162
|
const { md, watch } = runtime;
|
|
139
163
|
let reach = given;
|
|
140
164
|
let port = told;
|
|
141
165
|
const open = new Set();
|
|
142
|
-
function following(begin) {
|
|
166
|
+
function following(begin, locking = false) {
|
|
143
167
|
let stop = begin();
|
|
144
168
|
const restart = () => {
|
|
145
169
|
stop();
|
|
146
170
|
stop = begin();
|
|
147
171
|
};
|
|
148
172
|
open.add(restart);
|
|
173
|
+
const unwatch = locking ? runtime.watchLocks(restart) : () => { };
|
|
149
174
|
return () => {
|
|
150
175
|
open.delete(restart);
|
|
176
|
+
unwatch();
|
|
151
177
|
stop();
|
|
152
178
|
};
|
|
153
179
|
}
|
|
180
|
+
const unlocking = (rooms) => {
|
|
181
|
+
const locked = (rooms ?? []).filter((room) => runtime.locked(room));
|
|
182
|
+
return locked.length === 0
|
|
183
|
+
? null
|
|
184
|
+
: { pending: locked.map((room) => ({ room, awaits: 'unlock' })) };
|
|
185
|
+
};
|
|
186
|
+
const unlocked = (entries) => entries.filter((entry) => !runtime.locked(entry.room));
|
|
187
|
+
const intoLocked = (held) => held.some((move) => move?.room !== undefined && runtime.locked(move.room));
|
|
154
188
|
const within = (topic, input, deliver) => {
|
|
155
189
|
if (topic === 'rooms') {
|
|
156
190
|
return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
|
|
@@ -159,45 +193,60 @@ export function narrowed(runtime, given, told) {
|
|
|
159
193
|
return following(() => runtime.watchReadiness(port, reach, deliver));
|
|
160
194
|
}
|
|
161
195
|
if (topic === 'sync-status') {
|
|
162
|
-
return following(() => watch(topic, input, (status) =>
|
|
196
|
+
return following(() => watch(topic, input, (status) => {
|
|
197
|
+
const within = statusWithin(reach, status);
|
|
198
|
+
deliver({ ...within, attentionRequired: unlocked(within.attentionRequired) });
|
|
199
|
+
}), true);
|
|
163
200
|
}
|
|
164
201
|
if (topic === 'room-drafts') {
|
|
165
|
-
return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
|
|
202
|
+
return following(() => watch(topic, input, (drafts) => deliver(unlocked(draftsWithin(reach, drafts)))), true);
|
|
166
203
|
}
|
|
167
204
|
if (topic === 'queue') {
|
|
168
205
|
const room = input[0];
|
|
169
206
|
return following(() => {
|
|
170
|
-
if (!holds(reach, room)) {
|
|
207
|
+
if (!holds(reach, room) || runtime.locked(room)) {
|
|
171
208
|
deliver([]);
|
|
172
209
|
return () => { };
|
|
173
210
|
}
|
|
174
211
|
return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
|
|
175
|
-
});
|
|
212
|
+
}, true);
|
|
176
213
|
}
|
|
177
214
|
if (topic === 'query') {
|
|
178
215
|
const plan = runtime.plan(input[0], reach);
|
|
179
216
|
let held = null;
|
|
180
217
|
return following(() => {
|
|
218
|
+
const locked = unlocking(plan.rooms);
|
|
219
|
+
if (locked !== null) {
|
|
220
|
+
const answer = { result: locked, keys: [] };
|
|
221
|
+
if (held === null || changeOf(held, answer) !== null)
|
|
222
|
+
deliver(answer);
|
|
223
|
+
held = digestOf(answer);
|
|
224
|
+
return () => { };
|
|
225
|
+
}
|
|
181
226
|
let first = true;
|
|
182
|
-
|
|
227
|
+
let open = true;
|
|
228
|
+
const heard = (message) => {
|
|
183
229
|
if (!first) {
|
|
184
|
-
held =
|
|
230
|
+
held = digestApplied(held, message);
|
|
185
231
|
deliver(message);
|
|
186
232
|
return;
|
|
187
233
|
}
|
|
188
234
|
first = false;
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
deliver(next.message);
|
|
235
|
+
const change = held === null ? message : changeOf(held, message);
|
|
236
|
+
held = digestOf(message);
|
|
237
|
+
if (change !== null)
|
|
238
|
+
deliver(change);
|
|
239
|
+
};
|
|
240
|
+
const current = { ...plan, reach: planReach(reach), locked: runtime.lockedRooms() };
|
|
241
|
+
const stop = runtime.watchPlan(current, (message) => {
|
|
242
|
+
if (open)
|
|
243
|
+
heard(message);
|
|
199
244
|
});
|
|
200
|
-
|
|
245
|
+
return () => {
|
|
246
|
+
open = false;
|
|
247
|
+
stop();
|
|
248
|
+
};
|
|
249
|
+
}, true);
|
|
201
250
|
}
|
|
202
251
|
if (topic === 'conversation') {
|
|
203
252
|
return following(() => {
|
|
@@ -217,16 +266,32 @@ export function narrowed(runtime, given, told) {
|
|
|
217
266
|
}
|
|
218
267
|
return watch(topic, input, deliver);
|
|
219
268
|
};
|
|
269
|
+
const files = new Map();
|
|
270
|
+
let handed = 0;
|
|
271
|
+
async function hand(reading) {
|
|
272
|
+
const answer = await reading;
|
|
273
|
+
if (answer.kind !== 'binary')
|
|
274
|
+
return answer;
|
|
275
|
+
handed += 1;
|
|
276
|
+
const file = String(handed);
|
|
277
|
+
files.set(file, answer.file);
|
|
278
|
+
return { ...answer, file };
|
|
279
|
+
}
|
|
220
280
|
const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
|
|
221
281
|
const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
|
|
222
282
|
const view = {
|
|
223
283
|
...md,
|
|
224
284
|
rooms: () => roomsWithin(reach, md.rooms()),
|
|
225
|
-
query: ((input) =>
|
|
285
|
+
query: ((input) => {
|
|
286
|
+
const plan = runtime.plan(input, reach);
|
|
287
|
+
return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
|
|
288
|
+
}),
|
|
226
289
|
search: (input) => port.search === 'required'
|
|
227
|
-
? runtime.search(input, reach)
|
|
290
|
+
? runtime.search(input, reach, runtime.lockedRooms())
|
|
228
291
|
: Promise.resolve(undeclaredSearch()),
|
|
229
292
|
types(room) {
|
|
293
|
+
if (holds(reach, room) && runtime.locked(room))
|
|
294
|
+
throw lockedError(room);
|
|
230
295
|
if (wholly(reach, room))
|
|
231
296
|
return md.types(room);
|
|
232
297
|
if (!holds(reach, room))
|
|
@@ -237,50 +302,114 @@ export function narrowed(runtime, given, told) {
|
|
|
237
302
|
async save(room, roomDrafts, writtenBy) {
|
|
238
303
|
if (!holds(reach, room))
|
|
239
304
|
throw unreached(room);
|
|
240
|
-
|
|
241
|
-
|
|
305
|
+
if (runtime.locked(room))
|
|
306
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
307
|
+
const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
|
|
308
|
+
const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
|
|
242
309
|
if (outside !== undefined) {
|
|
243
310
|
return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
|
|
244
311
|
}
|
|
312
|
+
if (intoLocked(held))
|
|
313
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
245
314
|
return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
|
|
246
315
|
},
|
|
247
316
|
async saveParts(room, parts, writtenBy) {
|
|
248
317
|
if (!holds(reach, room))
|
|
249
318
|
throw unreached(room);
|
|
250
|
-
|
|
319
|
+
const filed = reach === null ? undefined : parts.find(({ parts: one }) => carriesFile(one));
|
|
320
|
+
if (filed !== undefined) {
|
|
321
|
+
return { outcome: 'refused', code: ATTACH_REQUIRED, retryable: false, file: filed.path };
|
|
322
|
+
}
|
|
323
|
+
if (runtime.locked(room))
|
|
324
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
325
|
+
const held = parts.map(({ parts: one }) => readParts(one).move);
|
|
326
|
+
if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
|
|
251
327
|
throw unreached(room);
|
|
252
328
|
}
|
|
329
|
+
if (intoLocked(held))
|
|
330
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
253
331
|
return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
|
|
254
332
|
},
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
333
|
+
resolve(room, path, destination) {
|
|
334
|
+
const at = runtime.located(room, path, destination);
|
|
335
|
+
return at !== null && !covers(reach, at.room, at.path)
|
|
336
|
+
? Promise.resolve(UNREADABLE)
|
|
337
|
+
: md.resolve(room, path, destination);
|
|
338
|
+
},
|
|
339
|
+
history: (room, path, query) => !covers(reach, room, path)
|
|
340
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
341
|
+
: runtime.locked(room)
|
|
342
|
+
? Promise.resolve(lockedRoom(room))
|
|
343
|
+
: md.history(room, path, query),
|
|
258
344
|
binaryFile: {
|
|
259
|
-
read: (room, path, revision) => covers(reach, room, path)
|
|
260
|
-
?
|
|
261
|
-
:
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
345
|
+
read: (room, path, revision) => !covers(reach, room, path)
|
|
346
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
347
|
+
: runtime.locked(room)
|
|
348
|
+
? Promise.resolve(lockedRoom(room))
|
|
349
|
+
: hand(md.binaryFile.read(room, path, revision)),
|
|
350
|
+
link: (room, path, revision) => !covers(reach, room, path)
|
|
351
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
352
|
+
: runtime.locked(room)
|
|
353
|
+
? Promise.resolve(lockedRoom(room))
|
|
354
|
+
: md.binaryFile.link(room, path, revision),
|
|
355
|
+
show: (room, path, revision) => !covers(reach, room, path)
|
|
356
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
357
|
+
: runtime.locked(room)
|
|
358
|
+
? Promise.resolve(lockedRoom(room))
|
|
359
|
+
: hand(md.binaryFile.show(room, path, revision)),
|
|
360
|
+
attach: (room, file) => !wholly(reach, room)
|
|
361
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
362
|
+
: runtime.locked(room)
|
|
363
|
+
? Promise.resolve(lockedRoom(room))
|
|
364
|
+
: md.binaryFile.attach(room, file),
|
|
365
|
+
async part(file, part) {
|
|
366
|
+
const key = files.get(file);
|
|
367
|
+
if (key === undefined)
|
|
368
|
+
return null;
|
|
369
|
+
const bytes = await md.binaryFile.part(key, part);
|
|
370
|
+
if (bytes === null)
|
|
371
|
+
files.delete(file);
|
|
372
|
+
return bytes;
|
|
373
|
+
},
|
|
268
374
|
},
|
|
269
|
-
reached: (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
270
|
-
|
|
375
|
+
reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
376
|
+
!runtime.locked(room) &&
|
|
377
|
+
(await md.reached(room, roomVersion, path)),
|
|
271
378
|
log: () => (reach === null ? md.log() : ''),
|
|
379
|
+
cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
|
|
272
380
|
roomDraft: {
|
|
273
|
-
list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
381
|
+
list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
|
|
382
|
+
async read(room, path) {
|
|
383
|
+
if (!covers(reach, room, path))
|
|
384
|
+
return null;
|
|
385
|
+
if (runtime.locked(room))
|
|
386
|
+
throw lockedError(room);
|
|
387
|
+
return shownDraft(reach, await md.roomDraft.read(room, path));
|
|
388
|
+
},
|
|
389
|
+
write(room, path, revision, parts, next) {
|
|
390
|
+
try {
|
|
391
|
+
if (reach !== null && carriesFile(parts))
|
|
392
|
+
throw attachRequired();
|
|
393
|
+
const move = readParts(parts).move;
|
|
394
|
+
if (!covers(reach, room, path) || !moves(reach, room, move))
|
|
395
|
+
throw unreached(room);
|
|
396
|
+
if (runtime.locked(room))
|
|
397
|
+
throw lockedError(room);
|
|
398
|
+
if (intoLocked([move]))
|
|
399
|
+
throw lockedError(move.room);
|
|
400
|
+
}
|
|
401
|
+
catch (error) {
|
|
402
|
+
return Promise.reject(error);
|
|
278
403
|
}
|
|
279
|
-
return
|
|
404
|
+
return md.roomDraft
|
|
405
|
+
.write(room, path, revision, parts, next)
|
|
406
|
+
.then((written) => writeWithin(reach, written));
|
|
280
407
|
},
|
|
281
408
|
async discard(room, path, revision) {
|
|
282
409
|
if (!covers(reach, room, path))
|
|
283
410
|
return staleWrite(null);
|
|
411
|
+
if (runtime.locked(room))
|
|
412
|
+
throw lockedError(room);
|
|
284
413
|
return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
|
|
285
414
|
},
|
|
286
415
|
},
|
package/dist/readiness.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Open } from './open.js';
|
|
2
2
|
export type CodeAvailability = Open<'stored' | 'absent'>;
|
|
3
|
-
export type RoomPreparation = Open<'complete' | 'acquiring' | 'preparing' | '
|
|
3
|
+
export type RoomPreparation = Open<'complete' | 'acquiring' | 'preparing' | 'refused' | 'unadmitted'>;
|
|
4
4
|
export type RoomCoverage = {
|
|
5
5
|
readonly room: string;
|
|
6
6
|
readonly state: RoomPreparation;
|
|
7
7
|
};
|
|
8
|
-
export type ConversationCoverage = Open<'complete' | 'acquiring' | '
|
|
8
|
+
export type ConversationCoverage = Open<'complete' | 'acquiring' | 'undeclared'>;
|
|
9
9
|
export type SearchObligation = Open<'required' | 'unused'>;
|
|
10
10
|
export type TargetCoverage = {
|
|
11
11
|
readonly complete: boolean;
|
|
@@ -18,17 +18,28 @@ export type Persistence = Open<'granted' | 'denied' | 'unavailable'>;
|
|
|
18
18
|
export type Durability = Open<'persistent' | 'best-effort'>;
|
|
19
19
|
export type ConnectionAvailability = Open<'connected' | 'connecting' | 'unreachable'>;
|
|
20
20
|
export type HouseOutcome = Open<'open' | 'write-halted' | 'refused'>;
|
|
21
|
-
export type
|
|
22
|
-
readonly cause: Open<'insufficient-space' | 'quota-exceeded'>;
|
|
23
|
-
readonly needed: number | null;
|
|
24
|
-
readonly available: number | null;
|
|
25
|
-
};
|
|
21
|
+
export type Space = Open<'full'>;
|
|
26
22
|
export type RefusedRoom = {
|
|
27
23
|
readonly room: string;
|
|
24
|
+
readonly name: string;
|
|
28
25
|
readonly file: string;
|
|
29
26
|
readonly rule: string;
|
|
30
27
|
readonly location: string | null;
|
|
31
28
|
};
|
|
29
|
+
export type InstallationStep = Open<'listing' | 'downloading' | 'writing' | 'replaying'>;
|
|
30
|
+
export type InstallationPause = Open<'hidden'>;
|
|
31
|
+
export type InstallationAmount = {
|
|
32
|
+
readonly done: number;
|
|
33
|
+
readonly total: number;
|
|
34
|
+
};
|
|
35
|
+
export type Installation = {
|
|
36
|
+
readonly step: InstallationStep | null;
|
|
37
|
+
readonly paused: InstallationPause | null;
|
|
38
|
+
readonly rooms: InstallationAmount;
|
|
39
|
+
readonly parts: InstallationAmount;
|
|
40
|
+
readonly bytes: InstallationAmount;
|
|
41
|
+
readonly received: InstallationAmount;
|
|
42
|
+
};
|
|
32
43
|
export type ReadinessStatus = Open<'preparing' | 'paused' | 'refused' | 'ready' | 'lost'>;
|
|
33
44
|
export type Readiness = {
|
|
34
45
|
readonly status: ReadinessStatus;
|
|
@@ -40,7 +51,8 @@ export type Readiness = {
|
|
|
40
51
|
readonly persistence: Persistence;
|
|
41
52
|
readonly connection: ConnectionAvailability;
|
|
42
53
|
readonly house: HouseOutcome;
|
|
43
|
-
readonly
|
|
54
|
+
readonly space: Space | null;
|
|
55
|
+
readonly installation: Installation;
|
|
44
56
|
readonly refused: readonly RefusedRoom[];
|
|
45
57
|
readonly lost: boolean;
|
|
46
58
|
};
|
|
@@ -48,6 +60,5 @@ export type ReadinessFacts = Omit<Readiness, 'status' | 'ready' | 'usable' | 'du
|
|
|
48
60
|
readonly coverage: Omit<TargetCoverage, 'complete'>;
|
|
49
61
|
readonly established: boolean;
|
|
50
62
|
};
|
|
51
|
-
export declare const SETTLED_ROOMS: ReadonlySet<string>;
|
|
52
63
|
export declare function readinessOf(facts: ReadinessFacts): Readiness;
|
|
53
64
|
//# sourceMappingURL=readiness.d.ts.map
|
package/dist/readiness.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,MAAM,MAAM,gBAAgB,GAAG,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,
|
|
1
|
+
{"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../src/readiness.ts"],"names":[],"mappings":"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"}
|
package/dist/readiness.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const COMPLETE_ROOMS = new Set(['complete', 'unadmitted']);
|
|
2
|
-
|
|
2
|
+
const SETTLED_ROOMS = new Set([...COMPLETE_ROOMS, 'refused']);
|
|
3
3
|
export function readinessOf(facts) {
|
|
4
4
|
const { established, coverage: held, ...reported } = facts;
|
|
5
5
|
const settledConversations = held.conversations === 'complete' || held.conversations === 'undeclared';
|
|
@@ -15,12 +15,12 @@ export function readinessOf(facts) {
|
|
|
15
15
|
const usable = stored && (ready || established);
|
|
16
16
|
const status = ready
|
|
17
17
|
? 'ready'
|
|
18
|
-
: facts.
|
|
18
|
+
: facts.space !== null || facts.installation.paused !== null
|
|
19
19
|
? 'paused'
|
|
20
|
-
:
|
|
21
|
-
? '
|
|
22
|
-
:
|
|
23
|
-
? '
|
|
20
|
+
: settled && !complete
|
|
21
|
+
? 'refused'
|
|
22
|
+
: facts.lost && !established
|
|
23
|
+
? 'lost'
|
|
24
24
|
: 'preparing';
|
|
25
25
|
return {
|
|
26
26
|
...reported,
|
package/dist/reads.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;
|
|
1
|
+
{"version":3,"file":"reads.d.ts","sourceRoot":"","sources":["../src/reads.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EAOR,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG;IAC9B,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9C,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAkCF,wBAAgB,SAAS,CACvB,OAAO,EAAE,OAAO,EAChB,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,EACzC,UAAU,EAAE,MAAM,MAAM,GACvB,SAAS,CA4FX"}
|
package/dist/reads.js
CHANGED
|
@@ -5,7 +5,7 @@ function declaredAs(declaration) {
|
|
|
5
5
|
return declared;
|
|
6
6
|
}
|
|
7
7
|
function sameHeld(one, other) {
|
|
8
|
-
return one
|
|
8
|
+
return one === other;
|
|
9
9
|
}
|
|
10
10
|
function failed(answer) {
|
|
11
11
|
return answer?.kind === 'transport-uncertainty';
|
|
@@ -20,7 +20,7 @@ export function doorReads(adapter, declaration, generation) {
|
|
|
20
20
|
let carrying = false;
|
|
21
21
|
function joined(read, authorization, request, ask) {
|
|
22
22
|
const key = `${read} ${request.locator} ${request.pageToken ?? ''}`;
|
|
23
|
-
const { held, ...named } = request;
|
|
23
|
+
const { held, received, ...named } = request;
|
|
24
24
|
const asked = JSON.stringify([declaredAs(declaration(request.locator)), named]);
|
|
25
25
|
const asking = generation();
|
|
26
26
|
const current = reading.get(key);
|
|
@@ -28,6 +28,7 @@ export function doorReads(adapter, declaration, generation) {
|
|
|
28
28
|
current.authorization === authorization &&
|
|
29
29
|
current.asked === asked &&
|
|
30
30
|
sameHeld(current.held, held) &&
|
|
31
|
+
current.received === received &&
|
|
31
32
|
(!current.settled || current.holder < asking)) {
|
|
32
33
|
if (current.settled && !current.continued)
|
|
33
34
|
reading.delete(key);
|
|
@@ -49,6 +50,7 @@ export function doorReads(adapter, declaration, generation) {
|
|
|
49
50
|
authorization,
|
|
50
51
|
asked,
|
|
51
52
|
held,
|
|
53
|
+
received,
|
|
52
54
|
answer,
|
|
53
55
|
from: asking,
|
|
54
56
|
holder: asking,
|
package/dist/recovery.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export type AttemptOptions = {
|
|
|
8
8
|
};
|
|
9
9
|
export type RecoveryOptions = {
|
|
10
10
|
readonly firstMs?: number;
|
|
11
|
-
readonly
|
|
11
|
+
readonly maxMs?: number;
|
|
12
12
|
readonly attempts?: number;
|
|
13
13
|
readonly inFlight?: number;
|
|
14
14
|
};
|
|
@@ -20,6 +20,6 @@ export type Recovery = {
|
|
|
20
20
|
scope(inFlight?: number): Recovery;
|
|
21
21
|
retire(): Promise<void>;
|
|
22
22
|
};
|
|
23
|
-
export declare function retryDelay(tries: number, firstMs?: number,
|
|
23
|
+
export declare function retryDelay(tries: number, firstMs?: number, maxMs?: number): number;
|
|
24
24
|
export declare function createRecovery(options?: RecoveryOptions): Recovery;
|
|
25
25
|
//# sourceMappingURL=recovery.d.ts.map
|
package/dist/recovery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnE,MAAM,MAAM,OAAO,GAAG,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;AAElE,MAAM,MAAM,cAAc,GAAG;IAAE,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,QAAQ,GAAG;IACrB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClF,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,MAAM,IAAI,IAAI,CAAC;IACf,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IACnC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB,CAAC;AAsBF,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,SAAW,EAAE,KAAK,SAAS,GAAG,MAAM,CAGpF;AAwKD,wBAAgB,cAAc,CAAC,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAStE"}
|
package/dist/recovery.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// A first retry waits about a second, so a passing failure clears before the next attempt.
|
|
2
2
|
const FIRST_MS = 1_000;
|
|
3
3
|
// Waits stop doubling at half a minute, so work resumes soon after a long failure ends.
|
|
4
|
-
const
|
|
4
|
+
const MAX_MS = 30_000;
|
|
5
5
|
const ATTEMPTS = 8;
|
|
6
|
-
export function retryDelay(tries, firstMs = FIRST_MS,
|
|
7
|
-
const
|
|
8
|
-
return
|
|
6
|
+
export function retryDelay(tries, firstMs = FIRST_MS, maxMs = MAX_MS) {
|
|
7
|
+
const longest = Math.min(maxMs, firstMs * 2 ** tries);
|
|
8
|
+
return longest / 2 + (Math.random() * longest) / 2;
|
|
9
9
|
}
|
|
10
10
|
function owner(backoff, inFlight, release = () => { }) {
|
|
11
11
|
const intents = new Map();
|
|
@@ -84,7 +84,8 @@ function owner(backoff, inFlight, release = () => { }) {
|
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
if (result === 'again') {
|
|
87
|
-
|
|
87
|
+
// The next attempt waits the doubling backoff, up to its maximum.
|
|
88
|
+
const delay = retryDelay(intent.tries - 1, backoff.firstMs, backoff.maxMs);
|
|
88
89
|
wait(key, intent, Date.now() + delay, false);
|
|
89
90
|
}
|
|
90
91
|
else
|
|
@@ -135,7 +136,7 @@ function owner(backoff, inFlight, release = () => { }) {
|
|
|
135
136
|
wait(key, intent, options.at, true);
|
|
136
137
|
else if (options.again === true) {
|
|
137
138
|
intent.tries = 1;
|
|
138
|
-
wait(key, intent, Date.now() + retryDelay(0, backoff.firstMs, backoff.
|
|
139
|
+
wait(key, intent, Date.now() + retryDelay(0, backoff.firstMs, backoff.maxMs), false);
|
|
139
140
|
}
|
|
140
141
|
else
|
|
141
142
|
launch(key, intent);
|
|
@@ -191,7 +192,7 @@ function owner(backoff, inFlight, release = () => { }) {
|
|
|
191
192
|
export function createRecovery(options = {}) {
|
|
192
193
|
return owner({
|
|
193
194
|
firstMs: options.firstMs ?? FIRST_MS,
|
|
194
|
-
|
|
195
|
+
maxMs: options.maxMs ?? MAX_MS,
|
|
195
196
|
attempts: options.attempts ?? ATTEMPTS,
|
|
196
197
|
}, options.inFlight ?? Infinity);
|
|
197
198
|
}
|