@quereus/sync 4.3.2 → 4.4.1

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 (78) hide show
  1. package/README.md +19 -1
  2. package/dist/src/create-sync-module.d.ts +11 -1
  3. package/dist/src/create-sync-module.d.ts.map +1 -1
  4. package/dist/src/create-sync-module.js +2 -2
  5. package/dist/src/create-sync-module.js.map +1 -1
  6. package/dist/src/index.d.ts +4 -3
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js +9 -3
  9. package/dist/src/index.js.map +1 -1
  10. package/dist/src/metadata/change-log.d.ts +39 -3
  11. package/dist/src/metadata/change-log.d.ts.map +1 -1
  12. package/dist/src/metadata/change-log.js +43 -8
  13. package/dist/src/metadata/change-log.js.map +1 -1
  14. package/dist/src/metadata/column-version.d.ts +62 -9
  15. package/dist/src/metadata/column-version.d.ts.map +1 -1
  16. package/dist/src/metadata/column-version.js +79 -25
  17. package/dist/src/metadata/column-version.js.map +1 -1
  18. package/dist/src/metadata/index.d.ts +1 -0
  19. package/dist/src/metadata/index.d.ts.map +1 -1
  20. package/dist/src/metadata/index.js +1 -0
  21. package/dist/src/metadata/index.js.map +1 -1
  22. package/dist/src/metadata/keys.d.ts +88 -22
  23. package/dist/src/metadata/keys.d.ts.map +1 -1
  24. package/dist/src/metadata/keys.js +134 -77
  25. package/dist/src/metadata/keys.js.map +1 -1
  26. package/dist/src/metadata/pk-identity.d.ts +60 -0
  27. package/dist/src/metadata/pk-identity.d.ts.map +1 -0
  28. package/dist/src/metadata/pk-identity.js +94 -0
  29. package/dist/src/metadata/pk-identity.js.map +1 -0
  30. package/dist/src/metadata/tombstones.d.ts +41 -11
  31. package/dist/src/metadata/tombstones.d.ts.map +1 -1
  32. package/dist/src/metadata/tombstones.js +58 -33
  33. package/dist/src/metadata/tombstones.js.map +1 -1
  34. package/dist/src/sync/change-applicator.d.ts +30 -1
  35. package/dist/src/sync/change-applicator.d.ts.map +1 -1
  36. package/dist/src/sync/change-applicator.js +161 -40
  37. package/dist/src/sync/change-applicator.js.map +1 -1
  38. package/dist/src/sync/maintenance.d.ts +70 -0
  39. package/dist/src/sync/maintenance.d.ts.map +1 -0
  40. package/dist/src/sync/maintenance.js +84 -0
  41. package/dist/src/sync/maintenance.js.map +1 -0
  42. package/dist/src/sync/protocol.d.ts +61 -10
  43. package/dist/src/sync/protocol.d.ts.map +1 -1
  44. package/dist/src/sync/protocol.js +15 -0
  45. package/dist/src/sync/protocol.js.map +1 -1
  46. package/dist/src/sync/snapshot-identity.d.ts +62 -0
  47. package/dist/src/sync/snapshot-identity.d.ts.map +1 -0
  48. package/dist/src/sync/snapshot-identity.js +88 -0
  49. package/dist/src/sync/snapshot-identity.js.map +1 -0
  50. package/dist/src/sync/snapshot-stream.d.ts +8 -1
  51. package/dist/src/sync/snapshot-stream.d.ts.map +1 -1
  52. package/dist/src/sync/snapshot-stream.js +166 -67
  53. package/dist/src/sync/snapshot-stream.js.map +1 -1
  54. package/dist/src/sync/snapshot.d.ts +1 -1
  55. package/dist/src/sync/snapshot.d.ts.map +1 -1
  56. package/dist/src/sync/snapshot.js +75 -44
  57. package/dist/src/sync/snapshot.js.map +1 -1
  58. package/dist/src/sync/staged-transaction-metadata.d.ts +75 -0
  59. package/dist/src/sync/staged-transaction-metadata.d.ts.map +1 -0
  60. package/dist/src/sync/staged-transaction-metadata.js +100 -0
  61. package/dist/src/sync/staged-transaction-metadata.js.map +1 -0
  62. package/dist/src/sync/store-adapter.d.ts +10 -4
  63. package/dist/src/sync/store-adapter.d.ts.map +1 -1
  64. package/dist/src/sync/store-adapter.js +244 -21
  65. package/dist/src/sync/store-adapter.js.map +1 -1
  66. package/dist/src/sync/sync-context.d.ts +54 -2
  67. package/dist/src/sync/sync-context.d.ts.map +1 -1
  68. package/dist/src/sync/sync-context.js +66 -0
  69. package/dist/src/sync/sync-context.js.map +1 -1
  70. package/dist/src/sync/sync-manager-impl.d.ts +70 -4
  71. package/dist/src/sync/sync-manager-impl.d.ts.map +1 -1
  72. package/dist/src/sync/sync-manager-impl.js +206 -36
  73. package/dist/src/sync/sync-manager-impl.js.map +1 -1
  74. package/dist/src/sync/wire.d.ts +47 -6
  75. package/dist/src/sync/wire.d.ts.map +1 -1
  76. package/dist/src/sync/wire.js +62 -11
  77. package/dist/src/sync/wire.js.map +1 -1
  78. package/package.json +6 -6
