orez-lite 0.12.14 → 0.12.16

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.
package/README.md CHANGED
@@ -86,3 +86,21 @@ CLI:
86
86
  ```sh
87
87
  orez-lite dev -- node server.js
88
88
  ```
89
+
90
+ ## Cloudflare data-object status
91
+
92
+ The Cloudflare data worker forwards `GET /<namespace>/_orez/status` to the
93
+ namespace's data Durable Object. The request must present the configured
94
+ `OREZ_DO_WRITE_BUDGET_ADMIN_TOKEN` as `x-orez-admin-token` or a bearer token.
95
+ The response identifies the namespace and object, reports database size,
96
+ application SQL reader/writer queue depth, recent write-grant wait p50/p99/max,
97
+ SQL rows read and written, and request/session counters.
98
+
99
+ These measurements are bounded, in-memory values since the current object boot.
100
+ They reset on eviction and do not add storage writes. The existing environment
101
+ variable name is retained for deployed compatibility even though the token now
102
+ protects the broader status route as well as write-budget controls.
103
+
104
+ Cloudflare namespace backup summaries also include `tableRows`, the row count
105
+ observed for every exported table during the existing streaming scan. Consumers
106
+ can persist fleet profiles without issuing a second set of table reads.
@@ -1 +1 @@
1
- {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/cf-deploy/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAcnD,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,OAAO,CAAA;QAChB,eAAe,EAAE,MAAM,CAAA;QACvB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;IACF,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,oCAAoC,GAC5C;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;CACtB,GACD;IACE,sEAAsE;IACtE,IAAI,EAAE,QAAQ,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,mBAAmB,EAAE,OAAO,CAAA;IAC5B,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5D,cAAc,CAAC,EAAE,0BAA0B,EAAE,CAAA;CAC9C,CAAA;AAEL,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,oCAAoC,GAC1C,MAAM,CAk0BR"}
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../src/cf-deploy/migration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAcnD,MAAM,MAAM,0BAA0B,GAAG;IACvC,OAAO,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,OAAO,EAAE,OAAO,CAAA;QAChB,eAAe,EAAE,MAAM,CAAA;QACvB,OAAO,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;IACF,IAAI,EAAE,MAAM,CAAA;CACb,CAAA;AAED,MAAM,MAAM,oCAAoC,GAC5C;IACE,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;CACtB,GACD;IACE,sEAAsE;IACtE,IAAI,EAAE,QAAQ,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,qBAAqB,EAAE,MAAM,CAAA;IAC7B,mBAAmB,EAAE,OAAO,CAAA;IAC5B,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5D,cAAc,CAAC,EAAE,0BAA0B,EAAE,CAAA;CAC9C,CAAA;AAEL,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,oCAAoC,GAC1C,MAAM,CA65BR"}
@@ -307,10 +307,54 @@ function migrationStatementTargetTable(sql) {
307
307
  }
308
308
 
309
309
  function appliedHasStatement(applied, baseId) {
310
- for (const id of applied) {
311
- if (id === baseId || id.startsWith(baseId + ':')) return true
310
+ return applied.has(baseId)
311
+ }
312
+
313
+ function knownMigrationStatementIds() {
314
+ const ids = new Set()
315
+ for (const [index, statement] of nativeSqlStatements.entries()) {
316
+ const item = typeof statement === 'string'
317
+ ? { id: 'statement-' + index, sql: statement }
318
+ : statement
319
+ if (!item || typeof item.sql !== 'string' || !item.sql.trim()) continue
320
+ ids.add(typeof item.id === 'string' && item.id ? item.id : 'statement-' + index)
312
321
  }
313
- return false
322
+ return [...ids]
323
+ }
324
+
325
+ const migrationStatementIds = knownMigrationStatementIds()
326
+
327
+ // The ledger grows with deployment history, while this worker can only act on
328
+ // the statement ids compiled into THIS bundle. Probe those ids through the
329
+ // ledger primary key in bounded packs instead of scanning every historical row
330
+ // once for prepare, once per migration file, and once again for finalize.
331
+ async function readAppliedMigrationStatements(tx) {
332
+ const applied = new Set()
333
+ const statementIdsPerQuery = 32
334
+ for (let offset = 0; offset < migrationStatementIds.length; offset += statementIdsPerQuery) {
335
+ const ids = migrationStatementIds.slice(offset, offset + statementIdsPerQuery)
336
+ const params = []
337
+ for (const id of ids) params.push(id, id + ':', id + ';')
338
+ const rows = await tx.query(
339
+ 'WITH expected(baseId, lowerId, upperId) AS (VALUES ' +
340
+ ids.map(() => '(?, ?, ?)').join(', ') +
341
+ ') SELECT expected.baseId FROM expected WHERE EXISTS (' +
342
+ 'SELECT 1 FROM ' + quoteIdentifier(migrationTable) +
343
+ ' WHERE id = expected.baseId OR (id >= expected.lowerId AND id < expected.upperId)' +
344
+ ' LIMIT 1)',
345
+ params,
346
+ )
347
+ for (const row of rows) applied.add(row.baseId)
348
+ }
349
+ return applied
350
+ }
351
+
352
+ async function deleteAppliedMigrationStatement(tx, baseId) {
353
+ await tx.exec(
354
+ 'DELETE FROM ' + quoteIdentifier(migrationTable) +
355
+ ' WHERE id = ? OR (id >= ? AND id < ?)',
356
+ [baseId, baseId + ':', baseId + ';'],
357
+ )
314
358
  }
315
359
 
316
360
  // A migration can create scratch/candidate/guard tables, use them, and drop
@@ -526,25 +570,27 @@ async function reconcilePhantomLedger(tx, applied) {
526
570
  await tx.exec('DROP TABLE IF EXISTS ' + quoteIdentifier('__new_' + table))
527
571
  }
528
572
  for (const baseId of resurrect) {
529
- for (const id of [...applied]) {
530
- if (id !== baseId && !id.startsWith(baseId + ':')) continue
531
- await tx.exec(
532
- 'DELETE FROM ' + quoteIdentifier(migrationTable) + ' WHERE id = ?',
533
- [id],
534
- )
535
- applied.delete(id)
536
- }
573
+ await deleteAppliedMigrationStatement(tx, baseId)
574
+ applied.delete(baseId)
537
575
  }
538
576
  }
539
577
 
540
- async function applyNativeSchema(tx, instance) {
541
- await tx.exec(
542
- 'CREATE TABLE IF NOT EXISTS ' + quoteIdentifier(migrationTable) +
543
- ' (id TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)',
544
- )
545
- const appliedRows = await tx.query('SELECT id FROM ' + quoteIdentifier(migrationTable))
546
- const applied = new Set(appliedRows.map((row) => row.id))
547
- await reconcilePhantomLedger(tx, applied)
578
+ async function applyNativeSchema(tx, instance, {
579
+ applied = null,
580
+ prepare = true,
581
+ migrationFile = null,
582
+ finalize = true,
583
+ } = {}) {
584
+ if (prepare) {
585
+ await tx.exec(
586
+ 'CREATE TABLE IF NOT EXISTS ' + quoteIdentifier(migrationTable) +
587
+ ' (id TEXT PRIMARY KEY, applied_at INTEGER NOT NULL)',
588
+ )
589
+ applied = await readAppliedMigrationStatements(tx)
590
+ } else if (!(applied instanceof Set)) {
591
+ throw new Error('migration ledger state is required after prepare')
592
+ }
593
+ if (prepare) await reconcilePhantomLedger(tx, applied)
548
594
  // register BEFORE the statements, not only after them. a cdc trigger whose
549
595
  // _orez_cdc_tables row is missing is invisible to beginSchemaChange, which
550
596
  // skips unregistered tables, so it never suspends capture and the next
@@ -555,9 +601,8 @@ async function applyNativeSchema(tx, instance) {
555
601
  // still runs and still owns publication; this one only heals. on a fresh
556
602
  // namespace every table is absent, ensureTable returns false for each, and
557
603
  // this is a no-op beyond creating the cdc bookkeeping tables early.
558
- await tx.registerTables(publicTables())
559
- const appliedIds = [...applied]
560
- const appliedStatementIds = new Set()
604
+ if (prepare) await tx.registerTables(publicTables())
605
+ const appliedStatementIds = new Set(applied)
561
606
  const supersededStatementIds = new Set()
562
607
  for (const [index, statement] of nativeSqlStatements.entries()) {
563
608
  const item = typeof statement === 'string'
@@ -565,16 +610,30 @@ async function applyNativeSchema(tx, instance) {
565
610
  : statement
566
611
  if (!item || typeof item.sql !== 'string' || !item.sql.trim()) continue
567
612
  const baseId = typeof item.id === 'string' && item.id ? item.id : 'statement-' + index
568
- if (
569
- applied.has(baseId) ||
570
- appliedIds.some((appliedId) => appliedId.startsWith(baseId + ':'))
571
- ) {
572
- appliedStatementIds.add(baseId)
573
- }
574
613
  for (const id of Array.isArray(item.supersedes) ? item.supersedes : []) {
575
614
  supersededStatementIds.add(id)
576
615
  }
577
616
  }
617
+ const pendingMigrationFiles = []
618
+ for (const [index, statement] of nativeSqlStatements.entries()) {
619
+ const item = typeof statement === 'string'
620
+ ? { id: 'statement-' + index, sql: statement }
621
+ : statement
622
+ if (!item || typeof item.sql !== 'string' || !item.sql.trim()) continue
623
+ if (!item.sql.split('\\n').some((line) => {
624
+ const trimmed = line.trim()
625
+ return trimmed.length > 0 && !trimmed.startsWith('--')
626
+ })) continue
627
+ const baseId = typeof item.id === 'string' && item.id ? item.id : 'statement-' + index
628
+ if (supersededStatementIds.has(baseId) || appliedStatementIds.has(baseId)) continue
629
+ const file = baseId.split(':')[0]
630
+ if (!pendingMigrationFiles.includes(file)) pendingMigrationFiles.push(file)
631
+ }
632
+ const selectedMigrationFile =
633
+ migrationFile === null && prepare ? (pendingMigrationFiles[0] ?? null) : migrationFile
634
+ const remainingMigrationFiles = pendingMigrationFiles.filter(
635
+ (file) => file !== selectedMigrationFile,
636
+ )
578
637
  // CREATE TABLE IF NOT EXISTS is a SILENT NO-OP against a table that already
579
638
  // exists in an older shape, so every column that only ever appears inside a
580
639
  // CREATE definition is unreachable on a namespace whose table predates it,
@@ -587,7 +646,7 @@ async function applyNativeSchema(tx, instance) {
587
646
  // failure compensation below, so at the start of every retry the CREATE is
588
647
  // unledgered and the pass skipped it. converging here is independent of
589
648
  // ledger state, which is the only thing that made it reachable at all.
590
- for (const [index, statement] of nativeSqlStatements.entries()) {
649
+ for (const [index, statement] of prepare ? nativeSqlStatements.entries() : []) {
591
650
  const item = typeof statement === 'string' ? null : statement
592
651
  if (!item || !Array.isArray(item.declaredColumns)) continue
593
652
  if (typeof item.sql !== 'string') continue
@@ -650,6 +709,9 @@ async function applyNativeSchema(tx, instance) {
650
709
  })) continue
651
710
  const baseId = typeof item.id === 'string' && item.id ? item.id : 'statement-' + index
652
711
  if (supersededStatementIds.has(baseId)) continue
712
+ if (selectedMigrationFile === null || baseId.split(':')[0] !== selectedMigrationFile) {
713
+ continue
714
+ }
653
715
  const id = baseId + ':' + hashMigrationSql(item.sql)
654
716
  // migration statement ids are immutable execution identities. the SQL hash
655
717
  // records which source version ran, but editing an old migration must never
@@ -696,46 +758,51 @@ async function applyNativeSchema(tx, instance) {
696
758
  )
697
759
  }
698
760
  }
699
- if (!applied.has(id)) {
761
+ if (!appliedStatementIds.has(baseId)) {
700
762
  await tx.exec(
701
763
  'INSERT INTO ' + quoteIdentifier(migrationTable) + ' (id, applied_at) VALUES (?, ?)',
702
764
  [id, Date.now()],
703
765
  )
704
- applied.add(id)
766
+ applied.add(baseId)
705
767
  appliedStatementIds.add(baseId)
706
- insertedThisRun.push(id)
768
+ insertedThisRun.push({ baseId, id })
769
+ }
770
+ }
771
+ if (finalize && remainingMigrationFiles.length === 0) {
772
+ await assertExpectedSchema(tx)
773
+ await tx.exec(
774
+ 'CREATE TABLE IF NOT EXISTS _zero_schema_tables (name TEXT PRIMARY KEY, schema_json TEXT NOT NULL)',
775
+ )
776
+ try {
777
+ for (const statement of schemaMetadataStatements()) {
778
+ await tx.exec(statement.sql, statement.params)
779
+ }
780
+ await tx.registerTables(publicTables())
781
+ } catch (error) {
782
+ // publication runs against every registered table, so a table this schema
783
+ // no longer has still gets queried here. without the label the error is
784
+ // indistinguishable from a migration statement failing.
785
+ throw new Error(
786
+ 'schema publication failed on instance ' + instance + ': ' +
787
+ (error && error.message ? error.message : String(error)),
788
+ { cause: error },
789
+ )
707
790
  }
708
791
  }
709
792
  } catch (error) {
710
- for (const insertedId of insertedThisRun) {
793
+ for (const inserted of insertedThisRun) {
711
794
  try {
712
795
  await tx.exec(
713
796
  'DELETE FROM ' + quoteIdentifier(migrationTable) + ' WHERE id = ?',
714
- [insertedId],
797
+ [inserted.id],
715
798
  )
716
799
  } catch {}
800
+ applied.delete(inserted.baseId)
801
+ appliedStatementIds.delete(inserted.baseId)
717
802
  }
718
803
  throw error
719
804
  }
720
- await assertExpectedSchema(tx)
721
- await tx.exec(
722
- 'CREATE TABLE IF NOT EXISTS _zero_schema_tables (name TEXT PRIMARY KEY, schema_json TEXT NOT NULL)',
723
- )
724
- try {
725
- for (const statement of schemaMetadataStatements()) {
726
- await tx.exec(statement.sql, statement.params)
727
- }
728
- await tx.registerTables(publicTables())
729
- } catch (error) {
730
- // publication runs against every registered table, so a table this schema
731
- // no longer has still gets queried here. without the label the error is
732
- // indistinguishable from a migration statement failing.
733
- throw new Error(
734
- 'schema publication failed on instance ' + instance + ': ' +
735
- (error && error.message ? error.message : String(error)),
736
- { cause: error },
737
- )
738
- }
805
+ return { applied, pendingMigrationFiles: remainingMigrationFiles }
739
806
  }
740
807
 
741
808
  // what the namespace actually looks like, for a failure message. the single
@@ -796,7 +863,7 @@ export async function ${runCloudflareMigrations}({
796
863
  await client.registerTables(resolvedPublicTables)
797
864
  return { tables: resolvedPublicTables.map((table) => table.publicTable) }
798
865
  }
799
- // the statement loop labels its own failures; acquiring the session and
866
+ // the migration-file loop labels its own failures; acquiring a session and
800
867
  // committing sit OUTSIDE every try/catch in applyNativeSchema, so a Durable
801
868
  // Object SQL error raised there arrives bare. the schema barrier hands that
802
869
  // string straight back as a 503 body, which is the entire diagnosis budget a
@@ -807,13 +874,37 @@ export async function ${runCloudflareMigrations}({
807
874
  // so what is left is only reachable through a message that says more.
808
875
  let phase = 'session-acquire'
809
876
  try {
877
+ let migrationState
810
878
  await client.transaction(() => {
811
879
  throw new Error('native schema migration does not use queryAst')
812
880
  }, async (tx) => {
813
- phase = 'reconcile'
814
- await applyNativeSchema(tx, instance)
815
- phase = 'commit'
881
+ phase = 'prepare'
882
+ migrationState = await applyNativeSchema(tx, instance, {
883
+ prepare: true,
884
+ migrationFile: null,
885
+ finalize: true,
886
+ })
887
+ phase = migrationState.pendingMigrationFiles.length > 0
888
+ ? 'first-migration-commit'
889
+ : 'finalize-commit'
816
890
  })
891
+ const remainingMigrationFiles = migrationState.pendingMigrationFiles
892
+ for (const [index, migrationFile] of remainingMigrationFiles.entries()) {
893
+ await client.transaction(() => {
894
+ throw new Error('native schema migration does not use queryAst')
895
+ }, async (tx) => {
896
+ phase = 'migration ' + migrationFile
897
+ migrationState = await applyNativeSchema(tx, instance, {
898
+ applied: migrationState.applied,
899
+ prepare: false,
900
+ migrationFile,
901
+ finalize: index === remainingMigrationFiles.length - 1,
902
+ })
903
+ phase = migrationState.pendingMigrationFiles.length === 0
904
+ ? 'finalize-commit'
905
+ : 'migration-commit ' + migrationFile
906
+ })
907
+ }
817
908
  } catch (error) {
818
909
  throw new Error(
819
910
  'schema migration failed on instance ' + instance + ' during ' + phase + ': ' +
@@ -1 +1 @@
1
- {"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/cf-deploy/migration.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"migration.js","sourceRoot":"","sources":["../../src/cf-deploy/migration.ts"],"names":[],"mappings":"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"}
@@ -80,6 +80,11 @@ export interface OrezRequestContext<Env extends OrezDataWorkerEnv> {
80
80
  force?: boolean;
81
81
  }): Promise<unknown>;
82
82
  }
83
+ export interface OrezApplicationSqlCommitContext<Env extends OrezDataWorkerEnv> {
84
+ env: Env;
85
+ executionContext: OrezExecutionContext;
86
+ instance: string;
87
+ }
83
88
  export interface OrezBackupConfig<Env extends OrezDataWorkerEnv> extends Partial<Pick<NamespaceBackupOptions<Env>, 'acceptedFormats' | 'chunkTargetBytes' | 'controlPlaneNamespace' | 'excludedTables' | 'keep' | 'keepControlPlane' | 'partBytes' | 'prefix' | 'runBudgetMs'>> {
84
89
  bucket(env: Env): NamespaceBackupBucket;
85
90
  /**
@@ -111,6 +116,12 @@ export interface OrezDataWorkerOptions<Env extends OrezDataWorkerEnv, S extends
111
116
  rows?: number;
112
117
  windowMs?: number;
113
118
  };
119
+ /**
120
+ * Notify an application-owned consumer after a transaction durably commits
121
+ * published CDC rows. Invocation and failure handling run through the
122
+ * Durable Object execution context, outside the application write result.
123
+ */
124
+ applicationSqlDidCommit?(context: OrezApplicationSqlCommitContext<Env>): MaybePromise<void>;
114
125
  setup?(context: OrezRequestContext<Env>): MaybePromise<void>;
115
126
  routes?(context: OrezRequestContext<Env>): MaybePromise<Response | null | undefined>;
116
127
  onError?(error: unknown, context: OrezErrorContext<Env>): MaybePromise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"lite-data-worker.d.ts","sourceRoot":"","sources":["../../src/cf-do/lite-data-worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lite-data-worker.d.ts","sourceRoot":"","sources":["../../src/cf-do/lite-data-worker.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import { ZeroDO as OrezZeroDO } from './worker.js';
6
6
  const STANDARD_DATA_PATHS = [
7
7
  '/_orez/backup/restore',
8
8
  '/_orez/backup/export',
9
+ '/_orez/status',
9
10
  '/_orez/write-budget/trip',
10
11
  '/_orez/write-budget/reopen',
11
12
  '/_orez/write-budget',
@@ -280,6 +281,9 @@ export function createOrezDataWorker(options) {
280
281
  class ZeroSqlDO extends OrezZeroDO {
281
282
  orezStorage;
282
283
  orezWorkerVersion;
284
+ orezEnv;
285
+ orezExecutionContext;
286
+ orezInstance;
283
287
  orezSchemaRunVersion = null;
284
288
  orezSchemaRun = null;
285
289
  orezReadyVersion = null;
@@ -301,13 +305,55 @@ export function createOrezDataWorker(options) {
301
305
  : env));
302
306
  this.orezStorage = ctx.storage;
303
307
  this.orezWorkerVersion = env.CF_VERSION?.id ?? '';
308
+ this.orezEnv = env;
309
+ this.orezExecutionContext = ctx;
310
+ const instance = ctx.id.name;
311
+ if (options.applicationSqlDidCommit && typeof instance !== 'string') {
312
+ throw new Error('application SQL commit notifications require a named Durable Object');
313
+ }
314
+ this.orezInstance = instance ?? '';
304
315
  ctx.storage.sql.exec(`CREATE TABLE IF NOT EXISTS ${readyTable} (id INTEGER PRIMARY KEY CHECK (id = 1), version TEXT NOT NULL)`);
305
316
  ctx.storage.sql.exec(`CREATE TABLE IF NOT EXISTS ${attemptTable} (id INTEGER PRIMARY KEY CHECK (id = 1), version TEXT NOT NULL, attempt_count INTEGER NOT NULL, last_error TEXT)`);
306
317
  ctx.storage.sql.exec(`CREATE TABLE IF NOT EXISTS ${restoreTable} (id INTEGER PRIMARY KEY CHECK (id = 1), started_at INTEGER NOT NULL)`);
307
318
  }
308
- applicationSqlDidCommit(_changed, mutated) {
319
+ applicationSqlDidCommit(published, mutated) {
309
320
  if (mutated)
310
321
  this.orezBumpBackupMarker();
322
+ if (published && options.applicationSqlDidCommit) {
323
+ const notification = Promise.resolve()
324
+ .then(() => options.applicationSqlDidCommit({
325
+ env: this.orezEnv,
326
+ executionContext: this.orezExecutionContext,
327
+ instance: this.orezInstance,
328
+ }))
329
+ .catch((error) => {
330
+ try {
331
+ console.error(JSON.stringify({
332
+ event: 'application_sql_commit_notification_failed',
333
+ instance: this.orezInstance,
334
+ error: errorMessage(error),
335
+ }));
336
+ }
337
+ catch {
338
+ // Reporting is post-commit too and cannot change the write result.
339
+ }
340
+ });
341
+ try {
342
+ this.orezExecutionContext.waitUntil(notification);
343
+ }
344
+ catch (error) {
345
+ try {
346
+ console.error(JSON.stringify({
347
+ event: 'application_sql_commit_notification_schedule_failed',
348
+ instance: this.orezInstance,
349
+ error: errorMessage(error),
350
+ }));
351
+ }
352
+ catch {
353
+ // The durable application write is already committed.
354
+ }
355
+ }
356
+ }
311
357
  }
312
358
  async orezImportBatch(statements) {
313
359
  if (statements.length === 0)
@@ -356,7 +402,7 @@ export function createOrezDataWorker(options) {
356
402
  result = await options.schema.migrate({ client, instance });
357
403
  }
358
404
  finally {
359
- // each migration statement commits through its own session, so a
405
+ // each migration file commits through its own session, so a
360
406
  // migrate() that throws partway has already moved the persisted
361
407
  // schema; the cached table shapes are stale on every exit
362
408
  this.invalidateSchemaCaches();
@@ -586,6 +632,12 @@ export function createOrezDataWorker(options) {
586
632
  // Observability must never replace the request's actual outcome.
587
633
  }
588
634
  };
635
+ const hasAdminToken = (request, env) => {
636
+ const supplied = request.headers.get('x-orez-admin-token') ??
637
+ request.headers.get('authorization')?.replace(/^Bearer\s+/i, '');
638
+ return Boolean(env.OREZ_DO_WRITE_BUDGET_ADMIN_TOKEN &&
639
+ supplied === env.OREZ_DO_WRITE_BUDGET_ADMIN_TOKEN);
640
+ };
589
641
  const worker = {
590
642
  async fetch(request, env, executionContext) {
591
643
  const route = new URL(request.url).pathname;
@@ -595,6 +647,13 @@ export function createOrezDataWorker(options) {
595
647
  const resolved = resolveOrezDataRequest(request, namespaceOptions);
596
648
  if (!resolved)
597
649
  return new Response('invalid namespace', { status: 400 });
650
+ // The DO constructor creates durable control tables. Reject the
651
+ // protected status probe at the worker boundary so an unauthenticated
652
+ // request cannot name or instantiate a cold object just to receive a
653
+ // 403 from inside it.
654
+ if (resolved.pathname === '/_orez/status' && !hasAdminToken(request, env)) {
655
+ return Response.json({ error: 'forbidden', sqlBillingSinceBoot: { rowsWritten: 0 } }, { status: 403 });
656
+ }
598
657
  const routedHeaders = new Headers(request.headers);
599
658
  routedHeaders.set(namespaceOptions.nsHeader, resolved.instance === 'singleton'
600
659
  ? 'singleton'
@@ -643,6 +702,7 @@ export function createOrezDataWorker(options) {
643
702
  }
644
703
  if (resolved.pathname === '/changes' ||
645
704
  resolved.pathname === '/snapshot' ||
705
+ resolved.pathname === '/_orez/status' ||
646
706
  resolved.pathname === '/_orez/write-budget' ||
647
707
  resolved.pathname === '/_orez/write-budget/trip' ||
648
708
  resolved.pathname === '/_orez/write-budget/reopen') {