orez 0.4.73 → 0.5.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 (73) hide show
  1. package/README.md +42 -1
  2. package/dist/cf-do/cdc.d.ts +148 -0
  3. package/dist/cf-do/cdc.d.ts.map +1 -0
  4. package/dist/cf-do/cdc.js +719 -0
  5. package/dist/cf-do/cdc.js.map +1 -0
  6. package/dist/cf-do/row-undo.d.ts +36 -0
  7. package/dist/cf-do/row-undo.d.ts.map +1 -0
  8. package/dist/cf-do/row-undo.js +209 -0
  9. package/dist/cf-do/row-undo.js.map +1 -0
  10. package/dist/cf-do/tx-journal.d.ts +32 -10
  11. package/dist/cf-do/tx-journal.d.ts.map +1 -1
  12. package/dist/cf-do/tx-journal.js +148 -31
  13. package/dist/cf-do/tx-journal.js.map +1 -1
  14. package/dist/cf-do/watermark.d.ts +7 -0
  15. package/dist/cf-do/watermark.d.ts.map +1 -1
  16. package/dist/cf-do/watermark.js +9 -0
  17. package/dist/cf-do/watermark.js.map +1 -1
  18. package/dist/cf-do/worker.d.ts +19 -1
  19. package/dist/cf-do/worker.d.ts.map +1 -1
  20. package/dist/cf-do/worker.js +218 -46
  21. package/dist/cf-do/worker.js.map +1 -1
  22. package/dist/cli.d.ts.map +1 -1
  23. package/dist/cli.js +1 -0
  24. package/dist/cli.js.map +1 -1
  25. package/dist/config.d.ts +35 -1
  26. package/dist/config.d.ts.map +1 -1
  27. package/dist/config.js +1 -0
  28. package/dist/config.js.map +1 -1
  29. package/dist/do-sql-tracking.d.ts +2 -0
  30. package/dist/do-sql-tracking.d.ts.map +1 -1
  31. package/dist/do-sql-tracking.js +11 -1
  32. package/dist/do-sql-tracking.js.map +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +146 -40
  36. package/dist/index.js.map +1 -1
  37. package/dist/pg-proxy-do-backend.d.ts +8 -0
  38. package/dist/pg-proxy-do-backend.d.ts.map +1 -1
  39. package/dist/pg-proxy-do-backend.js +301 -47
  40. package/dist/pg-proxy-do-backend.js.map +1 -1
  41. package/dist/pg-proxy.d.ts +22 -1
  42. package/dist/pg-proxy.d.ts.map +1 -1
  43. package/dist/pg-proxy.js +63 -1
  44. package/dist/pg-proxy.js.map +1 -1
  45. package/dist/pg-sqlite-compiler/index.d.ts.map +1 -1
  46. package/dist/pg-sqlite-compiler/index.js +9 -1
  47. package/dist/pg-sqlite-compiler/index.js.map +1 -1
  48. package/dist/pg-sqlite-compiler/passes/datetime.d.ts +2 -0
  49. package/dist/pg-sqlite-compiler/passes/datetime.d.ts.map +1 -1
  50. package/dist/pg-sqlite-compiler/passes/datetime.js +20 -18
  51. package/dist/pg-sqlite-compiler/passes/datetime.js.map +1 -1
  52. package/dist/pg-sqlite-compiler/passes/index.d.ts.map +1 -1
  53. package/dist/pg-sqlite-compiler/passes/index.js +6 -1
  54. package/dist/pg-sqlite-compiler/passes/index.js.map +1 -1
  55. package/dist/pg-sqlite-compiler/passes/json-functions.d.ts +3 -0
  56. package/dist/pg-sqlite-compiler/passes/json-functions.d.ts.map +1 -0
  57. package/dist/pg-sqlite-compiler/passes/json-functions.js +57 -0
  58. package/dist/pg-sqlite-compiler/passes/json-functions.js.map +1 -0
  59. package/dist/pg-sqlite-compiler/passes/row-json.d.ts +3 -0
  60. package/dist/pg-sqlite-compiler/passes/row-json.d.ts.map +1 -0
  61. package/dist/pg-sqlite-compiler/passes/row-json.js +230 -0
  62. package/dist/pg-sqlite-compiler/passes/row-json.js.map +1 -0
  63. package/dist/pg-sqlite-compiler/passes/schema.d.ts.map +1 -1
  64. package/dist/pg-sqlite-compiler/passes/schema.js +16 -1
  65. package/dist/pg-sqlite-compiler/passes/schema.js.map +1 -1
  66. package/dist/pg-sqlite-compiler/passes/string-functions.d.ts +11 -0
  67. package/dist/pg-sqlite-compiler/passes/string-functions.d.ts.map +1 -0
  68. package/dist/pg-sqlite-compiler/passes/string-functions.js +37 -0
  69. package/dist/pg-sqlite-compiler/passes/string-functions.js.map +1 -0
  70. package/dist/worker/local-sql-backend.d.ts.map +1 -1
  71. package/dist/worker/local-sql-backend.js +114 -13
  72. package/dist/worker/local-sql-backend.js.map +1 -1
  73. package/package.json +2 -2
