orez 0.4.44 → 0.4.46

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.
@@ -0,0 +1,27 @@
1
+ export type CursorPullTables = Record<string, // EXACT _zero_changes.table_name identity, e.g. 'public.file'
2
+ {
3
+ clientName: string;
4
+ primaryKey: string[];
5
+ }>;
6
+ export type ChangeLogRow = {
7
+ tableName: string;
8
+ op: 'INSERT' | 'UPDATE' | 'DELETE';
9
+ rowData: Record<string, unknown> | null;
10
+ oldData: Record<string, unknown> | null;
11
+ };
12
+ export type CursorDiffOp = {
13
+ op: 'put';
14
+ tableName: string;
15
+ row: Record<string, unknown>;
16
+ } | {
17
+ op: 'del';
18
+ tableName: string;
19
+ pk: Record<string, unknown>;
20
+ };
21
+ export declare function cursorDiffPatch(opts: {
22
+ changes: ChangeLogRow[];
23
+ tables: CursorPullTables;
24
+ skip: (logTableName: string) => boolean;
25
+ readRow: (clientTableName: string, pk: Record<string, unknown>) => Record<string, unknown> | undefined;
26
+ }): CursorDiffOp[];
27
+ //# sourceMappingURL=cursor-pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-pull.d.ts","sourceRoot":"","sources":["../../src/cf-do/cursor-pull.ts"],"names":[],"mappings":"AAoCA,MAAM,MAAM,gBAAgB,GAAG,MAAM,CACnC,MAAM,EAAE,8DAA8D;AACtE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAC7C,CAAA;AAID,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,EAAE,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAA;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,YAAY,GACpB;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAC9D;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CAAA;AAgBjE,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,OAAO,EAAE,YAAY,EAAE,CAAA;IACvB,MAAM,EAAE,gBAAgB,CAAA;IAIxB,IAAI,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAA;IAGvC,OAAO,EAAE,CACP,eAAe,EAAE,MAAM,EACvB,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;CACzC,GAAG,YAAY,EAAE,CA2BjB"}
@@ -0,0 +1,78 @@
1
+ // cursor-pull: the phase-2 delta primitive over the PRODUCTION change log
2
+ // (plans/zero-server-rewrite.md "build plan for the production composition").
3
+ // maps `_zero_changes` rows since a client's cookie into put/del row patches
4
+ // for an http-pull diff response.
5
+ //
6
+ // semantics follow the reference core (src/sync-server/sync-server.ts + its
7
+ // delta suite) exactly: collect the pks TOUCHED since the cookie, dedup,
8
+ // then resolve each against LIVE table state inside the pull transaction —
9
+ // row exists → put (current values), row gone → del. old row images in the
10
+ // log are used only to find pks (DELETE + pk-changing UPDATE), never as
11
+ // patch values, so op-coalescing bugs and serializer fidelity questions
12
+ // can't exist.
13
+ //
14
+ // table identity is EXPLICIT (2026-07-09 design review, blocker 1):
15
+ // production `_zero_changes.table_name` is schema-qualified
16
+ // (`public.file`, `soot_0.clients` — pg-proxy trackingRequest emits
17
+ // `<schema>.<table>`), so `tables` is keyed by the EXACT log identity and
18
+ // carries the zero/client table name to emit. rows matching neither the
19
+ // synced spec nor the host's `skip` classifier THROW — a silently dropped
20
+ // synced change is permanent client divergence, the one failure mode this
21
+ // module must never have.
22
+ //
23
+ // completeness contract (review, high 4): the caller must pass EVERY change
24
+ // row with `watermark > cookie` up to the watermark it returns as the next
25
+ // cookie, read atomically with the live point-reads. if the host caps the
26
+ // change read, it must return the last INCLUDED watermark as the cookie —
27
+ // never the global current watermark — so the remainder ships on the next
28
+ // pull. pk mutability (review, high 5): the main pg-proxy tracking path
29
+ // records old_data=null for UPDATEs, so a pk-changing UPDATE through it
30
+ // only surfaces the NEW pk. published-table pks must be immutable (enforce
31
+ // host-side) unless the tracker learns to capture old pk images.
32
+ //
33
+ // the host (soot's project pull endpoint) owns everything else: cookie
34
+ // compare against the watermark, floor/epoch snapshot fallback, LMID rows,
35
+ // and wire value conversion (its toZeroRow).
36
+ // pks touched by a change: NEW row for INSERT/UPDATE, OLD row for
37
+ // UPDATE/DELETE (when the tracker provides old images, a pk-changing
38
+ // UPDATE touches both, deleting the old pk)
39
+ function pksOf(change, primaryKey) {
40
+ const out = [];
41
+ for (const source of [change.rowData, change.oldData]) {
42
+ if (!source)
43
+ continue;
44
+ const pk = {};
45
+ for (const col of primaryKey)
46
+ pk[col] = source[col];
47
+ out.push(pk);
48
+ }
49
+ return out;
50
+ }
51
+ export function cursorDiffPatch(opts) {
52
+ const { changes, tables, skip, readRow } = opts;
53
+ const touched = new Map();
54
+ for (const change of changes) {
55
+ const spec = tables[change.tableName];
56
+ if (!spec) {
57
+ if (skip(change.tableName))
58
+ continue;
59
+ throw new Error(`cursor-pull: change log row for unmapped table '${change.tableName}' — ` +
60
+ `synced tables must be in the spec and internal tables must be classified by skip(); ` +
61
+ `silently dropping it would permanently diverge clients`);
62
+ }
63
+ for (const pk of pksOf(change, spec.primaryKey)) {
64
+ const key = `${spec.clientName} ${JSON.stringify(spec.primaryKey.map((c) => pk[c]))}`;
65
+ touched.set(key, { clientName: spec.clientName, pk });
66
+ }
67
+ }
68
+ const patch = [];
69
+ for (const { clientName, pk } of touched.values()) {
70
+ const row = readRow(clientName, pk);
71
+ if (row === undefined)
72
+ patch.push({ op: 'del', tableName: clientName, pk });
73
+ else
74
+ patch.push({ op: 'put', tableName: clientName, row });
75
+ }
76
+ return patch;
77
+ }
78
+ //# sourceMappingURL=cursor-pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-pull.js","sourceRoot":"","sources":["../../src/cf-do/cursor-pull.ts"],"names":[],"mappings":"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"}
@@ -36,6 +36,7 @@ export declare class DoBackend {
36
36
  private txChangeTablesSnapshotted;
37
37
  private txMetadataDirty;
38
38
  private txHasTrackedWrite;
39
+ private lastPersistedMetadata;
39
40
  private txOwner;
40
41
  constructor(doUrl: string, dbName?: string, namespace?: string, opts?: {
41
42
  fetch?: typeof fetch;
@@ -1 +1 @@
1
- {"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pg-proxy-do-backend.d.ts","sourceRoot":"","sources":["../src/pg-proxy-do-backend.ts"],"names":[],"mappings":"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"}
@@ -4764,6 +4764,14 @@ export class DoBackend {
4764
4764
  // round-trip to durable storage after every DDL statement in a migration.
4765
4765
  txMetadataDirty = false;
4766
4766
  txHasTrackedWrite = false;
4767
+ // durable-metadata rows as last read/written (kind\0key\0subkey -> value).
4768
+ // persistDurableMetadata diffs against this and writes only changed rows —
4769
+ // a full INSERT OR REPLACE of the whole set on every dirty commit/rollback
4770
+ // is what let a crash-looping embed boot re-write ~700 identical
4771
+ // _orez_pg_metadata rows per cycle into the SQL DO until the write circuit
4772
+ // tripped (2026-07-09 prod incident). null until the first load/persist,
4773
+ // which falls back to a full write.
4774
+ lastPersistedMetadata = null;
4767
4775
  // identifies the client process generation owning this backend's
4768
4776
  // transactions in the durable tx journal. a process that knows its previous
4769
4777
  // generation is dead (e.g. the zero-cache embed at boot) recovers orphaned
@@ -4855,11 +4863,13 @@ export class DoBackend {
4855
4863
  try {
4856
4864
  await this.ensureMetadataTable();
4857
4865
  const result = await this.doExecResult(`SELECT kind, key, subkey, value FROM ${quoteIdentifier(METADATA_TABLE)}`);
4866
+ this.lastPersistedMetadata = new Map();
4858
4867
  for (const row of result.rows) {
4859
4868
  const kind = String(row.kind ?? '');
4860
4869
  const key = String(row.key ?? '');
4861
4870
  const subkey = String(row.subkey ?? '');
4862
4871
  const value = String(row.value ?? '');
4872
+ this.lastPersistedMetadata.set(`${kind}\u0000${key}\u0000${subkey}`, value);
4863
4873
  if (kind === 'schema-column') {
4864
4874
  const metadata = JSON.parse(value);
4865
4875
  let table = this.schemaMetadata.get(key);
@@ -4944,7 +4954,6 @@ export class DoBackend {
4944
4954
  }
4945
4955
  async persistDurableMetadata() {
4946
4956
  try {
4947
- await this.ensureMetadataTable();
4948
4957
  const rows = [];
4949
4958
  for (const [tableName, columns] of this.schemaMetadata) {
4950
4959
  for (const [columnName, metadata] of columns) {
@@ -4964,21 +4973,40 @@ export class DoBackend {
4964
4973
  JSON.stringify(child),
4965
4974
  ]);
4966
4975
  }
4967
- if (rows.length === 0)
4976
+ // write only rows that differ from what durable storage already holds
4977
+ // (seeded by loadDurableMetadata, maintained below). every persisted row
4978
+ // is a real DO rows-written cost even when the value is identical —
4979
+ // INSERT OR REPLACE always rewrites — and this method fires on every
4980
+ // dirty commit AND every rollback, so a crash-looping embed boot used to
4981
+ // rewrite the entire set (~700 rows on a real app schema) several times
4982
+ // per ~4s cycle into the SQL DO until the write circuit tripped and
4983
+ // blocked auth (2026-07-09 prod incident).
4984
+ const known = this.lastPersistedMetadata;
4985
+ const changed = known === null
4986
+ ? rows
4987
+ : rows.filter(([kind, key, subkey, value]) => known.get(`${kind}\u0000${key}\u0000${subkey}`) !== value);
4988
+ if (changed.length === 0)
4968
4989
  return;
4990
+ await this.ensureMetadataTable();
4969
4991
  // single multi-row INSERT OR REPLACE per chunk. previously this was one
4970
4992
  // HTTP roundtrip per row, which dominated boot when migrations touched
4971
4993
  // many columns. Cloudflare DO SQLite has a lower host-param cap than
4972
4994
  // stock SQLite; 4 cols × 20 rows keeps metadata persistence comfortably
4973
4995
  // below that limit.
4974
4996
  const CHUNK = 20;
4975
- for (let i = 0; i < rows.length; i += CHUNK) {
4976
- const chunk = rows.slice(i, i + CHUNK);
4997
+ const persisted = this.lastPersistedMetadata ?? new Map();
4998
+ this.lastPersistedMetadata = persisted;
4999
+ for (let i = 0; i < changed.length; i += CHUNK) {
5000
+ const chunk = changed.slice(i, i + CHUNK);
4977
5001
  const placeholders = chunk.map(() => '(?, ?, ?, ?)').join(', ');
4978
5002
  const params = [];
4979
5003
  for (const row of chunk)
4980
5004
  params.push(...row);
4981
5005
  await this.doExecResult(`INSERT OR REPLACE INTO ${quoteIdentifier(METADATA_TABLE)} (kind, key, subkey, value) VALUES ${placeholders}`, params);
5006
+ // per-chunk so a mid-persist failure never marks unwritten rows as done
5007
+ for (const [kind, key, subkey, value] of chunk) {
5008
+ persisted.set(`${kind}\u0000${key}\u0000${subkey}`, value);
5009
+ }
4982
5010
  }
4983
5011
  }
4984
5012
  catch { }