@rocicorp/zero 1.6.0-canary.0 → 1.6.0-canary.2

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 (38) hide show
  1. package/out/analyze-query/src/analyze-cli.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/zero/package.js +1 -1
  4. package/out/zero/package.js.map +1 -1
  5. package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
  6. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  7. package/out/zero-cache/src/services/change-source/pg/change-source.js +13 -4
  8. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  9. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  10. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +8 -1
  11. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  12. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +1 -1
  13. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  14. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +10 -19
  15. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  16. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +1 -1
  17. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
  18. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
  19. package/out/zero-cache/src/services/change-source/pg/schema/init.js +9 -9
  20. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
  21. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +3 -3
  22. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  23. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js +7 -0
  24. package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
  25. package/out/zero-cache/src/workers/connection.js +2 -2
  26. package/out/zero-cache/src/workers/connection.js.map +1 -1
  27. package/out/zero-client/src/client/version.js +1 -1
  28. package/out/zql/src/builder/builder.d.ts.map +1 -1
  29. package/out/zql/src/builder/builder.js +7 -17
  30. package/out/zql/src/builder/builder.js.map +1 -1
  31. package/out/zql/src/ivm/memory-source.js +1 -1
  32. package/out/zql/src/ivm/take.js +2 -2
  33. package/out/zqlite/src/table-source.js +1 -1
  34. package/package.json +1 -1
  35. package/out/zql/src/ivm/cap.d.ts +0 -32
  36. package/out/zql/src/ivm/cap.d.ts.map +0 -1
  37. package/out/zql/src/ivm/cap.js +0 -205
  38. package/out/zql/src/ivm/cap.js.map +0 -1
@@ -4,12 +4,12 @@ import { once, toSorted } from "../../../shared/src/iterables.js";
4
4
  import { must } from "../../../shared/src/must.js";
5
5
  import { skipYields } from "./skip-yields.js";
6
6
  import { makeAddChange, makeEditChange, makeRemoveChange } from "./change.js";
7
- import { assertOrderingIncludesPK } from "../query/complete-ordering.js";
8
7
  import { compareValues, makeComparator, valuesEqual } from "./data.js";
9
8
  import { filterPush } from "./filter-push.js";
10
9
  import { constraintMatchesPrimaryKey, constraintMatchesRow, primaryKeyConstraintFromFilters } from "./constraint.js";
11
10
  import { BTreeSet } from "../../../shared/src/btree-set.js";
12
11
  import { createPredicate, transformFilters } from "../builder/filter.js";
12
+ import { assertOrderingIncludesPK } from "../query/complete-ordering.js";
13
13
  import { makeSourceChangeAdd, makeSourceChangeRemove } from "./source.js";
14
14
  //#region ../zql/src/ivm/memory-source.ts