package/README.md CHANGED
@@ -186,7 +186,48 @@ All options are optional with sensible defaults.
186
186
  | on-db-ready | `--on-db-ready=CMD` | `onDbReady: 'CMD'` or `onDbReady: fn` | after db + proxy ready, before zero |
187
187
  | on-healthy | `--on-healthy=CMD` | `onHealthy: 'CMD'` or `onHealthy: fn` | after all services ready |
188
188
 
189
- Shell commands receive env vars: `DATABASE_URL`, `OREZ_PG_PORT`, `OREZ_ZERO_PORT`. Change tracking triggers are re-installed after `onDbReady`.
189
+ Shell commands receive env vars: `DATABASE_URL`, `OREZ_PG_PORT`, `OREZ_ZERO_PORT`.
190
+ On the PGlite backend, change-tracking triggers are re-installed after
191
+ `onDbReady`.
192
+
193
+ #### Startup blocking and the callback context
194
+
195
+ `onDbReady` runs before zero-cache. On the PGlite and DO proxy backends, shell
196
+ hooks and context-aware callbacks hold every ordinary PG client at connection
197
+ startup until `onDbReady` returns, so an early application `SELECT` can't race
198
+ schema provisioning (or monopolize the shared DB mutex while a migration is
199
+ still creating tables).
200
+
201
+ - **Shell command:** receives the tagged connection strings via
202
+ `ZERO_UPSTREAM_DB` / `ZERO_CVR_DB` / `ZERO_CHANGE_DB` / `DATABASE_URL`, plus
203
+ `PGAPPNAME`. Connecting with any of these bypasses the barrier.
204
+ - **Context-aware callback:** declare a context parameter to opt into the
205
+ barrier and receive its privileged connection strings:
206
+
207
+ ```typescript
208
+ onDbReady: async (ctx) => {
209
+ // ctx.upstreamConnectionString / cvrConnectionString / cdbConnectionString
210
+ // are tagged so they bypass the startup barrier; ctx.applicationName is the
211
+ // tag itself (for clients that set application_name separately), and
212
+ // ctx.pgPort is the proxy port.
213
+ const sql = postgres(ctx.upstreamConnectionString)
214
+ await sql`CREATE TABLE ...`
215
+ await sql.end()
216
+ }
217
+ ```
218
+
219
+ A context-aware callback **must** provision through one of these privileged
220
+ connections. An ordinary (untagged) connection is held by the same barrier;
221
+ if the hook does that accidentally, the connection fails after a bounded wait
222
+ with an error pointing back to `HookContext` instead of hanging forever. Both
223
+ the hook and barrier default to a 30-second deadline; set
224
+ `onDbReadyTimeoutMs` higher for a legitimately longer migration.
225
+
226
+ - **Legacy callback:** a zero-argument callback (`onDbReady: async () => { ... }`)
227
+ does not opt into the barrier. It keeps the behavior from orez v0.4.73 and
228
+ earlier, including the ability to open its existing ordinary proxy connection.
229
+ Callback arity is the runtime contract, so callbacks that need the context
230
+ should declare `ctx` without a default value or rest-parameter wrapper.
190
231
 
