@agentshouse/mdruntime 0.1.0-cba6f2439bb25 → 0.1.0-cbbae1fff01c6
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 +10 -10
- package/dist/acceptance.d.ts +3 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +308 -0
- package/dist/actions.d.ts +20 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +251 -0
- package/dist/adapter.d.ts +95 -103
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +3 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +21 -56
- package/dist/bootstrap.d.ts +12 -11
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +213 -89
- package/dist/cell.d.ts +6 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +9 -0
- package/dist/chain.d.ts +2 -1
- package/dist/chain.d.ts.map +1 -1
- package/dist/change-set.d.ts +4 -0
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +6 -0
- package/dist/change.d.ts +1 -0
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +4 -2
- package/dist/chat-types.d.ts +5 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +13 -0
- package/dist/client.d.ts +24 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -5
- package/dist/collection.d.ts +23 -7
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +13 -19
- package/dist/compile.d.ts +6 -6
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +272 -332
- package/dist/connection.d.ts +5 -143
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +105 -5253
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +7 -0
- package/dist/conversation-live.d.ts +135 -0
- package/dist/conversation-live.d.ts.map +1 -0
- package/dist/conversation-live.js +247 -0
- package/dist/conversation-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +53 -0
- package/dist/conversation.d.ts +41 -47
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +874 -911
- package/dist/declaration.d.ts +10 -0
- package/dist/declaration.d.ts.map +1 -0
- package/dist/declaration.js +24 -0
- package/dist/discovery.d.ts +10 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +148 -0
- package/dist/durability.d.ts +15 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/entry.d.ts +2 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +17 -7
- package/dist/expectation.d.ts +4 -2
- package/dist/expectation.d.ts.map +1 -1
- package/dist/expectation.js +33 -11
- package/dist/failure.d.ts +1 -0
- package/dist/failure.d.ts.map +1 -1
- package/dist/failure.js +3 -0
- package/dist/figures.d.ts +49 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- package/dist/host.d.ts +20 -8
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +44 -34
- 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 +28 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/install.d.ts +54 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +538 -0
- package/dist/job.d.ts +5 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +7 -0
- package/dist/lifecycle.d.ts +7 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +272 -0
- package/dist/listing.d.ts +48 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +139 -0
- package/dist/live.d.ts +5 -4
- package/dist/live.d.ts.map +1 -1
- package/dist/live.js +64 -23
- package/dist/locks.d.ts +7 -0
- package/dist/locks.d.ts.map +1 -0
- package/dist/locks.js +33 -0
- package/dist/log.d.ts +1 -0
- package/dist/log.d.ts.map +1 -1
- package/dist/lost.d.ts +5 -0
- package/dist/lost.d.ts.map +1 -0
- package/dist/lost.js +50 -0
- package/dist/media.d.ts +2 -2
- package/dist/media.d.ts.map +1 -1
- package/dist/media.js +22 -12
- package/dist/memory.d.ts +14 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +177 -85
- package/dist/messages.d.ts +24 -3
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +89 -31
- package/dist/model.d.ts +2 -11
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +0 -23
- package/dist/models.d.ts +10 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +156 -0
- package/dist/observation.d.ts +2 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +14 -14
- package/dist/opened.d.ts +1 -1
- package/dist/opened.d.ts.map +1 -1
- package/dist/opened.js +5 -5
- package/dist/opening.d.ts +4 -0
- package/dist/opening.d.ts.map +1 -0
- package/dist/opening.js +59 -0
- package/dist/outcome.d.ts +4 -4
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +3 -0
- package/dist/overlay.d.ts +3 -1
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +43 -21
- package/dist/parts.d.ts +11 -0
- package/dist/parts.d.ts.map +1 -0
- package/dist/parts.js +21 -0
- package/dist/paths.d.ts +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +22 -0
- package/dist/preparation.d.ts +20 -0
- package/dist/preparation.d.ts.map +1 -0
- package/dist/preparation.js +233 -0
- 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 +16 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +270 -0
- package/dist/query.d.ts +14 -210
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -505
- package/dist/questions.d.ts +34 -0
- package/dist/questions.d.ts.map +1 -0
- package/dist/questions.js +122 -0
- package/dist/queue.d.ts +40 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +455 -0
- package/dist/reach.d.ts +15 -13
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +187 -140
- package/dist/react.d.ts +14 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +10 -1
- package/dist/read.d.ts +7 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/read.js +17 -0
- package/dist/readiness.d.ts +2 -16
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +4 -10
- package/dist/reads.d.ts +36 -10
- package/dist/reads.d.ts.map +1 -1
- package/dist/reads.js +160 -77
- package/dist/recovery.d.ts +1 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +35 -1
- package/dist/refresh.d.ts +7 -5
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +35 -7
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +57 -0
- package/dist/replica.d.ts +11 -17
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +64 -34
- package/dist/room-draft.d.ts +7 -8
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +100 -103
- package/dist/room-drafts.d.ts +24 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +217 -0
- package/dist/rows.d.ts +14 -21
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +49 -186
- package/dist/runtime.d.ts +34 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts +41 -86
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +239 -116
- package/dist/saves.d.ts +32 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +413 -0
- package/dist/search.d.ts +12 -63
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +9 -52
- package/dist/seed.d.ts +11 -2
- package/dist/seed.d.ts.map +1 -1
- package/dist/seed.js +71 -1
- package/dist/shared.d.ts +1 -7
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +13 -105
- package/dist/shown.d.ts +32 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +290 -0
- package/dist/socket/admission.d.ts +7 -0
- package/dist/socket/admission.d.ts.map +1 -0
- package/dist/socket/admission.js +39 -0
- package/dist/socket/answers.d.ts +6 -0
- package/dist/socket/answers.d.ts.map +1 -0
- package/dist/socket/answers.js +20 -0
- package/dist/socket/lanes.d.ts +20 -0
- package/dist/socket/lanes.d.ts.map +1 -0
- package/dist/socket/lanes.js +77 -0
- package/dist/socket/reads.d.ts +10 -0
- package/dist/socket/reads.d.ts.map +1 -0
- package/dist/socket/reads.js +31 -0
- package/dist/socket/session.d.ts +38 -0
- package/dist/socket/session.d.ts.map +1 -0
- package/dist/socket/session.js +23 -0
- package/dist/socket.d.ts +67 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +170 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +82 -0
- package/dist/status.d.ts +0 -6
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +0 -6
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/readiness.d.ts +10 -0
- package/dist/store/readiness.d.ts.map +1 -0
- package/dist/store/readiness.js +52 -0
- package/dist/store/records.d.ts +210 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +428 -0
- package/dist/store/room-held.d.ts +8 -0
- package/dist/store/room-held.d.ts.map +1 -0
- package/dist/store/room-held.js +17 -0
- package/dist/store/space.d.ts +11 -0
- package/dist/store/space.d.ts.map +1 -0
- package/dist/store/space.js +41 -0
- package/dist/store/watchers.d.ts +17 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +56 -0
- package/dist/store/writes.d.ts +24 -0
- package/dist/store/writes.d.ts.map +1 -0
- package/dist/store/writes.js +125 -0
- package/dist/store.d.ts +110 -157
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +162 -394
- package/dist/stored.d.ts +59 -38
- package/dist/stored.d.ts.map +1 -1
- package/dist/stored.js +287 -206
- package/dist/surface.d.ts +88 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +223 -0
- package/dist/sync.d.ts +19 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +521 -0
- package/dist/tables.d.ts +116 -56
- package/dist/tables.d.ts.map +1 -1
- package/dist/tables.js +214 -98
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/validation.d.ts +3 -4
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +42 -100
- package/dist/windows.d.ts +1 -12
- package/dist/windows.d.ts.map +1 -1
- package/dist/windows.js +2 -75
- package/dist/wire.d.ts +21 -9
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +10 -4
- package/package.json +3 -2
- package/dist/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/fulltext.d.ts +0 -27
- package/dist/fulltext.d.ts.map +0 -1
- package/dist/fulltext.js +0 -370
- package/dist/words.d.ts +0 -19
- package/dist/words.d.ts.map +0 -1
- package/dist/words.js +0 -156
package/dist/save.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { apply, ARRAY_INDEX, ATTACHMENT, links, parse, pointerSegments, references, relative, relativize, retarget, roomReferences, serialize, target, } from '@agentshouse/mdmodel';
|
|
1
|
+
import { apply, ARRAY_INDEX, ATTACHMENT, create, links, parse, pointerSegments, references, relative, relativize, retarget, roomReferences, serialize, target, } from '@agentshouse/mdmodel';
|
|
3
2
|
import { immutable, leaving, queuedFile, departure, } from './change.js';
|
|
4
|
-
import { collectionOf, documentsOf, governing, } from './collection.js';
|
|
5
|
-
import { changeBatchIdentity } from './identity.js';
|
|
3
|
+
import { collectionOf, definitionsAt, documentsOf, governing, } from './collection.js';
|
|
4
|
+
import { changeBatchIdentity, roomDraftRevision } from './identity.js';
|
|
6
5
|
import { overlaying } from './overlay.js';
|
|
7
|
-
import { ancestors
|
|
8
|
-
import { sorting } from './shared.js';
|
|
6
|
+
import { ancestors } from './paths.js';
|
|
7
|
+
import { entriesIn, sorting } from './shared.js';
|
|
8
|
+
import { changedParts, changesOf, moveTarget, withdrawnDrafts, } from './room-draft.js';
|
|
9
9
|
import { paced, ROW_WEIGHT, stepped } from './turn.js';
|
|
10
10
|
import { validatedCollection } from './validation.js';
|
|
11
11
|
function refuse(code, file, location) {
|
|
@@ -20,9 +20,6 @@ function refuse(code, file, location) {
|
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
22
|
function repointed(document, definition, from, to, moves, settled) {
|
|
23
|
-
const parsed = parse(document.content, from);
|
|
24
|
-
if (!parsed.ok)
|
|
25
|
-
return [];
|
|
26
23
|
const changes = [];
|
|
27
24
|
const names = new Set();
|
|
28
25
|
for (const { pointer, value } of definition === undefined
|
|
@@ -45,13 +42,13 @@ function repointed(document, definition, from, to, moves, settled) {
|
|
|
45
42
|
}
|
|
46
43
|
if (changes.length === 0)
|
|
47
44
|
return [];
|
|
48
|
-
const applied = apply(
|
|
45
|
+
const applied = apply(document, changes, definition);
|
|
49
46
|
if (applied.outcome !== 'applied')
|
|
50
47
|
return [];
|
|
51
48
|
const next = applied.document;
|
|
52
49
|
return [...names].map((name) => ({ kind: 'field', path: from, name, value: next.fields[name] }));
|
|
53
50
|
}
|
|
54
|
-
function edited(document, changes) {
|
|
51
|
+
function edited(document, changes, definition) {
|
|
55
52
|
const parts = new Map();
|
|
56
53
|
for (const change of changes) {
|
|
57
54
|
if (change.kind === 'preamble')
|
|
@@ -66,7 +63,7 @@ function edited(document, changes) {
|
|
|
66
63
|
}
|
|
67
64
|
if (parts.size === 0)
|
|
68
65
|
return document;
|
|
69
|
-
const applied = apply(document, [...parts.values()]);
|
|
66
|
+
const applied = apply(document, [...parts.values()], definition);
|
|
70
67
|
return applied.outcome === 'applied' ? applied.document : document;
|
|
71
68
|
}
|
|
72
69
|
function bodies(path, before, after) {
|
|
@@ -81,7 +78,7 @@ function bodies(path, before, after) {
|
|
|
81
78
|
}
|
|
82
79
|
return changes;
|
|
83
80
|
}
|
|
84
|
-
function relinks(path, moved, before, moves) {
|
|
81
|
+
function relinks(path, moved, before, moves, definition) {
|
|
85
82
|
const changes = [];
|
|
86
83
|
for (const link of links(before, path)) {
|
|
87
84
|
const destination = moves.get(link.target) ?? link.target;
|
|
@@ -94,7 +91,7 @@ function relinks(path, moved, before, moves) {
|
|
|
94
91
|
}
|
|
95
92
|
if (changes.length === 0)
|
|
96
93
|
return { kind: 'changes', changes: [] };
|
|
97
|
-
const applied = apply(before, changes);
|
|
94
|
+
const applied = apply(before, changes, definition);
|
|
98
95
|
if (applied.outcome === 'refuse') {
|
|
99
96
|
return {
|
|
100
97
|
kind: 'refused',
|
|
@@ -117,6 +114,15 @@ function relinks(path, moved, before, moves) {
|
|
|
117
114
|
function partKey(change) {
|
|
118
115
|
return change.kind === 'section' ? `section ${change.name}` : change.kind;
|
|
119
116
|
}
|
|
117
|
+
const NAMES_A_SKIP_TESTS = 64;
|
|
118
|
+
const ENCODED = /[%&\\]/u;
|
|
119
|
+
function movedNames(moves) {
|
|
120
|
+
const names = new Set([...moves.keys()].map((path) => path.slice(path.lastIndexOf('/') + 1)));
|
|
121
|
+
return names.size > NAMES_A_SKIP_TESTS ? null : [...names];
|
|
122
|
+
}
|
|
123
|
+
function cannotLink(text, names) {
|
|
124
|
+
return names !== null && !ENCODED.test(text) && !names.some((name) => text.includes(name));
|
|
125
|
+
}
|
|
120
126
|
function* rewrites(changes, visible) {
|
|
121
127
|
const moves = new Map();
|
|
122
128
|
const settled = new Set();
|
|
@@ -142,17 +148,20 @@ function* rewrites(changes, visible) {
|
|
|
142
148
|
}
|
|
143
149
|
if (moves.size === 0)
|
|
144
150
|
return { kind: 'changes', changes };
|
|
151
|
+
const names = movedNames(moves);
|
|
145
152
|
const merged = [...changes];
|
|
146
153
|
const added = [];
|
|
147
154
|
for (const [path, document] of yield* documentsOf(visible.collection)) {
|
|
148
155
|
if (settled.has(path))
|
|
149
156
|
continue;
|
|
150
157
|
const moved = moves.get(path) ?? path;
|
|
151
|
-
const definition =
|
|
158
|
+
const definition = definitionsAt(visible.collection.composition, path)(document.type);
|
|
152
159
|
const repointing = repointed(document, definition, path, moved, moves, settled);
|
|
153
160
|
added.push(...repointing);
|
|
154
161
|
const own = parts.get(path) ?? [];
|
|
155
|
-
const relinked =
|
|
162
|
+
const relinked = moved === path && own.length === 0 && cannotLink(document.content, names)
|
|
163
|
+
? { kind: 'changes', changes: [] }
|
|
164
|
+
: relinks(path, moved, edited(document, own.map((index) => merged[index]), definition), moves, definition);
|
|
156
165
|
if (relinked.kind === 'refused')
|
|
157
166
|
return relinked;
|
|
158
167
|
const keyed = new Map();
|
|
@@ -221,10 +230,10 @@ function crossed(document, definition, path, to) {
|
|
|
221
230
|
}
|
|
222
231
|
return changes;
|
|
223
232
|
}
|
|
224
|
-
function rewritten(path, document, changes) {
|
|
233
|
+
function rewritten(path, document, changes, definition) {
|
|
225
234
|
if (changes.length === 0)
|
|
226
235
|
return [];
|
|
227
|
-
const applied = apply(document, changes);
|
|
236
|
+
const applied = apply(document, changes, definition);
|
|
228
237
|
if (applied.outcome !== 'applied')
|
|
229
238
|
return [];
|
|
230
239
|
const after = applied.document;
|
|
@@ -239,7 +248,7 @@ function rewritten(path, document, changes) {
|
|
|
239
248
|
function roomPathOf(handle, path) {
|
|
240
249
|
return `/rooms/${handle}/${path}`;
|
|
241
250
|
}
|
|
242
|
-
|
|
251
|
+
function* leavingRewritten(batch, visible) {
|
|
243
252
|
const between = batch.between;
|
|
244
253
|
if (between === undefined)
|
|
245
254
|
return batch;
|
|
@@ -248,8 +257,8 @@ export function* leavingRewritten(batch, visible) {
|
|
|
248
257
|
for (const [path, document] of yield* documentsOf(visible.collection)) {
|
|
249
258
|
if (moved.has(path))
|
|
250
259
|
continue;
|
|
251
|
-
const definition =
|
|
252
|
-
derived.push(...rewritten(path, document, crossed(document, definition, path, (named) => moved.get(named))));
|
|
260
|
+
const definition = definitionsAt(visible.collection.composition, path)(document.type);
|
|
261
|
+
derived.push(...rewritten(path, document, crossed(document, definition, path, (named) => moved.get(named)), definition));
|
|
253
262
|
yield ROW_WEIGHT + visible.collection.text[path].length;
|
|
254
263
|
}
|
|
255
264
|
if (derived.length === 0)
|
|
@@ -291,7 +300,7 @@ function* incoming(collection, removed, candidates) {
|
|
|
291
300
|
for (const [path, document] of candidates === null
|
|
292
301
|
? yield* documentsOf(collection)
|
|
293
302
|
: read(candidates)) {
|
|
294
|
-
const definition =
|
|
303
|
+
const definition = definitionsAt(collection.composition, path)(document.type);
|
|
295
304
|
for (const { value, to } of definition === undefined ? [] : references(document, definition)) {
|
|
296
305
|
if (to.includes(ATTACHMENT))
|
|
297
306
|
continue;
|
|
@@ -321,6 +330,8 @@ function* incoming(collection, removed, candidates) {
|
|
|
321
330
|
function affected(change) {
|
|
322
331
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
323
332
|
}
|
|
333
|
+
const WRITE = ['write'];
|
|
334
|
+
const MOVE_OUT = ['write', 'erase'];
|
|
324
335
|
function guard(changes, input, removing) {
|
|
325
336
|
const overridden = new Map();
|
|
326
337
|
const existing = {
|
|
@@ -332,15 +343,9 @@ function guard(changes, input, removing) {
|
|
|
332
343
|
const occupied = (path) => input.folders.has(path) ? path : (ancestors(path).find((one) => existing.has(one)) ?? null);
|
|
333
344
|
for (const [index, change] of changes.entries()) {
|
|
334
345
|
for (const path of affected(change)) {
|
|
335
|
-
const
|
|
336
|
-
if (
|
|
337
|
-
return refuse(
|
|
338
|
-
if (covered(input.providerOwnedPaths, normalized)) {
|
|
339
|
-
return refuse('provider-owned-path', normalized);
|
|
340
|
-
}
|
|
341
|
-
const operation = change.kind === 'remove' ? removing : 'write';
|
|
342
|
-
if (!input.local && !covered(input.operations[operation], normalized))
|
|
343
|
-
return refuse(`${operation}-grant`, normalized);
|
|
346
|
+
const refused = input.rule(path, change.kind === 'remove' ? removing : WRITE);
|
|
347
|
+
if (refused !== null)
|
|
348
|
+
return refuse(refused.code, refused.path);
|
|
344
349
|
}
|
|
345
350
|
if (change.kind === 'create' || change.kind === 'arrival') {
|
|
346
351
|
const taken = existing.has(change.path) ? change.path : occupied(change.path);
|
|
@@ -401,9 +406,9 @@ function guard(changes, input, removing) {
|
|
|
401
406
|
return null;
|
|
402
407
|
}
|
|
403
408
|
function unrevised(input, path) {
|
|
404
|
-
return
|
|
409
|
+
return !input.local && !input.queued.has(path) && input.visible.revisions[path] === undefined;
|
|
405
410
|
}
|
|
406
|
-
|
|
411
|
+
function queuedDocuments(queue) {
|
|
407
412
|
const paths = new Set();
|
|
408
413
|
for (const batch of queue) {
|
|
409
414
|
for (const change of batch.changes) {
|
|
@@ -539,19 +544,16 @@ function* exceeding(limits, changes, effective, resulting) {
|
|
|
539
544
|
function shellRelative(text, path, handle, definition) {
|
|
540
545
|
if (!text.includes(`/rooms/${handle}/`))
|
|
541
546
|
return null;
|
|
542
|
-
const parsed = parse(text, path);
|
|
547
|
+
const parsed = parse(text, path, definition);
|
|
543
548
|
if (!parsed.ok)
|
|
544
549
|
return null;
|
|
545
550
|
const result = relativize(parsed.document, path, handle, definition(parsed.document.type));
|
|
546
551
|
return result.outcome === 'applied' && result.document.content !== text ? result.document : null;
|
|
547
552
|
}
|
|
548
553
|
function relativeField(path, name, value, handle, definition) {
|
|
549
|
-
|
|
550
|
-
if (definition === undefined ||
|
|
551
|
-
!opened.ok ||
|
|
552
|
-
!JSON.stringify(value ?? null).includes(`/rooms/${handle}/`))
|
|
554
|
+
if (definition === undefined || !JSON.stringify(value ?? null).includes(`/rooms/${handle}/`))
|
|
553
555
|
return value;
|
|
554
|
-
const held = apply(
|
|
556
|
+
const held = apply(create(definition.name, definition), [{ kind: 'field', name, value, prior: undefined }], definition);
|
|
555
557
|
if (held.outcome !== 'applied')
|
|
556
558
|
return value;
|
|
557
559
|
const result = relativize(held.document, path, handle, definition);
|
|
@@ -559,7 +561,7 @@ function relativeField(path, name, value, handle, definition) {
|
|
|
559
561
|
}
|
|
560
562
|
function relativeChanges(input) {
|
|
561
563
|
const { handle, composition, visible } = input;
|
|
562
|
-
const typed = (path) => (
|
|
564
|
+
const typed = (path) => definitionsAt(composition, path);
|
|
563
565
|
const body = (path, text) => shellRelative(text, path, handle, () => undefined)?.content ?? text;
|
|
564
566
|
return input.changes.map((change) => {
|
|
565
567
|
const definition = typed(change.path);
|
|
@@ -588,7 +590,7 @@ function relativeChanges(input) {
|
|
|
588
590
|
});
|
|
589
591
|
}
|
|
590
592
|
function unqueueable(file) {
|
|
591
|
-
return
|
|
593
|
+
return refuse('unknown-revision', file);
|
|
592
594
|
}
|
|
593
595
|
function isPart(change) {
|
|
594
596
|
return change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble';
|
|
@@ -596,8 +598,9 @@ function isPart(change) {
|
|
|
596
598
|
function touched(change) {
|
|
597
599
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
598
600
|
}
|
|
599
|
-
function partsApplied(content, path, changes) {
|
|
600
|
-
const
|
|
601
|
+
function partsApplied(content, path, changes, composition) {
|
|
602
|
+
const definitions = definitionsAt(composition, path);
|
|
603
|
+
const parsed = parse(content, path, definitions);
|
|
601
604
|
if (!parsed.ok)
|
|
602
605
|
return null;
|
|
603
606
|
const document = parsed.document;
|
|
@@ -620,12 +623,12 @@ function partsApplied(content, path, changes) {
|
|
|
620
623
|
else
|
|
621
624
|
parts.set('preamble', { kind: 'preamble', value: change.value, prior: document.preamble });
|
|
622
625
|
}
|
|
623
|
-
const applied = apply(document, [...parts.values()]);
|
|
626
|
+
const applied = apply(document, [...parts.values()], definitions(document.type));
|
|
624
627
|
return applied.outcome === 'applied' ? serialize(applied.document) : null;
|
|
625
628
|
}
|
|
626
|
-
function settledParts(changes, deferred) {
|
|
629
|
+
function settledParts(changes, deferred, composition) {
|
|
627
630
|
for (const [held, parts] of deferred) {
|
|
628
|
-
const content = partsApplied(held.content, held.path, parts);
|
|
631
|
+
const content = partsApplied(held.content, held.path, parts, composition);
|
|
629
632
|
if (content === null)
|
|
630
633
|
return held.path;
|
|
631
634
|
changes[changes.indexOf(held)] = { ...held, content };
|
|
@@ -700,7 +703,9 @@ function* relinked(batch, move, before, after, appending) {
|
|
|
700
703
|
for (const change of derived.changes) {
|
|
701
704
|
if (change === move)
|
|
702
705
|
continue;
|
|
703
|
-
const unsettled = isPart(change)
|
|
706
|
+
const unsettled = isPart(change)
|
|
707
|
+
? null
|
|
708
|
+
: settledParts(changes, deferred, after.collection.composition);
|
|
704
709
|
if (unsettled !== null)
|
|
705
710
|
return unqueueable(unsettled);
|
|
706
711
|
const outcome = folded(changes, change, appending, deferred);
|
|
@@ -711,7 +716,7 @@ function* relinked(batch, move, before, after, appending) {
|
|
|
711
716
|
if (outcome !== 'skipped')
|
|
712
717
|
changed = true;
|
|
713
718
|
}
|
|
714
|
-
const unsettled = settledParts(changes, deferred);
|
|
719
|
+
const unsettled = settledParts(changes, deferred, after.collection.composition);
|
|
715
720
|
if (unsettled !== null)
|
|
716
721
|
return unqueueable(unsettled);
|
|
717
722
|
if (!changed)
|
|
@@ -772,11 +777,10 @@ function withdrawnFile(batch, change, at) {
|
|
|
772
777
|
];
|
|
773
778
|
return immutable({ ...batch, id: changeBatchIdentity(), changes, preconditions });
|
|
774
779
|
}
|
|
775
|
-
|
|
780
|
+
function* requeuing(queue, changes, visible, changeable, state) {
|
|
776
781
|
const next = [...queue];
|
|
777
782
|
const origins = new Map();
|
|
778
783
|
const withdrawn = new Map();
|
|
779
|
-
const owners = new Set();
|
|
780
784
|
const queued = new Set();
|
|
781
785
|
const kept = [];
|
|
782
786
|
const originOf = (batch) => origins.get(batch) ?? batch.id;
|
|
@@ -822,7 +826,6 @@ export function* requeuing(queue, changes, visible, changeable, state) {
|
|
|
822
826
|
if (replaced !== null)
|
|
823
827
|
origins.set(replaced, origin);
|
|
824
828
|
}
|
|
825
|
-
owners.add(originOf(owner));
|
|
826
829
|
next.splice(index, following.length, ...rebuilt.filter((batch) => batch !== null));
|
|
827
830
|
queued.add(change.path);
|
|
828
831
|
}
|
|
@@ -832,56 +835,13 @@ export function* requeuing(queue, changes, visible, changeable, state) {
|
|
|
832
835
|
changes: kept,
|
|
833
836
|
queued,
|
|
834
837
|
withdrawn,
|
|
835
|
-
owners,
|
|
836
838
|
};
|
|
837
839
|
}
|
|
838
|
-
function
|
|
839
|
-
return precondition.kind === 'field' ||
|
|
840
|
-
precondition.kind === 'section' ||
|
|
841
|
-
precondition.kind === 'preamble'
|
|
842
|
-
? identity(precondition)
|
|
843
|
-
: `path ${precondition.path}`;
|
|
844
|
-
}
|
|
845
|
-
export function joined(queue, owner, extra) {
|
|
846
|
-
const later = new Set(queue.slice(queue.indexOf(owner) + 1).flatMap((batch) => batch.changes.flatMap(touched)));
|
|
847
|
-
const clash = extra.changes.flatMap(touched).find((path) => later.has(path));
|
|
848
|
-
if (clash !== undefined)
|
|
849
|
-
return unqueueable(clash);
|
|
850
|
-
const changes = [...owner.changes];
|
|
851
|
-
const deferred = new Map();
|
|
852
|
-
for (const change of extra.changes) {
|
|
853
|
-
const unsettled = isPart(change) ? null : settledParts(changes, deferred);
|
|
854
|
-
if (unsettled !== null)
|
|
855
|
-
return unqueueable(unsettled);
|
|
856
|
-
if (folded(changes, change, true, deferred) === 'refused')
|
|
857
|
-
return unqueueable(change.path);
|
|
858
|
-
}
|
|
859
|
-
const unsettled = settledParts(changes, deferred);
|
|
860
|
-
if (unsettled !== null)
|
|
861
|
-
return unqueueable(unsettled);
|
|
862
|
-
const held = new Set(owner.preconditions.map(covering));
|
|
863
|
-
const written = new Set(owner.changes.flatMap((change) => change.kind === 'create' || change.kind === 'replace' ? [change.path] : []));
|
|
864
|
-
const preconditions = [
|
|
865
|
-
...owner.preconditions,
|
|
866
|
-
...extra.preconditions.filter((precondition) => {
|
|
867
|
-
const key = covering(precondition);
|
|
868
|
-
return (!held.has(key) && (key === `path ${precondition.path}` || !written.has(precondition.path)));
|
|
869
|
-
}),
|
|
870
|
-
];
|
|
871
|
-
const batch = immutable({
|
|
872
|
-
...owner,
|
|
873
|
-
...(extra.validation === undefined ? {} : { validation: extra.validation }),
|
|
874
|
-
id: changeBatchIdentity(),
|
|
875
|
-
changes,
|
|
876
|
-
preconditions,
|
|
877
|
-
});
|
|
878
|
-
return { kind: 'joined', batch, queue: queue.map((item) => (item === owner ? batch : item)) };
|
|
879
|
-
}
|
|
880
|
-
export function* limiting(queue, batch, limits, state) {
|
|
840
|
+
function* limiting(queue, batch, limits, state) {
|
|
881
841
|
const at = queue.indexOf(batch);
|
|
882
842
|
const rewritten = yield* providerRewritten(batch, yield* state(queue.slice(0, at)));
|
|
883
843
|
const limited = yield* exceeding(limits, batch.changes, rewritten.changes, yield* state(queue.slice(0, at + 1)));
|
|
884
|
-
return limited?.
|
|
844
|
+
return limited?.refusal ?? null;
|
|
885
845
|
}
|
|
886
846
|
function typedText(content) {
|
|
887
847
|
if (content === undefined)
|
|
@@ -898,7 +858,7 @@ function touchedLibrary(resulting, touched, composition) {
|
|
|
898
858
|
})
|
|
899
859
|
.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));
|
|
900
860
|
const contents = new Map(entries.map(({ path, content }) => [path, content]));
|
|
901
|
-
const binaries = new Set(
|
|
861
|
+
const binaries = new Set(Array.from(entriesIn(resulting.binaries), ([path]) => path));
|
|
902
862
|
return validatedCollection(() => Promise.resolve({ entries, next: null }), async (paths) => {
|
|
903
863
|
const known = new Map();
|
|
904
864
|
const pace = paced();
|
|
@@ -907,7 +867,7 @@ function touchedLibrary(resulting, touched, composition) {
|
|
|
907
867
|
if (binaries.has(path))
|
|
908
868
|
known.set(path, { type: undefined, binary: true });
|
|
909
869
|
else if (content !== undefined && content !== null) {
|
|
910
|
-
const read = parse(content, path);
|
|
870
|
+
const read = parse(content, path, definitionsAt(composition, path));
|
|
911
871
|
if (read.ok)
|
|
912
872
|
known.set(path, { type: read.document.type ?? 'any', binary: false });
|
|
913
873
|
await pace(content.length + ROW_WEIGHT);
|
|
@@ -971,10 +931,11 @@ function placed(reference) {
|
|
|
971
931
|
function roomReferencesIn(path, content, composition) {
|
|
972
932
|
if (content === undefined)
|
|
973
933
|
return [];
|
|
974
|
-
const
|
|
934
|
+
const definitions = definitionsAt(composition, path);
|
|
935
|
+
const parsed = parse(content, path, definitions);
|
|
975
936
|
if (!parsed.ok)
|
|
976
937
|
return [];
|
|
977
|
-
return roomReferences(
|
|
938
|
+
return roomReferences(parsed.document, definitions(parsed.document.type));
|
|
978
939
|
}
|
|
979
940
|
function* admittedRooms(changes, visible, resulting, composition) {
|
|
980
941
|
const from = new Map();
|
|
@@ -1020,12 +981,12 @@ async function batching(input) {
|
|
|
1020
981
|
const rewritten = await stepped(rewrites(changes, input.visible));
|
|
1021
982
|
if (rewritten.kind === 'refused')
|
|
1022
983
|
return rewritten;
|
|
1023
|
-
const refusal = guard(changes, input,
|
|
984
|
+
const refusal = guard(changes, input, WRITE);
|
|
1024
985
|
if (refusal !== null)
|
|
1025
986
|
return refusal;
|
|
1026
987
|
const preconditions = await stepped(preconditionsOf(changes, input.visible, input.bases));
|
|
1027
988
|
const predicted = await stepped(anticipated(changes, preconditions, rewritten.changes, input.visible));
|
|
1028
|
-
const resulting = await stepped(overlaying(input.visible, [{ id: '', baseRoomVersion: input.baseRoomVersion, ...predicted }]));
|
|
989
|
+
const resulting = await stepped(overlaying(input.visible, [{ id: '', baseRoomVersion: input.baseRoomVersion, ...predicted }], input.composition));
|
|
1029
990
|
const judged = await judging(input.visible, resulting, input.composition, input.validate, new Set(changes.filter((change) => change.kind === 'remove').map((change) => change.path)), [...new Set(predicted.changes.flatMap(affected))]);
|
|
1030
991
|
if (judged.kind === 'refused')
|
|
1031
992
|
return judged;
|
|
@@ -1047,7 +1008,7 @@ async function batching(input) {
|
|
|
1047
1008
|
}),
|
|
1048
1009
|
};
|
|
1049
1010
|
}
|
|
1050
|
-
|
|
1011
|
+
const MOVE_DOCUMENTS = 'move-documents';
|
|
1051
1012
|
function heldAt(visible, path) {
|
|
1052
1013
|
return visible.documents[path] !== undefined || visible.binaries[path] !== undefined;
|
|
1053
1014
|
}
|
|
@@ -1056,7 +1017,7 @@ function arrivingText(path, to, source, moved) {
|
|
|
1056
1017
|
const document = source.visible.collection.document(path);
|
|
1057
1018
|
if (document === undefined)
|
|
1058
1019
|
return content;
|
|
1059
|
-
const definition =
|
|
1020
|
+
const definition = definitionsAt(source.composition, path)(document.type);
|
|
1060
1021
|
const changes = crossed(document, definition, path, (named, href) => {
|
|
1061
1022
|
const at = moved.get(named);
|
|
1062
1023
|
if (at !== undefined)
|
|
@@ -1065,13 +1026,14 @@ function arrivingText(path, to, source, moved) {
|
|
|
1065
1026
|
});
|
|
1066
1027
|
if (changes.length === 0)
|
|
1067
1028
|
return content;
|
|
1068
|
-
const applied = apply(document, changes);
|
|
1029
|
+
const applied = apply(document, changes, definition);
|
|
1069
1030
|
return applied.outcome === 'applied' ? serialize(applied.document) : content;
|
|
1070
1031
|
}
|
|
1071
1032
|
function arrivalOf({ path, to }, source, moved) {
|
|
1072
|
-
const { documents, revisions, fileIds, changes, binaries } = source.visible;
|
|
1033
|
+
const { documents, revisions, fileIds, created, changes, binaries } = source.visible;
|
|
1073
1034
|
const kept = {
|
|
1074
1035
|
...(fileIds[path] === undefined ? {} : { fileId: fileIds[path] }),
|
|
1036
|
+
...(created[path] === undefined ? {} : { created: created[path] }),
|
|
1075
1037
|
...(changes[path] === undefined ? {} : { change: changes[path] }),
|
|
1076
1038
|
};
|
|
1077
1039
|
const heads = {
|
|
@@ -1098,10 +1060,8 @@ function arrivalOf({ path, to }, source, moved) {
|
|
|
1098
1060
|
}
|
|
1099
1061
|
async function moving(input) {
|
|
1100
1062
|
const { source, destination, moves } = input;
|
|
1101
|
-
if (moves.length === 0)
|
|
1102
|
-
return refuse('no-change');
|
|
1103
1063
|
const removals = moves.map(({ path }) => ({ kind: 'remove', path }));
|
|
1104
|
-
const leaves = guard(removals, { ...source, local: input.local, bases: [] },
|
|
1064
|
+
const leaves = guard(removals, { ...source, local: input.local, bases: [] }, MOVE_OUT);
|
|
1105
1065
|
if (leaves !== null)
|
|
1106
1066
|
return leaves;
|
|
1107
1067
|
const uploading = moves.find(({ path }) => source.visible.binaries[path]?.state === 'pending');
|
|
@@ -1109,7 +1069,7 @@ async function moving(input) {
|
|
|
1109
1069
|
return refuse('unknown-revision', uploading.path);
|
|
1110
1070
|
const moved = new Map(moves.map(({ path, to }) => [path, to]));
|
|
1111
1071
|
const arrivals = moves.map((move) => arrivalOf(move, source, moved));
|
|
1112
|
-
const arrives = guard(arrivals, { ...destination, local: input.local, bases: [] },
|
|
1072
|
+
const arrives = guard(arrivals, { ...destination, local: input.local, bases: [] }, WRITE);
|
|
1113
1073
|
if (arrives !== null)
|
|
1114
1074
|
return arrives;
|
|
1115
1075
|
const bound = input.providerLimits.find((limit) => limit.name === MOVE_DOCUMENTS)?.value;
|
|
@@ -1138,7 +1098,7 @@ async function moving(input) {
|
|
|
1138
1098
|
between,
|
|
1139
1099
|
};
|
|
1140
1100
|
const effective = await stepped(leavingRewritten(leavingBatch, source.visible));
|
|
1141
|
-
const left = await stepped(overlaying(source.visible, [effective]));
|
|
1101
|
+
const left = await stepped(overlaying(source.visible, [effective], source.composition));
|
|
1142
1102
|
const sourceJudged = await judging(source.visible, left, source.composition, source.validate, new Set(moves.map(({ path }) => path)), [...new Set(effective.changes.map((change) => change.path))]);
|
|
1143
1103
|
if (sourceJudged.kind === 'refused')
|
|
1144
1104
|
return sourceJudged;
|
|
@@ -1150,7 +1110,7 @@ async function moving(input) {
|
|
|
1150
1110
|
...written,
|
|
1151
1111
|
between,
|
|
1152
1112
|
};
|
|
1153
|
-
const arrived = await stepped(overlaying(destination.visible, [arrivingBatch]));
|
|
1113
|
+
const arrived = await stepped(overlaying(destination.visible, [arrivingBatch], destination.composition));
|
|
1154
1114
|
const destinationJudged = await judging(destination.visible, arrived, destination.composition, destination.validate, new Set(), moves.map(({ to }) => to));
|
|
1155
1115
|
if (destinationJudged.kind === 'refused')
|
|
1156
1116
|
return destinationJudged;
|
|
@@ -1160,9 +1120,172 @@ async function moving(input) {
|
|
|
1160
1120
|
return limited;
|
|
1161
1121
|
return { kind: 'moved', leaving: immutable(leavingBatch), arriving: immutable(arrivingBatch) };
|
|
1162
1122
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1123
|
+
function changedUnderneath(saved, visible) {
|
|
1124
|
+
const parts = saved.flatMap(({ path, parts: held }) => changedParts(path, held, visible));
|
|
1125
|
+
return parts.length === 0
|
|
1126
|
+
? null
|
|
1127
|
+
: { kind: 'refused', refusal: { code: 'changed-underneath', retryable: false, parts } };
|
|
1128
|
+
}
|
|
1129
|
+
function sideOf(room, visible) {
|
|
1130
|
+
const { record } = room;
|
|
1131
|
+
return {
|
|
1132
|
+
room: record.locator,
|
|
1133
|
+
handle: record.declaration.handle,
|
|
1134
|
+
baseRoomVersion: record.roomVersion,
|
|
1135
|
+
composition: room.composition,
|
|
1136
|
+
rule: room.rule,
|
|
1137
|
+
visible,
|
|
1138
|
+
folders: room.folders,
|
|
1139
|
+
queued: queuedDocuments(room.queue),
|
|
1140
|
+
unmodeled: !room.modelled,
|
|
1141
|
+
validate: room.validate,
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
function carriedDrafts(ask, from, into) {
|
|
1145
|
+
return new Map(ask.saved.flatMap(({ path, parts }) => {
|
|
1146
|
+
const record = from.drafts.get(path);
|
|
1147
|
+
if (parts.move === undefined || record === undefined || ask.consumed.has(path))
|
|
1148
|
+
return [];
|
|
1149
|
+
const to = moveTarget(parts.move);
|
|
1150
|
+
if (into.drafts.has(to))
|
|
1151
|
+
return [];
|
|
1152
|
+
const locator = into.record.locator;
|
|
1153
|
+
return [[path, { ...record, locator, path: to, revision: roomDraftRevision() }]];
|
|
1154
|
+
}));
|
|
1155
|
+
}
|
|
1156
|
+
async function plannedMove(ask, source, into) {
|
|
1157
|
+
const destination = into.record.locator;
|
|
1158
|
+
const mixed = ask.saved.find(({ parts }) => Object.keys(parts).length !== 1 || parts.move?.room !== destination);
|
|
1159
|
+
if (mixed !== undefined)
|
|
1160
|
+
return refuse('mixed-room-move', mixed.path);
|
|
1161
|
+
const leavingVisible = await stepped(source.replay(source.queue));
|
|
1162
|
+
const changed = changedUnderneath(ask.saved, leavingVisible);
|
|
1163
|
+
if (changed !== null)
|
|
1164
|
+
return changed;
|
|
1165
|
+
const moves = ask.saved.map(({ path, parts }) => ({ path, to: moveTarget(parts.move) }));
|
|
1166
|
+
const built = await moving({
|
|
1167
|
+
source: sideOf(source, leavingVisible),
|
|
1168
|
+
destination: sideOf(into, await stepped(into.replay(into.queue))),
|
|
1169
|
+
moves,
|
|
1170
|
+
providerLimits: ask.providerLimits,
|
|
1171
|
+
local: ask.local,
|
|
1172
|
+
...(ask.writtenBy === undefined ? {} : { writtenBy: ask.writtenBy }),
|
|
1173
|
+
});
|
|
1174
|
+
if (built.kind === 'refused')
|
|
1175
|
+
return built;
|
|
1176
|
+
const { id } = built.leaving;
|
|
1177
|
+
const carried = carriedDrafts(ask, source, into);
|
|
1178
|
+
return {
|
|
1179
|
+
kind: 'planned',
|
|
1180
|
+
identifier: id,
|
|
1181
|
+
rooms: [
|
|
1182
|
+
{
|
|
1183
|
+
locator: source.record.locator,
|
|
1184
|
+
queue: [...source.queue, built.leaving],
|
|
1185
|
+
saved: new Map([[id, ask.saved]]),
|
|
1186
|
+
consumed: [...ask.consumed, ...carried.keys()],
|
|
1187
|
+
carried: [],
|
|
1188
|
+
},
|
|
1189
|
+
{
|
|
1190
|
+
locator: destination,
|
|
1191
|
+
queue: [...into.queue, built.arriving],
|
|
1192
|
+
saved: new Map([
|
|
1193
|
+
[id, [...carried.values()].map(({ path }) => ({ path, parts: {} }))],
|
|
1194
|
+
]),
|
|
1195
|
+
consumed: [],
|
|
1196
|
+
carried: [...carried.values()],
|
|
1197
|
+
},
|
|
1198
|
+
],
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
async function plannedWithin(ask, room) {
|
|
1202
|
+
const { record } = room;
|
|
1203
|
+
const visible = await stepped(room.replay(room.queue));
|
|
1204
|
+
const changed = changedUnderneath(ask.saved, visible);
|
|
1205
|
+
if (changed !== null)
|
|
1206
|
+
return changed;
|
|
1207
|
+
const parts = ask.saved.map(({ path, parts: held }) => changesOf(path, held));
|
|
1208
|
+
const changes = parts.flatMap(({ changes: made }) => made);
|
|
1209
|
+
const requeue = await stepped(requeuing(room.queue, changes, visible, (batch) => room.changeable.has(batch.id), room.replay));
|
|
1210
|
+
if (requeue.kind === 'refused')
|
|
1211
|
+
return requeue;
|
|
1212
|
+
const foreign = [...requeue.withdrawn.keys()].some((origin) => {
|
|
1213
|
+
const writer = room.queue.find((batch) => batch.id === origin)?.writtenBy;
|
|
1214
|
+
return writer?.app !== ask.writtenBy?.app || writer?.release !== ask.writtenBy?.release;
|
|
1215
|
+
});
|
|
1216
|
+
if (foreign)
|
|
1217
|
+
return unqueueable([...requeue.queued].at(-1));
|
|
1218
|
+
const input = {
|
|
1219
|
+
local: ask.local,
|
|
1220
|
+
baseRoomVersion: record.roomVersion,
|
|
1221
|
+
composition: room.composition,
|
|
1222
|
+
rule: room.rule,
|
|
1223
|
+
providerLimits: ask.providerLimits,
|
|
1224
|
+
handle: record.declaration.handle,
|
|
1225
|
+
visible,
|
|
1226
|
+
folders: room.folders,
|
|
1227
|
+
changes,
|
|
1228
|
+
bases: parts.flatMap(({ bases }) => bases),
|
|
1229
|
+
queued: queuedDocuments(room.queue),
|
|
1230
|
+
writtenBy: ask.writtenBy,
|
|
1231
|
+
unmodeled: !room.modelled,
|
|
1232
|
+
validate: room.validate,
|
|
1233
|
+
};
|
|
1234
|
+
const rewritten = requeue.withdrawn.size > 0;
|
|
1235
|
+
if (rewritten) {
|
|
1236
|
+
const whole = await batching({
|
|
1237
|
+
...input,
|
|
1238
|
+
providerLimits: [],
|
|
1239
|
+
queued: new Set([...input.queued, ...requeue.queued]),
|
|
1240
|
+
});
|
|
1241
|
+
if (whole.kind === 'refused')
|
|
1242
|
+
return whole;
|
|
1243
|
+
}
|
|
1244
|
+
const own = !rewritten
|
|
1245
|
+
? await batching(input)
|
|
1246
|
+
: requeue.changes.length === 0
|
|
1247
|
+
? null
|
|
1248
|
+
: await batching({
|
|
1249
|
+
...input,
|
|
1250
|
+
visible: await stepped(room.replay(requeue.queue)),
|
|
1251
|
+
changes: requeue.changes,
|
|
1252
|
+
queued: queuedDocuments(requeue.queue),
|
|
1253
|
+
});
|
|
1254
|
+
if (own?.kind === 'refused')
|
|
1255
|
+
return own;
|
|
1256
|
+
const queue = own === null ? requeue.queue : [...requeue.queue, own.batch];
|
|
1257
|
+
const saved = new Map();
|
|
1258
|
+
for (const [origin, rebuilt] of requeue.withdrawn) {
|
|
1259
|
+
if (rebuilt === null)
|
|
1260
|
+
continue;
|
|
1261
|
+
const limited = await stepped(limiting(queue, rebuilt, ask.providerLimits, room.replay));
|
|
1262
|
+
if (limited !== null)
|
|
1263
|
+
return { kind: 'refused', refusal: limited };
|
|
1264
|
+
saved.set(rebuilt.id, withdrawnDrafts(room.saved.get(origin) ?? [], changes));
|
|
1265
|
+
}
|
|
1266
|
+
if (own !== null) {
|
|
1267
|
+
saved.set(own.batch.id, ask.saved.filter(({ path }) => !requeue.queued.has(path)));
|
|
1268
|
+
}
|
|
1269
|
+
const carried = carriedDrafts(ask, room, room);
|
|
1270
|
+
return {
|
|
1271
|
+
kind: 'planned',
|
|
1272
|
+
identifier: own?.batch.id ??
|
|
1273
|
+
[...requeue.withdrawn].map(([origin, rebuilt]) => rebuilt?.id ?? origin).at(-1),
|
|
1274
|
+
rooms: [
|
|
1275
|
+
{
|
|
1276
|
+
locator: record.locator,
|
|
1277
|
+
queue,
|
|
1278
|
+
saved,
|
|
1279
|
+
consumed: [...ask.consumed, ...carried.keys()],
|
|
1280
|
+
carried: [...carried.values()],
|
|
1281
|
+
},
|
|
1282
|
+
],
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
export function destination(locator, saved) {
|
|
1286
|
+
const into = saved.find(({ parts }) => parts.move?.room !== undefined && parts.move.room !== locator);
|
|
1287
|
+
return into?.parts.move?.room ?? null;
|
|
1165
1288
|
}
|
|
1166
|
-
export function
|
|
1167
|
-
return
|
|
1289
|
+
export function planSave(ask, room, into) {
|
|
1290
|
+
return into === undefined ? plannedWithin(ask, room) : plannedMove(ask, room, into);
|
|
1168
1291
|
}
|