@secondlayer/shared 12.1.0 → 12.1.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.
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -601,12 +601,14 @@ interface ApiKeysTable {
601
601
  rate_limit: Generated<number>;
602
602
  ip_address: string;
603
603
  account_id: string;
604
- product: Generated<"account" | "streams" | "index" | "sentinel">;
604
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
605
605
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
606
606
  areas: unknown | null;
607
607
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
608
608
  last_used_at: Date | null;
609
609
  revoked_at: Date | null;
610
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
611
+ expires_at: Date | null;
610
612
  created_at: Generated<Date>;
611
613
  }
612
614
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -1024,7 +1026,7 @@ interface PendingForkBlocksTable {
1024
1026
  payload: ColumnType<unknown, unknown, unknown>;
1025
1027
  received_at: Generated<Date>;
1026
1028
  }
1027
- type ObserverJournalStatus = "received" | "processed" | "failed";
1029
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
1028
1030
  /**
1029
1031
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
1030
1032
  * processing columns are updated only after the current derived-state write
@@ -285,12 +285,14 @@ interface ApiKeysTable {
285
285
  rate_limit: Generated<number>;
286
286
  ip_address: string;
287
287
  account_id: string;
288
- product: Generated<"account" | "streams" | "index" | "sentinel">;
288
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
289
289
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
290
290
  areas: unknown | null;
291
291
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
292
292
  last_used_at: Date | null;
293
293
  revoked_at: Date | null;
294
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
295
+ expires_at: Date | null;
294
296
  created_at: Generated<Date>;
295
297
  }
296
298
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -708,7 +710,7 @@ interface PendingForkBlocksTable {
708
710
  payload: ColumnType<unknown, unknown, unknown>;
709
711
  received_at: Generated<Date>;
710
712
  }
711
- type ObserverJournalStatus = "received" | "processed" | "failed";
713
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
712
714
  /**
713
715
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
714
716
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -294,12 +294,14 @@ interface ApiKeysTable {
294
294
  rate_limit: Generated<number>;
295
295
  ip_address: string;
296
296
  account_id: string;
297
- product: Generated<"account" | "streams" | "index" | "sentinel">;
297
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
298
298
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
299
299
  areas: unknown | null;
300
300
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
301
301
  last_used_at: Date | null;
302
302
  revoked_at: Date | null;
303
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
304
+ expires_at: Date | null;
303
305
  created_at: Generated<Date>;
304
306
  }
305
307
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -717,7 +719,7 @@ interface PendingForkBlocksTable {
717
719
  payload: ColumnType<unknown, unknown, unknown>;
718
720
  received_at: Generated<Date>;
719
721
  }
720
- type ObserverJournalStatus = "received" | "processed" | "failed";
722
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
721
723
  /**
722
724
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
723
725
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -283,12 +283,14 @@ interface ApiKeysTable {
283
283
  rate_limit: Generated<number>;
284
284
  ip_address: string;
285
285
  account_id: string;
286
- product: Generated<"account" | "streams" | "index" | "sentinel">;
286
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
287
287
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
288
288
  areas: unknown | null;
289
289
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
290
290
  last_used_at: Date | null;
291
291
  revoked_at: Date | null;
292
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
293
+ expires_at: Date | null;
292
294
  created_at: Generated<Date>;
293
295
  }
294
296
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -706,7 +708,7 @@ interface PendingForkBlocksTable {
706
708
  payload: ColumnType<unknown, unknown, unknown>;
707
709
  received_at: Generated<Date>;
708
710
  }
709
- type ObserverJournalStatus = "received" | "processed" | "failed";
711
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
710
712
  /**
711
713
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
712
714
  * processing columns are updated only after the current derived-state write
@@ -496,12 +496,14 @@ interface ApiKeysTable {
496
496
  rate_limit: Generated<number>;
497
497
  ip_address: string;
498
498
  account_id: string;
499
- product: Generated<"account" | "streams" | "index" | "sentinel">;
499
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
500
500
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
501
501
  areas: unknown | null;
502
502
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
503
503
  last_used_at: Date | null;
504
504
  revoked_at: Date | null;
505
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
506
+ expires_at: Date | null;
505
507
  created_at: Generated<Date>;
506
508
  }
507
509
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -919,7 +921,7 @@ interface PendingForkBlocksTable {
919
921
  payload: ColumnType<unknown, unknown, unknown>;
920
922
  received_at: Generated<Date>;
921
923
  }
922
- type ObserverJournalStatus = "received" | "processed" | "failed";
924
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
923
925
  /**
924
926
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
925
927
  * processing columns are updated only after the current derived-state write
@@ -284,12 +284,14 @@ interface ApiKeysTable {
284
284
  rate_limit: Generated<number>;
285
285
  ip_address: string;
286
286
  account_id: string;
287
- product: Generated<"account" | "streams" | "index" | "sentinel">;
287
+ product: Generated<"account" | "streams" | "index" | "sentinel" | "docs">;
288
288
  /** Sentinel permission areas; set only on `product = 'sentinel'` keys. */