191
232
  ## Vite Plugin
192
233
 
@@ -0,0 +1,148 @@
1
+ import type { DurableSqlStorage } from './watermark.js';
2
+ /** Bump whenever the generated trigger bodies or buffer shape change. */
3
+ export declare const CDC_SCHEMA_VERSION = 2;
4
+ export interface CdcTableRegistration {
5
+ /** Physical, flattened SQLite table name. */
6
+ physicalTableName: string;
7
+ /** Schema-qualified identity exposed in `_zero_changes`. */
8
+ tableName: string;
9
+ /** Optional known column list. The live SQLite schema remains authoritative. */
10
+ columns?: string[];
11
+ /** False captures before/after images for transaction rollback only. */
12
+ publish?: boolean;
13
+ }
14
+ /**
15
+ * A row image in storage-journal form: one tagged string per column, carrying
16
+ * the value's SQLite storage class and an exact, lossless payload. This is the
17
+ * undo encoding, deliberately separate from the Zero wire encoding that
18
+ * `journalToWire` derives.
19
+ */
20
+ export type JournalRecord = Record<string, string>;
21
+ export interface CapturedRowChange {
22
+ physicalTableName: string;
23
+ tableName: string;
24
+ op: 'INSERT' | 'UPDATE' | 'DELETE';
25
+ /** Zero wire image (JSON-safe; blobs as postgres bytea text). */
26
+ rowData: Record<string, unknown> | null;
27
+ oldData: Record<string, unknown> | null;
28
+ /** Lossless storage-journal image used only for undo. */
29
+ rowJournal: JournalRecord | null;
30
+ oldJournal: JournalRecord | null;
31
+ /** Exact decimal rowid text, or null for WITHOUT ROWID tables. */
32
+ newRowid: string | null;
33
+ oldRowid: string | null;
34
+ /** Omitted for normal published changes; false means rollback-only. */
35
+ publish?: boolean;
36
+ }
37
+ export interface SuspendedCdcTable {
38
+ physicalTableName: string;
39
+ tableName: string;
40
+ publish?: boolean;
41
+ }
42
+ /** Stable-identity and writability metadata read from the live SQLite schema. */
43
+ export interface TableIdentity {
44
+ /** rowid alias usable in SQL, or null for a WITHOUT ROWID table. */
45
+ rowidAlias: string | null;
46
+ /** The INTEGER PRIMARY KEY column, which *is* the rowid, when one exists. */
47
+ rowidColumn: string | null;
48
+ /** Declared primary-key columns in key order. */
49
+ keyColumns: string[];
50
+ /** Columns undo may write. Excludes generated columns. */
51
+ writableColumns: string[];
52
+ /** Every column captured in a row image, generated columns included. */
53
+ columns: string[];
54
+ }
55
+ /**
56
+ * Rebuild the exact SQLite value for an undo statement. Integers and reals go
57
+ * back through CAST so the full int64 range and every double survive without
58
+ * depending on the driver's numeric binding.
59
+ */
60
+ export declare function journalValueSqlBinding(encoded: string): {
61
+ expr: string;
62
+ params: unknown[];
63
+ };
64
+ export declare function parseJournalRecord(value: unknown): JournalRecord | null;
65
+ /**
66
+ * Read stable-identity metadata from the live schema. Returns null when the
67
+ * table cannot be undone row-by-row (no rowid and no primary key), which keeps
68
+ * capture off it entirely so the caller falls back to table snapshots.
69
+ */
70
+ export declare function tableIdentity(sql: DurableSqlStorage, table: string): TableIdentity | null;
71
+ export interface TriggerDefinition {
72
+ name: string;
73
+ sql: string;
74
+ }
75
+ /**
76
+ * Drop every trigger on these tables and return their definitions.
77
+ *
78
+ * A restore must not fire the table's own business triggers. Undoing an INSERT
79
+ * with a DELETE would run its AFTER DELETE trigger and write side effects the
80
+ * original transaction never made, and if that side effect lands on a captured
81
+ * table, its CDC trigger stages a phantom change on top. Dropping only the
82
+ * generated CDC triggers leaves both holes open, so every trigger goes.
83
+ */
84
+ export declare function suspendTriggers(sql: DurableSqlStorage, tables: Iterable<string>): TriggerDefinition[];
85
+ /** Recreate triggers suspended for a restore, verbatim. */
86
+ export declare function restoreTriggers(sql: DurableSqlStorage, triggers: TriggerDefinition[]): void;
87
+ /** The columns a restore is allowed to write. Empty when the table is gone. */
88
+ export declare function writableColumns(sql: DurableSqlStorage, table: string): string[];
89
+ /**
90
+ * Transactional logical-row capture for the authoritative SQLite database.
91
+ *
92
+ * Generated AFTER triggers write full before/after row images to a staging
93
+ * table in the same SQLite statement as the application write. The owner
94
+ * drains that staging table before its storage transaction returns and moves
95
+ * the rows to either `_zero_changes` or `_zero_pending_changes`. Consequently
96
+ * a failed statement or storage transaction cannot leave an orphaned change.
97
+ *
98
+ * Every mutator of the in-memory registration cache runs inside the owner's
99
+ * storage transaction, so the cache can outlive an abort that rolled its SQLite
100
+ * side back. `reload()` re-derives the whole cache from SQLite and MUST be
101
+ * called on any aborted transaction; see `atomically` in worker.ts.
102
+ */
103
+ export declare class TransactionalCdc {
104
+ #private;
105
+ private readonly sql;
106
+ constructor(sql: DurableSqlStorage);
107
+ get active(): boolean;
108
+ /** Force the next per-table ensure to re-read SQLite's live schema. */
109
+ invalidateSchema(): void;
110
+ /**
111
+ * Re-derive every cached decision from SQLite. Called after an aborted
112
+ * storage transaction, where SQLite rolled back the trigger and metadata
113
+ * writes but this object still remembers making them. Without it a table can
114
+ * stay "registered and verified" in memory with no trigger on disk, and every
115
+ * later write to it is silently uncaptured.
116
+ */
117
+ reload(): void;
118
+ private loadRegistrations;
119
+ private ensureTables;
120
+ private tableExists;
121
+ private triggersExist;
122
+ private registered;
123
+ capturesTable(tableName: string): boolean;
124
+ /** True when a DDL statement must atomically suspend and rebuild CDC triggers. */
125
+ capturesSchemaChange(sql: string): boolean;
126
+ private dropTriggers;
127
+ /**
128
+ * Drop generated triggers before SQLite rewrites a captured table. SQLite
129
+ * refuses DROP/RENAME COLUMN while any trigger still references the old row
130
+ * shape. The caller must run this, the DDL, and finishSchemaChange in one
131
+ * storage transaction so capture is never observably disabled.
132
+ */
133
+ beginSchemaChange(sql: string): SuspendedCdcTable[];
134
+ /** Re-introspect changed tables and rebuild their triggers from the live shape. */
135
+ finishSchemaChange(suspended: SuspendedCdcTable[]): void;
136
+ private installTriggers;
137
+ /**
138
+ * Ensure one table is captured. Returns false when the table does not exist
139
+ * or cannot be undone row-by-row, which leaves the caller on its table
140
+ * snapshot path rather than capturing changes it could never roll back.
141
+ */
142
+ ensureTable(registration: CdcTableRegistration, refresh?: boolean): boolean;
143
+ /** Replace the captured-table set with the caller's authoritative list. */
144
+ syncTables(registrations: CdcTableRegistration[]): void;
145
+ /** Drain all changes captured by the just-completed SQLite statement. */
146
+ drain(): CapturedRowChange[];
147
+ }
148
+ //# sourceMappingURL=cdc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdc.d.ts","sourceRoot":"","sources":["../../src/cf-do/cdc.ts"],"names":[],"mappings":"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"}