@agentshouse/mdruntime 0.1.0-cd3ee807e46ae → 0.1.0-cd507e16e5fc0
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 +19 -16
- package/dist/acceptance.d.ts +6 -0
- package/dist/acceptance.d.ts.map +1 -0
- package/dist/acceptance.js +389 -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 +157 -57
- package/dist/adapter.d.ts.map +1 -1
- package/dist/attached-model.d.ts +7 -10
- package/dist/attached-model.d.ts.map +1 -1
- package/dist/attached-model.js +40 -41
- package/dist/attempt.d.ts.map +1 -1
- package/dist/attempt.js +14 -1
- 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 +31 -11
- package/dist/bootstrap.d.ts.map +1 -1
- package/dist/bootstrap.js +324 -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 +12 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +64 -0
- package/dist/change-set.d.ts +9 -14
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -63
- package/dist/change.d.ts +32 -1
- package/dist/change.d.ts.map +1 -1
- package/dist/change.js +10 -1
- 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 +43 -16
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +101 -12
- package/dist/collection.d.ts +11 -7
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +38 -79
- package/dist/compile.d.ts +16 -0
- package/dist/compile.d.ts.map +1 -0
- package/dist/compile.js +717 -0
- package/dist/connection.d.ts +8 -116
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +104 -2410
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/{chat/context.js → context.js} +1 -4
- package/dist/conversation-live.d.ts +136 -0
- package/dist/conversation-live.d.ts.map +1 -0
- package/dist/conversation-live.js +248 -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 +57 -40
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +992 -543
- package/dist/digest.d.ts +7 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +113 -0
- package/dist/discovery.d.ts +10 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +175 -0
- package/dist/durability.d.ts +19 -1
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +20 -0
- package/dist/entry.d.ts.map +1 -0
- package/dist/entry.js +161 -0
- package/dist/figures.d.ts +49 -0
- package/dist/figures.d.ts.map +1 -0
- package/dist/figures.js +197 -0
- package/dist/file.d.ts +2 -19
- package/dist/file.d.ts.map +1 -1
- package/dist/file.js +7 -122
- package/dist/holdings.d.ts +29 -0
- package/dist/holdings.d.ts.map +1 -0
- package/dist/holdings.js +95 -0
- package/dist/host.d.ts +12 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +130 -20
- package/dist/index.d.ts +34 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -0
- package/dist/install.d.ts +56 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +556 -0
- package/dist/job.d.ts +33 -0
- package/dist/job.d.ts.map +1 -0
- package/dist/job.js +54 -0
- package/dist/lifecycle.d.ts +7 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +268 -0
- package/dist/listing.d.ts +53 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +176 -0
- package/dist/live.d.ts +23 -0
- package/dist/live.d.ts.map +1 -0
- package/dist/live.js +165 -0
- package/dist/locks.d.ts +9 -0
- package/dist/locks.d.ts.map +1 -0
- package/dist/locks.js +61 -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 +61 -0
- package/dist/media.d.ts +8 -0
- package/dist/media.d.ts.map +1 -0
- package/dist/media.js +218 -0
- package/dist/memory.d.ts +19 -5
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +254 -94
- package/dist/messages.d.ts +52 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +168 -0
- package/dist/model.d.ts +11 -11
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +7 -10
- package/dist/models.d.ts +14 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +195 -0
- package/dist/name.d.ts +4 -0
- package/dist/name.d.ts.map +1 -0
- package/dist/name.js +122 -0
- package/dist/observation.d.ts +22 -4
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +120 -14
- package/dist/opened.d.ts +22 -0
- package/dist/opened.d.ts.map +1 -0
- package/dist/opened.js +107 -0
- package/dist/opening.d.ts +4 -0
- package/dist/opening.d.ts.map +1 -0
- package/dist/opening.js +57 -0
- package/dist/outcome.d.ts +53 -8
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +43 -0
- package/dist/overlay.d.ts +4 -4
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +111 -182
- package/dist/{chat/parts.d.ts → parts.d.ts} +11 -9
- package/dist/parts.d.ts.map +1 -0
- package/dist/{chat/parts.js → parts.js} +45 -46
- package/dist/paths.d.ts +2 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +26 -0
- package/dist/preparation.d.ts +20 -0
- package/dist/preparation.d.ts.map +1 -0
- package/dist/preparation.js +226 -0
- package/dist/queries.d.ts +16 -0
- package/dist/queries.d.ts.map +1 -0
- package/dist/queries.js +272 -0
- package/dist/query.d.ts +50 -183
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -464
- package/dist/{chat/questions.d.ts → questions.d.ts} +5 -2
- package/dist/questions.d.ts.map +1 -0
- package/dist/{chat/questions.js → questions.js} +12 -1
- package/dist/reach.d.ts +21 -7
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +289 -89
- package/dist/react.d.ts +16 -6
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +7 -17
- package/dist/{chat/read.d.ts → read.d.ts} +2 -0
- package/dist/read.d.ts.map +1 -0
- package/dist/{chat/read.js → read.js} +4 -0
- package/dist/readiness.d.ts +49 -0
- package/dist/readiness.d.ts.map +1 -0
- package/dist/readiness.js +27 -0
- package/dist/reads.d.ts +37 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +171 -0
- package/dist/recovery.d.ts +26 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +232 -0
- package/dist/refresh.d.ts +17 -14
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +143 -51
- package/dist/refusal.d.ts +5 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +56 -0
- package/dist/replica.d.ts +56 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +333 -154
- package/dist/room-draft.d.ts +37 -6
- package/dist/room-draft.d.ts.map +1 -1
- package/dist/room-draft.js +161 -74
- package/dist/room-drafts.d.ts +24 -0
- package/dist/room-drafts.d.ts.map +1 -0
- package/dist/room-drafts.js +216 -0
- package/dist/rows.d.ts +30 -37
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +59 -126
- package/dist/runtime.d.ts +43 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts +56 -9
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +548 -174
- package/dist/saves.d.ts +70 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +1008 -0
- package/dist/search.d.ts +15 -55
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -121
- package/dist/seed.d.ts +25 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +146 -0
- package/dist/shared.d.ts +15 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +425 -0
- package/dist/shown.d.ts +31 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +295 -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/rooms.d.ts +44 -0
- package/dist/socket/rooms.d.ts.map +1 -0
- package/dist/socket/rooms.js +90 -0
- package/dist/socket/session.d.ts +39 -0
- package/dist/socket/session.d.ts.map +1 -0
- package/dist/socket/session.js +23 -0
- package/dist/socket.d.ts +70 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +175 -0
- package/dist/source.d.ts +61 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +81 -0
- package/dist/status.d.ts +5 -2
- package/dist/status.d.ts.map +1 -1
- package/dist/status.js +3 -7
- package/dist/store/fences.d.ts +16 -0
- package/dist/store/fences.d.ts.map +1 -0
- package/dist/store/fences.js +26 -0
- package/dist/store/installs.d.ts +30 -0
- package/dist/store/installs.d.ts.map +1 -0
- package/dist/store/installs.js +34 -0
- package/dist/store/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 +212 -0
- package/dist/store/records.d.ts.map +1 -0
- package/dist/store/records.js +431 -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 +43 -0
- package/dist/store/watchers.d.ts +17 -0
- package/dist/store/watchers.d.ts.map +1 -0
- package/dist/store/watchers.js +57 -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 +106 -117
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +138 -490
- package/dist/stored.d.ts +156 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +649 -0
- 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 +532 -0
- package/dist/tables.d.ts +417 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +740 -0
- package/dist/tallies.d.ts +18 -0
- package/dist/tallies.d.ts.map +1 -0
- package/dist/tallies.js +129 -0
- package/dist/transfer.d.ts +0 -5
- package/dist/transfer.d.ts.map +1 -1
- package/dist/turn.d.ts +9 -0
- package/dist/turn.d.ts.map +1 -0
- package/dist/turn.js +75 -0
- package/dist/validation.d.ts +29 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +104 -0
- package/dist/windows.d.ts +11 -0
- package/dist/windows.d.ts.map +1 -0
- package/dist/windows.js +16 -0
- package/dist/wire.d.ts +181 -33
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +62 -31
- package/package.json +22 -19
- package/AGENTS.md +0 -318
- package/dist/chat/acts.d.ts +0 -34
- 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/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 -60
- 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 -20
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -59
- package/dist/chat/markdown.d.ts +0 -19
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -187
- package/dist/chat/message.d.ts +0 -6
- package/dist/chat/message.d.ts.map +0 -1
- package/dist/chat/message.js +0 -192
- package/dist/chat/messages.d.ts +0 -21
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -151
- 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 -31
- package/dist/chat/overlay.d.ts.map +0 -1
- package/dist/chat/overlay.js +0 -97
- package/dist/chat/parts.d.ts.map +0 -1
- 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 -63
- package/dist/chat/provider.d.ts.map +0 -1
- package/dist/chat/provider.js +0 -645
- package/dist/chat/question.d.ts +0 -9
- package/dist/chat/question.d.ts.map +0 -1
- package/dist/chat/question.js +0 -80
- package/dist/chat/questions.d.ts.map +0 -1
- package/dist/chat/read.d.ts.map +0 -1
- package/dist/chat/ready.d.ts +0 -33
- package/dist/chat/ready.d.ts.map +0 -1
- package/dist/chat/ready.js +0 -91
- 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 -18
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -440
package/dist/save.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { definitionOf } from './model.js';
|
|
2
|
-
import { apply, ATTACHMENT, links, parse, pointerSegments, references, relative, relativize, retarget, serialize, target, } from '@agentshouse/mdmodel';
|
|
3
|
-
import { immutable, queuedFile, departure, } from './change.js';
|
|
4
|
-
import { collectionOf, documentsOf, governing,
|
|
2
|
+
import { apply, ARRAY_INDEX, ATTACHMENT, links, parse, pointerSegments, references, relative, relativize, retarget, roomReferences, serialize, target, } from '@agentshouse/mdmodel';
|
|
3
|
+
import { immutable, leaving, queuedFile, departure, } from './change.js';
|
|
4
|
+
import { collectionOf, documentsOf, governing, } from './collection.js';
|
|
5
5
|
import { changeBatchIdentity } from './identity.js';
|
|
6
|
-
import {
|
|
7
|
-
import { covered, normalize } from './paths.js';
|
|
6
|
+
import { overlaying } from './overlay.js';
|
|
7
|
+
import { ancestors, authoredAt, covered, normalize } from './paths.js';
|
|
8
|
+
import { entriesIn, sorting } from './shared.js';
|
|
9
|
+
import { paced, ROW_WEIGHT, stepped } from './turn.js';
|
|
10
|
+
import { validatedCollection } from './validation.js';
|
|
8
11
|
function refuse(code, file, location) {
|
|
9
12
|
return {
|
|
10
13
|
kind: 'refused',
|
|
@@ -20,7 +23,7 @@ function repointed(document, definition, from, to, moves, settled) {
|
|
|
20
23
|
const parsed = parse(document.content, from);
|
|
21
24
|
if (!parsed.ok)
|
|
22
25
|
return [];
|
|
23
|
-
|
|
26
|
+
const changes = [];
|
|
24
27
|
const names = new Set();
|
|
25
28
|
for (const { pointer, value } of definition === undefined
|
|
26
29
|
? []
|
|
@@ -32,38 +35,39 @@ function repointed(document, definition, from, to, moves, settled) {
|
|
|
32
35
|
const destination = moves.get(named) ?? named;
|
|
33
36
|
if (target(to, value) === destination)
|
|
34
37
|
continue;
|
|
35
|
-
|
|
38
|
+
changes.push({
|
|
36
39
|
kind: 'reference',
|
|
37
40
|
pointer,
|
|
38
41
|
value: retarget(value, relative(to, destination)),
|
|
39
42
|
prior: value,
|
|
40
43
|
});
|
|
41
|
-
if (applied.outcome !== 'applied')
|
|
42
|
-
continue;
|
|
43
|
-
next = applied.document;
|
|
44
44
|
names.add(name);
|
|
45
45
|
}
|
|
46
|
+
if (changes.length === 0)
|
|
47
|
+
return [];
|
|
48
|
+
const applied = apply(parsed.document, changes);
|
|
49
|
+
if (applied.outcome !== 'applied')
|
|
50
|
+
return [];
|
|
51
|
+
const next = applied.document;
|
|
46
52
|
return [...names].map((name) => ({ kind: 'field', path: from, name, value: next.fields[name] }));
|
|
47
53
|
}
|
|
48
|
-
function edited(document,
|
|
49
|
-
|
|
54
|
+
function edited(document, changes) {
|
|
55
|
+
const parts = new Map();
|
|
50
56
|
for (const change of changes) {
|
|
51
|
-
if (change.
|
|
52
|
-
|
|
53
|
-
if (change.kind
|
|
54
|
-
|
|
55
|
-
const applied = apply(next, change.kind === 'preamble'
|
|
56
|
-
? { kind: 'preamble', value: change.value, prior: next.preamble }
|
|
57
|
-
: {
|
|
57
|
+
if (change.kind === 'preamble')
|
|
58
|
+
parts.set('preamble', { kind: 'preamble', value: change.value, prior: document.preamble });
|
|
59
|
+
if (change.kind === 'section')
|
|
60
|
+
parts.set(`section ${change.name}`, {
|
|
58
61
|
kind: 'section',
|
|
59
62
|
name: change.name,
|
|
60
63
|
value: change.value,
|
|
61
|
-
prior:
|
|
64
|
+
prior: document.sections[change.name] ?? '',
|
|
62
65
|
});
|
|
63
|
-
if (applied.outcome === 'applied')
|
|
64
|
-
next = applied.document;
|
|
65
66
|
}
|
|
66
|
-
|
|
67
|
+
if (parts.size === 0)
|
|
68
|
+
return document;
|
|
69
|
+
const applied = apply(document, [...parts.values()]);
|
|
70
|
+
return applied.outcome === 'applied' ? applied.document : document;
|
|
67
71
|
}
|
|
68
72
|
function bodies(path, before, after) {
|
|
69
73
|
const changes = [];
|
|
@@ -78,7 +82,7 @@ function bodies(path, before, after) {
|
|
|
78
82
|
return changes;
|
|
79
83
|
}
|
|
80
84
|
function relinks(path, moved, before, moves) {
|
|
81
|
-
|
|
85
|
+
const changes = [];
|
|
82
86
|
for (const link of links(before, path)) {
|
|
83
87
|
const destination = moves.get(link.target) ?? link.target;
|
|
84
88
|
if (destination === link.target && moved === path)
|
|
@@ -86,20 +90,23 @@ function relinks(path, moved, before, moves) {
|
|
|
86
90
|
const to = relative(moved, destination);
|
|
87
91
|
if (to === relative(path, link.target))
|
|
88
92
|
continue;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
93
|
+
changes.push({ kind: 'link', href: link.href, to });
|
|
94
|
+
}
|
|
95
|
+
if (changes.length === 0)
|
|
96
|
+
return { kind: 'changes', changes: [] };
|
|
97
|
+
const applied = apply(before, changes);
|
|
98
|
+
if (applied.outcome === 'refuse') {
|
|
99
|
+
return {
|
|
100
|
+
kind: 'refused',
|
|
101
|
+
refusal: {
|
|
102
|
+
code: applied.refusal.rule,
|
|
103
|
+
retryable: false,
|
|
104
|
+
file: path,
|
|
105
|
+
...(applied.refusal.location === undefined ? {} : { location: applied.refusal.location }),
|
|
106
|
+
},
|
|
107
|
+
};
|
|
102
108
|
}
|
|
109
|
+
const after = applied.document;
|
|
103
110
|
if (after === before)
|
|
104
111
|
return { kind: 'changes', changes: [] };
|
|
105
112
|
if (before.type === undefined) {
|
|
@@ -107,19 +114,14 @@ function relinks(path, moved, before, moves) {
|
|
|
107
114
|
}
|
|
108
115
|
return { kind: 'changes', changes: bodies(path, before, after) };
|
|
109
116
|
}
|
|
110
|
-
function
|
|
111
|
-
|
|
112
|
-
const item = merged[index];
|
|
113
|
-
if (item.path !== path)
|
|
114
|
-
continue;
|
|
115
|
-
if (item.kind === 'section' || item.kind === 'preamble')
|
|
116
|
-
merged.splice(index, 1);
|
|
117
|
-
}
|
|
117
|
+
function partKey(change) {
|
|
118
|
+
return change.kind === 'section' ? `section ${change.name}` : change.kind;
|
|
118
119
|
}
|
|
119
|
-
function rewrites(changes, visible) {
|
|
120
|
+
function* rewrites(changes, visible) {
|
|
120
121
|
const moves = new Map();
|
|
121
122
|
const settled = new Set();
|
|
122
|
-
|
|
123
|
+
const parts = new Map();
|
|
124
|
+
for (const [index, change] of changes.entries()) {
|
|
123
125
|
if (change.kind === 'move')
|
|
124
126
|
moves.set(change.path, change.to);
|
|
125
127
|
if (change.kind === 'remove' ||
|
|
@@ -130,54 +132,143 @@ function rewrites(changes, visible) {
|
|
|
130
132
|
}
|
|
131
133
|
if (change.kind === 'field')
|
|
132
134
|
settled.add(`${change.path} ${change.name}`);
|
|
135
|
+
if (isPart(change)) {
|
|
136
|
+
const held = parts.get(change.path);
|
|
137
|
+
if (held === undefined)
|
|
138
|
+
parts.set(change.path, [index]);
|
|
139
|
+
else
|
|
140
|
+
held.push(index);
|
|
141
|
+
}
|
|
133
142
|
}
|
|
134
143
|
if (moves.size === 0)
|
|
135
144
|
return { kind: 'changes', changes };
|
|
136
145
|
const merged = [...changes];
|
|
137
146
|
const added = [];
|
|
138
|
-
for (const [path, document] of documentsOf(visible.collection)) {
|
|
147
|
+
for (const [path, document] of yield* documentsOf(visible.collection)) {
|
|
139
148
|
if (settled.has(path))
|
|
140
149
|
continue;
|
|
141
150
|
const moved = moves.get(path) ?? path;
|
|
142
151
|
const definition = definitionOf(governing(visible.collection.composition, path), document.type);
|
|
143
|
-
|
|
144
|
-
|
|
152
|
+
const repointing = repointed(document, definition, path, moved, moves, settled);
|
|
153
|
+
added.push(...repointing);
|
|
154
|
+
const own = parts.get(path) ?? [];
|
|
155
|
+
const relinked = relinks(path, moved, edited(document, own.map((index) => merged[index])), moves);
|
|
145
156
|
if (relinked.kind === 'refused')
|
|
146
157
|
return relinked;
|
|
158
|
+
const keyed = new Map();
|
|
159
|
+
for (const index of own) {
|
|
160
|
+
const key = partKey(merged[index]);
|
|
161
|
+
if (!keyed.has(key))
|
|
162
|
+
keyed.set(key, index);
|
|
163
|
+
}
|
|
147
164
|
for (const change of relinked.changes) {
|
|
148
165
|
if (change.kind === 'replace') {
|
|
149
|
-
|
|
166
|
+
for (const index of own) {
|
|
167
|
+
const kind = merged[index]?.kind;
|
|
168
|
+
if (kind === 'section' || kind === 'preamble')
|
|
169
|
+
merged[index] = null;
|
|
170
|
+
}
|
|
150
171
|
added.push(change);
|
|
151
172
|
continue;
|
|
152
173
|
}
|
|
153
|
-
const index =
|
|
154
|
-
|
|
155
|
-
(change.kind !== 'section' || (item.kind === 'section' && item.name === change.name)));
|
|
156
|
-
if (index === -1)
|
|
174
|
+
const index = keyed.get(partKey(change));
|
|
175
|
+
if (index === undefined)
|
|
157
176
|
added.push(change);
|
|
158
177
|
else
|
|
159
178
|
merged[index] = change;
|
|
160
179
|
}
|
|
180
|
+
const text = visible.collection.text[path].length;
|
|
181
|
+
const rewritten = repointing.length > 0 || relinked.changes.length > 0;
|
|
182
|
+
yield ROW_WEIGHT + text + (rewritten ? text : 0);
|
|
161
183
|
}
|
|
162
|
-
return {
|
|
184
|
+
return {
|
|
185
|
+
kind: 'changes',
|
|
186
|
+
changes: [...added, ...merged.filter((change) => change !== null)],
|
|
187
|
+
};
|
|
163
188
|
}
|
|
164
|
-
function anticipated(changes, preconditions, rewritten, visible) {
|
|
165
|
-
const
|
|
189
|
+
function* anticipated(changes, preconditions, rewritten, visible) {
|
|
190
|
+
const given = new Set(changes);
|
|
191
|
+
const derived = rewritten.filter((change) => !given.has(change));
|
|
166
192
|
return {
|
|
167
193
|
changes: rewritten,
|
|
168
|
-
preconditions: [...preconditionsOf(derived, visible, []), ...preconditions],
|
|
194
|
+
preconditions: [...(yield* preconditionsOf(derived, visible, [])), ...preconditions],
|
|
169
195
|
};
|
|
170
196
|
}
|
|
171
|
-
export function providerRewritten(batch, visible) {
|
|
172
|
-
const rewritten = rewrites(batch.changes, visible);
|
|
197
|
+
export function* providerRewritten(batch, visible) {
|
|
198
|
+
const rewritten = yield* rewrites(batch.changes, visible);
|
|
173
199
|
if (rewritten.kind === 'refused')
|
|
174
200
|
return batch;
|
|
175
201
|
return {
|
|
176
202
|
...batch,
|
|
177
|
-
...anticipated(batch.changes, batch.preconditions, rewritten.changes, visible),
|
|
203
|
+
...(yield* anticipated(batch.changes, batch.preconditions, rewritten.changes, visible)),
|
|
178
204
|
};
|
|
179
205
|
}
|
|
180
|
-
function
|
|
206
|
+
function crossed(document, definition, path, to) {
|
|
207
|
+
const changes = [];
|
|
208
|
+
for (const link of links(document, path)) {
|
|
209
|
+
const written = to(link.target, link.href);
|
|
210
|
+
if (written !== undefined)
|
|
211
|
+
changes.push({ kind: 'link', href: link.href, to: written });
|
|
212
|
+
}
|
|
213
|
+
for (const { pointer, value } of definition === undefined
|
|
214
|
+
? []
|
|
215
|
+
: references(document, definition)) {
|
|
216
|
+
const named = target(path, value);
|
|
217
|
+
const written = named === null ? undefined : to(named, value);
|
|
218
|
+
if (written !== undefined) {
|
|
219
|
+
changes.push({ kind: 'reference', pointer, value: retarget(value, written), prior: value });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return changes;
|
|
223
|
+
}
|
|
224
|
+
function rewritten(path, document, changes) {
|
|
225
|
+
if (changes.length === 0)
|
|
226
|
+
return [];
|
|
227
|
+
const applied = apply(document, changes);
|
|
228
|
+
if (applied.outcome !== 'applied')
|
|
229
|
+
return [];
|
|
230
|
+
const after = applied.document;
|
|
231
|
+
if (document.type === undefined)
|
|
232
|
+
return [{ kind: 'replace', path, content: serialize(after) }];
|
|
233
|
+
const names = new Set(changes.flatMap((change) => change.kind === 'reference' ? [pointerSegments(change.pointer)[0] ?? ''] : []));
|
|
234
|
+
return [
|
|
235
|
+
...[...names].map((name) => ({ kind: 'field', path, name, value: after.fields[name] })),
|
|
236
|
+
...bodies(path, document, after),
|
|
237
|
+
];
|
|
238
|
+
}
|
|
239
|
+
function roomPathOf(handle, path) {
|
|
240
|
+
return `/rooms/${handle}/${path}`;
|
|
241
|
+
}
|
|
242
|
+
export function* leavingRewritten(batch, visible) {
|
|
243
|
+
const between = batch.between;
|
|
244
|
+
if (between === undefined)
|
|
245
|
+
return batch;
|
|
246
|
+
const moved = new Map(between.moves.map(({ path, to }) => [path, roomPathOf(between.destination.handle, to)]));
|
|
247
|
+
const derived = [];
|
|
248
|
+
for (const [path, document] of yield* documentsOf(visible.collection)) {
|
|
249
|
+
if (moved.has(path))
|
|
250
|
+
continue;
|
|
251
|
+
const definition = definitionOf(governing(visible.collection.composition, path), document.type);
|
|
252
|
+
derived.push(...rewritten(path, document, crossed(document, definition, path, (named) => moved.get(named))));
|
|
253
|
+
yield ROW_WEIGHT + visible.collection.text[path].length;
|
|
254
|
+
}
|
|
255
|
+
if (derived.length === 0)
|
|
256
|
+
return batch;
|
|
257
|
+
return {
|
|
258
|
+
...batch,
|
|
259
|
+
changes: [...derived, ...batch.changes],
|
|
260
|
+
preconditions: [...(yield* preconditionsOf(derived, visible, [])), ...batch.preconditions],
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
export function rewriting(batch, locator) {
|
|
264
|
+
return leaving(batch, locator) || batch.changes.some((change) => change.kind === 'move');
|
|
265
|
+
}
|
|
266
|
+
export function* effectiveIn(batch, locator, visible) {
|
|
267
|
+
return leaving(batch, locator)
|
|
268
|
+
? yield* leavingRewritten(batch, visible)
|
|
269
|
+
: yield* providerRewritten(batch, visible);
|
|
270
|
+
}
|
|
271
|
+
function* incoming(collection, removed, candidates) {
|
|
181
272
|
const found = new Map();
|
|
182
273
|
const note = (target, file) => {
|
|
183
274
|
if (!removed.has(target))
|
|
@@ -186,7 +277,20 @@ function incoming(collection, removed) {
|
|
|
186
277
|
referrers.add(file);
|
|
187
278
|
found.set(target, referrers);
|
|
188
279
|
};
|
|
189
|
-
|
|
280
|
+
const read = function* (paths) {
|
|
281
|
+
const seen = new Set();
|
|
282
|
+
for (const path of paths) {
|
|
283
|
+
if (seen.has(path))
|
|
284
|
+
continue;
|
|
285
|
+
seen.add(path);
|
|
286
|
+
const document = collection.document(path);
|
|
287
|
+
if (document !== undefined)
|
|
288
|
+
yield [path, document];
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
for (const [path, document] of candidates === null
|
|
292
|
+
? yield* documentsOf(collection)
|
|
293
|
+
: read(candidates)) {
|
|
190
294
|
const definition = definitionOf(governing(collection.composition, path), document.type);
|
|
191
295
|
for (const { value, to } of definition === undefined ? [] : references(document, definition)) {
|
|
192
296
|
if (to.includes(ATTACHMENT))
|
|
@@ -195,8 +299,9 @@ function incoming(collection, removed) {
|
|
|
195
299
|
if (named !== null)
|
|
196
300
|
note(named, path);
|
|
197
301
|
}
|
|
302
|
+
yield ROW_WEIGHT + collection.text[path].length;
|
|
198
303
|
}
|
|
199
|
-
const [first] =
|
|
304
|
+
const [first] = yield* sorting(found.keys());
|
|
200
305
|
if (first === undefined)
|
|
201
306
|
return null;
|
|
202
307
|
const every = new Set();
|
|
@@ -209,33 +314,43 @@ function incoming(collection, removed) {
|
|
|
209
314
|
code: 'referenced-missing-file',
|
|
210
315
|
retryable: false,
|
|
211
316
|
file: first,
|
|
212
|
-
referrers:
|
|
317
|
+
referrers: yield* sorting(every),
|
|
213
318
|
},
|
|
214
319
|
};
|
|
215
320
|
}
|
|
216
321
|
function affected(change) {
|
|
217
322
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
218
323
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
324
|
+
const WRITE = ['write'];
|
|
325
|
+
const MOVE_OUT = ['write', 'erase'];
|
|
326
|
+
function guard(changes, input, removing) {
|
|
327
|
+
const overridden = new Map();
|
|
328
|
+
const existing = {
|
|
329
|
+
has: (path) => overridden.get(path) ??
|
|
330
|
+
(Object.hasOwn(input.visible.documents, path) || Object.hasOwn(input.visible.binaries, path)),
|
|
331
|
+
add: (path) => void overridden.set(path, true),
|
|
332
|
+
delete: (path) => void overridden.set(path, false),
|
|
333
|
+
};
|
|
334
|
+
const occupied = (path) => input.folders.has(path) ? path : (ancestors(path).find((one) => existing.has(one)) ?? null);
|
|
224
335
|
for (const [index, change] of changes.entries()) {
|
|
225
336
|
for (const path of affected(change)) {
|
|
226
337
|
const normalized = normalize(path);
|
|
227
338
|
if (normalized === null || normalized === '')
|
|
228
339
|
return refuse('room-root', path);
|
|
229
|
-
if (covered(input.providerOwnedPaths, normalized)
|
|
340
|
+
if (covered(input.providerOwnedPaths, normalized) ||
|
|
341
|
+
(input.authoredPaths !== undefined && !authoredAt(input.authoredPaths, normalized))) {
|
|
230
342
|
return refuse('provider-owned-path', normalized);
|
|
231
343
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
344
|
+
if (!input.pathRule(normalized))
|
|
345
|
+
return refuse('invalid-path', normalized);
|
|
346
|
+
for (const operation of change.kind === 'remove' ? removing : WRITE)
|
|
347
|
+
if (!input.local && !covered(input.operations[operation], normalized))
|
|
348
|
+
return refuse(`${operation}-grant`, normalized);
|
|
235
349
|
}
|
|
236
|
-
if (change.kind === 'create') {
|
|
237
|
-
|
|
238
|
-
|
|
350
|
+
if (change.kind === 'create' || change.kind === 'arrival') {
|
|
351
|
+
const taken = existing.has(change.path) ? change.path : occupied(change.path);
|
|
352
|
+
if (taken !== null)
|
|
353
|
+
return refuse('path-collision', taken);
|
|
239
354
|
existing.add(change.path);
|
|
240
355
|
continue;
|
|
241
356
|
}
|
|
@@ -245,6 +360,9 @@ function guard(changes, input) {
|
|
|
245
360
|
input.bases.some((base) => base.kind === 'absent' && base.path === change.path))) {
|
|
246
361
|
return refuse('path-collision', change.path);
|
|
247
362
|
}
|
|
363
|
+
const taken = occupied(change.path);
|
|
364
|
+
if (taken !== null)
|
|
365
|
+
return refuse('path-collision', taken);
|
|
248
366
|
if (!input.local &&
|
|
249
367
|
existing.has(change.path) &&
|
|
250
368
|
input.visible.revisions[departure(changes, index)] === undefined) {
|
|
@@ -256,8 +374,9 @@ function guard(changes, input) {
|
|
|
256
374
|
if (change.kind === 'move') {
|
|
257
375
|
if (!existing.has(change.path))
|
|
258
376
|
return refuse('path-absent', change.path);
|
|
259
|
-
|
|
260
|
-
|
|
377
|
+
const taken = existing.has(change.to) ? change.to : occupied(change.to);
|
|
378
|
+
if (taken !== null)
|
|
379
|
+
return refuse('path-collision', taken);
|
|
261
380
|
if (unrevised(input, change.path)) {
|
|
262
381
|
return refuse('unknown-revision', change.path);
|
|
263
382
|
}
|
|
@@ -275,7 +394,7 @@ function guard(changes, input) {
|
|
|
275
394
|
continue;
|
|
276
395
|
}
|
|
277
396
|
if (change.kind === 'replace') {
|
|
278
|
-
if (
|
|
397
|
+
if (unrevised(input, change.path)) {
|
|
279
398
|
return refuse('unknown-revision', change.path);
|
|
280
399
|
}
|
|
281
400
|
continue;
|
|
@@ -289,6 +408,22 @@ function guard(changes, input) {
|
|
|
289
408
|
function unrevised(input, path) {
|
|
290
409
|
return (!input.local && input.queued?.has(path) !== true && input.visible.revisions[path] === undefined);
|
|
291
410
|
}
|
|
411
|
+
export function queuedDocuments(queue) {
|
|
412
|
+
const paths = new Set();
|
|
413
|
+
for (const batch of queue) {
|
|
414
|
+
for (const change of batch.changes) {
|
|
415
|
+
if (change.kind === 'binary' || (change.kind === 'arrival' && !('content' in change)))
|
|
416
|
+
continue;
|
|
417
|
+
if (change.kind === 'remove')
|
|
418
|
+
paths.delete(change.path);
|
|
419
|
+
else if (change.kind !== 'move')
|
|
420
|
+
paths.add(change.path);
|
|
421
|
+
else if (paths.delete(change.path))
|
|
422
|
+
paths.add(change.to);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return paths;
|
|
426
|
+
}
|
|
292
427
|
function identity(precondition) {
|
|
293
428
|
const part = precondition.kind === 'field' || precondition.kind === 'section' ? precondition.name : '';
|
|
294
429
|
return `${precondition.kind} ${precondition.path} ${part}`;
|
|
@@ -306,7 +441,7 @@ function sameTarget(precondition, change) {
|
|
|
306
441
|
return ((precondition.kind !== 'field' && precondition.kind !== 'section') ||
|
|
307
442
|
((change.kind === 'field' || change.kind === 'section') && precondition.name === change.name));
|
|
308
443
|
}
|
|
309
|
-
function preconditionsOf(changes, visible, bases) {
|
|
444
|
+
function* preconditionsOf(changes, visible, bases) {
|
|
310
445
|
const preconditions = [];
|
|
311
446
|
const seen = new Set();
|
|
312
447
|
const add = (precondition) => {
|
|
@@ -317,6 +452,7 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
317
452
|
preconditions.push(precondition);
|
|
318
453
|
};
|
|
319
454
|
for (const change of changes) {
|
|
455
|
+
yield ROW_WEIGHT;
|
|
320
456
|
if (change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble') {
|
|
321
457
|
const based = bases.find((base) => sameTarget(base, change));
|
|
322
458
|
if (based !== undefined) {
|
|
@@ -364,10 +500,13 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
364
500
|
function depth(path) {
|
|
365
501
|
return path.split('/').length;
|
|
366
502
|
}
|
|
367
|
-
function
|
|
368
|
-
const written =
|
|
503
|
+
function* exceeding(limits, changes, effective, resulting) {
|
|
504
|
+
const written = effective.map((change) => (change.kind === 'move' ? change.to : change.path));
|
|
369
505
|
const created = changes
|
|
370
|
-
.filter((change) => change.kind === 'create' ||
|
|
506
|
+
.filter((change) => change.kind === 'create' ||
|
|
507
|
+
change.kind === 'move' ||
|
|
508
|
+
change.kind === 'binary' ||
|
|
509
|
+
change.kind === 'arrival')
|
|
371
510
|
.map((change) => (change.kind === 'move' ? change.to : change.path));
|
|
372
511
|
for (const limit of limits) {
|
|
373
512
|
const value = limit.value;
|
|
@@ -381,9 +520,13 @@ function exceeded(limits, changes, resulting) {
|
|
|
381
520
|
return refuse('provider-limit', undefined, limit.name);
|
|
382
521
|
}
|
|
383
522
|
if (limit.name === 'document-size') {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
523
|
+
for (const path of written) {
|
|
524
|
+
const text = resulting.documents[path] ?? '';
|
|
525
|
+
if (new TextEncoder().encode(text).byteLength > value) {
|
|
526
|
+
return refuse('provider-limit', path, limit.name);
|
|
527
|
+
}
|
|
528
|
+
yield ROW_WEIGHT + text.length;
|
|
529
|
+
}
|
|
387
530
|
}
|
|
388
531
|
if (limit.name === 'path-length') {
|
|
389
532
|
const long = created.find((path) => path.length > value);
|
|
@@ -413,7 +556,7 @@ function relativeField(path, name, value, handle, definition) {
|
|
|
413
556
|
!opened.ok ||
|
|
414
557
|
!JSON.stringify(value ?? null).includes(`/rooms/${handle}/`))
|
|
415
558
|
return value;
|
|
416
|
-
const held = apply(opened.document, { kind: 'field', name, value, prior: undefined });
|
|
559
|
+
const held = apply(opened.document, [{ kind: 'field', name, value, prior: undefined }]);
|
|
417
560
|
if (held.outcome !== 'applied')
|
|
418
561
|
return value;
|
|
419
562
|
const result = relativize(held.document, path, handle, definition);
|
|
@@ -449,15 +592,6 @@ function relativeChanges(input) {
|
|
|
449
592
|
return { ...change, fields, sections };
|
|
450
593
|
});
|
|
451
594
|
}
|
|
452
|
-
function unmodeledType(collection, composition) {
|
|
453
|
-
for (const [path, document] of documentsOf(collection)) {
|
|
454
|
-
if (document.type !== undefined &&
|
|
455
|
-
document.type !== 'any' &&
|
|
456
|
-
governing(composition, path).status === 'unavailable')
|
|
457
|
-
return true;
|
|
458
|
-
}
|
|
459
|
-
return false;
|
|
460
|
-
}
|
|
461
595
|
function unqueueable(file) {
|
|
462
596
|
return { kind: 'refused', refusal: { code: 'unknown-revision', retryable: false, file } };
|
|
463
597
|
}
|
|
@@ -467,29 +601,44 @@ function isPart(change) {
|
|
|
467
601
|
function touched(change) {
|
|
468
602
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
469
603
|
}
|
|
470
|
-
function
|
|
604
|
+
function partsApplied(content, path, changes) {
|
|
471
605
|
const parsed = parse(content, path);
|
|
472
606
|
if (!parsed.ok)
|
|
473
607
|
return null;
|
|
474
608
|
const document = parsed.document;
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
609
|
+
const parts = new Map();
|
|
610
|
+
for (const change of changes) {
|
|
611
|
+
if (change.kind === 'field')
|
|
612
|
+
parts.set(`field ${change.name}`, {
|
|
613
|
+
kind: 'field',
|
|
614
|
+
name: change.name,
|
|
615
|
+
value: change.value,
|
|
616
|
+
prior: document.fields[change.name],
|
|
617
|
+
});
|
|
618
|
+
else if (change.kind === 'section')
|
|
619
|
+
parts.set(`section ${change.name}`, {
|
|
484
620
|
kind: 'section',
|
|
485
621
|
name: change.name,
|
|
486
622
|
value: change.value,
|
|
487
|
-
prior: document.sections[change.name],
|
|
488
|
-
}
|
|
489
|
-
|
|
623
|
+
prior: document.sections[change.name] ?? '',
|
|
624
|
+
});
|
|
625
|
+
else
|
|
626
|
+
parts.set('preamble', { kind: 'preamble', value: change.value, prior: document.preamble });
|
|
627
|
+
}
|
|
628
|
+
const applied = apply(document, [...parts.values()]);
|
|
490
629
|
return applied.outcome === 'applied' ? serialize(applied.document) : null;
|
|
491
630
|
}
|
|
492
|
-
function
|
|
631
|
+
function settledParts(changes, deferred) {
|
|
632
|
+
for (const [held, parts] of deferred) {
|
|
633
|
+
const content = partsApplied(held.content, held.path, parts);
|
|
634
|
+
if (content === null)
|
|
635
|
+
return held.path;
|
|
636
|
+
changes[changes.indexOf(held)] = { ...held, content };
|
|
637
|
+
}
|
|
638
|
+
deferred.clear();
|
|
639
|
+
return null;
|
|
640
|
+
}
|
|
641
|
+
function folded(changes, change, appending, deferred) {
|
|
493
642
|
const held = changes.find((item) => item.path === change.path && (item.kind === 'create' || item.kind === 'replace'));
|
|
494
643
|
const whole = held === undefined ? -1 : changes.indexOf(held);
|
|
495
644
|
const occupied = changes.some((item) => !isPart(item) && item !== held && touched(item).includes(change.path));
|
|
@@ -510,10 +659,11 @@ function folded(changes, change, appending) {
|
|
|
510
659
|
return 'appended';
|
|
511
660
|
}
|
|
512
661
|
if ('content' in held) {
|
|
513
|
-
const
|
|
514
|
-
if (
|
|
515
|
-
|
|
516
|
-
|
|
662
|
+
const parts = deferred.get(held);
|
|
663
|
+
if (parts === undefined)
|
|
664
|
+
deferred.set(held, [change]);
|
|
665
|
+
else
|
|
666
|
+
parts.push(change);
|
|
517
667
|
return 'folded';
|
|
518
668
|
}
|
|
519
669
|
if (change.kind === 'preamble')
|
|
@@ -544,17 +694,21 @@ function folded(changes, change, appending) {
|
|
|
544
694
|
changes.push(change);
|
|
545
695
|
return 'appended';
|
|
546
696
|
}
|
|
547
|
-
function relinked(batch, move, before, after, appending) {
|
|
548
|
-
const derived = rewrites([move], after);
|
|
697
|
+
function* relinked(batch, move, before, after, appending) {
|
|
698
|
+
const derived = yield* rewrites([move], after);
|
|
549
699
|
if (derived.kind === 'refused')
|
|
550
700
|
return derived;
|
|
551
701
|
const changes = [...batch.changes];
|
|
552
702
|
const appended = [];
|
|
553
703
|
let changed = false;
|
|
704
|
+
const deferred = new Map();
|
|
554
705
|
for (const change of derived.changes) {
|
|
555
706
|
if (change === move)
|
|
556
707
|
continue;
|
|
557
|
-
const
|
|
708
|
+
const unsettled = isPart(change) ? null : settledParts(changes, deferred);
|
|
709
|
+
if (unsettled !== null)
|
|
710
|
+
return unqueueable(unsettled);
|
|
711
|
+
const outcome = folded(changes, change, appending, deferred);
|
|
558
712
|
if (outcome === 'refused')
|
|
559
713
|
return unqueueable(change.path);
|
|
560
714
|
if (outcome === 'appended')
|
|
@@ -562,9 +716,13 @@ function relinked(batch, move, before, after, appending) {
|
|
|
562
716
|
if (outcome !== 'skipped')
|
|
563
717
|
changed = true;
|
|
564
718
|
}
|
|
719
|
+
const unsettled = settledParts(changes, deferred);
|
|
720
|
+
if (unsettled !== null)
|
|
721
|
+
return unqueueable(unsettled);
|
|
565
722
|
if (!changed)
|
|
566
723
|
return { kind: 'relinked', batch };
|
|
567
724
|
const held = new Set(batch.preconditions.map(identity));
|
|
725
|
+
const added = yield* preconditionsOf(appended, before, []);
|
|
568
726
|
return {
|
|
569
727
|
kind: 'relinked',
|
|
570
728
|
batch: immutable({
|
|
@@ -573,7 +731,7 @@ function relinked(batch, move, before, after, appending) {
|
|
|
573
731
|
changes,
|
|
574
732
|
preconditions: [
|
|
575
733
|
...batch.preconditions,
|
|
576
|
-
...
|
|
734
|
+
...added.filter((precondition) => !held.has(identity(precondition))),
|
|
577
735
|
],
|
|
578
736
|
}),
|
|
579
737
|
};
|
|
@@ -619,7 +777,7 @@ function withdrawnFile(batch, change, at) {
|
|
|
619
777
|
];
|
|
620
778
|
return immutable({ ...batch, id: changeBatchIdentity(), changes, preconditions });
|
|
621
779
|
}
|
|
622
|
-
export function
|
|
780
|
+
export function* requeuing(queue, changes, visible, changeable, state) {
|
|
623
781
|
const next = [...queue];
|
|
624
782
|
const origins = new Map();
|
|
625
783
|
const withdrawn = new Map();
|
|
@@ -642,19 +800,19 @@ export function requeued(queue, changes, visible, changeable, state) {
|
|
|
642
800
|
return unqueueable(change.path);
|
|
643
801
|
const following = next.slice(index);
|
|
644
802
|
const rebuilt = [];
|
|
645
|
-
let before = change.kind === 'move' ? state(next.slice(0, index)) : visible;
|
|
803
|
+
let before = change.kind === 'move' ? yield* state(next.slice(0, index)) : visible;
|
|
646
804
|
for (const [offset, batch] of following.entries()) {
|
|
647
805
|
let current = batch;
|
|
648
806
|
if (change.kind === 'move') {
|
|
649
|
-
const after = state(next.slice(0, index + offset + 1));
|
|
807
|
+
const after = yield* state(next.slice(0, index + offset + 1));
|
|
650
808
|
const appending = offset === 0 && created(batch, queuedFile(batch, change.path, held.localId));
|
|
651
|
-
const relinking = relinked(batch, change, before, after, appending);
|
|
809
|
+
const relinking = yield* relinked(batch, change, before, after, appending);
|
|
652
810
|
if (relinking.kind === 'refused')
|
|
653
811
|
return relinking;
|
|
654
812
|
current = relinking.batch;
|
|
655
813
|
before = after;
|
|
656
814
|
}
|
|
657
|
-
if (current !== batch && !open(batch))
|
|
815
|
+
if (current !== batch && (!open(batch) || batch.between !== undefined))
|
|
658
816
|
return unqueueable(change.path);
|
|
659
817
|
rebuilt.push(offset === 0
|
|
660
818
|
? withdrawnFile(current, change, queuedFile(current, change.path, held.localId))
|
|
@@ -695,10 +853,17 @@ export function joined(queue, owner, extra) {
|
|
|
695
853
|
if (clash !== undefined)
|
|
696
854
|
return unqueueable(clash);
|
|
697
855
|
const changes = [...owner.changes];
|
|
856
|
+
const deferred = new Map();
|
|
698
857
|
for (const change of extra.changes) {
|
|
699
|
-
|
|
858
|
+
const unsettled = isPart(change) ? null : settledParts(changes, deferred);
|
|
859
|
+
if (unsettled !== null)
|
|
860
|
+
return unqueueable(unsettled);
|
|
861
|
+
if (folded(changes, change, true, deferred) === 'refused')
|
|
700
862
|
return unqueueable(change.path);
|
|
701
863
|
}
|
|
864
|
+
const unsettled = settledParts(changes, deferred);
|
|
865
|
+
if (unsettled !== null)
|
|
866
|
+
return unqueueable(unsettled);
|
|
702
867
|
const held = new Set(owner.preconditions.map(covering));
|
|
703
868
|
const written = new Set(owner.changes.flatMap((change) => change.kind === 'create' || change.kind === 'replace' ? [change.path] : []));
|
|
704
869
|
const preconditions = [
|
|
@@ -717,49 +882,66 @@ export function joined(queue, owner, extra) {
|
|
|
717
882
|
});
|
|
718
883
|
return { kind: 'joined', batch, queue: queue.map((item) => (item === owner ? batch : item)) };
|
|
719
884
|
}
|
|
720
|
-
export function
|
|
721
|
-
const
|
|
885
|
+
export function* limiting(queue, batch, limits, state) {
|
|
886
|
+
const at = queue.indexOf(batch);
|
|
887
|
+
const rewritten = yield* providerRewritten(batch, yield* state(queue.slice(0, at)));
|
|
888
|
+
const limited = yield* exceeding(limits, batch.changes, rewritten.changes, yield* state(queue.slice(0, at + 1)));
|
|
722
889
|
return limited?.kind === 'refused' ? limited.refusal : null;
|
|
723
890
|
}
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
const
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
const
|
|
739
|
-
const
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
891
|
+
function typedText(content) {
|
|
892
|
+
if (content === undefined)
|
|
893
|
+
return false;
|
|
894
|
+
const parsed = parse(content);
|
|
895
|
+
return parsed.ok && parsed.document.type !== undefined && parsed.document.type !== 'any';
|
|
896
|
+
}
|
|
897
|
+
function touchedLibrary(resulting, touched, composition) {
|
|
898
|
+
const entries = touched
|
|
899
|
+
.flatMap((path) => {
|
|
900
|
+
const content = resulting.documents[path];
|
|
901
|
+
const binary = resulting.binaries[path] !== undefined;
|
|
902
|
+
return content === undefined && !binary ? [] : [{ path, content: content ?? null }];
|
|
903
|
+
})
|
|
904
|
+
.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));
|
|
905
|
+
const contents = new Map(entries.map(({ path, content }) => [path, content]));
|
|
906
|
+
const binaries = new Set(Array.from(entriesIn(resulting.binaries), ([path]) => path));
|
|
907
|
+
return validatedCollection(() => Promise.resolve({ entries, next: null }), async (paths) => {
|
|
908
|
+
const known = new Map();
|
|
909
|
+
const pace = paced();
|
|
910
|
+
for (const path of paths) {
|
|
911
|
+
const content = contents.get(path);
|
|
912
|
+
if (binaries.has(path))
|
|
913
|
+
known.set(path, { type: undefined, binary: true });
|
|
914
|
+
else if (content !== undefined && content !== null) {
|
|
915
|
+
const read = parse(content, path);
|
|
916
|
+
if (read.ok)
|
|
917
|
+
known.set(path, { type: read.document.type ?? 'any', binary: false });
|
|
918
|
+
await pace(content.length + ROW_WEIGHT);
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return known;
|
|
922
|
+
}, composition);
|
|
923
|
+
}
|
|
924
|
+
async function judging(visible, resulting, composition, validate, removed, touched) {
|
|
743
925
|
if (removed.size > 0) {
|
|
744
|
-
const referenced = incoming(collectionOf(resulting.documents,
|
|
926
|
+
const referenced = await stepped(incoming(collectionOf(resulting.documents, composition), removed, null));
|
|
745
927
|
if (referenced !== null)
|
|
746
928
|
return referenced;
|
|
747
929
|
}
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
930
|
+
const typedPaths = [];
|
|
931
|
+
const pace = paced();
|
|
932
|
+
for (const path of touched) {
|
|
933
|
+
const before = visible.documents[path];
|
|
934
|
+
const after = resulting.documents[path];
|
|
935
|
+
if (typedText(before) || typedText(after))
|
|
936
|
+
typedPaths.push(path);
|
|
937
|
+
await pace((before?.length ?? 0) + (after?.length ?? 0) + ROW_WEIGHT);
|
|
938
|
+
}
|
|
939
|
+
const withoutModel = typedPaths.find((path) => governing(composition, path).status === 'unavailable');
|
|
757
940
|
if (withoutModel !== undefined)
|
|
758
941
|
return refuse('model-unavailable', withoutModel);
|
|
759
|
-
const
|
|
760
|
-
? resulting
|
|
761
|
-
:
|
|
762
|
-
const verdict = validateCollection(validationText, Object.keys(resulting.binaries), input.composition);
|
|
942
|
+
const verdict = typedPaths.length > 0
|
|
943
|
+
? await validate(resulting, touched)
|
|
944
|
+
: await touchedLibrary(resulting, touched, composition);
|
|
763
945
|
if (verdict.verdict === 'refuse') {
|
|
764
946
|
return {
|
|
765
947
|
kind: 'refused',
|
|
@@ -772,12 +954,92 @@ export function buildBatch(input) {
|
|
|
772
954
|
},
|
|
773
955
|
};
|
|
774
956
|
}
|
|
775
|
-
|
|
957
|
+
return {
|
|
958
|
+
kind: 'judged',
|
|
959
|
+
validated: typedPaths
|
|
960
|
+
.map((path) => governing(composition, path))
|
|
961
|
+
.find((model) => model.status !== 'unavailable'),
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function placed(reference) {
|
|
965
|
+
const key = roomPathOf(reference.handle, reference.path);
|
|
966
|
+
if (reference.kind === 'link')
|
|
967
|
+
return `link ${key}`;
|
|
968
|
+
if (reference.kind === 'item')
|
|
969
|
+
return `section ${reference.section} ${key}`;
|
|
970
|
+
const pointer = reference.pointer
|
|
971
|
+
.split('/')
|
|
972
|
+
.map((segment) => (ARRAY_INDEX.test(segment) ? '-' : segment))
|
|
973
|
+
.join('/');
|
|
974
|
+
return `field ${pointer} ${key}`;
|
|
975
|
+
}
|
|
976
|
+
function roomReferencesIn(path, content, composition) {
|
|
977
|
+
if (content === undefined)
|
|
978
|
+
return [];
|
|
979
|
+
const parsed = parse(content, path);
|
|
980
|
+
if (!parsed.ok)
|
|
981
|
+
return [];
|
|
982
|
+
return roomReferences(parsed.document, definitionOf(governing(composition, path), parsed.document.type));
|
|
983
|
+
}
|
|
984
|
+
function* admittedRooms(changes, visible, resulting, composition) {
|
|
985
|
+
const from = new Map();
|
|
986
|
+
for (const [index, change] of changes.entries()) {
|
|
987
|
+
if (change.kind === 'move')
|
|
988
|
+
from.set(change.to, departure(changes, index));
|
|
989
|
+
}
|
|
990
|
+
for (const path of [...new Set(changes.flatMap(affected))].sort()) {
|
|
991
|
+
const now = resulting.documents[path];
|
|
992
|
+
if (now === undefined)
|
|
993
|
+
continue;
|
|
994
|
+
const held = new Set(roomReferencesIn(path, visible.documents[from.get(path) ?? path], composition).map(placed));
|
|
995
|
+
for (const reference of roomReferencesIn(path, now, composition)) {
|
|
996
|
+
if (reference.kind === 'link' || reference.crossRoom === true)
|
|
997
|
+
continue;
|
|
998
|
+
if (held.has(placed(reference)))
|
|
999
|
+
continue;
|
|
1000
|
+
return refuse('unresolved-reference', path, reference.kind === 'field' ? reference.pointer : reference.section);
|
|
1001
|
+
}
|
|
1002
|
+
yield ROW_WEIGHT + now.length;
|
|
1003
|
+
}
|
|
1004
|
+
return null;
|
|
1005
|
+
}
|
|
1006
|
+
function validationOf(validated) {
|
|
1007
|
+
return validated === undefined
|
|
1008
|
+
? {}
|
|
1009
|
+
: {
|
|
1010
|
+
validation: {
|
|
1011
|
+
identity: validated.snapshot.identity,
|
|
1012
|
+
version: validated.snapshot.version,
|
|
1013
|
+
source: validated.status,
|
|
1014
|
+
},
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
async function batching(input) {
|
|
1018
|
+
const changes = relativeChanges(input);
|
|
1019
|
+
const structural = changes.find((change) => change.kind === 'move' || change.kind === 'remove');
|
|
1020
|
+
if (structural !== undefined && input.unmodeled) {
|
|
1021
|
+
return refuse('model-unavailable', structural.path);
|
|
1022
|
+
}
|
|
1023
|
+
if (changes.length === 0)
|
|
1024
|
+
return refuse('no-change');
|
|
1025
|
+
const rewritten = await stepped(rewrites(changes, input.visible));
|
|
1026
|
+
if (rewritten.kind === 'refused')
|
|
1027
|
+
return rewritten;
|
|
1028
|
+
const refusal = guard(changes, input, WRITE);
|
|
1029
|
+
if (refusal !== null)
|
|
1030
|
+
return refusal;
|
|
1031
|
+
const preconditions = await stepped(preconditionsOf(changes, input.visible, input.bases));
|
|
1032
|
+
const predicted = await stepped(anticipated(changes, preconditions, rewritten.changes, input.visible));
|
|
1033
|
+
const resulting = await stepped(overlaying(input.visible, [{ id: '', baseRoomVersion: input.baseRoomVersion, ...predicted }]));
|
|
1034
|
+
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))]);
|
|
1035
|
+
if (judged.kind === 'refused')
|
|
1036
|
+
return judged;
|
|
1037
|
+
const crossing = await stepped(admittedRooms(changes, input.visible, resulting, input.composition));
|
|
1038
|
+
if (crossing !== null)
|
|
1039
|
+
return crossing;
|
|
1040
|
+
const limited = await stepped(exceeding(input.providerLimits, changes, predicted.changes, resulting));
|
|
776
1041
|
if (limited !== null)
|
|
777
1042
|
return limited;
|
|
778
|
-
const validated = typedPaths
|
|
779
|
-
.map((path) => governing(input.composition, path))
|
|
780
|
-
.find((model) => model.status !== 'unavailable');
|
|
781
1043
|
return {
|
|
782
1044
|
kind: 'batch',
|
|
783
1045
|
batch: immutable({
|
|
@@ -786,15 +1048,127 @@ export function buildBatch(input) {
|
|
|
786
1048
|
changes,
|
|
787
1049
|
preconditions,
|
|
788
1050
|
...(input.writtenBy === undefined ? {} : { writtenBy: input.writtenBy }),
|
|
789
|
-
...(validated
|
|
790
|
-
? {}
|
|
791
|
-
: {
|
|
792
|
-
validation: {
|
|
793
|
-
identity: validated.snapshot.identity,
|
|
794
|
-
version: validated.snapshot.version,
|
|
795
|
-
source: validated.status,
|
|
796
|
-
},
|
|
797
|
-
}),
|
|
1051
|
+
...validationOf(judged.validated),
|
|
798
1052
|
}),
|
|
799
1053
|
};
|
|
800
1054
|
}
|
|
1055
|
+
export const MOVE_DOCUMENTS = 'move-documents';
|
|
1056
|
+
function heldAt(visible, path) {
|
|
1057
|
+
return visible.documents[path] !== undefined || visible.binaries[path] !== undefined;
|
|
1058
|
+
}
|
|
1059
|
+
function arrivingText(path, to, source, moved) {
|
|
1060
|
+
const content = source.visible.documents[path];
|
|
1061
|
+
const document = source.visible.collection.document(path);
|
|
1062
|
+
if (document === undefined)
|
|
1063
|
+
return content;
|
|
1064
|
+
const definition = definitionOf(governing(source.composition, path), document.type);
|
|
1065
|
+
const changes = crossed(document, definition, path, (named, href) => {
|
|
1066
|
+
const at = moved.get(named);
|
|
1067
|
+
if (at !== undefined)
|
|
1068
|
+
return target(to, href) === at ? undefined : relative(to, at);
|
|
1069
|
+
return heldAt(source.visible, named) ? roomPathOf(source.handle, named) : undefined;
|
|
1070
|
+
});
|
|
1071
|
+
if (changes.length === 0)
|
|
1072
|
+
return content;
|
|
1073
|
+
const applied = apply(document, changes);
|
|
1074
|
+
return applied.outcome === 'applied' ? serialize(applied.document) : content;
|
|
1075
|
+
}
|
|
1076
|
+
function arrivalOf({ path, to }, source, moved) {
|
|
1077
|
+
const { documents, revisions, fileIds, created, changes, binaries } = source.visible;
|
|
1078
|
+
const kept = {
|
|
1079
|
+
...(fileIds[path] === undefined ? {} : { fileId: fileIds[path] }),
|
|
1080
|
+
...(created[path] === undefined ? {} : { created: created[path] }),
|
|
1081
|
+
...(changes[path] === undefined ? {} : { change: changes[path] }),
|
|
1082
|
+
};
|
|
1083
|
+
const heads = {
|
|
1084
|
+
...(revisions[path] === undefined ? {} : { revision: revisions[path] }),
|
|
1085
|
+
...kept,
|
|
1086
|
+
};
|
|
1087
|
+
const binary = binaries[path];
|
|
1088
|
+
if (binary?.state === 'accepted') {
|
|
1089
|
+
const { byteLength, mediaType, sha256 } = binary;
|
|
1090
|
+
return {
|
|
1091
|
+
kind: 'arrival',
|
|
1092
|
+
path: to,
|
|
1093
|
+
binary: { byteLength, mediaType, sha256 },
|
|
1094
|
+
...heads,
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
const content = arrivingText(path, to, source, moved);
|
|
1098
|
+
return {
|
|
1099
|
+
kind: 'arrival',
|
|
1100
|
+
path: to,
|
|
1101
|
+
content,
|
|
1102
|
+
...(content === documents[path] ? heads : kept),
|
|
1103
|
+
};
|
|
1104
|
+
}
|
|
1105
|
+
async function moving(input) {
|
|
1106
|
+
const { source, destination, moves, pathRule } = input;
|
|
1107
|
+
if (moves.length === 0)
|
|
1108
|
+
return refuse('no-change');
|
|
1109
|
+
const removals = moves.map(({ path }) => ({ kind: 'remove', path }));
|
|
1110
|
+
const leaves = guard(removals, { ...source, local: input.local, bases: [], pathRule }, MOVE_OUT);
|
|
1111
|
+
if (leaves !== null)
|
|
1112
|
+
return leaves;
|
|
1113
|
+
const uploading = moves.find(({ path }) => source.visible.binaries[path]?.state === 'pending');
|
|
1114
|
+
if (uploading !== undefined)
|
|
1115
|
+
return refuse('unknown-revision', uploading.path);
|
|
1116
|
+
const moved = new Map(moves.map(({ path, to }) => [path, to]));
|
|
1117
|
+
const arrivals = moves.map((move) => arrivalOf(move, source, moved));
|
|
1118
|
+
const arrives = guard(arrivals, { ...destination, local: input.local, bases: [], pathRule }, WRITE);
|
|
1119
|
+
if (arrives !== null)
|
|
1120
|
+
return arrives;
|
|
1121
|
+
const bound = input.providerLimits.find((limit) => limit.name === MOVE_DOCUMENTS)?.value;
|
|
1122
|
+
if (typeof bound === 'number' && moves.length > bound) {
|
|
1123
|
+
return refuse('provider-limit', undefined, MOVE_DOCUMENTS);
|
|
1124
|
+
}
|
|
1125
|
+
if (source.unmodeled)
|
|
1126
|
+
return refuse('model-unavailable', moves[0].path);
|
|
1127
|
+
const id = changeBatchIdentity();
|
|
1128
|
+
const between = {
|
|
1129
|
+
source: { room: source.room, baseRoomVersion: source.baseRoomVersion },
|
|
1130
|
+
destination: {
|
|
1131
|
+
room: destination.room,
|
|
1132
|
+
baseRoomVersion: destination.baseRoomVersion,
|
|
1133
|
+
handle: destination.handle,
|
|
1134
|
+
},
|
|
1135
|
+
moves,
|
|
1136
|
+
};
|
|
1137
|
+
const written = input.writtenBy === undefined ? {} : { writtenBy: input.writtenBy };
|
|
1138
|
+
const leavingBatch = {
|
|
1139
|
+
id,
|
|
1140
|
+
baseRoomVersion: source.baseRoomVersion,
|
|
1141
|
+
changes: removals,
|
|
1142
|
+
preconditions: moves.map(({ path }) => existence(source.visible, path)),
|
|
1143
|
+
...written,
|
|
1144
|
+
between,
|
|
1145
|
+
};
|
|
1146
|
+
const effective = await stepped(leavingRewritten(leavingBatch, source.visible));
|
|
1147
|
+
const left = await stepped(overlaying(source.visible, [effective]));
|
|
1148
|
+
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))]);
|
|
1149
|
+
if (sourceJudged.kind === 'refused')
|
|
1150
|
+
return sourceJudged;
|
|
1151
|
+
const arrivingBatch = {
|
|
1152
|
+
id,
|
|
1153
|
+
baseRoomVersion: destination.baseRoomVersion,
|
|
1154
|
+
changes: arrivals,
|
|
1155
|
+
preconditions: moves.map(({ to }) => ({ kind: 'absent', path: to })),
|
|
1156
|
+
...written,
|
|
1157
|
+
between,
|
|
1158
|
+
};
|
|
1159
|
+
const arrived = await stepped(overlaying(destination.visible, [arrivingBatch]));
|
|
1160
|
+
const destinationJudged = await judging(destination.visible, arrived, destination.composition, destination.validate, new Set(), moves.map(({ to }) => to));
|
|
1161
|
+
if (destinationJudged.kind === 'refused')
|
|
1162
|
+
return destinationJudged;
|
|
1163
|
+
const limited = (await stepped(exceeding(input.providerLimits, removals, effective.changes, left))) ??
|
|
1164
|
+
(await stepped(exceeding(input.providerLimits, arrivals, arrivals, arrived)));
|
|
1165
|
+
if (limited !== null)
|
|
1166
|
+
return limited;
|
|
1167
|
+
return { kind: 'moved', leaving: immutable(leavingBatch), arriving: immutable(arrivingBatch) };
|
|
1168
|
+
}
|
|
1169
|
+
export function buildMove(input) {
|
|
1170
|
+
return moving(input);
|
|
1171
|
+
}
|
|
1172
|
+
export function buildBatch(input) {
|
|
1173
|
+
return batching(input);
|
|
1174
|
+
}
|