@agentshouse/mdruntime 0.1.0-cacb4c3f6734e → 0.1.0-cae97ad2e9142
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 +23 -10
- package/dist/adapter.d.ts +126 -30
- 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 +36 -6
- 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 +186 -45
- 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 +9 -14
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -56
- package/dist/change.d.ts +45 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +34 -0
- package/dist/client.d.ts +35 -14
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +107 -17
- package/dist/collection.d.ts +9 -13
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +46 -56
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +767 -0
- package/dist/connection.d.ts +58 -19
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +3659 -726
- package/dist/conversation.d.ts +41 -12
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +588 -180
- 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 +5 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +19 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +151 -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/fence.d.ts +6 -0
- package/dist/fence.d.ts.map +1 -0
- package/dist/fence.js +10 -0
- package/dist/file.d.ts +2 -10
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +3 -120
- 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 +15 -2
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +132 -21
- package/dist/identity.d.ts +4 -0
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +16 -1
- package/dist/index.d.ts +20 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/live.d.ts +22 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +124 -0
- package/dist/memory.d.ts +13 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +99 -31
- 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 +14 -4
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +13 -2
- 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 +19 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +113 -12
- 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 +62 -3
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +67 -1
- package/dist/overlay.d.ts +15 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +136 -180
- package/dist/query.d.ts +70 -4
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +53 -38
- package/dist/reach.d.ts +17 -4
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +226 -65
- package/dist/react.d.ts +31 -20
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +13 -21
- package/dist/readiness.d.ts +64 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +33 -0
- package/dist/reads.d.ts +11 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +100 -0
- package/dist/recovery.d.ts +25 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +198 -0
- package/dist/refresh.d.ts +19 -8
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +125 -57
- package/dist/replica.d.ts +59 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +321 -155
- package/dist/room-draft.d.ts +41 -9
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +186 -37
- package/dist/rows.d.ts +37 -35
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +168 -100
- package/dist/save.d.ts +71 -4
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +815 -146
- package/dist/search.d.ts +41 -29
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +37 -105
- package/dist/seed.d.ts +16 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +75 -0
- package/dist/shared.d.ts +16 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +431 -0
- package/dist/status.d.ts +6 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -8
- package/dist/store.d.ts +124 -58
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +362 -344
- package/dist/stored.d.ts +150 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +564 -0
- package/dist/tables.d.ts +354 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +624 -0
- 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 +30 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +162 -0
- package/dist/windows.d.ts +22 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +89 -0
- package/dist/wire.d.ts +169 -33
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +68 -31
- package/dist/words.d.ts +19 -0
- package/dist/words.d.ts.map +1 -0
- package/dist/words.js +150 -0
- package/package.json +26 -15
- package/AGENTS.md +0 -244
- 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 -18
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -433
package/dist/reach.js
CHANGED
|
@@ -1,34 +1,47 @@
|
|
|
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
|
+
import { runtimeError } from './failure.js';
|
|
5
|
+
import { failure, lockedRoom, ROOM_LOCKED, undeclared, UNREADABLE, } from './outcome.js';
|
|
4
6
|
import { beneath } from './paths.js';
|
|
5
|
-
import {
|
|
6
|
-
import { moveTarget, readParts } from './room-draft.js';
|
|
7
|
+
import { moveTarget, readParts, staleWrite, } from './room-draft.js';
|
|
7
8
|
import { documentKey } from './rows.js';
|
|
9
|
+
import { undeclaredSearch } from './search.js';
|
|
8
10
|
const UNHELD_TYPES = { collection: modelTypes(NO_MODEL), typedSelection: null };
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return Promise.resolve(UNDECLARED);
|
|
11
|
+
function unconversed(name) {
|
|
12
|
+
return () => Promise.resolve(undeclared(name));
|
|
12
13
|
}
|
|
13
14
|
const NO_CONVERSATION = {
|
|
14
15
|
list: () => Promise.resolve([]),
|
|
15
16
|
read: (conversation) => Promise.resolve(unheldView(conversation)),
|
|
16
|
-
create:
|
|
17
|
-
send:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
17
|
+
create: unconversed('conversation.create'),
|
|
18
|
+
send: unconversed('conversation.send'),
|
|
19
|
+
attach: unconversed('conversation.attach'),
|
|
20
|
+
answer: unconversed('conversation.answer'),
|
|
21
|
+
interrupt: unconversed('conversation.interrupt'),
|
|
22
|
+
kill: unconversed('conversation.kill'),
|
|
23
|
+
cancel: unconversed('conversation.cancel'),
|
|
24
|
+
delete: unconversed('conversation.delete'),
|
|
23
25
|
};
|
|
24
26
|
const NO_CHAT_DRAFT = {
|
|
25
27
|
write: () => Promise.resolve(),
|
|
28
|
+
prepend: () => Promise.resolve(),
|
|
26
29
|
discard: () => Promise.resolve(),
|
|
27
30
|
};
|
|
31
|
+
function areasOf(reach) {
|
|
32
|
+
return reach.areas ?? [];
|
|
33
|
+
}
|
|
34
|
+
function typedAreas(reach, room) {
|
|
35
|
+
return areasOf(reach).filter((area) => area.room === room && area.types.length > 0);
|
|
36
|
+
}
|
|
37
|
+
function fenced(reach, room, path) {
|
|
38
|
+
return areasOf(reach).some((area) => area.room === room && beneath(area.path, path));
|
|
39
|
+
}
|
|
28
40
|
export function holds(reach, room) {
|
|
29
41
|
return (reach === null ||
|
|
30
42
|
reach.rooms.includes(room) ||
|
|
31
|
-
reach.documents.some((document) => document.room === room)
|
|
43
|
+
reach.documents.some((document) => document.room === room) ||
|
|
44
|
+
typedAreas(reach, room).length > 0);
|
|
32
45
|
}
|
|
33
46
|
function wholly(reach, room) {
|
|
34
47
|
return reach === null || reach.rooms.includes(room);
|
|
@@ -38,15 +51,19 @@ export function governs(reach, room) {
|
|
|
38
51
|
return { collection: true, selection: room.typedSelection !== null };
|
|
39
52
|
}
|
|
40
53
|
const selected = (path) => room.typedSelection?.roots.some((root) => beneath(root, path)) ?? false;
|
|
41
|
-
const paths =
|
|
42
|
-
.
|
|
43
|
-
|
|
54
|
+
const paths = [
|
|
55
|
+
...reach.documents
|
|
56
|
+
.filter((document) => document.room === room.locator)
|
|
57
|
+
.map(({ path }) => path),
|
|
58
|
+
...typedAreas(reach, room.locator).map(({ path }) => path),
|
|
59
|
+
];
|
|
44
60
|
return { collection: paths.some((path) => !selected(path)), selection: paths.some(selected) };
|
|
45
61
|
}
|
|
46
62
|
function covers(reach, room, path) {
|
|
47
63
|
return (reach === null ||
|
|
48
|
-
reach
|
|
49
|
-
|
|
64
|
+
(!fenced(reach, room, path) &&
|
|
65
|
+
(reach.rooms.includes(room) ||
|
|
66
|
+
reach.documents.some((document) => document.room === room && document.path === path))));
|
|
50
67
|
}
|
|
51
68
|
function conversing(reach) {
|
|
52
69
|
return reach === null || reach.conversations;
|
|
@@ -59,6 +76,9 @@ export function planReach(reach) {
|
|
|
59
76
|
documents: [
|
|
60
77
|
...new Set(reach.documents.map(({ room, path }) => documentKey(room, path))),
|
|
61
78
|
].sort(),
|
|
79
|
+
areas: areasOf(reach)
|
|
80
|
+
.map(({ room, path, types }) => ({ room, path, types: [...new Set(types)].sort() }))
|
|
81
|
+
.sort((left, right) => documentKey(left.room, left.path) < documentKey(right.room, right.path) ? -1 : 1),
|
|
62
82
|
};
|
|
63
83
|
}
|
|
64
84
|
function roomsWithin(reach, rooms) {
|
|
@@ -74,7 +94,7 @@ function typesWithin(reach, room, types) {
|
|
|
74
94
|
};
|
|
75
95
|
}
|
|
76
96
|
function moves(reach, room, move) {
|
|
77
|
-
return move === undefined || covers(reach, room, moveTarget(move));
|
|
97
|
+
return move === undefined || covers(reach, move.room ?? room, moveTarget(move));
|
|
78
98
|
}
|
|
79
99
|
function draftWithin(reach, draft) {
|
|
80
100
|
return covers(reach, draft.room, draft.path) && moves(reach, draft.room, draft.parts.move);
|
|
@@ -88,7 +108,7 @@ function shownDraft(reach, draft) {
|
|
|
88
108
|
function writeWithin(reach, write) {
|
|
89
109
|
return write.outcome === 'written'
|
|
90
110
|
? { outcome: 'written', roomDraft: shownDraft(reach, write.roomDraft) }
|
|
91
|
-
:
|
|
111
|
+
: staleWrite(shownDraft(reach, write.current));
|
|
92
112
|
}
|
|
93
113
|
function savedWithin(reach, room, result) {
|
|
94
114
|
if (reach === null || result.outcome === 'saved')
|
|
@@ -107,76 +127,120 @@ function savedWithin(reach, room, result) {
|
|
|
107
127
|
function statusWithin(reach, status) {
|
|
108
128
|
return {
|
|
109
129
|
...status,
|
|
110
|
-
attentionRequired: status.attentionRequired.filter((entry) => covers(reach, entry.room, entry.path)),
|
|
130
|
+
attentionRequired: status.attentionRequired.filter((entry) => 'refusal' in entry ? wholly(reach, entry.room) : covers(reach, entry.room, entry.path)),
|
|
111
131
|
};
|
|
112
132
|
}
|
|
113
133
|
function queueWithin(reach, room, entries) {
|
|
114
|
-
return entries
|
|
115
|
-
(
|
|
134
|
+
return entries
|
|
135
|
+
.filter(({ batch }) => batch.changes.every((change) => covers(reach, room, change.path) &&
|
|
136
|
+
(change.kind !== 'move' || covers(reach, room, change.to))))
|
|
137
|
+
.map((entry) => {
|
|
138
|
+
const { between, ...batch } = entry.batch;
|
|
139
|
+
if (between === undefined)
|
|
140
|
+
return entry;
|
|
141
|
+
return wholly(reach, between.source.room) && wholly(reach, between.destination.room)
|
|
142
|
+
? entry
|
|
143
|
+
: { ...entry, batch };
|
|
144
|
+
});
|
|
116
145
|
}
|
|
117
146
|
function unreached(room) {
|
|
118
|
-
return
|
|
147
|
+
return runtimeError('room-not-held', `No Local Replica for ${room}`);
|
|
119
148
|
}
|
|
120
|
-
|
|
149
|
+
function lockedError(room) {
|
|
150
|
+
return runtimeError(ROOM_LOCKED, `${room} is locked until House confirms its access`, true);
|
|
151
|
+
}
|
|
152
|
+
function deviceUnreached() {
|
|
153
|
+
return runtimeError('device-unreached', 'Only the panel cleans up this device');
|
|
154
|
+
}
|
|
155
|
+
export function narrowed(runtime, given, told) {
|
|
121
156
|
const { md, watch } = runtime;
|
|
122
157
|
let reach = given;
|
|
158
|
+
let port = told;
|
|
123
159
|
const open = new Set();
|
|
124
|
-
function following(begin) {
|
|
160
|
+
function following(begin, locking = false) {
|
|
125
161
|
let stop = begin();
|
|
126
162
|
const restart = () => {
|
|
127
163
|
stop();
|
|
128
164
|
stop = begin();
|
|
129
165
|
};
|
|
130
166
|
open.add(restart);
|
|
167
|
+
const unwatch = locking ? runtime.watchLocks(restart) : () => { };
|
|
131
168
|
return () => {
|
|
132
169
|
open.delete(restart);
|
|
170
|
+
unwatch();
|
|
133
171
|
stop();
|
|
134
172
|
};
|
|
135
173
|
}
|
|
174
|
+
const unlocking = (rooms) => {
|
|
175
|
+
const locked = (rooms ?? []).filter((room) => runtime.locked(room));
|
|
176
|
+
return locked.length === 0
|
|
177
|
+
? null
|
|
178
|
+
: { pending: locked.map((room) => ({ room, awaits: 'unlock' })) };
|
|
179
|
+
};
|
|
180
|
+
const unlocked = (entries) => entries.filter((entry) => !runtime.locked(entry.room));
|
|
181
|
+
const intoLocked = (held) => held.some((move) => move?.room !== undefined && runtime.locked(move.room));
|
|
136
182
|
const within = (topic, input, deliver) => {
|
|
137
183
|
if (topic === 'rooms') {
|
|
138
184
|
return following(() => watch(topic, input, (rooms) => deliver(roomsWithin(reach, rooms))));
|
|
139
185
|
}
|
|
186
|
+
if (topic === 'readiness') {
|
|
187
|
+
return following(() => runtime.watchReadiness(port, reach, deliver));
|
|
188
|
+
}
|
|
140
189
|
if (topic === 'sync-status') {
|
|
141
|
-
return following(() => watch(topic, input, (status) =>
|
|
190
|
+
return following(() => watch(topic, input, (status) => {
|
|
191
|
+
const within = statusWithin(reach, status);
|
|
192
|
+
deliver({ ...within, attentionRequired: unlocked(within.attentionRequired) });
|
|
193
|
+
}), true);
|
|
142
194
|
}
|
|
143
195
|
if (topic === 'room-drafts') {
|
|
144
|
-
return following(() => watch(topic, input, (drafts) => deliver(draftsWithin(reach, drafts))));
|
|
196
|
+
return following(() => watch(topic, input, (drafts) => deliver(unlocked(draftsWithin(reach, drafts)))), true);
|
|
145
197
|
}
|
|
146
198
|
if (topic === 'queue') {
|
|
147
199
|
const room = input[0];
|
|
148
200
|
return following(() => {
|
|
149
|
-
if (!holds(reach, room)) {
|
|
201
|
+
if (!holds(reach, room) || runtime.locked(room)) {
|
|
150
202
|
deliver([]);
|
|
151
203
|
return () => { };
|
|
152
204
|
}
|
|
153
205
|
return watch(topic, input, (entries) => deliver(queueWithin(reach, room, entries)));
|
|
154
|
-
});
|
|
206
|
+
}, true);
|
|
155
207
|
}
|
|
156
208
|
if (topic === 'query') {
|
|
157
209
|
const plan = runtime.plan(input[0], reach);
|
|
158
210
|
let held = null;
|
|
159
211
|
return following(() => {
|
|
212
|
+
const locked = unlocking(plan.rooms);
|
|
213
|
+
if (locked !== null) {
|
|
214
|
+
const answer = { result: locked, keys: [] };
|
|
215
|
+
if (held === null || changeOf(held, answer) !== null)
|
|
216
|
+
deliver(answer);
|
|
217
|
+
held = digestOf(answer);
|
|
218
|
+
return () => { };
|
|
219
|
+
}
|
|
160
220
|
let first = true;
|
|
161
|
-
|
|
221
|
+
let open = true;
|
|
222
|
+
const heard = (message) => {
|
|
162
223
|
if (!first) {
|
|
163
|
-
held =
|
|
224
|
+
held = digestApplied(held, message);
|
|
164
225
|
deliver(message);
|
|
165
226
|
return;
|
|
166
227
|
}
|
|
167
228
|
first = false;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
deliver(next.change);
|
|
229
|
+
const change = held === null ? message : changeOf(held, message);
|
|
230
|
+
held = digestOf(message);
|
|
231
|
+
if (change !== null)
|
|
232
|
+
deliver(change);
|
|
233
|
+
};
|
|
234
|
+
const current = { ...plan, reach: planReach(reach), locked: runtime.lockedRooms() };
|
|
235
|
+
const stop = runtime.watchPlan(current, (message) => {
|
|
236
|
+
if (open)
|
|
237
|
+
heard(message);
|
|
178
238
|
});
|
|
179
|
-
|
|
239
|
+
return () => {
|
|
240
|
+
open = false;
|
|
241
|
+
stop();
|
|
242
|
+
};
|
|
243
|
+
}, true);
|
|
180
244
|
}
|
|
181
245
|
if (topic === 'conversation') {
|
|
182
246
|
return following(() => {
|
|
@@ -186,7 +250,7 @@ export function narrowed(runtime, given) {
|
|
|
186
250
|
return () => { };
|
|
187
251
|
});
|
|
188
252
|
}
|
|
189
|
-
if (topic === 'conversations') {
|
|
253
|
+
if (topic === 'conversations' || topic === 'agents') {
|
|
190
254
|
return following(() => {
|
|
191
255
|
if (conversing(reach))
|
|
192
256
|
return watch(topic, input, deliver);
|
|
@@ -196,14 +260,32 @@ export function narrowed(runtime, given) {
|
|
|
196
260
|
}
|
|
197
261
|
return watch(topic, input, deliver);
|
|
198
262
|
};
|
|
263
|
+
const files = new Map();
|
|
264
|
+
let handed = 0;
|
|
265
|
+
const hand = async (reading) => {
|
|
266
|
+
const answer = await reading;
|
|
267
|
+
if (answer.kind !== 'binary')
|
|
268
|
+
return answer;
|
|
269
|
+
handed += 1;
|
|
270
|
+
const file = String(handed);
|
|
271
|
+
files.set(file, answer.file);
|
|
272
|
+
return { ...answer, file };
|
|
273
|
+
};
|
|
199
274
|
const conversation = () => (conversing(reach) ? md.conversation : NO_CONVERSATION);
|
|
200
275
|
const chatDraft = () => (conversing(reach) ? md.chatDraft : NO_CHAT_DRAFT);
|
|
201
276
|
const view = {
|
|
202
277
|
...md,
|
|
203
278
|
rooms: () => roomsWithin(reach, md.rooms()),
|
|
204
|
-
query: ((input) =>
|
|
205
|
-
|
|
279
|
+
query: ((input) => {
|
|
280
|
+
const plan = runtime.plan(input, reach);
|
|
281
|
+
return Promise.resolve(unlocking(plan.rooms) ?? runtime.query({ ...plan, locked: runtime.lockedRooms() }));
|
|
282
|
+
}),
|
|
283
|
+
search: (input) => port.search === 'required'
|
|
284
|
+
? runtime.search(input, reach, runtime.lockedRooms())
|
|
285
|
+
: Promise.resolve(undeclaredSearch()),
|
|
206
286
|
types(room) {
|
|
287
|
+
if (holds(reach, room) && runtime.locked(room))
|
|
288
|
+
throw lockedError(room);
|
|
207
289
|
if (wholly(reach, room))
|
|
208
290
|
return md.types(room);
|
|
209
291
|
if (!holds(reach, room))
|
|
@@ -214,30 +296,98 @@ export function narrowed(runtime, given) {
|
|
|
214
296
|
async save(room, roomDrafts, writtenBy) {
|
|
215
297
|
if (!holds(reach, room))
|
|
216
298
|
throw unreached(room);
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
299
|
+
if (runtime.locked(room))
|
|
300
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
301
|
+
const held = (await Promise.all(roomDrafts.map(({ path }) => md.roomDraft.read(room, path)))).map((draft) => draft?.parts.move);
|
|
302
|
+
const outside = roomDrafts.find(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]));
|
|
303
|
+
if (outside !== undefined) {
|
|
304
|
+
return { outcome: 'refused', code: 'stale', retryable: false, file: outside.path };
|
|
305
|
+
}
|
|
306
|
+
if (intoLocked(held))
|
|
307
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
221
308
|
return savedWithin(reach, room, await md.save(room, roomDrafts, writtenBy));
|
|
222
309
|
},
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
310
|
+
async saveParts(room, parts, writtenBy) {
|
|
311
|
+
if (!holds(reach, room))
|
|
312
|
+
throw unreached(room);
|
|
313
|
+
if (runtime.locked(room))
|
|
314
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
315
|
+
const held = parts.map(({ parts: one }) => readParts(one).move);
|
|
316
|
+
if (parts.some(({ path }, at) => !covers(reach, room, path) || !moves(reach, room, held[at]))) {
|
|
317
|
+
throw unreached(room);
|
|
318
|
+
}
|
|
319
|
+
if (intoLocked(held))
|
|
320
|
+
return { outcome: 'refused', code: ROOM_LOCKED, retryable: true };
|
|
321
|
+
return savedWithin(reach, room, await md.saveParts(room, parts, writtenBy));
|
|
322
|
+
},
|
|
323
|
+
resolve(room, path, destination) {
|
|
324
|
+
const at = runtime.located(room, path, destination);
|
|
325
|
+
return at !== null && !covers(reach, at.room, at.path)
|
|
326
|
+
? Promise.resolve(UNREADABLE)
|
|
327
|
+
: md.resolve(room, path, destination);
|
|
328
|
+
},
|
|
329
|
+
history: (room, path, query) => !covers(reach, room, path)
|
|
330
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
331
|
+
: runtime.locked(room)
|
|
332
|
+
? Promise.resolve(lockedRoom(room))
|
|
333
|
+
: md.history(room, path, query),
|
|
334
|
+
binaryFile: {
|
|
335
|
+
read: (room, path, revision) => !covers(reach, room, path)
|
|
336
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
337
|
+
: runtime.locked(room)
|
|
338
|
+
? Promise.resolve(lockedRoom(room))
|
|
339
|
+
: hand(md.binaryFile.read(room, path, revision)),
|
|
340
|
+
link: (room, path, revision) => !covers(reach, room, path)
|
|
341
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
342
|
+
: runtime.locked(room)
|
|
343
|
+
? Promise.resolve(lockedRoom(room))
|
|
344
|
+
: md.binaryFile.link(room, path, revision),
|
|
345
|
+
async part(file, part) {
|
|
346
|
+
const key = files.get(file);
|
|
347
|
+
if (key === undefined)
|
|
348
|
+
return null;
|
|
349
|
+
const bytes = await md.binaryFile.part(key, part);
|
|
350
|
+
if (bytes === null)
|
|
351
|
+
files.delete(file);
|
|
352
|
+
return bytes;
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
reached: async (room, roomVersion, path) => (path === undefined ? wholly(reach, room) : covers(reach, room, path)) &&
|
|
356
|
+
!runtime.locked(room) &&
|
|
357
|
+
(await md.reached(room, roomVersion, path)),
|
|
228
358
|
log: () => (reach === null ? md.log() : ''),
|
|
359
|
+
cleanUp: () => (reach === null ? md.cleanUp() : Promise.reject(deviceUnreached())),
|
|
229
360
|
roomDraft: {
|
|
230
|
-
list: () => md.roomDraft.list().then((drafts) => draftsWithin(reach, drafts)),
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
361
|
+
list: () => md.roomDraft.list().then((drafts) => unlocked(draftsWithin(reach, drafts))),
|
|
362
|
+
async read(room, path) {
|
|
363
|
+
if (!covers(reach, room, path))
|
|
364
|
+
return null;
|
|
365
|
+
if (runtime.locked(room))
|
|
366
|
+
throw lockedError(room);
|
|
367
|
+
return shownDraft(reach, await md.roomDraft.read(room, path));
|
|
368
|
+
},
|
|
369
|
+
write(room, path, revision, parts, next) {
|
|
370
|
+
try {
|
|
371
|
+
const move = readParts(parts).move;
|
|
372
|
+
if (!covers(reach, room, path) || !moves(reach, room, move))
|
|
373
|
+
throw unreached(room);
|
|
374
|
+
if (runtime.locked(room))
|
|
375
|
+
throw lockedError(room);
|
|
376
|
+
if (intoLocked([move]))
|
|
377
|
+
throw lockedError(move.room);
|
|
378
|
+
}
|
|
379
|
+
catch (error) {
|
|
380
|
+
return Promise.reject(error);
|
|
235
381
|
}
|
|
236
|
-
return
|
|
382
|
+
return md.roomDraft
|
|
383
|
+
.write(room, path, revision, parts, next)
|
|
384
|
+
.then((written) => writeWithin(reach, written));
|
|
237
385
|
},
|
|
238
386
|
async discard(room, path, revision) {
|
|
239
387
|
if (!covers(reach, room, path))
|
|
240
|
-
return
|
|
388
|
+
return staleWrite(null);
|
|
389
|
+
if (runtime.locked(room))
|
|
390
|
+
throw lockedError(room);
|
|
241
391
|
return writeWithin(reach, await md.roomDraft.discard(room, path, revision));
|
|
242
392
|
},
|
|
243
393
|
},
|
|
@@ -245,7 +395,12 @@ export function narrowed(runtime, given) {
|
|
|
245
395
|
list: () => conversation().list(),
|
|
246
396
|
read: (id, options) => conversation().read(id, options),
|
|
247
397
|
create: (input) => conversation().create(input),
|
|
248
|
-
send: (id) => conversation().send(id),
|
|
398
|
+
send: (id, operation, draft) => conversation().send(id, operation, draft),
|
|
399
|
+
attach: (room, file) => !wholly(reach, room)
|
|
400
|
+
? Promise.resolve(failure({ kind: 'room-not-readable', locator: room }))
|
|
401
|
+
: runtime.locked(room)
|
|
402
|
+
? Promise.resolve(lockedRoom(room))
|
|
403
|
+
: conversation().attach(room, file),
|
|
249
404
|
answer: (id, answer) => conversation().answer(id, answer),
|
|
250
405
|
interrupt: (id) => conversation().interrupt(id),
|
|
251
406
|
kill: (id) => conversation().kill(id),
|
|
@@ -253,7 +408,8 @@ export function narrowed(runtime, given) {
|
|
|
253
408
|
delete: (id) => conversation().delete(id),
|
|
254
409
|
},
|
|
255
410
|
chatDraft: {
|
|
256
|
-
write: (id, draft) => chatDraft().write(id, draft),
|
|
411
|
+
write: (id, draft, revision) => chatDraft().write(id, draft, revision),
|
|
412
|
+
prepend: (id, draft) => chatDraft().prepend(id, draft),
|
|
257
413
|
discard: (id) => chatDraft().discard(id),
|
|
258
414
|
},
|
|
259
415
|
observe: observing(within),
|
|
@@ -266,5 +422,10 @@ export function narrowed(runtime, given) {
|
|
|
266
422
|
for (const restart of [...open])
|
|
267
423
|
restart();
|
|
268
424
|
},
|
|
425
|
+
facts(next) {
|
|
426
|
+
port = next;
|
|
427
|
+
for (const restart of [...open])
|
|
428
|
+
restart();
|
|
429
|
+
},
|
|
269
430
|
};
|
|
270
431
|
}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,32 +1,43 @@
|
|
|
1
1
|
import type { MdRuntimeClient } from './client.js';
|
|
2
|
-
import type { AppRoom, ConnectionRefusal, SaveResult } from './connection.js';
|
|
3
|
-
import type { ServiceMode } from './adapter.js';
|
|
4
|
-
import type { ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
|
|
2
|
+
import type { AppRoom, ConnectionRefusal, SavedRoomDraft, SaveResult } from './connection.js';
|
|
3
|
+
import type { Member, ServiceMode } from './adapter.js';
|
|
4
|
+
import type { ConversationAgent, ConversationEntry, ConversationOptions, ConversationView } from './conversation.js';
|
|
5
|
+
import { type RuntimeError } from './failure.js';
|
|
5
6
|
import type { QueueEntry } from './outcome.js';
|
|
6
|
-
import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult } from './query.js';
|
|
7
|
+
import type { DocumentQuery, DocumentResult, GroupQuery, GroupResult, PendingResult } from './query.js';
|
|
8
|
+
import type { Readiness } from './readiness.js';
|
|
7
9
|
import type { RoomDraft, RoomDraftParts } from './room-draft.js';
|
|
8
10
|
import type { SyncStatus } from './status.js';
|
|
9
11
|
type Client = MdRuntimeClient | null;
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
export declare function useObserve(client: Client, topic: '
|
|
17
|
-
export declare function useObserve(client: Client, topic: '
|
|
18
|
-
export declare function useObserve(client: Client, topic: '
|
|
19
|
-
export declare function useObserve(client: Client, topic: '
|
|
20
|
-
export declare function useObserve(client: Client, topic: '
|
|
21
|
-
export declare function useObserve(client: Client, topic: '
|
|
22
|
-
export declare function useObserve(client: Client, topic: '
|
|
12
|
+
export type Observed<T> = {
|
|
13
|
+
readonly state: 'loading';
|
|
14
|
+
} | {
|
|
15
|
+
readonly state: 'ready';
|
|
16
|
+
readonly value: T;
|
|
17
|
+
};
|
|
18
|
+
export declare function useObserve(client: Client, topic: 'deployment-facts'): Observed<unknown>;
|
|
19
|
+
export declare function useObserve(client: Client, topic: 'rooms'): Observed<readonly AppRoom[]>;
|
|
20
|
+
export declare function useObserve(client: Client, topic: 'readiness'): Observed<Readiness>;
|
|
21
|
+
export declare function useObserve(client: Client, topic: 'connection-refusal'): Observed<ConnectionRefusal | null>;
|
|
22
|
+
export declare function useObserve(client: Client, topic: 'storage-loss'): Observed<string | null>;
|
|
23
|
+
export declare function useObserve(client: Client, topic: 'sync-status'): Observed<SyncStatus>;
|
|
24
|
+
export declare function useObserve(client: Client, topic: 'service-mode'): Observed<ServiceMode>;
|
|
25
|
+
export declare function useObserve(client: Client, topic: 'member'): Observed<Member | null>;
|
|
26
|
+
export declare function useObserve(client: Client, topic: 'query', query: DocumentQuery): Observed<DocumentResult | PendingResult>;
|
|
27
|
+
export declare function useObserve(client: Client, topic: 'query', query: GroupQuery): Observed<GroupResult | PendingResult>;
|
|
28
|
+
export declare function useObserve(client: Client, topic: 'queue', locator: string): Observed<readonly QueueEntry[]>;
|
|
29
|
+
export declare function useObserve(client: Client, topic: 'room-drafts'): Observed<readonly RoomDraft[]>;
|
|
30
|
+
export declare function useObserve(client: Client, topic: 'presentation'): Observed<unknown>;
|
|
31
|
+
export declare function useObserve(client: Client, topic: 'conversation', conversation: string, options: ConversationOptions): Observed<ConversationView>;
|
|
32
|
+
export declare function useObserve(client: Client, topic: 'conversations'): Observed<readonly ConversationEntry[]>;
|
|
33
|
+
export declare function useObserve(client: Client, topic: 'agents'): Observed<readonly ConversationAgent[]>;
|
|
23
34
|
export type Saving = {
|
|
24
35
|
readonly busy: boolean;
|
|
25
36
|
readonly outcome: SaveResult | null;
|
|
26
|
-
readonly failure:
|
|
27
|
-
save(room: string,
|
|
37
|
+
readonly failure: RuntimeError | null;
|
|
38
|
+
save(room: string, parts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
|
|
39
|
+
saveWritten(room: string, roomDrafts: readonly SavedRoomDraft[]): Promise<SaveResult>;
|
|
28
40
|
};
|
|
29
|
-
export declare function saveRoomDrafts(client: MdRuntimeClient, room: string, roomDrafts: ReadonlyMap<string, RoomDraftParts>): Promise<SaveResult>;
|
|
30
41
|
export declare function useSave(client: MdRuntimeClient): Saving;
|
|
31
42
|
export {};
|
|
32
43
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9F,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EACV,iBAAiB,EACjB,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,aAAa,EACd,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,KAAK,MAAM,GAAG,eAAe,GAAG,IAAI,CAAC;AAErC,MAAM,MAAM,QAAQ,CAAC,CAAC,IAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GAC7B;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC;AAUnD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;AACzF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;AACzF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;AACpF,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,oBAAoB,GAC1B,QAAQ,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;AACtC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAC3F,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;AACvF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAC;AACzF,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AACrF,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,aAAa,GACnB,QAAQ,CAAC,cAAc,GAAG,aAAa,CAAC,CAAC;AAC5C,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,UAAU,GAChB,QAAQ,CAAC,WAAW,GAAG,aAAa,CAAC,CAAC;AACzC,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,MAAM,GACd,QAAQ,CAAC,SAAS,UAAU,EAAE,CAAC,CAAC;AACnC,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,CAAC,SAAS,SAAS,EAAE,CAAC,CAAC;AACjG,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;AACrF,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,cAAc,EACrB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,mBAAmB,GAC3B,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAC9B,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,GACrB,QAAQ,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;AAC1C,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;AAsCpG,MAAM,MAAM,MAAM,GAAG;IACnB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IACtC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACpF,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,cAAc,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACvF,CAAC;AAMF,wBAAgB,OAAO,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA8BvD"}
|
package/dist/react.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { useCallback,
|
|
1
|
+
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
|
2
|
+
import { failed } from './failure.js';
|
|
3
|
+
const LOADING = { state: 'loading' };
|
|
2
4
|
export function useObserve(client, topic, ...input) {
|
|
3
5
|
const key = JSON.stringify([topic, ...input]);
|
|
4
6
|
const [held, setHeld] = useState(null);
|
|
5
7
|
const opened = useRef(input);
|
|
6
8
|
opened.current = input;
|
|
7
|
-
|
|
9
|
+
useLayoutEffect(() => {
|
|
8
10
|
if (client === null)
|
|
9
11
|
return;
|
|
10
12
|
let live = true;
|
|
@@ -18,7 +20,7 @@ export function useObserve(client, topic, ...input) {
|
|
|
18
20
|
observation = open;
|
|
19
21
|
const take = (value) => {
|
|
20
22
|
if (live)
|
|
21
|
-
setHeld({ client, key, value });
|
|
23
|
+
setHeld({ client, key, observed: { state: 'ready', value } });
|
|
22
24
|
};
|
|
23
25
|
take(open.current());
|
|
24
26
|
open.subscribe(take);
|
|
@@ -28,35 +30,25 @@ export function useObserve(client, topic, ...input) {
|
|
|
28
30
|
observation?.close();
|
|
29
31
|
};
|
|
30
32
|
}, [client, key]);
|
|
31
|
-
return held !== null && held.client === client && held.key === key ? held.
|
|
33
|
+
return held !== null && held.client === client && held.key === key ? held.observed : LOADING;
|
|
32
34
|
}
|
|
33
35
|
const IDLE = { busy: false, outcome: null, failure: null };
|
|
34
|
-
export async function saveRoomDrafts(client, room, roomDrafts) {
|
|
35
|
-
const kept = [];
|
|
36
|
-
for (const [path, parts] of roomDrafts) {
|
|
37
|
-
const prior = await client.roomDraft.read(room, path);
|
|
38
|
-
const write = await client.roomDraft.write(room, path, prior?.revision ?? null, parts);
|
|
39
|
-
if (write.outcome !== 'written' || write.roomDraft === null) {
|
|
40
|
-
throw new Error(`the Room Draft at ${path} was not written`);
|
|
41
|
-
}
|
|
42
|
-
kept.push({ path, revision: write.roomDraft.revision });
|
|
43
|
-
}
|
|
44
|
-
return client.save(room, kept);
|
|
45
|
-
}
|
|
46
36
|
export function useSave(client) {
|
|
47
37
|
const [state, setState] = useState(IDLE);
|
|
48
|
-
const
|
|
38
|
+
const settled = useCallback(async (saving) => {
|
|
49
39
|
setState({ busy: true, outcome: null, failure: null });
|
|
50
40
|
try {
|
|
51
|
-
const outcome = await
|
|
41
|
+
const outcome = await saving();
|
|
52
42
|
setState({ busy: false, outcome, failure: null });
|
|
53
43
|
return outcome;
|
|
54
44
|
}
|
|
55
45
|
catch (error) {
|
|
56
|
-
const failure =
|
|
46
|
+
const failure = failed(error);
|
|
57
47
|
setState({ busy: false, outcome: null, failure });
|
|
58
48
|
throw failure;
|
|
59
49
|
}
|
|
60
|
-
}, [
|
|
61
|
-
|
|
50
|
+
}, []);
|
|
51
|
+
const save = useCallback((room, parts) => settled(() => client.saveParts(room, [...parts].map(([path, one]) => ({ path, parts: one })))), [client, settled]);
|
|
52
|
+
const saveWritten = useCallback((room, roomDrafts) => settled(() => client.save(room, roomDrafts)), [client, settled]);
|
|
53
|
+
return { ...state, save, saveWritten };
|
|
62
54
|
}
|