@@ -7,48 +7,64 @@
7
7
  import type { Row, SqlValue } from '@quereus/quereus';
8
8
  import type { KVStore, WriteBatch } from '@quereus/store';
9
9
  import { type HLC } from '../clock/hlc.js';
10
+ import type { PkKeyingResolver } from './pk-identity.js';
10
11
  /**
11
12
  * Tombstone record.
12
13
  */
13
14
  export interface Tombstone {
14
15
  hlc: HLC;
15
16
  createdAt: number;
17
+ /**
18
+ * The deleted row's ADDRESS — its raw primary-key values, one spelling from
19
+ * the row's equivalence class. UNCONDITIONAL (unlike `priorRow`): the record's
20
+ * key holds only the lossy pk identity, so the value is the only place the
21
+ * wire-transportable pk can come from.
22
+ */
23
+ pk: SqlValue[];
16
24
  /**
17
25
  * Optional last-known row image before deletion (the engine's `oldRow` at delete
18
26
  * time). Persisted so it reaches a receiver via `getChangesSince`, which
19
27
  * re-resolves deletions from the tombstone. Best-effort audit/undo metadata:
20
28
  * absent when the delete carried no `oldRow` and on snapshot-reconstructed
21
- * tombstones. A tombstone with no `priorRow` serializes to the fixed 38-byte head.
29
+ * tombstones.
22
30
  */
23
31
  priorRow?: Row;
24
32
  }
25
33
  /**
26
34
  * Serialize a tombstone for storage.
27
35
  *
28
- * Format: 30 bytes HLC + 8 bytes createdAt, then only when a `priorRow` is
29
- * present a trailing JSON array of the row's values, each through the column
30
- * version `encodeSqlValue` helper so `Uint8Array`/`bigint`/`null` cells round-trip.
31
- * A tombstone with no `priorRow` serializes to the unchanged 38-byte head.
36
+ * Format: 30 bytes HLC + 8 bytes createdAt + JSON payload `{ k, pr? }`
37
+ * (see {@link SerializedTombstonePayload}). The payload is unconditional the
38
+ * pk must always be recoverable from the value.
32
39
  */
33
40
  export declare function serializeTombstone(tombstone: Tombstone): Uint8Array;
34
41
  /**
35
- * Deserialize a tombstone from storage. Absent-tolerant: bytes beyond the 38-byte
36
- * head are the JSON-encoded `priorRow` (see {@link serializeTombstone}); a
37
- * head-only buffer (no before-image, or a snapshot-reconstructed tombstone)
38
- * deserializes with `priorRow` absent.
42
+ * Deserialize a tombstone from storage. The payload's `pr` (before-image) is
43
+ * optional; the pk is required (see {@link serializeTombstone}).
39
44
  */
40
45
  export declare function deserializeTombstone(buffer: Uint8Array): Tombstone;
41
46
  /**
42
47
  * Tombstone store operations.
48
+ *
49
+ * Every pk-taking method derives the record key's pk IDENTITY through the
50
+ * per-table {@link PkKeyingResolver} passed at construction, so callers keep
51
+ * addressing rows by raw pk while the storage keys collapse spellings.
43
52
  */