289
289
  areas: unknown | null;
290
290
  tier: "free" | "build" | "scale" | "enterprise" | "internal" | null;
291
291
  last_used_at: Date | null;
292
292
  revoked_at: Date | null;
293
+ /** Set only on `docs` keys (24h). A key past this instant never authenticates. */
294
+ expires_at: Date | null;
293
295
  created_at: Generated<Date>;
294
296
  }
295
297
  /** Singleton self-host / publisher identity. Network is immutable. */
@@ -707,7 +709,7 @@ interface PendingForkBlocksTable {
707
709
  payload: ColumnType<unknown, unknown, unknown>;
708
710
  received_at: Generated<Date>;
709
711
  }
710
- type ObserverJournalStatus = "received" | "processed" | "failed";
712
+ type ObserverJournalStatus = "received" | "processed" | "failed" | "retried";
711
713
  /**
712
714
  * Exact observer callback receipt. `raw_body` is immutable evidence; the
713
715
  * processing columns are updated only after the current derived-state write
@@ -119,7 +119,7 @@ type StreamsEventBase = {
119
119
  */
120
120
  matched?: string[]
121
121
  /**
122
- * Which chain this event came from (plan 059). Every Stacks Streams
122
+ * Which chain this event came from. Every Stacks Streams
123
123
  * response sets this to `"stacks"`; optional here for back-compat with
124
124
  * fixtures/tests that pre-date the field — the same reasoning as
125
125
  * `finalized?`. Cursors stay per-chain but chain-agnostic in shape, so this
@@ -0,0 +1,50 @@
1
+ import { type Kysely, sql } from "kysely";
2
+ import { onChainPlane } from "../src/db/migration-role.ts";
3
+
4
+ /**
5
+ * Observer journal status `retried`: a `failed` row whose exact bytes (same
6
+ * `raw_body_sha256`) were later `processed`, i.e. the node redelivered the
7
+ * block and it succeeded. `failed` now means unresolved, which is what the
8
+ * health check and canonical audit count. `error` stays on the row.
9
+ *
10
+ * Backfills existing rows with the same rule. `down` turns `retried` rows back
11
+ * into `failed` before restoring the three-value constraint.
12
+ */
13
+ export async function up(db: Kysely<unknown>): Promise<void> {
14
+ await onChainPlane(async () => {
15
+ await sql`SET lock_timeout = '30s'`.execute(db);
16
+ await sql`ALTER TABLE observer_journal DROP CONSTRAINT observer_journal_status_check`.execute(
17
+ db,
18
+ );
19
+ await sql`
20
+ ALTER TABLE observer_journal ADD CONSTRAINT observer_journal_status_check
21
+ CHECK (status IN ('received', 'processed', 'failed', 'retried'))
22
+ `.execute(db);
23
+ await sql`
24
+ UPDATE observer_journal f SET status = 'retried'
25
+ WHERE f.status = 'failed'
26
+ AND EXISTS (
27
+ SELECT 1 FROM observer_journal p
28
+ WHERE p.status = 'processed' AND p.network = f.network
29
+ AND p.raw_body_sha256 = f.raw_body_sha256
30
+ AND p.sequence > f.sequence
31
+ )
32
+ `.execute(db);
33
+ });
34
+ }
35
+
36
+ export async function down(db: Kysely<unknown>): Promise<void> {
37
+ await onChainPlane(async () => {
38
+ await sql`SET lock_timeout = '30s'`.execute(db);
39
+ await sql`UPDATE observer_journal SET status = 'failed' WHERE status = 'retried'`.execute(
40
+ db,
41
+ );
42
+ await sql`ALTER TABLE observer_journal DROP CONSTRAINT observer_journal_status_check`.execute(
43
+ db,
44
+ );
45
+ await sql`
46
+ ALTER TABLE observer_journal ADD CONSTRAINT observer_journal_status_check
47
+ CHECK (status IN ('received', 'processed', 'failed'))
48
+ `.execute(db);
49
+ });
50
+ }
@@ -0,0 +1,52 @@
1
+ import { type Kysely, sql } from "kysely";
2
+ import { onControlPlane } from "../src/db/migration-role.ts";
3
+
4
+ /**
5
+ * Docs keys: `api_keys.product = 'docs'`, short-lived (24h) read keys minted
6
+ * for a signed-in reader so code samples can carry their own key. They resolve
7
+ * on the Streams and Index read planes only. `expires_at` is null for every
8
+ * other key. At most one active docs key per account (minting a new one revokes
9
+ * the previous).
10
+ */
11
+ export async function up(db: Kysely<unknown>): Promise<void> {
12
+ await onControlPlane(async () => {
13
+ await sql`SET lock_timeout = '30s'`.execute(db);
14
+ await sql`ALTER TABLE api_keys ADD COLUMN IF NOT EXISTS expires_at timestamptz`.execute(
15
+ db,
16
+ );
17
+ await sql`
18
+ ALTER TABLE api_keys DROP CONSTRAINT IF EXISTS api_keys_product_check
19
+ `.execute(db);
20
+ await sql`
21
+ ALTER TABLE api_keys
22
+ ADD CONSTRAINT api_keys_product_check
23
+ CHECK (product IN ('account', 'streams', 'index', 'sentinel', 'docs'))
24
+ `.execute(db);
25
+ await sql`
26
+ CREATE UNIQUE INDEX IF NOT EXISTS api_keys_one_active_docs_per_account
27
+ ON api_keys (account_id)
28
+ WHERE status = 'active' AND product = 'docs'
29
+ `.execute(db);
30
+ });
31
+ }
32
+
33
+ export async function down(db: Kysely<unknown>): Promise<void> {
34
+ await onControlPlane(async () => {
35
+ await sql`SET lock_timeout = '30s'`.execute(db);
36
+ await sql`DROP INDEX IF EXISTS api_keys_one_active_docs_per_account`.execute(
37
+ db,
38
+ );
39
+ await sql`DELETE FROM api_keys WHERE product = 'docs'`.execute(db);
40
+ await sql`
41
+ ALTER TABLE api_keys DROP CONSTRAINT IF EXISTS api_keys_product_check
42
+ `.execute(db);
43
+ await sql`
44
+ ALTER TABLE api_keys
45
+ ADD CONSTRAINT api_keys_product_check
46
+ CHECK (product IN ('account', 'streams', 'index', 'sentinel'))
47
+ `.execute(db);
48
+ await sql`ALTER TABLE api_keys DROP COLUMN IF EXISTS expires_at`.execute(
49
+ db,
50
+ );
51
+ });
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "12.1.0",
3
+ "version": "12.1.1",
4
4
  "description": "Internal building blocks shared across Secondlayer packages.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -249,7 +249,7 @@
249
249
  "prepublishOnly": "bun run build"
250
250
  },
251
251
  "dependencies": {
252
- "@secondlayer/stacks": "^6.2.0",
252
+ "@secondlayer/stacks": "^6.2.1",
253
253
  "kysely": "0.28.17",
254
254
  "kysely-postgres-js": "3.0.0",
255
255
  "postgres": "^3.4.6",