@agentshouse/mdruntime 0.1.0-c95464765b116 → 0.1.0-c95f0f04f2113
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 +248 -0
- package/dist/adapter.d.ts +153 -84
- 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/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 +319 -107
- 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 -16
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +11 -88
- 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 +3 -0
- package/dist/chat-types.d.ts.map +1 -0
- package/dist/chat-types.js +2 -0
- package/dist/client.d.ts +32 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +98 -11
- package/dist/collection.d.ts +11 -21
- package/dist/collection.d.ts.map +1 -1
- package/dist/collection.js +39 -291
- 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 +7 -129
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +97 -3344
- 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-row.d.ts +33 -0
- package/dist/conversation-row.d.ts.map +1 -0
- package/dist/conversation-row.js +47 -0
- package/dist/conversation.d.ts +43 -18
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +762 -299
- 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 +7 -4
- package/dist/durability.d.ts.map +1 -1
- package/dist/durability.js +5 -0
- package/dist/entry.d.ts +5 -2
- package/dist/entry.d.ts.map +1 -1
- package/dist/entry.js +33 -28
- package/dist/figures.d.ts +48 -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/host.d.ts +7 -8
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +101 -24
- package/dist/identity.d.ts +0 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +0 -6
- package/dist/index.d.ts +31 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/install.d.ts +56 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +560 -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 +267 -0
- package/dist/listing.d.ts +53 -0
- package/dist/listing.d.ts.map +1 -0
- package/dist/listing.js +175 -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 -7
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +248 -103
- 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 -12
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +7 -19
- package/dist/models.d.ts +14 -0
- package/dist/models.d.ts.map +1 -0
- package/dist/models.js +193 -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 +17 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +100 -5
- 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 +56 -0
- package/dist/outcome.d.ts +46 -7
- package/dist/outcome.d.ts.map +1 -1
- package/dist/outcome.js +42 -0
- package/dist/overlay.d.ts +4 -5
- package/dist/overlay.d.ts.map +1 -1
- package/dist/overlay.js +106 -156
- 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 +1 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +4 -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 +27 -185
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +3 -464
- package/dist/{chat/questions.d.ts → questions.d.ts} +3 -2
- package/dist/questions.d.ts.map +1 -0
- package/dist/{chat/questions.js → questions.js} +8 -1
- package/dist/reach.d.ts +19 -9
- package/dist/reach.d.ts.map +1 -1
- package/dist/reach.js +287 -99
- package/dist/react.d.ts +8 -4
- 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 +14 -17
- package/dist/readiness.d.ts.map +1 -1
- package/dist/readiness.js +2 -8
- package/dist/reads.d.ts +36 -0
- package/dist/reads.d.ts.map +1 -0
- package/dist/reads.js +136 -0
- package/dist/recovery.d.ts +3 -2
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +43 -8
- package/dist/refresh.d.ts +17 -14
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +143 -52
- 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 +55 -33
- package/dist/replica.d.ts.map +1 -1
- package/dist/replica.js +331 -181
- 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 +31 -29
- package/dist/rows.d.ts.map +1 -1
- package/dist/rows.js +59 -116
- package/dist/runtime.d.ts +42 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +1 -0
- package/dist/save.d.ts +53 -14
- package/dist/save.d.ts.map +1 -1
- package/dist/save.js +534 -187
- package/dist/saves.d.ts +70 -0
- package/dist/saves.d.ts.map +1 -0
- package/dist/saves.js +1004 -0
- package/dist/search.d.ts +15 -77
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +10 -184
- 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 +7 -3
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js +119 -66
- package/dist/shown.d.ts +31 -0
- package/dist/shown.d.ts.map +1 -0
- package/dist/shown.js +294 -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 +43 -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 +4 -5
- 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 +408 -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 -149
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +136 -712
- package/dist/stored.d.ts +156 -0
- package/dist/stored.d.ts.map +1 -0
- package/dist/stored.js +637 -0
- package/dist/surface.d.ts +86 -0
- package/dist/surface.d.ts.map +1 -0
- package/dist/surface.js +217 -0
- package/dist/sync.d.ts +20 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +531 -0
- package/dist/tables.d.ts +407 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/tables.js +724 -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 +5 -3
- package/dist/turn.d.ts.map +1 -1
- package/dist/turn.js +51 -21
- 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 +49 -6
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js +15 -2
- package/package.json +18 -19
- package/AGENTS.md +0 -300
- package/dist/acquisition.d.ts +0 -14
- package/dist/acquisition.d.ts.map +0 -1
- package/dist/acquisition.js +0 -24
- package/dist/chat/acts.d.ts +0 -33
- package/dist/chat/acts.d.ts.map +0 -1
- package/dist/chat/acts.js +0 -36
- package/dist/chat/context.d.ts +0 -3
- package/dist/chat/context.d.ts.map +0 -1
- package/dist/chat/input.d.ts +0 -9
- package/dist/chat/input.d.ts.map +0 -1
- package/dist/chat/input.js +0 -99
- package/dist/chat/kit.d.ts +0 -61
- package/dist/chat/kit.d.ts.map +0 -1
- package/dist/chat/kit.js +0 -123
- package/dist/chat/lasting.d.ts +0 -6
- package/dist/chat/lasting.d.ts.map +0 -1
- package/dist/chat/lasting.js +0 -19
- package/dist/chat/list.d.ts +0 -27
- package/dist/chat/list.d.ts.map +0 -1
- package/dist/chat/list.js +0 -63
- package/dist/chat/markdown.d.ts +0 -20
- package/dist/chat/markdown.d.ts.map +0 -1
- package/dist/chat/markdown.js +0 -188
- 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 -22
- package/dist/chat/messages.d.ts.map +0 -1
- package/dist/chat/messages.js +0 -155
- 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 -620
- 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 -34
- 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/fence.d.ts +0 -6
- package/dist/fence.d.ts.map +0 -1
- package/dist/fence.js +0 -10
- package/dist/read-side.d.ts +0 -25
- package/dist/read-side.d.ts.map +0 -1
- package/dist/read-side.js +0 -639
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 {
|
|
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, covered, normalize } from './paths.js';
|
|
8
|
+
import { 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,13 +277,20 @@ function incoming(collection, removed, candidates) {
|
|
|
186
277
|
referrers.add(file);
|
|
187
278
|
found.set(target, referrers);
|
|
188
279
|
};
|
|
189
|
-
const read =
|
|
190
|
-
|
|
191
|
-
|
|
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);
|
|
192
286
|
const document = collection.document(path);
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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)) {
|
|
196
294
|
const definition = definitionOf(governing(collection.composition, path), document.type);
|
|
197
295
|
for (const { value, to } of definition === undefined ? [] : references(document, definition)) {
|
|
198
296
|
if (to.includes(ATTACHMENT))
|
|
@@ -201,8 +299,9 @@ function incoming(collection, removed, candidates) {
|
|
|
201
299
|
if (named !== null)
|
|
202
300
|
note(named, path);
|
|
203
301
|
}
|
|
302
|
+
yield ROW_WEIGHT + collection.text[path].length;
|
|
204
303
|
}
|
|
205
|
-
const [first] =
|
|
304
|
+
const [first] = yield* sorting(found.keys());
|
|
206
305
|
if (first === undefined)
|
|
207
306
|
return null;
|
|
208
307
|
const every = new Set();
|
|
@@ -215,14 +314,16 @@ function incoming(collection, removed, candidates) {
|
|
|
215
314
|
code: 'referenced-missing-file',
|
|
216
315
|
retryable: false,
|
|
217
316
|
file: first,
|
|
218
|
-
referrers:
|
|
317
|
+
referrers: yield* sorting(every),
|
|
219
318
|
},
|
|
220
319
|
};
|
|
221
320
|
}
|
|
222
321
|
function affected(change) {
|
|
223
322
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
224
323
|
}
|
|
225
|
-
|
|
324
|
+
const WRITE = ['write'];
|
|
325
|
+
const MOVE_OUT = ['write', 'erase'];
|
|
326
|
+
function guard(changes, input, removing) {
|
|
226
327
|
const overridden = new Map();
|
|
227
328
|
const existing = {
|
|
228
329
|
has: (path) => overridden.get(path) ??
|
|
@@ -230,6 +331,7 @@ function guard(changes, input) {
|
|
|
230
331
|
add: (path) => void overridden.set(path, true),
|
|
231
332
|
delete: (path) => void overridden.set(path, false),
|
|
232
333
|
};
|
|
334
|
+
const occupied = (path) => input.folders.has(path) ? path : (ancestors(path).find((one) => existing.has(one)) ?? null);
|
|
233
335
|
for (const [index, change] of changes.entries()) {
|
|
234
336
|
for (const path of affected(change)) {
|
|
235
337
|
const normalized = normalize(path);
|
|
@@ -238,13 +340,14 @@ function guard(changes, input) {
|
|
|
238
340
|
if (covered(input.providerOwnedPaths, normalized)) {
|
|
239
341
|
return refuse('provider-owned-path', normalized);
|
|
240
342
|
}
|
|
241
|
-
const operation
|
|
242
|
-
|
|
243
|
-
|
|
343
|
+
for (const operation of change.kind === 'remove' ? removing : WRITE)
|
|
344
|
+
if (!input.local && !covered(input.operations[operation], normalized))
|
|
345
|
+
return refuse(`${operation}-grant`, normalized);
|
|
244
346
|
}
|
|
245
|
-
if (change.kind === 'create') {
|
|
246
|
-
|
|
247
|
-
|
|
347
|
+
if (change.kind === 'create' || change.kind === 'arrival') {
|
|
348
|
+
const taken = existing.has(change.path) ? change.path : occupied(change.path);
|
|
349
|
+
if (taken !== null)
|
|
350
|
+
return refuse('path-collision', taken);
|
|
248
351
|
existing.add(change.path);
|
|
249
352
|
continue;
|
|
250
353
|
}
|
|
@@ -254,6 +357,9 @@ function guard(changes, input) {
|
|
|
254
357
|
input.bases.some((base) => base.kind === 'absent' && base.path === change.path))) {
|
|
255
358
|
return refuse('path-collision', change.path);
|
|
256
359
|
}
|
|
360
|
+
const taken = occupied(change.path);
|
|
361
|
+
if (taken !== null)
|
|
362
|
+
return refuse('path-collision', taken);
|
|
257
363
|
if (!input.local &&
|
|
258
364
|
existing.has(change.path) &&
|
|
259
365
|
input.visible.revisions[departure(changes, index)] === undefined) {
|
|
@@ -265,8 +371,9 @@ function guard(changes, input) {
|
|
|
265
371
|
if (change.kind === 'move') {
|
|
266
372
|
if (!existing.has(change.path))
|
|
267
373
|
return refuse('path-absent', change.path);
|
|
268
|
-
|
|
269
|
-
|
|
374
|
+
const taken = existing.has(change.to) ? change.to : occupied(change.to);
|
|
375
|
+
if (taken !== null)
|
|
376
|
+
return refuse('path-collision', taken);
|
|
270
377
|
if (unrevised(input, change.path)) {
|
|
271
378
|
return refuse('unknown-revision', change.path);
|
|
272
379
|
}
|
|
@@ -284,7 +391,7 @@ function guard(changes, input) {
|
|
|
284
391
|
continue;
|
|
285
392
|
}
|
|
286
393
|
if (change.kind === 'replace') {
|
|
287
|
-
if (
|
|
394
|
+
if (unrevised(input, change.path)) {
|
|
288
395
|
return refuse('unknown-revision', change.path);
|
|
289
396
|
}
|
|
290
397
|
continue;
|
|
@@ -298,6 +405,22 @@ function guard(changes, input) {
|
|
|
298
405
|
function unrevised(input, path) {
|
|
299
406
|
return (!input.local && input.queued?.has(path) !== true && input.visible.revisions[path] === undefined);
|
|
300
407
|
}
|
|
408
|
+
export function queuedDocuments(queue) {
|
|
409
|
+
const paths = new Set();
|
|
410
|
+
for (const batch of queue) {
|
|
411
|
+
for (const change of batch.changes) {
|
|
412
|
+
if (change.kind === 'binary' || (change.kind === 'arrival' && !('content' in change)))
|
|
413
|
+
continue;
|
|
414
|
+
if (change.kind === 'remove')
|
|
415
|
+
paths.delete(change.path);
|
|
416
|
+
else if (change.kind !== 'move')
|
|
417
|
+
paths.add(change.path);
|
|
418
|
+
else if (paths.delete(change.path))
|
|
419
|
+
paths.add(change.to);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return paths;
|
|
423
|
+
}
|
|
301
424
|
function identity(precondition) {
|
|
302
425
|
const part = precondition.kind === 'field' || precondition.kind === 'section' ? precondition.name : '';
|
|
303
426
|
return `${precondition.kind} ${precondition.path} ${part}`;
|
|
@@ -315,7 +438,7 @@ function sameTarget(precondition, change) {
|
|
|
315
438
|
return ((precondition.kind !== 'field' && precondition.kind !== 'section') ||
|
|
316
439
|
((change.kind === 'field' || change.kind === 'section') && precondition.name === change.name));
|
|
317
440
|
}
|
|
318
|
-
function preconditionsOf(changes, visible, bases) {
|
|
441
|
+
function* preconditionsOf(changes, visible, bases) {
|
|
319
442
|
const preconditions = [];
|
|
320
443
|
const seen = new Set();
|
|
321
444
|
const add = (precondition) => {
|
|
@@ -326,6 +449,7 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
326
449
|
preconditions.push(precondition);
|
|
327
450
|
};
|
|
328
451
|
for (const change of changes) {
|
|
452
|
+
yield ROW_WEIGHT;
|
|
329
453
|
if (change.kind === 'field' || change.kind === 'section' || change.kind === 'preamble') {
|
|
330
454
|
const based = bases.find((base) => sameTarget(base, change));
|
|
331
455
|
if (based !== undefined) {
|
|
@@ -373,10 +497,13 @@ function preconditionsOf(changes, visible, bases) {
|
|
|
373
497
|
function depth(path) {
|
|
374
498
|
return path.split('/').length;
|
|
375
499
|
}
|
|
376
|
-
function
|
|
500
|
+
function* exceeding(limits, changes, effective, resulting) {
|
|
377
501
|
const written = effective.map((change) => (change.kind === 'move' ? change.to : change.path));
|
|
378
502
|
const created = changes
|
|
379
|
-
.filter((change) => change.kind === 'create' ||
|
|
503
|
+
.filter((change) => change.kind === 'create' ||
|
|
504
|
+
change.kind === 'move' ||
|
|
505
|
+
change.kind === 'binary' ||
|
|
506
|
+
change.kind === 'arrival')
|
|
380
507
|
.map((change) => (change.kind === 'move' ? change.to : change.path));
|
|
381
508
|
for (const limit of limits) {
|
|
382
509
|
const value = limit.value;
|
|
@@ -390,9 +517,13 @@ function exceeded(limits, changes, effective, resulting) {
|
|
|
390
517
|
return refuse('provider-limit', undefined, limit.name);
|
|
391
518
|
}
|
|
392
519
|
if (limit.name === 'document-size') {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
520
|
+
for (const path of written) {
|
|
521
|
+
const text = resulting.documents[path] ?? '';
|
|
522
|
+
if (new TextEncoder().encode(text).byteLength > value) {
|
|
523
|
+
return refuse('provider-limit', path, limit.name);
|
|
524
|
+
}
|
|
525
|
+
yield ROW_WEIGHT + text.length;
|
|
526
|
+
}
|
|
396
527
|
}
|
|
397
528
|
if (limit.name === 'path-length') {
|
|
398
529
|
const long = created.find((path) => path.length > value);
|
|
@@ -422,7 +553,7 @@ function relativeField(path, name, value, handle, definition) {
|
|
|
422
553
|
!opened.ok ||
|
|
423
554
|
!JSON.stringify(value ?? null).includes(`/rooms/${handle}/`))
|
|
424
555
|
return value;
|
|
425
|
-
const held = apply(opened.document, { kind: 'field', name, value, prior: undefined });
|
|
556
|
+
const held = apply(opened.document, [{ kind: 'field', name, value, prior: undefined }]);
|
|
426
557
|
if (held.outcome !== 'applied')
|
|
427
558
|
return value;
|
|
428
559
|
const result = relativize(held.document, path, handle, definition);
|
|
@@ -458,17 +589,6 @@ function relativeChanges(input) {
|
|
|
458
589
|
return { ...change, fields, sections };
|
|
459
590
|
});
|
|
460
591
|
}
|
|
461
|
-
function unmodeledType(collection, composition) {
|
|
462
|
-
if (available(composition))
|
|
463
|
-
return false;
|
|
464
|
-
for (const [path, document] of documentsOf(collection)) {
|
|
465
|
-
if (document.type !== undefined &&
|
|
466
|
-
document.type !== 'any' &&
|
|
467
|
-
governing(composition, path).status === 'unavailable')
|
|
468
|
-
return true;
|
|
469
|
-
}
|
|
470
|
-
return false;
|
|
471
|
-
}
|
|
472
592
|
function unqueueable(file) {
|
|
473
593
|
return { kind: 'refused', refusal: { code: 'unknown-revision', retryable: false, file } };
|
|
474
594
|
}
|
|
@@ -478,29 +598,44 @@ function isPart(change) {
|
|
|
478
598
|
function touched(change) {
|
|
479
599
|
return change.kind === 'move' ? [change.path, change.to] : [change.path];
|
|
480
600
|
}
|
|
481
|
-
function
|
|
601
|
+
function partsApplied(content, path, changes) {
|
|
482
602
|
const parsed = parse(content, path);
|
|
483
603
|
if (!parsed.ok)
|
|
484
604
|
return null;
|
|
485
605
|
const document = parsed.document;
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
606
|
+
const parts = new Map();
|
|
607
|
+
for (const change of changes) {
|
|
608
|
+
if (change.kind === 'field')
|
|
609
|
+
parts.set(`field ${change.name}`, {
|
|
610
|
+
kind: 'field',
|
|
611
|
+
name: change.name,
|
|
612
|
+
value: change.value,
|
|
613
|
+
prior: document.fields[change.name],
|
|
614
|
+
});
|
|
615
|
+
else if (change.kind === 'section')
|
|
616
|
+
parts.set(`section ${change.name}`, {
|
|
495
617
|
kind: 'section',
|
|
496
618
|
name: change.name,
|
|
497
619
|
value: change.value,
|
|
498
|
-
prior: document.sections[change.name],
|
|
499
|
-
}
|
|
500
|
-
|
|
620
|
+
prior: document.sections[change.name] ?? '',
|
|
621
|
+
});
|
|
622
|
+
else
|
|
623
|
+
parts.set('preamble', { kind: 'preamble', value: change.value, prior: document.preamble });
|
|
624
|
+
}
|
|
625
|
+
const applied = apply(document, [...parts.values()]);
|
|
501
626
|
return applied.outcome === 'applied' ? serialize(applied.document) : null;
|
|
502
627
|
}
|
|
503
|
-
function
|
|
628
|
+
function settledParts(changes, deferred) {
|
|
629
|
+
for (const [held, parts] of deferred) {
|
|
630
|
+
const content = partsApplied(held.content, held.path, parts);
|
|
631
|
+
if (content === null)
|
|
632
|
+
return held.path;
|
|
633
|
+
changes[changes.indexOf(held)] = { ...held, content };
|
|
634
|
+
}
|
|
635
|
+
deferred.clear();
|
|
636
|
+
return null;
|
|
637
|
+
}
|
|
638
|
+
function folded(changes, change, appending, deferred) {
|
|
504
639
|
const held = changes.find((item) => item.path === change.path && (item.kind === 'create' || item.kind === 'replace'));
|
|
505
640
|
const whole = held === undefined ? -1 : changes.indexOf(held);
|
|
506
641
|
const occupied = changes.some((item) => !isPart(item) && item !== held && touched(item).includes(change.path));
|
|
@@ -521,10 +656,11 @@ function folded(changes, change, appending) {
|
|
|
521
656
|
return 'appended';
|
|
522
657
|
}
|
|
523
658
|
if ('content' in held) {
|
|
524
|
-
const
|
|
525
|
-
if (
|
|
526
|
-
|
|
527
|
-
|
|
659
|
+
const parts = deferred.get(held);
|
|
660
|
+
if (parts === undefined)
|
|
661
|
+
deferred.set(held, [change]);
|
|
662
|
+
else
|
|
663
|
+
parts.push(change);
|
|
528
664
|
return 'folded';
|
|
529
665
|
}
|
|
530
666
|
if (change.kind === 'preamble')
|
|
@@ -555,17 +691,21 @@ function folded(changes, change, appending) {
|
|
|
555
691
|
changes.push(change);
|
|
556
692
|
return 'appended';
|
|
557
693
|
}
|
|
558
|
-
function relinked(batch, move, before, after, appending) {
|
|
559
|
-
const derived = rewrites([move], after);
|
|
694
|
+
function* relinked(batch, move, before, after, appending) {
|
|
695
|
+
const derived = yield* rewrites([move], after);
|
|
560
696
|
if (derived.kind === 'refused')
|
|
561
697
|
return derived;
|
|
562
698
|
const changes = [...batch.changes];
|
|
563
699
|
const appended = [];
|
|
564
700
|
let changed = false;
|
|
701
|
+
const deferred = new Map();
|
|
565
702
|
for (const change of derived.changes) {
|
|
566
703
|
if (change === move)
|
|
567
704
|
continue;
|
|
568
|
-
const
|
|
705
|
+
const unsettled = isPart(change) ? null : settledParts(changes, deferred);
|
|
706
|
+
if (unsettled !== null)
|
|
707
|
+
return unqueueable(unsettled);
|
|
708
|
+
const outcome = folded(changes, change, appending, deferred);
|
|
569
709
|
if (outcome === 'refused')
|
|
570
710
|
return unqueueable(change.path);
|
|
571
711
|
if (outcome === 'appended')
|
|
@@ -573,9 +713,13 @@ function relinked(batch, move, before, after, appending) {
|
|
|
573
713
|
if (outcome !== 'skipped')
|
|
574
714
|
changed = true;
|
|
575
715
|
}
|
|
716
|
+
const unsettled = settledParts(changes, deferred);
|
|
717
|
+
if (unsettled !== null)
|
|
718
|
+
return unqueueable(unsettled);
|
|
576
719
|
if (!changed)
|
|
577
720
|
return { kind: 'relinked', batch };
|
|
578
721
|
const held = new Set(batch.preconditions.map(identity));
|
|
722
|
+
const added = yield* preconditionsOf(appended, before, []);
|
|
579
723
|
return {
|
|
580
724
|
kind: 'relinked',
|
|
581
725
|
batch: immutable({
|
|
@@ -584,7 +728,7 @@ function relinked(batch, move, before, after, appending) {
|
|
|
584
728
|
changes,
|
|
585
729
|
preconditions: [
|
|
586
730
|
...batch.preconditions,
|
|
587
|
-
...
|
|
731
|
+
...added.filter((precondition) => !held.has(identity(precondition))),
|
|
588
732
|
],
|
|
589
733
|
}),
|
|
590
734
|
};
|
|
@@ -630,7 +774,7 @@ function withdrawnFile(batch, change, at) {
|
|
|
630
774
|
];
|
|
631
775
|
return immutable({ ...batch, id: changeBatchIdentity(), changes, preconditions });
|
|
632
776
|
}
|
|
633
|
-
export function
|
|
777
|
+
export function* requeuing(queue, changes, visible, changeable, state) {
|
|
634
778
|
const next = [...queue];
|
|
635
779
|
const origins = new Map();
|
|
636
780
|
const withdrawn = new Map();
|
|
@@ -653,19 +797,19 @@ export function requeued(queue, changes, visible, changeable, state) {
|
|
|
653
797
|
return unqueueable(change.path);
|
|
654
798
|
const following = next.slice(index);
|
|
655
799
|
const rebuilt = [];
|
|
656
|
-
let before = change.kind === 'move' ? state(next.slice(0, index)) : visible;
|
|
800
|
+
let before = change.kind === 'move' ? yield* state(next.slice(0, index)) : visible;
|
|
657
801
|
for (const [offset, batch] of following.entries()) {
|
|
658
802
|
let current = batch;
|
|
659
803
|
if (change.kind === 'move') {
|
|
660
|
-
const after = state(next.slice(0, index + offset + 1));
|
|
804
|
+
const after = yield* state(next.slice(0, index + offset + 1));
|
|
661
805
|
const appending = offset === 0 && created(batch, queuedFile(batch, change.path, held.localId));
|
|
662
|
-
const relinking = relinked(batch, change, before, after, appending);
|
|
806
|
+
const relinking = yield* relinked(batch, change, before, after, appending);
|
|
663
807
|
if (relinking.kind === 'refused')
|
|
664
808
|
return relinking;
|
|
665
809
|
current = relinking.batch;
|
|
666
810
|
before = after;
|
|
667
811
|
}
|
|
668
|
-
if (current !== batch && !open(batch))
|
|
812
|
+
if (current !== batch && (!open(batch) || batch.between !== undefined))
|
|
669
813
|
return unqueueable(change.path);
|
|
670
814
|
rebuilt.push(offset === 0
|
|
671
815
|
? withdrawnFile(current, change, queuedFile(current, change.path, held.localId))
|
|
@@ -706,10 +850,17 @@ export function joined(queue, owner, extra) {
|
|
|
706
850
|
if (clash !== undefined)
|
|
707
851
|
return unqueueable(clash);
|
|
708
852
|
const changes = [...owner.changes];
|
|
853
|
+
const deferred = new Map();
|
|
709
854
|
for (const change of extra.changes) {
|
|
710
|
-
|
|
855
|
+
const unsettled = isPart(change) ? null : settledParts(changes, deferred);
|
|
856
|
+
if (unsettled !== null)
|
|
857
|
+
return unqueueable(unsettled);
|
|
858
|
+
if (folded(changes, change, true, deferred) === 'refused')
|
|
711
859
|
return unqueueable(change.path);
|
|
712
860
|
}
|
|
861
|
+
const unsettled = settledParts(changes, deferred);
|
|
862
|
+
if (unsettled !== null)
|
|
863
|
+
return unqueueable(unsettled);
|
|
713
864
|
const held = new Set(owner.preconditions.map(covering));
|
|
714
865
|
const written = new Set(owner.changes.flatMap((change) => change.kind === 'create' || change.kind === 'replace' ? [change.path] : []));
|
|
715
866
|
const preconditions = [
|
|
@@ -728,62 +879,66 @@ export function joined(queue, owner, extra) {
|
|
|
728
879
|
});
|
|
729
880
|
return { kind: 'joined', batch, queue: queue.map((item) => (item === owner ? batch : item)) };
|
|
730
881
|
}
|
|
731
|
-
export function
|
|
882
|
+
export function* limiting(queue, batch, limits, state) {
|
|
732
883
|
const at = queue.indexOf(batch);
|
|
733
|
-
const
|
|
884
|
+
const rewritten = yield* providerRewritten(batch, yield* state(queue.slice(0, at)));
|
|
885
|
+
const limited = yield* exceeding(limits, batch.changes, rewritten.changes, yield* state(queue.slice(0, at + 1)));
|
|
734
886
|
return limited?.kind === 'refused' ? limited.refusal : null;
|
|
735
887
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
const
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
const
|
|
751
|
-
const
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
888
|
+
function typedText(content) {
|
|
889
|
+
if (content === undefined)
|
|
890
|
+
return false;
|
|
891
|
+
const parsed = parse(content);
|
|
892
|
+
return parsed.ok && parsed.document.type !== undefined && parsed.document.type !== 'any';
|
|
893
|
+
}
|
|
894
|
+
function touchedLibrary(resulting, touched, composition) {
|
|
895
|
+
const entries = touched
|
|
896
|
+
.flatMap((path) => {
|
|
897
|
+
const content = resulting.documents[path];
|
|
898
|
+
const binary = resulting.binaries[path] !== undefined;
|
|
899
|
+
return content === undefined && !binary ? [] : [{ path, content: content ?? null }];
|
|
900
|
+
})
|
|
901
|
+
.sort((left, right) => (left.path < right.path ? -1 : left.path > right.path ? 1 : 0));
|
|
902
|
+
const contents = new Map(entries.map(({ path, content }) => [path, content]));
|
|
903
|
+
const binaries = new Set(Object.keys(resulting.binaries).filter((path) => resulting.binaries[path] !== undefined));
|
|
904
|
+
return validatedCollection(() => Promise.resolve({ entries, next: null }), async (paths) => {
|
|
905
|
+
const known = new Map();
|
|
906
|
+
const pace = paced();
|
|
907
|
+
for (const path of paths) {
|
|
908
|
+
const content = contents.get(path);
|
|
909
|
+
if (binaries.has(path))
|
|
910
|
+
known.set(path, { type: undefined, binary: true });
|
|
911
|
+
else if (content !== undefined && content !== null) {
|
|
912
|
+
const read = parse(content, path);
|
|
913
|
+
if (read.ok)
|
|
914
|
+
known.set(path, { type: read.document.type ?? 'any', binary: false });
|
|
915
|
+
await pace(content.length + ROW_WEIGHT);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return known;
|
|
919
|
+
}, composition);
|
|
920
|
+
}
|
|
921
|
+
async function judging(visible, resulting, composition, validate, removed, touched) {
|
|
761
922
|
if (removed.size > 0) {
|
|
762
|
-
const
|
|
763
|
-
const referenced = incoming(collectionOf(resulting.documents, input.composition), removed, referrers === null ? null : [...referrers, ...predicted.changes.flatMap(affected)]);
|
|
923
|
+
const referenced = await stepped(incoming(collectionOf(resulting.documents, composition), removed, null));
|
|
764
924
|
if (referenced !== null)
|
|
765
925
|
return referenced;
|
|
766
926
|
}
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
const withoutModel = typedPaths.find((path) => governing(
|
|
927
|
+
const typedPaths = [];
|
|
928
|
+
const pace = paced();
|
|
929
|
+
for (const path of touched) {
|
|
930
|
+
const before = visible.documents[path];
|
|
931
|
+
const after = resulting.documents[path];
|
|
932
|
+
if (typedText(before) || typedText(after))
|
|
933
|
+
typedPaths.push(path);
|
|
934
|
+
await pace((before?.length ?? 0) + (after?.length ?? 0) + ROW_WEIGHT);
|
|
935
|
+
}
|
|
936
|
+
const withoutModel = typedPaths.find((path) => governing(composition, path).status === 'unavailable');
|
|
777
937
|
if (withoutModel !== undefined)
|
|
778
938
|
return refuse('model-unavailable', withoutModel);
|
|
779
|
-
const verdict =
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
: validateCollection(needsModel
|
|
783
|
-
? resulting.documents
|
|
784
|
-
: Object.fromEntries(touched.flatMap((path) => resulting.documents[path] === undefined
|
|
785
|
-
? []
|
|
786
|
-
: [[path, resulting.documents[path]]])), Object.keys(resulting.binaries), input.composition);
|
|
939
|
+
const verdict = typedPaths.length > 0
|
|
940
|
+
? await validate(resulting, touched)
|
|
941
|
+
: await touchedLibrary(resulting, touched, composition);
|
|
787
942
|
if (verdict.verdict === 'refuse') {
|
|
788
943
|
return {
|
|
789
944
|
kind: 'refused',
|
|
@@ -796,12 +951,92 @@ export function buildBatch(input) {
|
|
|
796
951
|
},
|
|
797
952
|
};
|
|
798
953
|
}
|
|
799
|
-
|
|
954
|
+
return {
|
|
955
|
+
kind: 'judged',
|
|
956
|
+
validated: typedPaths
|
|
957
|
+
.map((path) => governing(composition, path))
|
|
958
|
+
.find((model) => model.status !== 'unavailable'),
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
function placed(reference) {
|
|
962
|
+
const key = roomPathOf(reference.handle, reference.path);
|
|
963
|
+
if (reference.kind === 'link')
|
|
964
|
+
return `link ${key}`;
|
|
965
|
+
if (reference.kind === 'item')
|
|
966
|
+
return `section ${reference.section} ${key}`;
|
|
967
|
+
const pointer = reference.pointer
|
|
968
|
+
.split('/')
|
|
969
|
+
.map((segment) => (ARRAY_INDEX.test(segment) ? '-' : segment))
|
|
970
|
+
.join('/');
|
|
971
|
+
return `field ${pointer} ${key}`;
|
|
972
|
+
}
|
|
973
|
+
function roomReferencesIn(path, content, composition) {
|
|
974
|
+
if (content === undefined)
|
|
975
|
+
return [];
|
|
976
|
+
const parsed = parse(content, path);
|
|
977
|
+
if (!parsed.ok)
|
|
978
|
+
return [];
|
|
979
|
+
return roomReferences(parsed.document, definitionOf(governing(composition, path), parsed.document.type));
|
|
980
|
+
}
|
|
981
|
+
function* admittedRooms(changes, visible, resulting, composition) {
|
|
982
|
+
const from = new Map();
|
|
983
|
+
for (const [index, change] of changes.entries()) {
|
|
984
|
+
if (change.kind === 'move')
|
|
985
|
+
from.set(change.to, departure(changes, index));
|
|
986
|
+
}
|
|
987
|
+
for (const path of [...new Set(changes.flatMap(affected))].sort()) {
|
|
988
|
+
const now = resulting.documents[path];
|
|
989
|
+
if (now === undefined)
|
|
990
|
+
continue;
|
|
991
|
+
const held = new Set(roomReferencesIn(path, visible.documents[from.get(path) ?? path], composition).map(placed));
|
|
992
|
+
for (const reference of roomReferencesIn(path, now, composition)) {
|
|
993
|
+
if (reference.kind === 'link' || reference.crossRoom === true)
|
|
994
|
+
continue;
|
|
995
|
+
if (held.has(placed(reference)))
|
|
996
|
+
continue;
|
|
997
|
+
return refuse('unresolved-reference', path, reference.kind === 'field' ? reference.pointer : reference.section);
|
|
998
|
+
}
|
|
999
|
+
yield ROW_WEIGHT + now.length;
|
|
1000
|
+
}
|
|
1001
|
+
return null;
|
|
1002
|
+
}
|
|
1003
|
+
function validationOf(validated) {
|
|
1004
|
+
return validated === undefined
|
|
1005
|
+
? {}
|
|
1006
|
+
: {
|
|
1007
|
+
validation: {
|
|
1008
|
+
identity: validated.snapshot.identity,
|
|
1009
|
+
version: validated.snapshot.version,
|
|
1010
|
+
source: validated.status,
|
|
1011
|
+
},
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
async function batching(input) {
|
|
1015
|
+
const changes = relativeChanges(input);
|
|
1016
|
+
const structural = changes.find((change) => change.kind === 'move' || change.kind === 'remove');
|
|
1017
|
+
if (structural !== undefined && input.unmodeled) {
|
|
1018
|
+
return refuse('model-unavailable', structural.path);
|
|
1019
|
+
}
|
|
1020
|
+
if (changes.length === 0)
|
|
1021
|
+
return refuse('no-change');
|
|
1022
|
+
const rewritten = await stepped(rewrites(changes, input.visible));
|
|
1023
|
+
if (rewritten.kind === 'refused')
|
|
1024
|
+
return rewritten;
|
|
1025
|
+
const refusal = guard(changes, input, WRITE);
|
|
1026
|
+
if (refusal !== null)
|
|
1027
|
+
return refusal;
|
|
1028
|
+
const preconditions = await stepped(preconditionsOf(changes, input.visible, input.bases));
|
|
1029
|
+
const predicted = await stepped(anticipated(changes, preconditions, rewritten.changes, input.visible));
|
|
1030
|
+
const resulting = await stepped(overlaying(input.visible, [{ id: '', baseRoomVersion: input.baseRoomVersion, ...predicted }]));
|
|
1031
|
+
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))]);
|
|
1032
|
+
if (judged.kind === 'refused')
|
|
1033
|
+
return judged;
|
|
1034
|
+
const crossing = await stepped(admittedRooms(changes, input.visible, resulting, input.composition));
|
|
1035
|
+
if (crossing !== null)
|
|
1036
|
+
return crossing;
|
|
1037
|
+
const limited = await stepped(exceeding(input.providerLimits, changes, predicted.changes, resulting));
|
|
800
1038
|
if (limited !== null)
|
|
801
1039
|
return limited;
|
|
802
|
-
const validated = typedPaths
|
|
803
|
-
.map((path) => governing(input.composition, path))
|
|
804
|
-
.find((model) => model.status !== 'unavailable');
|
|
805
1040
|
return {
|
|
806
1041
|
kind: 'batch',
|
|
807
1042
|
batch: immutable({
|
|
@@ -810,15 +1045,127 @@ export function buildBatch(input) {
|
|
|
810
1045
|
changes,
|
|
811
1046
|
preconditions,
|
|
812
1047
|
...(input.writtenBy === undefined ? {} : { writtenBy: input.writtenBy }),
|
|
813
|
-
...(validated
|
|
814
|
-
? {}
|
|
815
|
-
: {
|
|
816
|
-
validation: {
|
|
817
|
-
identity: validated.snapshot.identity,
|
|
818
|
-
version: validated.snapshot.version,
|
|
819
|
-
source: validated.status,
|
|
820
|
-
},
|
|
821
|
-
}),
|
|
1048
|
+
...validationOf(judged.validated),
|
|
822
1049
|
}),
|
|
823
1050
|
};
|
|
824
1051
|
}
|
|
1052
|
+
export const MOVE_DOCUMENTS = 'move-documents';
|
|
1053
|
+
function heldAt(visible, path) {
|
|
1054
|
+
return visible.documents[path] !== undefined || visible.binaries[path] !== undefined;
|
|
1055
|
+
}
|
|
1056
|
+
function arrivingText(path, to, source, moved) {
|
|
1057
|
+
const content = source.visible.documents[path];
|
|
1058
|
+
const document = source.visible.collection.document(path);
|
|
1059
|
+
if (document === undefined)
|
|
1060
|
+
return content;
|
|
1061
|
+
const definition = definitionOf(governing(source.composition, path), document.type);
|
|
1062
|
+
const changes = crossed(document, definition, path, (named, href) => {
|
|
1063
|
+
const at = moved.get(named);
|
|
1064
|
+
if (at !== undefined)
|
|
1065
|
+
return target(to, href) === at ? undefined : relative(to, at);
|
|
1066
|
+
return heldAt(source.visible, named) ? roomPathOf(source.handle, named) : undefined;
|
|
1067
|
+
});
|
|
1068
|
+
if (changes.length === 0)
|
|
1069
|
+
return content;
|
|
1070
|
+
const applied = apply(document, changes);
|
|
1071
|
+
return applied.outcome === 'applied' ? serialize(applied.document) : content;
|
|
1072
|
+
}
|
|
1073
|
+
function arrivalOf({ path, to }, source, moved) {
|
|
1074
|
+
const { documents, revisions, fileIds, created, changes, binaries } = source.visible;
|
|
1075
|
+
const kept = {
|
|
1076
|
+
...(fileIds[path] === undefined ? {} : { fileId: fileIds[path] }),
|
|
1077
|
+
...(created[path] === undefined ? {} : { created: created[path] }),
|
|
1078
|
+
...(changes[path] === undefined ? {} : { change: changes[path] }),
|
|
1079
|
+
};
|
|
1080
|
+
const heads = {
|
|
1081
|
+
...(revisions[path] === undefined ? {} : { revision: revisions[path] }),
|
|
1082
|
+
...kept,
|
|
1083
|
+
};
|
|
1084
|
+
const binary = binaries[path];
|
|
1085
|
+
if (binary?.state === 'accepted') {
|
|
1086
|
+
const { byteLength, mediaType, sha256 } = binary;
|
|
1087
|
+
return {
|
|
1088
|
+
kind: 'arrival',
|
|
1089
|
+
path: to,
|
|
1090
|
+
binary: { byteLength, mediaType, sha256 },
|
|
1091
|
+
...heads,
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
const content = arrivingText(path, to, source, moved);
|
|
1095
|
+
return {
|
|
1096
|
+
kind: 'arrival',
|
|
1097
|
+
path: to,
|
|
1098
|
+
content,
|
|
1099
|
+
...(content === documents[path] ? heads : kept),
|
|
1100
|
+
};
|
|
1101
|
+
}
|
|
1102
|
+
async function moving(input) {
|
|
1103
|
+
const { source, destination, moves } = input;
|
|
1104
|
+
if (moves.length === 0)
|
|
1105
|
+
return refuse('no-change');
|
|
1106
|
+
const removals = moves.map(({ path }) => ({ kind: 'remove', path }));
|
|
1107
|
+
const leaves = guard(removals, { ...source, local: input.local, bases: [] }, MOVE_OUT);
|
|
1108
|
+
if (leaves !== null)
|
|
1109
|
+
return leaves;
|
|
1110
|
+
const uploading = moves.find(({ path }) => source.visible.binaries[path]?.state === 'pending');
|
|
1111
|
+
if (uploading !== undefined)
|
|
1112
|
+
return refuse('unknown-revision', uploading.path);
|
|
1113
|
+
const moved = new Map(moves.map(({ path, to }) => [path, to]));
|
|
1114
|
+
const arrivals = moves.map((move) => arrivalOf(move, source, moved));
|
|
1115
|
+
const arrives = guard(arrivals, { ...destination, local: input.local, bases: [] }, WRITE);
|
|
1116
|
+
if (arrives !== null)
|
|
1117
|
+
return arrives;
|
|
1118
|
+
const bound = input.providerLimits.find((limit) => limit.name === MOVE_DOCUMENTS)?.value;
|
|
1119
|
+
if (typeof bound === 'number' && moves.length > bound) {
|
|
1120
|
+
return refuse('provider-limit', undefined, MOVE_DOCUMENTS);
|
|
1121
|
+
}
|
|
1122
|
+
if (source.unmodeled)
|
|
1123
|
+
return refuse('model-unavailable', moves[0].path);
|
|
1124
|
+
const id = changeBatchIdentity();
|
|
1125
|
+
const between = {
|
|
1126
|
+
source: { room: source.room, baseRoomVersion: source.baseRoomVersion },
|
|
1127
|
+
destination: {
|
|
1128
|
+
room: destination.room,
|
|
1129
|
+
baseRoomVersion: destination.baseRoomVersion,
|
|
1130
|
+
handle: destination.handle,
|
|
1131
|
+
},
|
|
1132
|
+
moves,
|
|
1133
|
+
};
|
|
1134
|
+
const written = input.writtenBy === undefined ? {} : { writtenBy: input.writtenBy };
|
|
1135
|
+
const leavingBatch = {
|
|
1136
|
+
id,
|
|
1137
|
+
baseRoomVersion: source.baseRoomVersion,
|
|
1138
|
+
changes: removals,
|
|
1139
|
+
preconditions: moves.map(({ path }) => existence(source.visible, path)),
|
|
1140
|
+
...written,
|
|
1141
|
+
between,
|
|
1142
|
+
};
|
|
1143
|
+
const effective = await stepped(leavingRewritten(leavingBatch, source.visible));
|
|
1144
|
+
const left = await stepped(overlaying(source.visible, [effective]));
|
|
1145
|
+
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))]);
|
|
1146
|
+
if (sourceJudged.kind === 'refused')
|
|
1147
|
+
return sourceJudged;
|
|
1148
|
+
const arrivingBatch = {
|
|
1149
|
+
id,
|
|
1150
|
+
baseRoomVersion: destination.baseRoomVersion,
|
|
1151
|
+
changes: arrivals,
|
|
1152
|
+
preconditions: moves.map(({ to }) => ({ kind: 'absent', path: to })),
|
|
1153
|
+
...written,
|
|
1154
|
+
between,
|
|
1155
|
+
};
|
|
1156
|
+
const arrived = await stepped(overlaying(destination.visible, [arrivingBatch]));
|
|
1157
|
+
const destinationJudged = await judging(destination.visible, arrived, destination.composition, destination.validate, new Set(), moves.map(({ to }) => to));
|
|
1158
|
+
if (destinationJudged.kind === 'refused')
|
|
1159
|
+
return destinationJudged;
|
|
1160
|
+
const limited = (await stepped(exceeding(input.providerLimits, removals, effective.changes, left))) ??
|
|
1161
|
+
(await stepped(exceeding(input.providerLimits, arrivals, arrivals, arrived)));
|
|
1162
|
+
if (limited !== null)
|
|
1163
|
+
return limited;
|
|
1164
|
+
return { kind: 'moved', leaving: immutable(leavingBatch), arriving: immutable(arrivingBatch) };
|
|
1165
|
+
}
|
|
1166
|
+
export function buildMove(input) {
|
|
1167
|
+
return moving(input);
|
|
1168
|
+
}
|
|
1169
|
+
export function buildBatch(input) {
|
|
1170
|
+
return batching(input);
|
|
1171
|
+
}
|