edytor 3.0.0 → 4.0.0

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.
Files changed (143) hide show
  1. package/README.md +2 -2
  2. package/dist/cloudflare/DocumentRoom.d.ts +13 -9
  3. package/dist/cloudflare/DocumentRoom.js +10 -6
  4. package/dist/cloudflare/room/context.d.ts +27 -26
  5. package/dist/cloudflare/room/context.js +2 -2
  6. package/dist/cloudflare/room/purge.d.ts +6 -3
  7. package/dist/cloudflare/room/purge.js +44 -19
  8. package/dist/cloudflare/room/updates.d.ts +3 -4
  9. package/dist/cloudflare/room/updates.js +6 -8
  10. package/dist/crdt/attribution/attribution.d.ts +31 -12
  11. package/dist/crdt/attribution/attribution.js +56 -18
  12. package/dist/crdt/attribution/block.d.ts +3 -3
  13. package/dist/crdt/attribution/block.js +7 -8
  14. package/dist/crdt/attribution/index.d.ts +1 -1
  15. package/dist/crdt/attribution/index.js +1 -1
  16. package/dist/crdt/data.d.ts +62 -31
  17. package/dist/crdt/data.js +211 -103
  18. package/dist/crdt/doc/delete.d.ts +1 -1
  19. package/dist/crdt/doc/delete.js +13 -30
  20. package/dist/crdt/doc/funnel.js +29 -24
  21. package/dist/crdt/doc/gate.d.ts +3 -3
  22. package/dist/crdt/doc/history.d.ts +25 -9
  23. package/dist/crdt/doc/history.js +150 -40
  24. package/dist/crdt/doc/layout.js +11 -22
  25. package/dist/crdt/doc/meta.js +12 -17
  26. package/dist/crdt/doc/moves.d.ts +1 -1
  27. package/dist/crdt/doc/moves.js +52 -32
  28. package/dist/crdt/doc/reads.js +2 -2
  29. package/dist/crdt/doc/seed.js +2 -2
  30. package/dist/crdt/doc/split-merge.js +12 -15
  31. package/dist/crdt/doc/steps.d.ts +25 -13
  32. package/dist/crdt/doc/steps.js +52 -122
  33. package/dist/crdt/doc/types.d.ts +21 -9
  34. package/dist/crdt/document.d.ts +16 -5
  35. package/dist/crdt/document.js +21 -4
  36. package/dist/crdt/edytor-doc.d.ts +62 -64
  37. package/dist/crdt/edytor-doc.js +18 -13
  38. package/dist/crdt/engine-api.d.ts +33 -1
  39. package/dist/crdt/engine.d.ts +0 -1
  40. package/dist/crdt/engine.js +1 -4
  41. package/dist/crdt/flow.d.ts +1 -1
  42. package/dist/crdt/flow.js +25 -27
  43. package/dist/crdt/index.d.ts +26 -25
  44. package/dist/crdt/index.js +1 -1
  45. package/dist/crdt/placement/display.d.ts +5 -30
  46. package/dist/crdt/placement/display.js +39 -144
  47. package/dist/crdt/placement/keys.d.ts +58 -0
  48. package/dist/crdt/placement/keys.js +90 -0
  49. package/dist/crdt/placement/model.d.ts +119 -118
  50. package/dist/crdt/placement/model.js +242 -142
  51. package/dist/crdt/placement/resolve.d.ts +123 -35
  52. package/dist/crdt/placement/resolve.js +187 -153
  53. package/dist/crdt/placement/slots.d.ts +134 -0
  54. package/dist/crdt/placement/slots.js +152 -0
  55. package/dist/crdt/providers/room.d.ts +16 -2
  56. package/dist/crdt/providers/room.js +64 -17
  57. package/dist/crdt/providers/websocket.js +5 -3
  58. package/dist/crdt/purge.d.ts +17 -8
  59. package/dist/crdt/purge.js +236 -126
  60. package/dist/crdt/restore.d.ts +2 -2
  61. package/dist/crdt/restore.js +18 -34
  62. package/dist/crdt/schema.d.ts +22 -21
  63. package/dist/crdt/schema.js +29 -23
  64. package/dist/crdt/storage.d.ts +1 -1
  65. package/dist/crdt/storage.js +1 -1
  66. package/dist/crdt/structs.d.ts +15 -15
  67. package/dist/crdt/structs.js +8 -22
  68. package/dist/crdt/text/index/cache.js +4 -0
  69. package/dist/crdt/text/index/claims.js +12 -0
  70. package/dist/crdt/text/index/fold.d.ts +2 -3
  71. package/dist/crdt/text/index/fold.js +194 -44
  72. package/dist/crdt/text/index/layout.js +5 -8
  73. package/dist/crdt/text/index/placement.d.ts +26 -18
  74. package/dist/crdt/text/index/placement.js +404 -138
  75. package/dist/crdt/text/index/records.d.ts +3 -3
  76. package/dist/crdt/text/index/records.js +24 -31
  77. package/dist/crdt/text/index/shared.d.ts +11 -3
  78. package/dist/crdt/text/index/shared.js +12 -3
  79. package/dist/crdt/text/index/state.d.ts +21 -17
  80. package/dist/crdt/text/index/state.js +15 -17
  81. package/dist/crdt/text/index/streams.d.ts +10 -5
  82. package/dist/crdt/text/index/streams.js +78 -27
  83. package/dist/crdt/text/items.d.ts +10 -3
  84. package/dist/crdt/text/items.js +7 -0
  85. package/dist/crdt/text/model.d.ts +77 -62
  86. package/dist/crdt/text/model.js +84 -169
  87. package/dist/crdt/text/ranges.d.ts +1 -1
  88. package/dist/crdt/text/ranges.js +3 -3
  89. package/dist/crdt/text/rows.d.ts +13 -7
  90. package/dist/crdt/text/rows.js +24 -7
  91. package/dist/crdt/text/runs.d.ts +17 -12
  92. package/dist/crdt/text/runs.js +24 -7
  93. package/dist/crdt/text/streams.d.ts +26 -13
  94. package/dist/crdt/text/streams.js +41 -14
  95. package/dist/crdt/vendor/yjs/UPSTREAM.md +568 -21
  96. package/dist/crdt/vendor/yjs/dts/global.d.ts +2 -0
  97. package/dist/crdt/vendor/yjs/dts/index.d.ts +1 -1
  98. package/dist/crdt/vendor/yjs/dts/structs/AbstractStruct.d.ts +7 -0
  99. package/dist/crdt/vendor/yjs/dts/structs/Item.d.ts +194 -10
  100. package/dist/crdt/vendor/yjs/dts/utils/Doc.d.ts +6 -3
  101. package/dist/crdt/vendor/yjs/dts/utils/StructStore.d.ts +5 -18
  102. package/dist/crdt/vendor/yjs/dts/utils/Transaction.d.ts +15 -1
  103. package/dist/crdt/vendor/yjs/dts/utils/UpdateDecoder.d.ts +14 -6
  104. package/dist/crdt/vendor/yjs/dts/utils/UpdateEncoder.d.ts +33 -6
  105. package/dist/crdt/vendor/yjs/dts/utils/ids.d.ts +1 -65
  106. package/dist/crdt/vendor/yjs/dts/utils/marks.d.ts +6 -1
  107. package/dist/crdt/vendor/yjs/dts/ynode.d.ts +43 -7
  108. package/dist/crdt/vendor/yjs/global.d.ts +2 -0
  109. package/dist/crdt/vendor/yjs/src/index.js +1 -1
  110. package/dist/crdt/vendor/yjs/src/structs/AbstractStruct.js +10 -0
  111. package/dist/crdt/vendor/yjs/src/structs/Item.js +610 -51
  112. package/dist/crdt/vendor/yjs/src/utils/BlockSet.js +18 -9
  113. package/dist/crdt/vendor/yjs/src/utils/Doc.js +5 -3
  114. package/dist/crdt/vendor/yjs/src/utils/StructStore.js +5 -0
  115. package/dist/crdt/vendor/yjs/src/utils/Transaction.js +36 -13
  116. package/dist/crdt/vendor/yjs/src/utils/UpdateDecoder.js +88 -18
  117. package/dist/crdt/vendor/yjs/src/utils/UpdateEncoder.js +119 -32
  118. package/dist/crdt/vendor/yjs/src/utils/encoding.js +13 -1
  119. package/dist/crdt/vendor/yjs/src/utils/ids.js +7 -7
  120. package/dist/crdt/vendor/yjs/src/utils/marks.js +193 -8
  121. package/dist/crdt/vendor/yjs/src/utils/redo.js +1 -1
  122. package/dist/crdt/vendor/yjs/src/utils/transaction-helpers.js +1 -1
  123. package/dist/crdt/vendor/yjs/src/utils/updates.js +3 -3
  124. package/dist/crdt/vendor/yjs/src/ynode.js +177 -12
  125. package/dist/edytor.svelte.js +4 -1
  126. package/dist/events/beforeInputCommands.js +2 -2
  127. package/dist/events/onPageHide.d.ts +3 -0
  128. package/dist/events/onPageHide.js +16 -0
  129. package/dist/export/forms.d.ts +25 -25
  130. package/dist/surface/observer.svelte.js +2 -2
  131. package/dist/surface/projector.svelte.d.ts +15 -3
  132. package/dist/surface/projector.svelte.js +59 -8
  133. package/package.json +2 -2
  134. package/dist/crdt/placement/rank.d.ts +0 -87
  135. package/dist/crdt/placement/rank.js +0 -332
  136. package/dist/crdt/placement/source.d.ts +0 -43
  137. package/dist/crdt/placement/source.js +0 -66
  138. package/dist/crdt/text/delete-index.d.ts +0 -129
  139. package/dist/crdt/text/delete-index.js +0 -365
  140. package/dist/crdt/text/deletes.d.ts +0 -76
  141. package/dist/crdt/text/deletes.js +0 -362
  142. package/dist/crdt/text/index/anchored.d.ts +0 -17
  143. package/dist/crdt/text/index/anchored.js +0 -197