44
53
  export declare class TombstoneStore {
45
54
  private readonly kv;
46
55
  private readonly retentionHorizonMs;
47
- constructor(kv: KVStore, retentionHorizonMs: number);
56
+ private readonly keying;
57
+ constructor(kv: KVStore, retentionHorizonMs: number, keying: PkKeyingResolver);
58
+ private identity;
48
59
  /**
49
60
  * Get the tombstone for a row, if it exists.
50
61
  */
51
62
  getTombstone(schemaName: string, tableName: string, pk: SqlValue[]): Promise<Tombstone | undefined>;
63
+ /**
64
+ * Get the tombstone for a row by pk IDENTITY (as recovered from a parsed
65
+ * `tb:`/`cl:` key — no raw pk needed).
66
+ */
67
+ getTombstoneByIdentity(schemaName: string, tableName: string, identity: string): Promise<Tombstone | undefined>;
52
68
  /**
53
69
  * Create a tombstone for a deleted row. `priorRow` (optional) is the row's
54
70
  * last-known image, persisted as best-effort audit/undo metadata.
@@ -56,11 +72,19 @@ export declare class TombstoneStore {
56
72
  setTombstone(schemaName: string, tableName: string, pk: SqlValue[], hlc: HLC, priorRow?: Row): Promise<void>;
57
73
  /**
58
74
  * Set tombstone in a batch. `priorRow` (optional) is the row's last-known image,
59
- * persisted as best-effort audit/undo metadata.
75
+ * persisted as best-effort audit/undo metadata. The key's pk IDENTITY is always
76
+ * derived locally — no caller-supplied-identity variant exists (see
77
+ * `ColumnVersionStore.setColumnVersionBatch`).
60
78
  */
61
79
  setTombstoneBatch(batch: WriteBatch, schemaName: string, tableName: string, pk: SqlValue[], hlc: HLC, priorRow?: Row): void;
62
80
  /**
63
81
  * Delete a tombstone (used when resurrecting a row).
82
+ *
83
+ * NOTE: no production caller. If one is added, it must ALSO delete the paired
84
+ * `cl:` change-log delete entry (`changeLog.deleteEntryBatch(batch, tombstone.hlc,
85
+ * 'delete', schema, table, pk)`) in the same batch — otherwise the entry outlives
86
+ * its target and becomes permanent index garbage, the leak `SyncManagerImpl.
87
+ * pruneTombstones` was fixed to avoid.
64
88
  */
65
89
  deleteTombstone(schemaName: string, tableName: string, pk: SqlValue[]): Promise<void>;
66
90
  /**
@@ -71,6 +95,12 @@ export declare class TombstoneStore {
71
95
  /**
72
96
  * Prune expired tombstones.
73
97
  * Returns the number of tombstones deleted.
98
+ *
99
+ * NOTE: no production caller — `SyncManagerImpl.pruneTombstones` is the wired
100
+ * all-tables equivalent. If this per-table variant is wired up, it needs the same
101
+ * paired `cl:` change-log delete-entry removal that one does (see
102
+ * {@link deleteTombstone}); this store has no `ChangeLogStore` handle, so that
103
+ * would mean threading one in or moving the sweep up a level.
74
104
  */
75
105
  pruneExpired(schemaName: string, tableName: string): Promise<number>;
76
106
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tombstones.d.ts","sourceRoot":"","sources":["../../../src/metadata/tombstones.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,KAAK,GAAG,EAA4C,MAAM,iBAAiB,CAAC;AAOrF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAenE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAWlE;AAED;;GAEG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBADlB,EAAE,EAAE,OAAO,EACX,kBAAkB,EAAE,MAAM;IAG7C;;OAEG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,GACb,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAOjC;;;OAGG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,GAAG,EAAE,GAAG,EACR,QAAQ,CAAC,EAAE,GAAG,GACb,OAAO,CAAC,IAAI,CAAC;IAMhB;;;OAGG;IACH,iBAAiB,CACf,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,GAAG,EAAE,GAAG,EACR,QAAQ,CAAC,EAAE,GAAG,GACb,IAAI;IAMP;;OAEG;IACG,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,GACb,OAAO,CAAC,IAAI,CAAC;IAKhB;;;OAGG;IACG,oBAAoB,CACxB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,WAAW,EAAE,GAAG,EAChB,iBAAiB,EAAE,OAAO,GACzB,OAAO,CAAC,OAAO,CAAC;IAanB;;;OAGG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB1E;;OAEG;IACI,gBAAgB,CACrB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,aAAa,CAAC;QAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE,CAAC;CAc3D"}
1
+ {"version":3,"file":"tombstones.d.ts","sourceRoot":"","sources":["../../../src/metadata/tombstones.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,KAAK,GAAG,EAA4C,MAAM,iBAAiB,CAAC;AAGrF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAKzD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,EAAE,EAAE,QAAQ,EAAE,CAAC;IACf;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,GAAG,CAAC;CAChB;AAYD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAiBnE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAalE;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAFN,EAAE,EAAE,OAAO,EACX,kBAAkB,EAAE,MAAM,EAC1B,MAAM,EAAE,gBAAgB;IAG3C,OAAO,CAAC,QAAQ;IAIhB;;OAEG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,GACb,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAIjC;;;OAGG;IACG,sBAAsB,CAC1B,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAOjC;;;OAGG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,GAAG,EAAE,GAAG,EACR,QAAQ,CAAC,EAAE,GAAG,GACb,OAAO,CAAC,IAAI,CAAC;IAMhB;;;;;OAKG;IACH,iBAAiB,CACf,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,GAAG,EAAE,GAAG,EACR,QAAQ,CAAC,EAAE,GAAG,GACb,IAAI;IAMP;;;;;;;;OAQG;IACG,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,GACb,OAAO,CAAC,IAAI,CAAC;IAKhB;;;OAGG;IACG,oBAAoB,CACxB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,WAAW,EAAE,GAAG,EAChB,iBAAiB,EAAE,OAAO,GACzB,OAAO,CAAC,OAAO,CAAC;IAanB;;;;;;;;;OASG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB1E;;OAEG;IACI,gBAAgB,CACrB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,aAAa,CAAC;QAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE,CAAC;CAS3D"}
@@ -6,16 +6,15 @@
6
6
  */
7
7
  import { serializeHLC, deserializeHLC, compareHLC } from '../clock/hlc.js';
8
8
  import { encodeSqlValue, decodeSqlValue } from './column-version.js';
9
- import { buildTombstoneKey, buildTombstoneScanBounds, decodePK } from './keys.js';
9
+ import { buildTombstoneKey, buildTombstoneScanBounds, encodePkIdentity } from './keys.js';
10
10
  /** Fixed-size head of a serialized tombstone: 30 bytes HLC + 8 bytes createdAt. */
11
11
  const TOMBSTONE_HEAD_BYTES = 38;
12
12
  /**
13
13
  * Serialize a tombstone for storage.
14
14
  *
15
- * Format: 30 bytes HLC + 8 bytes createdAt, then only when a `priorRow` is
16
- * present a trailing JSON array of the row's values, each through the column
17
- * version `encodeSqlValue` helper so `Uint8Array`/`bigint`/`null` cells round-trip.
18
- * A tombstone with no `priorRow` serializes to the unchanged 38-byte head.
15
+ * Format: 30 bytes HLC + 8 bytes createdAt + JSON payload `{ k, pr? }`
16
+ * (see {@link SerializedTombstonePayload}). The payload is unconditional the
17
+ * pk must always be recoverable from the value.
19
18
  */
20
19
  export function serializeTombstone(tombstone) {
21
20
  const head = new Uint8Array(TOMBSTONE_HEAD_BYTES);
@@ -23,46 +22,62 @@ export function serializeTombstone(tombstone) {
23
22
  head.set(hlcBytes, 0);
24
23
  const view = new DataView(head.buffer);
25
24
  view.setBigUint64(30, BigInt(tombstone.createdAt), false);
26
- if (tombstone.priorRow === undefined)
27
- return head;
28
- const payload = new TextEncoder().encode(JSON.stringify(tombstone.priorRow.map(encodeSqlValue)));
29
- const result = new Uint8Array(head.length + payload.length);
25
+ const payload = {
26
+ k: tombstone.pk.map(encodeSqlValue),
27
+ ...(tombstone.priorRow !== undefined ? { pr: tombstone.priorRow.map(encodeSqlValue) } : {}),
28
+ };
29
+ const payloadBytes = new TextEncoder().encode(JSON.stringify(payload));
30
+ const result = new Uint8Array(head.length + payloadBytes.length);
30
31
  result.set(head, 0);
31
- result.set(payload, head.length);
32
+ result.set(payloadBytes, head.length);
32
33
  return result;
33
34
  }
34
35
  /**
35
- * Deserialize a tombstone from storage. Absent-tolerant: bytes beyond the 38-byte
36
- * head are the JSON-encoded `priorRow` (see {@link serializeTombstone}); a
37
- * head-only buffer (no before-image, or a snapshot-reconstructed tombstone)
38
- * deserializes with `priorRow` absent.
36
+ * Deserialize a tombstone from storage. The payload's `pr` (before-image) is
37
+ * optional; the pk is required (see {@link serializeTombstone}).
39
38
  */
40
39
  export function deserializeTombstone(buffer) {
41
40
  const hlc = deserializeHLC(buffer.slice(0, 30));
42
41
  const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
43
42
  const createdAt = Number(view.getBigUint64(30, false));
44
- const tombstone = { hlc, createdAt };
45
- if (buffer.byteLength > TOMBSTONE_HEAD_BYTES) {
46
- const values = JSON.parse(new TextDecoder().decode(buffer.slice(TOMBSTONE_HEAD_BYTES)));
47
- tombstone.priorRow = values.map(decodeSqlValue);
43
+ const payload = JSON.parse(new TextDecoder().decode(buffer.slice(TOMBSTONE_HEAD_BYTES)));
44
+ const tombstone = { hlc, createdAt, pk: payload.k.map(decodeSqlValue) };
45
+ if (payload.pr !== undefined) {
46
+ tombstone.priorRow = payload.pr.map(decodeSqlValue);
48
47
  }
49
48
  return tombstone;
50
49
  }
51
50
  /**
52
51
  * Tombstone store operations.
52
+ *
53
+ * Every pk-taking method derives the record key's pk IDENTITY through the
54
+ * per-table {@link PkKeyingResolver} passed at construction, so callers keep
55
+ * addressing rows by raw pk while the storage keys collapse spellings.
53
56
  */
54
57
  export class TombstoneStore {
55
58
  kv;
56
59
  retentionHorizonMs;
57
- constructor(kv, retentionHorizonMs) {
60
+ keying;
61
+ constructor(kv, retentionHorizonMs, keying) {
58
62
  this.kv = kv;
59
63
  this.retentionHorizonMs = retentionHorizonMs;
64
+ this.keying = keying;
65
+ }
66
+ identity(schemaName, tableName, pk) {
67
+ return encodePkIdentity(pk, this.keying(schemaName, tableName));
60
68
  }
61
69
  /**
62
70
  * Get the tombstone for a row, if it exists.
63
71
  */
64
72
  async getTombstone(schemaName, tableName, pk) {
65
- const key = buildTombstoneKey(schemaName, tableName, pk);
73
+ return this.getTombstoneByIdentity(schemaName, tableName, this.identity(schemaName, tableName, pk));
74
+ }
75
+ /**
76
+ * Get the tombstone for a row by pk IDENTITY (as recovered from a parsed
77
+ * `tb:`/`cl:` key — no raw pk needed).
78
+ */
79
+ async getTombstoneByIdentity(schemaName, tableName, identity) {
80
+ const key = buildTombstoneKey(schemaName, tableName, identity);
66
81
  const data = await this.kv.get(key);
67
82
  if (!data)
68
83
  return undefined;
@@ -73,24 +88,32 @@ export class TombstoneStore {
73
88
  * last-known image, persisted as best-effort audit/undo metadata.
74
89
  */
75
90
  async setTombstone(schemaName, tableName, pk, hlc, priorRow) {
76
- const key = buildTombstoneKey(schemaName, tableName, pk);
77
- const tombstone = { hlc, createdAt: Date.now(), ...(priorRow !== undefined ? { priorRow } : {}) };
91
+ const key = buildTombstoneKey(schemaName, tableName, this.identity(schemaName, tableName, pk));
92
+ const tombstone = { hlc, createdAt: Date.now(), pk, ...(priorRow !== undefined ? { priorRow } : {}) };
78
93
  await this.kv.put(key, serializeTombstone(tombstone));
79
94
  }
80
95
  /**
81
96
  * Set tombstone in a batch. `priorRow` (optional) is the row's last-known image,
82
- * persisted as best-effort audit/undo metadata.
97
+ * persisted as best-effort audit/undo metadata. The key's pk IDENTITY is always
98
+ * derived locally — no caller-supplied-identity variant exists (see
99
+ * `ColumnVersionStore.setColumnVersionBatch`).
83
100
  */
84
101
  setTombstoneBatch(batch, schemaName, tableName, pk, hlc, priorRow) {
85
- const key = buildTombstoneKey(schemaName, tableName, pk);
86
- const tombstone = { hlc, createdAt: Date.now(), ...(priorRow !== undefined ? { priorRow } : {}) };
102
+ const key = buildTombstoneKey(schemaName, tableName, this.identity(schemaName, tableName, pk));
103
+ const tombstone = { hlc, createdAt: Date.now(), pk, ...(priorRow !== undefined ? { priorRow } : {}) };
87
104
  batch.put(key, serializeTombstone(tombstone));
88
105
  }
89
106
  /**
90
107
  * Delete a tombstone (used when resurrecting a row).
108
+ *
109
+ * NOTE: no production caller. If one is added, it must ALSO delete the paired
110
+ * `cl:` change-log delete entry (`changeLog.deleteEntryBatch(batch, tombstone.hlc,
111
+ * 'delete', schema, table, pk)`) in the same batch — otherwise the entry outlives
112
+ * its target and becomes permanent index garbage, the leak `SyncManagerImpl.
113
+ * pruneTombstones` was fixed to avoid.
91
114
  */
92
115
  async deleteTombstone(schemaName, tableName, pk) {
93
- const key = buildTombstoneKey(schemaName, tableName, pk);
116
+ const key = buildTombstoneKey(schemaName, tableName, this.identity(schemaName, tableName, pk));
94
117
  await this.kv.delete(key);
95
118
  }
96
119
  /**
@@ -113,6 +136,12 @@ export class TombstoneStore {
113
136
  /**
114
137
  * Prune expired tombstones.
115
138
  * Returns the number of tombstones deleted.
139
+ *
140
+ * NOTE: no production caller — `SyncManagerImpl.pruneTombstones` is the wired
141
+ * all-tables equivalent. If this per-table variant is wired up, it needs the same
142
+ * paired `cl:` change-log delete-entry removal that one does (see
143
+ * {@link deleteTombstone}); this store has no `ChangeLogStore` handle, so that
144
+ * would mean threading one in or moving the sweep up a level.
116
145
  */
117
146
  async pruneExpired(schemaName, tableName) {
118
147
  const bounds = buildTombstoneScanBounds(schemaName, tableName);
@@ -135,13 +164,9 @@ export class TombstoneStore {
135
164
  async *getAllTombstones(schemaName, tableName) {
136
165
  const bounds = buildTombstoneScanBounds(schemaName, tableName);
137
166
  for await (const entry of this.kv.iterate(bounds)) {
138
- // Extract PK from key: tb:{schema}.{table}:{pk_json}
139
- const keyStr = new TextDecoder().decode(entry.key);
140
- const firstColon = keyStr.indexOf(':');
141
- const secondColon = keyStr.indexOf(':', firstColon + 1);
142
- const pkJson = keyStr.slice(secondColon + 1);
143
- const pk = decodePK(pkJson);
144
- yield { pk, tombstone: deserializeTombstone(entry.value) };
167
+ // The key holds only the lossy pk identity; the raw pk comes from the value.
168
+ const tombstone = deserializeTombstone(entry.value);
169
+ yield { pk: tombstone.pk, tombstone };
145
170
  }
146
171
  }
147
172
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tombstones.js","sourceRoot":"","sources":["../../../src/metadata/tombstones.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tombstones.js","sourceRoot":"","sources":["../../../src/metadata/tombstones.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,25 @@ export interface ResolvedChange {
22
22
  oldColumnVersion?: ColumnVersion;
23
23
  /** For delete changes: the prior tombstone whose stale delete entry to clean up in the change log. */
24
24
  oldTombstone?: Tombstone;
25
+ /**
26
+ * For a row's winning in-batch delete under `allowResurrection`: columns of this
27
+ * row whose same-batch write beat the delete, so the post-commit cleanup keeps
28
+ * them. Filled by {@link reconcileInBatchDeletes}.
29
+ */
30
+ keepColumns?: Set<string>;
31
+ /**
32
+ * For a column change that BEAT a same-batch delete under `allowResurrection`:
33
+ * the delete erased this cell's local lineage before the write landed, so the
34
+ * write records no before-image. {@link oldColumnVersion} still travels with it
35
+ * — its stale `cl:` entry must be dropped, and the delete's cleanup now skips
36
+ * this column. Filled by {@link reconcileInBatchDeletes}.
37
+ */
38
+ priorErasedByInBatchDelete?: boolean;
39
+ /**
40
+ * Table exists only via this same batch's create_table — no local schema (and so
41
+ * no resolvable pk-identity keying) until Phase 2's DDL runs.
42
+ */
43
+ freshLocalTable?: boolean;
25
44
  }
26
45
  /**
27
46
  * Apply change sets from a remote peer.
@@ -84,8 +103,13 @@ export declare function drainReappearedTables(ctx: SyncContext, tables: Readonly
84
103
  * Resolve CRDT conflicts for a single change WITHOUT writing metadata.
85
104
  *
86
105
  * Phase 1 of the 3-phase apply pattern.
106
+ *
107
+ * `freshLocalTable` marks a table that exists only via the SAME batch's
108
+ * create_table: it has no local schema yet (so no pk-identity keying) and no
109
+ * local metadata, so every read is skipped and the change resolves as a first
110
+ * write. Phase 3 commits its metadata after the DDL has executed.
87
111
  */
88
- export declare function resolveChange(ctx: SyncContext, change: Change): Promise<ResolvedChange>;
112
+ export declare function resolveChange(ctx: SyncContext, change: Change, freshLocalTable?: boolean): Promise<ResolvedChange>;
89
113
  /**
90
114
  * Commit CRDT metadata for resolved changes.
91
115
  *
@@ -102,6 +126,11 @@ export declare function resolveChange(ctx: SyncContext, change: Change): Promise
102
126
  * pre-batch prior entry is deleted once. Mirrors the local write-path dedup in
103
127
  * `recordDataEvent` / `recordColumnVersions`, keeping the delete and column paths
104
128
  * symmetric.
129
+ *
130
+ * Cross-type (delete vs column) same-row collisions were already settled upstream by
131
+ * {@link reconcileInBatchDeletes}: every column change still `'applied'` here is one
132
+ * that must be written, and a winning delete's {@link ResolvedChange.keepColumns}
133
+ * names the columns its cleanup must leave alone.
105
134
  */
106
135
  export declare function commitChangeMetadata(ctx: SyncContext, resolvedChanges: ResolvedChange[]): Promise<void>;
107
136
  //# sourceMappingURL=change-applicator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"change-applicator.d.ts","sourceRoot":"","sources":["../../../src/sync/change-applicator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,KAAK,EACX,SAAS,EACT,MAAM,EAGN,WAAW,EACX,iBAAiB,EAGjB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,aAAa,CAAC;IACjC,sGAAsG;IACtG,YAAY,CAAC,EAAE,SAAS,CAAC;CACzB;AA2CD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,SAAS,EAAE,GAClB,OAAO,CAAC,WAAW,CAAC,CAwNtB;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,WAAW,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAsFD;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAC1C,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GACtD,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAClC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,cAAc,CAAC,CAkHzB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,oBAAoB,CACzC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,cAAc,EAAE,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsCf"}
1
+ {"version":3,"file":"change-applicator.d.ts","sourceRoot":"","sources":["../../../src/sync/change-applicator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE3D,OAAO,KAAK,EACX,SAAS,EACT,MAAM,EAGN,WAAW,EACX,iBAAiB,EAGjB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIrD;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,OAAO,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,yEAAyE;IACzE,gBAAgB,CAAC,EAAE,aAAa,CAAC;IACjC,sGAAsG;IACtG,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B;;;;;;OAMG;IACH,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AA2CD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,SAAS,EAAE,GAClB,OAAO,CAAC,WAAW,CAAC,CAiPtB;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,gBAAgB,CACrC,GAAG,EAAE,WAAW,EAChB,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAsBjB;AA6FD;;;;;;;;GAQG;AACH,wBAAsB,qBAAqB,CAC1C,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,aAAa,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,GACtD,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAClC,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,EACd,eAAe,UAAQ,GACrB,OAAO,CAAC,cAAc,CAAC,CAkHzB;AAyDD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,oBAAoB,CACzC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,cAAc,EAAE,GAC/B,OAAO,CAAC,IAAI,CAAC,CAiDf"}