15
15
  /**
@@ -2,8 +2,8 @@ import { assert, unreachable } from "../../../shared/src/asserts.js";
2
2
  import { hasOwn } from "../../../shared/src/has-own.js";
3
3
  import { throwOutput } from "./operator.js";
4
4
  import { makeAddChange, makeRemoveChange } from "./change.js";
5
- import { assertOrderingIncludesPK } from "../query/complete-ordering.js";
6
5
  import { compareValues } from "./data.js";
6
+ import { assertOrderingIncludesPK } from "../query/complete-ordering.js";
7
7
  //#region ../zql/src/ivm/take.ts
8
8
  var MAX_BOUND_KEY = "maxBound";
9
9
  /**
@@ -405,6 +405,6 @@ function makePartitionKeyComparator(partitionKey) {
405
405
  };
406
406
  }
407
407
  //#endregion
408
- export { Take, constraintMatchesPartitionKey, makePartitionKeyComparator };
408
+ export { Take };
409
409
 
410
410
  //# sourceMappingURL=take.js.map
@@ -1,8 +1,8 @@
1
1
  import { assert, unreachable } from "../../shared/src/asserts.js";
2
2
  import { must } from "../../shared/src/must.js";
3
- import { assertOrderingIncludesPK } from "../../zql/src/query/complete-ordering.js";
4
3
  import { makeComparator } from "../../zql/src/ivm/data.js";
5
4
  import { createPredicate, transformFilters } from "../../zql/src/builder/filter.js";
5
+ import { assertOrderingIncludesPK } from "../../zql/src/query/complete-ordering.js";
6
6
  import { genPushAndWriteWithSplitEdit, generateWithOverlay, generateWithOverlayUnordered, generateWithStart } from "../../zql/src/ivm/memory-source.js";
7
7
  import { timeSampled } from "../../otel/src/maybe-time.js";
8
8
  import { compile, format, sql } from "./internal/sql.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rocicorp/zero",
3
- "version": "1.6.0-canary.0",
3
+ "version": "1.6.0-canary.2",
4
4
  "description": "Zero is a web framework for serverless web development.",
5
5
  "homepage": "https://zero.rocicorp.dev",
6
6
  "bugs": {
@@ -1,32 +0,0 @@
1
- import { type Change } from './change.ts';
2
- import type { Node } from './data.ts';
3
- import { type FetchRequest, type Input, type Operator, type Output, type Storage } from './operator.ts';
4
- import type { SourceSchema } from './schema.ts';
5
- import { type Stream } from './stream.ts';
6
- import { type PartitionKey } from './take.ts';
7
- /**
8
- * The Cap operator is a count-based limiter for EXISTS subqueries that
9
- * does not require ordering. Unlike Take, it tracks membership by primary
10
- * key set rather than by a sorted bound. This means:
11
- *
12
- * - No comparator needed (no ordering requirement)
13
- * - No `start` or `reverse` fetch support
14
- * - No `#rowHiddenFromFetch` complexity (we can defer when adding to the pk set)
15
- *
16
- * Cap is used in EXISTS child pipelines where only the count of matching
17
- * rows matters, not their order. This allows SQLite to skip ORDER BY
18
- * entirely, enabling much faster query plans.
19
- *
20
- * Cap can count rows globally or by unique value of some partition key
21
- * (same as Take).
22
- */
23
- export declare class Cap implements Operator {
24
- #private;
25
- constructor(input: Input, storage: Storage, limit: number, partitionKey?: PartitionKey);
26
- setOutput(output: Output): void;
27
- getSchema(): SourceSchema;
28
- fetch(req: FetchRequest): Stream<Node | 'yield'>;
29
- push(change: Change): Stream<'yield'>;
30
- destroy(): void;
31
- }
32
- //# sourceMappingURL=cap.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cap.d.ts","sourceRoot":"","sources":["../../../../../zql/src/ivm/cap.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,MAAM,EAAkB,MAAM,aAAa,CAAC;AAExE,OAAO,KAAK,EAAa,IAAI,EAAC,MAAM,WAAW,CAAC;AAChD,OAAO,EAEL,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,OAAO,EACb,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,aAAa,CAAC;AACxC,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,WAAW,CAAC;AAanB;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,GAAI,YAAW,QAAQ;;gBAWhC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,YAAY;IAa7B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,SAAS,IAAI,YAAY;IAIxB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAAC,IAAI,GAAG,OAAO,CAAC;IA0FhD,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;IAsHtC,OAAO,IAAI,IAAI;CAGhB"}
@@ -1,205 +0,0 @@
1
- import { assert } from "../../../shared/src/asserts.js";
2
- import { throwOutput } from "./operator.js";
3
- import { makeAddChange } from "./change.js";
4
- import { constraintMatchesPartitionKey, makePartitionKeyComparator } from "./take.js";
5
- //#region ../zql/src/ivm/cap.ts
6
- /**
7
- * The Cap operator is a count-based limiter for EXISTS subqueries that
8
- * does not require ordering. Unlike Take, it tracks membership by primary
9
- * key set rather than by a sorted bound. This means:
10
- *
11
- * - No comparator needed (no ordering requirement)
12
- * - No `start` or `reverse` fetch support
13
- * - No `#rowHiddenFromFetch` complexity (we can defer when adding to the pk set)
14
- *
15
- * Cap is used in EXISTS child pipelines where only the count of matching
16
- * rows matters, not their order. This allows SQLite to skip ORDER BY
17
- * entirely, enabling much faster query plans.
18
- *
19
- * Cap can count rows globally or by unique value of some partition key
20
- * (same as Take).
21
- */
22
- var Cap = class {
23
- #input;
24
- #storage;
25
- #limit;
26
- #partitionKey;
27
- #partitionKeyComparator;
28
- #primaryKey;
29
- #output = throwOutput;
30
- constructor(input, storage, limit, partitionKey) {
31
- assert(limit >= 0, "Limit must be non-negative");
32
- input.setOutput(this);
33
- this.#input = input;
34
- this.#storage = storage;
35
- this.#limit = limit;
36
- this.#partitionKey = partitionKey;
37
- this.#partitionKeyComparator = partitionKey && makePartitionKeyComparator(partitionKey);
38
- this.#primaryKey = input.getSchema().primaryKey;
39
- }
40
- setOutput(output) {
41
- this.#output = output;
42
- }
43
- getSchema() {
44
- return this.#input.getSchema();
45
- }
46
- *fetch(req) {
47
- assert(!req.start, "Cap does not support start");
48
- assert(!req.reverse, "Cap does not support reverse");
49
- assert(!this.#partitionKey || req.constraint !== void 0 && constraintMatchesPartitionKey(req.constraint, this.#partitionKey), "Cap fetch: constraint must match partition key when partitioned");
50
- const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);
51
- const capState = this.#storage.get(capStateKey);
52
- if (!capState) {
53
- yield* this.#initialFetch(req);
54
- return;
55
- }
56
- if (capState.size === 0) return;
57
- for (const pk of capState.pks) {
58
- const constraint = deserializePKToConstraint(pk, this.#primaryKey);
59
- for (const inputNode of this.#input.fetch({ constraint })) {
60
- if (inputNode === "yield") {
61
- yield inputNode;
62
- continue;
63
- }
64
- yield inputNode;
65
- }
66
- }
67
- }
68
- *#initialFetch(req) {
69
- if (this.#limit === 0) return;
70
- assert(constraintMatchesPartitionKey(req.constraint, this.#partitionKey), "Constraint should match partition key");
71
- const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);
72
- assert(this.#storage.get(capStateKey) === void 0, "Cap state should be undefined");
73
- let size = 0;
74
- const pks = [];
75
- let downstreamEarlyReturn = true;
76
- let exceptionThrown = false;
77
- try {
78
- for (const inputNode of this.#input.fetch(req)) {
79
- if (inputNode === "yield") {
80
- yield "yield";
81
- continue;
82
- }
83
- yield inputNode;
84
- pks.push(serializePK(inputNode.row, this.#primaryKey));
85
- size++;
86
- if (size === this.#limit) break;
87
- }
88
- downstreamEarlyReturn = false;
89
- } catch (e) {
90
- exceptionThrown = true;
91
- throw e;
92
- } finally {
93
- if (!exceptionThrown) {
94
- this.#storage.set(capStateKey, {
95
- size,
96
- pks
97
- });
98
- assert(!downstreamEarlyReturn, "Unexpected early return prevented full hydration");
99
- }
100
- }
101
- }
102
- *push(change) {
103
- if (change[0] === 2) {
104
- yield* this.#pushEditChange(change);
105
- return;
106
- }
107
- const capStateKey = getCapStateKey(this.#partitionKey, change[1].row);
108
- const capState = this.#storage.get(capStateKey);
109
- if (!capState) return;
110
- const pk = serializePK(change[1].row, this.#primaryKey);
111
- if (change[0] === 0) {
112
- if (capState.size < this.#limit) {
113
- const pks = [...capState.pks, pk];
114
- this.#storage.set(capStateKey, {
115
- size: capState.size + 1,
116
- pks
117
- });
118
- yield* this.#output.push(change, this);
119
- return;
120
- }
121
- return;
122
- } else if (change[0] === 1) {
123
- const pkIndex = capState.pks.indexOf(pk);
124
- if (pkIndex === -1) return;
125
- const pks = [...capState.pks];
126
- pks.splice(pkIndex, 1);
127
- const newSize = capState.size - 1;
128
- const pkSet = new Set(pks);
129
- const constraint = this.#partitionKey ? Object.fromEntries(this.#partitionKey.map((key) => [key, change[1].row[key]])) : void 0;
130
- let replacement;
131
- for (const node of this.#input.fetch({ constraint })) {
132
- if (node === "yield") {
133
- yield node;
134
- continue;
135
- }
136
- const nodePK = serializePK(node.row, this.#primaryKey);
137
- if (!pkSet.has(nodePK)) {
138
- replacement = node;
139
- break;
140
- }
141
- }
142
- if (replacement) {
143
- this.#storage.set(capStateKey, {
144
- size: newSize,
145
- pks
146
- });
147
- yield* this.#output.push(change, this);
148
- const replacementPK = serializePK(replacement.row, this.#primaryKey);
149
- pks.push(replacementPK);
150
- this.#storage.set(capStateKey, {
151
- size: newSize + 1,
152
- pks
153
- });
154
- yield* this.#output.push(makeAddChange(replacement), this);
155
- } else {
156
- this.#storage.set(capStateKey, {
157
- size: newSize,
158
- pks
159
- });
160
- yield* this.#output.push(change, this);
161
- }
162
- } else if (change[0] === 3) {
163
- if (new Set(capState.pks).has(pk)) yield* this.#output.push(change, this);
164
- }
165
- }
166
- *#pushEditChange(change) {
167
- assert(!this.#partitionKeyComparator || this.#partitionKeyComparator(change[2].row, change[1].row) === 0, "Unexpected change of partition key");
168
- const capStateKey = getCapStateKey(this.#partitionKey, change[2].row);
169
- const capState = this.#storage.get(capStateKey);
170
- if (!capState) return;
171
- const oldPK = serializePK(change[2].row, this.#primaryKey);
172
- if (new Set(capState.pks).has(oldPK)) {
173
- const newPK = serializePK(change[1].row, this.#primaryKey);
174
- if (oldPK !== newPK) {
175
- const pks = capState.pks.map((p) => p === oldPK ? newPK : p);
176
- this.#storage.set(capStateKey, {
177
- size: capState.size,
178
- pks
179
- });
180
- }
181
- yield* this.#output.push(change, this);
182
- }
183
- }
184
- destroy() {
185
- this.#input.destroy();
186
- }
187
- };
188
- function getCapStateKey(partitionKey, rowOrConstraint) {
189
- const partitionValues = [];
190
- if (partitionKey && rowOrConstraint) for (const key of partitionKey) partitionValues.push(rowOrConstraint[key]);
191
- return JSON.stringify(["cap", ...partitionValues]);
192
- }
193
- function serializePK(row, primaryKey) {
194
- return JSON.stringify(primaryKey.map((k) => row[k]));
195
- }
196
- function deserializePKToConstraint(pk, primaryKey) {
197
- const values = JSON.parse(pk);
198
- const constraint = {};
199
- for (let i = 0; i < primaryKey.length; i++) constraint[primaryKey[i]] = values[i];
200
- return constraint;
201
- }
202
- //#endregion
203
- export { Cap };
204
-
205
- //# sourceMappingURL=cap.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cap.js","names":["#input","#storage","#limit","#partitionKey","#partitionKeyComparator","#primaryKey","#output","#initialFetch","#pushEditChange"],"sources":["../../../../../zql/src/ivm/cap.ts"],"sourcesContent":["import {assert} from '../../../shared/src/asserts.ts';\nimport type {Row, Value} from '../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../zero-protocol/src/primary-key.ts';\nimport {ChangeIndex} from './change-index.ts';\nimport {ChangeType} from './change-type.ts';\nimport {makeAddChange, type Change, type EditChange} from './change.ts';\nimport type {Constraint} from './constraint.ts';\nimport type {Comparator, Node} from './data.ts';\nimport {\n throwOutput,\n type FetchRequest,\n type Input,\n type Operator,\n type Output,\n type Storage,\n} from './operator.ts';\nimport type {SourceSchema} from './schema.ts';\nimport {type Stream} from './stream.ts';\nimport {\n constraintMatchesPartitionKey,\n makePartitionKeyComparator,\n type PartitionKey,\n} from './take.ts';\n\ntype CapState = {\n size: number;\n pks: string[];\n};\n\ninterface CapStorage {\n get(key: string): CapState | undefined;\n set(key: string, value: CapState): void;\n del(key: string): void;\n}\n\n/**\n * The Cap operator is a count-based limiter for EXISTS subqueries that\n * does not require ordering. Unlike Take, it tracks membership by primary\n * key set rather than by a sorted bound. This means:\n *\n * - No comparator needed (no ordering requirement)\n * - No `start` or `reverse` fetch support\n * - No `#rowHiddenFromFetch` complexity (we can defer when adding to the pk set)\n *\n * Cap is used in EXISTS child pipelines where only the count of matching\n * rows matters, not their order. This allows SQLite to skip ORDER BY\n * entirely, enabling much faster query plans.\n *\n * Cap can count rows globally or by unique value of some partition key\n * (same as Take).\n */\nexport class Cap implements Operator {\n readonly #input: Input;\n readonly #storage: CapStorage;\n readonly #limit: number;\n readonly #partitionKey: PartitionKey | undefined;\n readonly #partitionKeyComparator: Comparator | undefined;\n readonly #primaryKey: PrimaryKey;\n\n #output: Output = throwOutput;\n\n constructor(\n input: Input,\n storage: Storage,\n limit: number,\n partitionKey?: PartitionKey,\n ) {\n assert(limit >= 0, 'Limit must be non-negative');\n input.setOutput(this);\n this.#input = input;\n this.#storage = storage as CapStorage;\n this.#limit = limit;\n this.#partitionKey = partitionKey;\n this.#partitionKeyComparator =\n partitionKey && makePartitionKeyComparator(partitionKey);\n this.#primaryKey = input.getSchema().primaryKey;\n }\n\n setOutput(output: Output): void {\n this.#output = output;\n }\n\n getSchema(): SourceSchema {\n return this.#input.getSchema();\n }\n\n *fetch(req: FetchRequest): Stream<Node | 'yield'> {\n assert(!req.start, 'Cap does not support start');\n assert(!req.reverse, 'Cap does not support reverse');\n\n // Cap is only built for non-flipped EXISTS subqueries, whose only\n // downstream consumer is a Join that always fetches with a constraint\n // built from the correlation's childField — which is Cap's partition\n // key. So either partitionKey is undefined, or constraint matches.\n assert(\n !this.#partitionKey ||\n (req.constraint !== undefined &&\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey)),\n 'Cap fetch: constraint must match partition key when partitioned',\n );\n\n const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n yield* this.#initialFetch(req);\n return;\n }\n if (capState.size === 0) {\n return;\n }\n // PK-based point lookups: fetch each tracked row by its PK directly,\n // rather than scanning the partition and filtering.\n for (const pk of capState.pks) {\n const constraint = deserializePKToConstraint(pk, this.#primaryKey);\n for (const inputNode of this.#input.fetch({constraint})) {\n if (inputNode === 'yield') {\n yield inputNode;\n continue;\n }\n yield inputNode;\n }\n }\n }\n\n *#initialFetch(req: FetchRequest): Stream<Node | 'yield'> {\n if (this.#limit === 0) {\n return;\n }\n\n assert(\n constraintMatchesPartitionKey(req.constraint, this.#partitionKey),\n 'Constraint should match partition key',\n );\n\n const capStateKey = getCapStateKey(this.#partitionKey, req.constraint);\n assert(\n this.#storage.get(capStateKey) === undefined,\n 'Cap state should be undefined',\n );\n\n let size = 0;\n const pks: string[] = [];\n let downstreamEarlyReturn = true;\n let exceptionThrown = false;\n try {\n for (const inputNode of this.#input.fetch(req)) {\n if (inputNode === 'yield') {\n yield 'yield';\n continue;\n }\n yield inputNode;\n pks.push(serializePK(inputNode.row, this.#primaryKey));\n size++;\n if (size === this.#limit) {\n break;\n }\n }\n downstreamEarlyReturn = false;\n } catch (e) {\n exceptionThrown = true;\n throw e;\n } finally {\n if (!exceptionThrown) {\n this.#storage.set(capStateKey, {size, pks});\n // If it becomes necessary to support downstream early return, this\n // assert should be removed, and replaced with code that consumes\n // the input stream until limit is reached or the input stream is\n // exhausted so that capState is properly hydrated.\n assert(\n !downstreamEarlyReturn,\n 'Unexpected early return prevented full hydration',\n );\n }\n }\n }\n\n *push(change: Change): Stream<'yield'> {\n if (change[ChangeIndex.TYPE] === ChangeType.EDIT) {\n yield* this.#pushEditChange(change);\n return;\n }\n\n const capStateKey = getCapStateKey(\n this.#partitionKey,\n change[ChangeIndex.NODE].row,\n );\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n return;\n }\n\n const pk = serializePK(change[ChangeIndex.NODE].row, this.#primaryKey);\n\n if (change[ChangeIndex.TYPE] === ChangeType.ADD) {\n if (capState.size < this.#limit) {\n const pks = [...capState.pks, pk];\n this.#storage.set(capStateKey, {size: capState.size + 1, pks});\n yield* this.#output.push(change, this);\n return;\n }\n // Full — drop\n return;\n } else if (change[ChangeIndex.TYPE] === ChangeType.REMOVE) {\n const pkIndex = capState.pks.indexOf(pk);\n if (pkIndex === -1) {\n // Not in our set — drop\n return;\n }\n // Remove from set\n const pks = [...capState.pks];\n pks.splice(pkIndex, 1);\n const newSize = capState.size - 1;\n\n // Try to refill: fetch from input with partition constraint,\n // find first row NOT in PK set\n const pkSet = new Set(pks);\n const constraint = this.#partitionKey\n ? (Object.fromEntries(\n this.#partitionKey.map(\n key => [key, change[ChangeIndex.NODE].row[key]] as const,\n ),\n ) as Constraint)\n : undefined;\n\n let replacement: Node | undefined;\n for (const node of this.#input.fetch({constraint})) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const nodePK = serializePK(node.row, this.#primaryKey);\n if (!pkSet.has(nodePK)) {\n replacement = node;\n break;\n }\n }\n\n if (replacement) {\n // Store state WITHOUT replacement during remove forward,\n // matching Take's pattern of hiding in-flight changes from re-fetches.\n this.#storage.set(capStateKey, {size: newSize, pks});\n yield* this.#output.push(change, this);\n // Now add replacement to set and forward the add.\n const replacementPK = serializePK(replacement.row, this.#primaryKey);\n pks.push(replacementPK);\n this.#storage.set(capStateKey, {size: newSize + 1, pks});\n yield* this.#output.push(makeAddChange(replacement), this);\n } else {\n this.#storage.set(capStateKey, {size: newSize, pks});\n yield* this.#output.push(change, this);\n }\n } else if (change[ChangeIndex.TYPE] === ChangeType.CHILD) {\n const pkSet = new Set(capState.pks);\n if (pkSet.has(pk)) {\n yield* this.#output.push(change, this);\n }\n }\n }\n\n *#pushEditChange(change: EditChange): Stream<'yield'> {\n assert(\n !this.#partitionKeyComparator ||\n this.#partitionKeyComparator(\n change[ChangeIndex.OLD_NODE].row,\n change[ChangeIndex.NODE].row,\n ) === 0,\n 'Unexpected change of partition key',\n );\n const capStateKey = getCapStateKey(\n this.#partitionKey,\n change[ChangeIndex.OLD_NODE].row,\n );\n const capState = this.#storage.get(capStateKey);\n if (!capState) {\n return;\n }\n\n const oldPK = serializePK(\n change[ChangeIndex.OLD_NODE].row,\n this.#primaryKey,\n );\n const pkSet = new Set(capState.pks);\n if (pkSet.has(oldPK)) {\n // Update the PK in our set if it changed\n const newPK = serializePK(change[ChangeIndex.NODE].row, this.#primaryKey);\n if (oldPK !== newPK) {\n const pks = capState.pks.map(p => (p === oldPK ? newPK : p));\n this.#storage.set(capStateKey, {size: capState.size, pks});\n }\n yield* this.#output.push(change, this);\n }\n // If not in our set, drop\n }\n\n destroy(): void {\n this.#input.destroy();\n }\n}\n\nfunction getCapStateKey(\n partitionKey: PartitionKey | undefined,\n rowOrConstraint: Row | Constraint | undefined,\n): string {\n const partitionValues: Value[] = [];\n\n if (partitionKey && rowOrConstraint) {\n for (const key of partitionKey) {\n partitionValues.push(rowOrConstraint[key]);\n }\n }\n\n return JSON.stringify(['cap', ...partitionValues]);\n}\n\nfunction serializePK(row: Row, primaryKey: PrimaryKey): string {\n return JSON.stringify(primaryKey.map(k => row[k]));\n}\n\nfunction deserializePKToConstraint(\n pk: string,\n primaryKey: PrimaryKey,\n): Constraint {\n const values = JSON.parse(pk) as Value[];\n const constraint: Record<string, Value> = {};\n for (let i = 0; i < primaryKey.length; i++) {\n constraint[primaryKey[i]] = values[i];\n }\n return constraint;\n}\n"],"mappings":"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"}