@@ -3,13 +3,28 @@ import { blockAttributionOf } from './block.js';
3
3
  /** Reserved replicated root for all attribution metadata (`SCHEMA.roots.attribution`). */
4
4
  export { ATTRIBUTION_ROOT };
5
5
  /**
6
- * Origin of every metadata write this module performs (`u/`/`c/`
7
- * dictionary publishes only — per-edit record writes are retired). Kept
8
- * out of undo capture; tooling classifies it as bookkeeping.
6
+ * Origin of the profile writes this module performs on its own
7
+ * (`setProfile`; the binding joins the transaction of the replica's first
8
+ * write, whatever its origin). Kept out of undo capture; tooling classifies
9
+ * it as bookkeeping.
9
10
  */
10
11
  export const ATTRIBUTION_ORIGIN = Symbol('edytor.attribution');
11
12
  const ACTOR_PREFIX = 'u/'; // actorId → profile records
12
13
  const CLIENT_PREFIX = 'c/'; // replica clientID → actorId records
14
+ /** The actor each attached document's replica writes for (its attribution controller's). */
15
+ const localActors = new WeakMap();
16
+ /**
17
+ * The actor `doc`'s own replica writes for: its binding (`c/<clientID>`),
18
+ * else, before its first write, the actor its attribution controller was
19
+ * attached with (`undefined`: a raw doc). The provider's `saved` reads it.
20
+ */
21
+ export const writerOf = (doc) => {
22
+ // A raw doc without the root gets none (reading would create it).
23
+ const bound = doc.share?.has(ATTRIBUTION_ROOT)
24
+ ? doc.get(ATTRIBUTION_ROOT).getAttr(`${CLIENT_PREFIX}${doc.clientID}`)
25
+ : undefined;
26
+ return typeof bound === 'string' && bound.length > 0 ? bound : localActors.get(doc);
27
+ };
13
28
  const sanitizeProfile = (value) => {
14
29
  const v = (value ?? undefined);
15
30
  const out = {};
@@ -32,14 +47,45 @@ export const profileOf = (actor) => ({
32
47
  */
33
48
  export const bindAttribution = (_Y) => {
34
49
  /**
35
- * Attach the actor dictionary to `doc`: publishes this replica's
36
- * `c/`+`u/` records and returns the read-through view. No listeners —
37
- * ordinary edits perform no attribution work.
50
+ * Attach the actor dictionary to `doc` and return the read-through view.
51
+ * This replica's `c/`+`u/` records are written with its first write
52
+ * (`bind`, below), never at attach: a replica that only reads leaves the
53
+ * document as it found it.
38
54
  */
39
55
  const attach = (doc, opts) => {
40
56
  const actor = opts.actor;
41
57
  const root = doc.get(ATTRIBUTION_ROOT);
42
58
  let destroyed = false;
59
+ /** The client id this replica's binding was written for (`null`: none yet). */
60
+ let bound = null;
61
+ /**
62
+ * The binding, inside the transaction of the replica's first write
63
+ * under its client id (and again for a new client id, fork patch
64
+ * YP15): `c/<clientID>`, and `u/<actorId>` when the stored profile
65
+ * differs (it is not rewritten at every reload). A binding the
66
+ * document already holds for the id (an attached doc, the room's
67
+ * rebinding) stands.
68
+ */
69
+ const bind = (transaction) => {
70
+ const tr = transaction;
71
+ const client = doc.clientID;
72
+ if (destroyed || bound === client || !tr.local || !tr.insertSet.clients.has(client))
73
+ return;
74
+ bound = client;
75
+ if (root.getAttr(`${CLIENT_PREFIX}${client}`) !== undefined)
76
+ return;
77
+ root.setAttr(`${CLIENT_PREFIX}${client}`, actor.id);
78
+ // A profile this transaction wrote (`setProfile`) stands.
79
+ const key = `${ACTOR_PREFIX}${actor.id}`;
80
+ if (tr.changed.get(root)?.has(key))
81
+ return;
82
+ const next = profileOf(actor);
83
+ const stored = sanitizeProfile(root.getAttr(key));
84
+ if (stored.name !== next.name || stored.color !== next.color)
85
+ root.setAttr(key, next);
86
+ };
87
+ doc.on('beforeCommit', bind);
88
+ localActors.set(doc, actor.id);
43
89
  const setProfile = (profile) => {
44
90
  if (destroyed)
45
91
  return;
@@ -47,17 +93,6 @@ export const bindAttribution = (_Y) => {
47
93
  root.setAttr(`${ACTOR_PREFIX}${actor.id}`, sanitizeProfile(profile));
48
94
  }, ATTRIBUTION_ORIGIN);
49
95
  };
50
- doc.transact(() => {
51
- root.setAttr(`${CLIENT_PREFIX}${doc.clientID}`, actor.id);
52
- // `u/` is rewritten only when the stored profile actually differs —
53
- // `c/<clientID>` is always fresh per attach (new clientID) but the
54
- // profile item + tombstone shouldn't regrow on every reload.
55
- const next = profileOf(actor);
56
- const stored = sanitizeProfile(root.getAttr(`${ACTOR_PREFIX}${actor.id}`));
57
- if (stored.name !== next.name || stored.color !== next.color) {
58
- root.setAttr(`${ACTOR_PREFIX}${actor.id}`, next);
59
- }
60
- }, ATTRIBUTION_ORIGIN);
61
96
  const view = {
62
97
  get actors() {
63
98
  const out = new Map();
@@ -73,7 +108,7 @@ export const bindAttribution = (_Y) => {
73
108
  return typeof value === 'string' && value.length > 0 ? value : undefined;
74
109
  },
75
110
  setProfile,
76
- // `b/<id>` records live on the `blockattr` root and `l` on
111
+ // block records live on the `blockattr` root and `l` on
77
112
  // the block node — plain replicated reads, no observer needed.
78
113
  block: (blockId) => blockAttributionOf(doc, blockId)
79
114
  };
@@ -82,6 +117,9 @@ export const bindAttribution = (_Y) => {
82
117
  setProfile,
83
118
  destroy: () => {
84
119
  destroyed = true;
120
+ doc.off('beforeCommit', bind);
121
+ if (localActors.get(doc) === actor.id)
122
+ localActors.delete(doc);
85
123
  }
86
124
  };
87
125
  };
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * One block gets one small replicated record plus one block-node attr:
5
5
  *
6
- * - `b/<blockId>` → nested node on the `blockattr` root
6
+ * - `<blockId>` → nested node on the `blockattr` root
7
7
  * (`SCHEMA.roots.blockAttribution`) carrying `c` (createdBy actorId)
8
8
  * and `k/<actorId>` → true contributor membership.
9
9
  * - `l` (lastChangedBy) lives on the block node itself —
@@ -27,7 +27,7 @@
27
27
  * again after its creation was undone, or concurrently by two peers), and a
28
28
  * delayed remote write always addresses the incarnation its author saw.
29
29
  * Every block node carries the replicated nonce `n` of its incarnation;
30
- * every `b/<id>` record is stamped (`i`) with the nonce it belongs
30
+ * every record is stamped (`i`) with the nonce it belongs
31
31
  * to, and `ensureRecord` swaps in a FRESH record whenever the live node's
32
32
  * nonce doesn't match — a late write to a dead incarnation lands on an
33
33
  * orphaned record the recreated block never reads. An undo/redo copy of the
@@ -48,7 +48,7 @@
48
48
  * - Semantic no-ops (same-value type/data, empty ranges, pure moves)
49
49
  * are suppressed by the CALLERS: ops stamp only after a real write.
50
50
  *
51
- * Known residual: `b/<id>` nodes are LWW map entries — concurrent FIRST
51
+ * Known residual: record nodes are LWW map entries — concurrent FIRST
52
52
  * touches of a record-less block (foreign/migrated docs may lack records)
53
53
  * can lose one contributor add. Convergent; heals on the next touch.
54
54
  *
@@ -1,17 +1,16 @@
1
1
  import { REGISTRY_KEY } from '../placement/model.js';
2
- import { BLOCK_ATTR_ROOT, isNodeLike, LAST_CHANGED_ATTR, NONCE, REC_PREFIX } from '../schema.js';
2
+ import { BLOCK_ATTR_ROOT, isNodeLike, LAST_CHANGED_ATTR, NONCE } from '../schema.js';
3
3
  import { attrItems, newNode as makeNode } from '../structs.js';
4
- // `BLOCK_ATTR_ROOT`/`LAST_CHANGED_ATTR`/`REC_PREFIX` live in the shared
4
+ // `BLOCK_ATTR_ROOT`/`LAST_CHANGED_ATTR` live in the shared
5
5
  // `../schema.js` leaf — re-exported so existing import sites stay.
6
6
  export { BLOCK_ATTR_ROOT, LAST_CHANGED_ATTR };
7
7
  const REC_NODE = 'brec';
8
8
  const CREATED_KEY = 'c';
9
9
  const CONTRIBUTOR_PREFIX = 'k/';
10
- /** Incarnation stamp on a `b/` record: the nonce `n` of the node it belongs to. */
10
+ /** Incarnation stamp on a record: the nonce `n` of the node it belongs to. */
11
11
  const INCARNATION_KEY = 'i';
12
- const recKey = (id) => `${REC_PREFIX}${id}`;
13
12
  const recordOf = (doc, id) => {
14
- const v = doc.get(BLOCK_ATTR_ROOT).getAttr(recKey(id));
13
+ const v = doc.get(BLOCK_ATTR_ROOT).getAttr(id);
15
14
  return isNodeLike(v) ? v : null;
16
15
  };
17
16
  const blockNodeOf = (doc, id) => {
@@ -19,7 +18,7 @@ const blockNodeOf = (doc, id) => {
19
18
  return isNodeLike(v) ? v : null;
20
19
  };
21
20
  /**
22
- * Reads resolve whatever record node the `b/<id>` attr currently elects.
21
+ * Reads resolve whatever record node the block's attr currently elects.
23
22
  * Isolation is enforced on the WRITE side — `ensureRecord` swaps a fresh
24
23
  * record in when the attr winner's incarnation stamp doesn't match the live
25
24
  * block node's nonce — and the attr winner is already convergent.
@@ -74,7 +73,7 @@ export const blockAttributionOf = (doc, id) => {
74
73
  export const bindBlockAttribution = (Y) => {
75
74
  const newNode = (name) => makeNode(Y, name);
76
75
  /**
77
- * Get-or-create the `b/<id>` record for `node`'s incarnation (its nonce).
76
+ * Get-or-create the record for `node`'s incarnation (its nonce).
78
77
  * A record stamped for another incarnation is dead state — a fresh record
79
78
  * replaces it as the attr winner (the orphan stays readable only as the
80
79
  * last-incarnation fallback). `node` defaults to the id's current registry
@@ -87,7 +86,7 @@ export const bindBlockAttribution = (Y) => {
87
86
  return existing;
88
87
  }
89
88
  const rec = newNode(REC_NODE);
90
- doc.get(BLOCK_ATTR_ROOT).setAttr(recKey(id), rec);
89
+ doc.get(BLOCK_ATTR_ROOT).setAttr(id, rec);
91
90
  if (n !== undefined)
92
91
  rec.setAttr(INCARNATION_KEY, n);
93
92
  return rec;
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Public surface of the attribution service. `block.ts` holds the
3
- * compact per-block records (`b/<blockId>` + the block-node `l` attr)
3
+ * compact per-block records (`blockattr` `<blockId>` + the block-node `l` attr)
4
4
  * written inside the owning facade op's transaction. `attribution.ts`
5
5
  * holds the actor dictionary (`u/`/`c/`) plus inert reads over
6
6
  * pre-existing `a/` per-edit records written by retired builds.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Public surface of the attribution service. `block.ts` holds the
3
- * compact per-block records (`b/<blockId>` + the block-node `l` attr)
3
+ * compact per-block records (`blockattr` `<blockId>` + the block-node `l` attr)
4
4
  * written inside the owning facade op's transaction. `attribution.ts`
5
5
  * holds the actor dictionary (`u/`/`c/`) plus inert reads over
6
6
  * pre-existing `a/` per-edit records written by retired builds.
@@ -5,27 +5,30 @@
5
5
  * leaf's path as an RFC 6901 pointer without its leading `/` (`~` → `~0`,
6
6
  * `/` → `~1`). A leaf is a primitive, `null` or an empty container (`{}`,
7
7
  * `[]`), so an emptied one persists. An array is its `[]` leaf plus its
8
- * items, as `Y.Array` holds them: item `id` keeps its value under the
9
- * segment `~id` (a primitive at it, an object's or array's leaves under it)
10
- * and its place in the rank `~id#` (`placement/rank.ts`), a move's in
11
- * `~id>`; `~` and a letter is no escape, so no key reads as an item. Each
12
- * attr is a map entry, so different keys and different items merge, one
13
- * key is last writer wins, and an item lives while its first rank does: a
14
- * delete removes its ranks and leaves, so a concurrent edit inside it or
15
- * move of it leaves orphans the read skips. A path names an item by index
16
- * or by id, so a held item is reached wherever peers moved it; an id that
17
- * names no live item (removed, or its array gone) refuses the patch, so
18
- * nothing is written under a dead item. A key starting with `~` is `~0…`
19
- * in a path (`keySegment`).
8
+ * items: item `id` keeps its value under the segment `~id` (a primitive at
9
+ * it, an object's or array's leaves under it), and its existence and place
10
+ * are its SLOT `{ p, i }` in the owner's one order sequence — the node's
11
+ * list part (`placement/slots.ts`, fork patch YP22): an item lives while a
12
+ * live slot of its id does (the first live slot of an id counts: two peers
13
+ * adopting one array write two), the order is the sequence's, and a move is
14
+ * a move record there. `~` and a letter is no escape, so no key reads as an
15
+ * item. Each leaf is a map entry, so different keys and different items
16
+ * merge and one key is last writer wins; a delete removes the item's slots
17
+ * and leaves, so a concurrent edit inside it or move of it leaves orphans
18
+ * the read skips. A path names an item by index or by id, so a held item
19
+ * is reached wherever peers moved it; an id that names no live item
20
+ * refuses the patch, so nothing is written under a dead item. A key
21
+ * starting with `~` is `~0…` in a path (`keySegment`).
20
22
  *
21
23
  * Read rule: the leaves are read as a tree; a path with live items is an
22
- * array (sorted by rank, then id), one with keys an object (it beats a
23
- * primitive leaf at the same path: Ada sets `a = 1` while Bob sets
24
- * `a.b = 2`), else its leaf. A leaf holding an object or an array (an
25
- * atomic path's, `data.atomic`, or an array 0.1.0-next.6 wrote) reads as
26
- * its keys or as items with ids and ranks derived from the array (as any
27
- * array assigned where no item is), so two replicas writing into it write
28
- * the same items; a patch opens it only along its path.
24
+ * array (in slot order), one with keys an object (it beats a primitive leaf
25
+ * at the same path: Ada sets `a = 1` while Bob sets `a.b = 2`), else its
26
+ * leaf. A leaf holding an object or an array (an atomic path's,
27
+ * `data.atomic`, or an array 0.1.0-next.6 wrote) reads as its keys or as
28
+ * items with ids derived from the array (as any array assigned where no
29
+ * item is), so two replicas writing into it write the same items; a patch
30
+ * opens it only along its path, and the first write through it gives every
31
+ * item its slot.
29
32
  */
30
33
  import type { EngineNode } from './engine-api.js';
31
34
  type JsonObj = Record<string, unknown>;
@@ -43,6 +46,28 @@ export type DataPatch = {
43
46
  };
44
47
  /** An attr write a patch plans: the key and its value, `undefined` to delete it. */
45
48
  export type LeafWrite = readonly [key: string, value: unknown];
49
+ /**
50
+ * A sequence write a patch plans (`placement/slots.ts`): new items' slots
51
+ * after item `after` (`null`: first) of the array at `path`, a move of items
52
+ * there, or the removal of items' slots.
53
+ */
54
+ export type SlotWrite = {
55
+ seq: 'insert';
56
+ path: string;
57
+ after: string | null;
58
+ ids: string[];
59
+ } | {
60
+ seq: 'move';
61
+ path: string;
62
+ after: string | null;
63
+ ids: string[];
64
+ } | {
65
+ seq: 'remove';
66
+ path: string;
67
+ ids: string[];
68
+ };
69
+ /** One write a data patch plans. */
70
+ export type DataWrite = LeafWrite | SlotWrite;
46
71
  export declare const isObject: (v: unknown) => v is JsonObj;
47
72
  /**
48
73
  * Key `k` as a patch path segment: a leading `~` as `~0` (RFC 6901), so a
@@ -62,8 +87,8 @@ export declare const segmentKey: (s: string) => string;
62
87
  * `arrange` pairs those items by position.
63
88
  */
64
89
  export declare const common: (a: readonly string[], b: readonly string[]) => [number, number][];
65
- /** A new node's data, as leaves. */
66
- export declare const dataLeaves: (data: unknown) => Map<string, unknown>;
90
+ /** A new node's data, as the writes that give it (its leaves and its arrays' slots). */
91
+ export declare const dataWrites: (data: unknown) => DataWrite[];
67
92
  /** A path of the data as a leaf key (`d/` and its pointer). */
68
93
  export declare const leafKey: (path: readonly string[]) => string;
69
94
  /** `node`'s data (`undefined` when it has none). */
@@ -76,7 +101,7 @@ export declare const itemIds: (node: EngineNode, path: readonly string[]) => str
76
101
  /**
77
102
  * `node`'s data as it reads once `patches` are applied (nothing written),
78
103
  * with the ids of the array items at a path (`itemIds`): an item a patch
79
- * makes has no id yet (`''`), so a later patch names it by index.
104
+ * makes has no slot yet (`''`), so a later patch names it by index.
80
105
  * `null` when a patch fits no value.
81
106
  */
82
107
  export declare const previewData: (node: EngineNode | undefined, patches: readonly DataPatch[]) => {
@@ -86,14 +111,20 @@ export declare const previewData: (node: EngineNode | undefined, patches: readon
86
111
  /** `data` with `patches` applied in order, as a fresh value (a root patch replaces it); `null` when one fits no value. */
87
112
  export declare const applyPatch: (data: JsonObj, patches: readonly DataPatch[]) => JsonObj | null;
88
113
  /**
89
- * The attr writes that give `node` the data `patches` make of its own (new
90
- * items get ids from `rand`, ranks from `client`), or `null` when a patch
91
- * fits no value there: only the leaves of the keys and items a patch
92
- * touches change, so a concurrent edit of another key or item is kept. An
93
- * atomic path is written as one leaf and the leaves under it are deleted.
94
- * An unchanged value writes nothing.
114
+ * The writes that give `node` the data `patches` make of its own (new
115
+ * items get ids from `rand`), or `null` when a patch fits no value there:
116
+ * only the leaves of the keys and items a patch touches change, so a
117
+ * concurrent edit of another key or item is kept, and only the slots of
118
+ * the items it makes, moves or removes. An atomic path is written as one
119
+ * leaf and the leaves and slots under it are dropped. An unchanged value
120
+ * writes nothing.
121
+ */
122
+ export declare const patchWrites: (node: EngineNode, patches: readonly DataPatch[], client?: number, rand?: () => number, atomic?: readonly string[]) => DataWrite[] | null;
123
+ /**
124
+ * Write `writes` on `node`: its attrs, and its arrays' slots in its one
125
+ * sequence (`placement/slots.ts`). On a detached node (a block or atom being
126
+ * created) the slots are appended in order; on an integrated one each write
127
+ * goes after the item it names, read from the sequence as it stands.
95
128
  */
96
- export declare const patchWrites: (node: EngineNode, patches: readonly DataPatch[], client?: number, rand?: () => number, atomic?: readonly string[]) => LeafWrite[] | null;
97
- /** Write `writes` on `node` (a detached one too: a block or atom being created). */
98
- export declare const writeLeaves: (node: EngineNode, writes: Iterable<LeafWrite>) => void;
129
+ export declare const writeData: (node: EngineNode, writes: Iterable<DataWrite>) => void;
99
130
  export {};