@secondlayer/shared 7.11.2 → 9.0.0

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 (60) hide show
  1. package/dist/src/archive/range-digest.d.ts +16 -169
  2. package/dist/src/archive/semantic-digest-builder.d.ts +16 -169
  3. package/dist/src/archive/status.js +11 -3
  4. package/dist/src/archive/status.js.map +3 -3
  5. package/dist/src/coverage/index.d.ts +15 -169
  6. package/dist/src/crypto/secrets.js +22 -3
  7. package/dist/src/crypto/secrets.js.map +3 -3
  8. package/dist/src/db/index.d.ts +18 -211
  9. package/dist/src/db/index.js +23 -16
  10. package/dist/src/db/index.js.map +4 -4
  11. package/dist/src/db/queries/chain-reorgs.d.ts +16 -169
  12. package/dist/src/db/queries/chain-reorgs.js +23 -16
  13. package/dist/src/db/queries/chain-reorgs.js.map +4 -4
  14. package/dist/src/db/queries/contracts.d.ts +16 -169
  15. package/dist/src/db/queries/instance.d.ts +16 -169
  16. package/dist/src/db/queries/integrity.d.ts +16 -169
  17. package/dist/src/db/queries/subgraph-gaps.d.ts +16 -169
  18. package/dist/src/db/queries/subgraph-operations.d.ts +17 -170
  19. package/dist/src/db/queries/subgraph-operations.js +1 -15
  20. package/dist/src/db/queries/subgraph-operations.js.map +3 -3
  21. package/dist/src/db/queries/subgraphs.d.ts +17 -191
  22. package/dist/src/db/queries/subgraphs.js +30 -1068
  23. package/dist/src/db/queries/subgraphs.js.map +5 -12
  24. package/dist/src/db/queries/subscriptions.d.ts +16 -169
  25. package/dist/src/db/queries/subscriptions.js +22 -3
  26. package/dist/src/db/queries/subscriptions.js.map +3 -3
  27. package/dist/src/db/queries/sync-scope.d.ts +1006 -0
  28. package/dist/src/db/queries/sync-scope.js +116 -0
  29. package/dist/src/db/queries/sync-scope.js.map +10 -0
  30. package/dist/src/db/schema.d.ts +17 -198
  31. package/dist/src/errors.d.ts +1 -22
  32. package/dist/src/errors.js +2 -4
  33. package/dist/src/errors.js.map +3 -3
  34. package/dist/src/index.d.ts +22 -256
  35. package/dist/src/index.js +24 -20
  36. package/dist/src/index.js.map +6 -6
  37. package/dist/src/mode.d.ts +16 -2
  38. package/dist/src/mode.js +25 -4
  39. package/dist/src/mode.js.map +3 -3
  40. package/dist/src/node/local-client.d.ts +16 -169
  41. package/dist/src/runtime/index.d.ts +137 -18
  42. package/dist/src/runtime/index.js +261 -41
  43. package/dist/src/runtime/index.js.map +9 -7
  44. package/dist/src/schemas/index.d.ts +5 -25
  45. package/dist/src/schemas/index.js +1 -2
  46. package/dist/src/schemas/index.js.map +3 -3
  47. package/dist/src/schemas/subgraphs.d.ts +5 -25
  48. package/dist/src/schemas/subgraphs.js +1 -2
  49. package/dist/src/schemas/subgraphs.js.map +3 -3
  50. package/dist/src/streams-rows/index.d.ts +399 -0
  51. package/dist/src/streams-rows/index.js +336 -0
  52. package/dist/src/streams-rows/index.js.map +17 -0
  53. package/dist/src/subgraphs/spec.d.ts +0 -9
  54. package/migrations/0118_drop_retired_control_tables.ts +53 -0
  55. package/migrations/0119_drop_accounts_plan.ts +29 -0
  56. package/migrations/0120_sync_scopes.ts +42 -0
  57. package/package.json +10 -6
  58. package/dist/src/x402.d.ts +0 -47
  59. package/dist/src/x402.js +0 -79
  60. package/dist/src/x402.js.map +0 -10
@@ -10,14 +10,28 @@
10
10
  * 2026-05-14 shared-rip this also serves subgraphs + subscriptions.
11
11
  */
12
12
  type InstanceMode = "oss" | "platform";
13
+ /** What the operator wrote in the env — `archive` is the honest name for the
14
+ * metered public-archive deployment and aliases `platform` behaviorally. */
15
+ type DeclaredInstanceMode = InstanceMode | "archive";
13
16
  /**
14
17
  * Resolve the active instance mode from `process.env.INSTANCE_MODE`.
15
18
  * Defaults to `"oss"` — the safest default for self-hosters who deploy
16
- * without setting the variable.
19
+ * without setting the variable. `archive` normalizes to `platform` here so
20
+ * every behavioral branch stays a two-way choice; use
21
+ * `getDeclaredInstanceMode()` for display surfaces.
17
22
  */
18
23
  declare function getInstanceMode(): InstanceMode;
24
+ /** The mode as declared in the env, for status/identity surfaces. */
25
+ declare function getDeclaredInstanceMode(): DeclaredInstanceMode;
26
+ /**
27
+ * True when public reads are credit-metered (the free window, retention, and
28
+ * credits gates arm). Platform/archive deployments meter by default;
29
+ * self-host never does unless the operator explicitly sets
30
+ * `METERED_READS=true`. `METERED_READS=false` disarms a metered deployment.
31
+ */
32
+ declare function isMeteredReads(): boolean;
19
33
  /** True when the active mode is `"platform"` (shared multi-tenant). */
20
34
  declare function isPlatformMode(): boolean;
21
35
  /** True when the active mode is `"oss"` (self-hosted). */
22
36
  declare function isOssMode(): boolean;
23
- export { isPlatformMode, isOssMode, getInstanceMode, InstanceMode };
37
+ export { isPlatformMode, isOssMode, isMeteredReads, getInstanceMode, getDeclaredInstanceMode, InstanceMode, DeclaredInstanceMode };
package/dist/src/mode.js CHANGED
@@ -15,14 +15,33 @@ var __export = (target, all) => {
15
15
  };
16
16
 
17
17
  // src/mode.ts
18
- var VALID_MODES = ["oss", "platform"];
19
- function getInstanceMode() {
18
+ var VALID_MODES = [
19
+ "oss",
20
+ "platform",
21
+ "archive"
22
+ ];
23
+ function declaredMode() {
20
24
  const raw = process.env.INSTANCE_MODE?.trim().toLowerCase();
21
25
  if (raw && VALID_MODES.includes(raw)) {
22
26
  return raw;
23
27
  }
24
28
  return "oss";
25
29
  }
30
+ function getInstanceMode() {
31
+ const declared = declaredMode();
32
+ return declared === "archive" ? "platform" : declared;
33
+ }
34
+ function getDeclaredInstanceMode() {
35
+ return declaredMode();
36
+ }
37
+ function isMeteredReads() {
38
+ const override = process.env.METERED_READS?.trim().toLowerCase();
39
+ if (override === "true")
40
+ return true;
41
+ if (override === "false")
42
+ return false;
43
+ return getInstanceMode() === "platform";
44
+ }
26
45
  function isPlatformMode() {
27
46
  return getInstanceMode() === "platform";
28
47
  }
@@ -32,8 +51,10 @@ function isOssMode() {
32
51
  export {
33
52
  isPlatformMode,
34
53
  isOssMode,
35
- getInstanceMode
54
+ isMeteredReads,
55
+ getInstanceMode,
56
+ getDeclaredInstanceMode
36
57
  };
37
58
 
38
- //# debugId=B04DA9673CE8B2EF64756E2164756E21
59
+ //# debugId=F90A93497EE7AEC664756E2164756E21
39
60
  //# sourceMappingURL=mode.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/mode.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Instance modes for the Secondlayer platform.\n *\n * - `oss`: self-hosted, single-tenant. No auth middleware, no platform routes\n * (projects, admin). Everything runs against a single `DATABASE_URL`.\n * Intended for `docker compose up`.\n *\n * - `platform`: control-plane mode. Magic-link auth, API keys, projects,\n * admin. Serves the dashboard + CLI against a single shared DB. Post\n * 2026-05-14 shared-rip this also serves subgraphs + subscriptions.\n */\n\nexport type InstanceMode = \"oss\" | \"platform\";\n\nconst VALID_MODES: readonly InstanceMode[] = [\"oss\", \"platform\"];\n\n/**\n * Resolve the active instance mode from `process.env.INSTANCE_MODE`.\n * Defaults to `\"oss\"` — the safest default for self-hosters who deploy\n * without setting the variable.\n */\nexport function getInstanceMode(): InstanceMode {\n\tconst raw = process.env.INSTANCE_MODE?.trim().toLowerCase();\n\tif (raw && (VALID_MODES as readonly string[]).includes(raw)) {\n\t\treturn raw as InstanceMode;\n\t}\n\treturn \"oss\";\n}\n\n/** True when the active mode is `\"platform\"` (shared multi-tenant). */\nexport function isPlatformMode(): boolean {\n\treturn getInstanceMode() === \"platform\";\n}\n\n/** True when the active mode is `\"oss\"` (self-hosted). */\nexport function isOssMode(): boolean {\n\treturn getInstanceMode() === \"oss\";\n}\n"
5
+ "/**\n * Instance modes for the Secondlayer platform.\n *\n * - `oss`: self-hosted, single-tenant. No auth middleware, no platform routes\n * (projects, admin). Everything runs against a single `DATABASE_URL`.\n * Intended for `docker compose up`.\n *\n * - `platform`: control-plane mode. Magic-link auth, API keys, projects,\n * admin. Serves the dashboard + CLI against a single shared DB. Post\n * 2026-05-14 shared-rip this also serves subgraphs + subscriptions.\n */\n\nexport type InstanceMode = \"oss\" | \"platform\";\n\n/** What the operator wrote in the env — `archive` is the honest name for the\n * metered public-archive deployment and aliases `platform` behaviorally. */\nexport type DeclaredInstanceMode = InstanceMode | \"archive\";\n\nconst VALID_MODES: readonly DeclaredInstanceMode[] = [\n\t\"oss\",\n\t\"platform\",\n\t\"archive\",\n];\n\nfunction declaredMode(): DeclaredInstanceMode {\n\tconst raw = process.env.INSTANCE_MODE?.trim().toLowerCase();\n\tif (raw && (VALID_MODES as readonly string[]).includes(raw)) {\n\t\treturn raw as DeclaredInstanceMode;\n\t}\n\treturn \"oss\";\n}\n\n/**\n * Resolve the active instance mode from `process.env.INSTANCE_MODE`.\n * Defaults to `\"oss\"` — the safest default for self-hosters who deploy\n * without setting the variable. `archive` normalizes to `platform` here so\n * every behavioral branch stays a two-way choice; use\n * `getDeclaredInstanceMode()` for display surfaces.\n */\nexport function getInstanceMode(): InstanceMode {\n\tconst declared = declaredMode();\n\treturn declared === \"archive\" ? \"platform\" : declared;\n}\n\n/** The mode as declared in the env, for status/identity surfaces. */\nexport function getDeclaredInstanceMode(): DeclaredInstanceMode {\n\treturn declaredMode();\n}\n\n/**\n * True when public reads are credit-metered (the free window, retention, and\n * credits gates arm). Platform/archive deployments meter by default;\n * self-host never does unless the operator explicitly sets\n * `METERED_READS=true`. `METERED_READS=false` disarms a metered deployment.\n */\nexport function isMeteredReads(): boolean {\n\tconst override = process.env.METERED_READS?.trim().toLowerCase();\n\tif (override === \"true\") return true;\n\tif (override === \"false\") return false;\n\treturn getInstanceMode() === \"platform\";\n}\n\n/** True when the active mode is `\"platform\"` (shared multi-tenant). */\nexport function isPlatformMode(): boolean {\n\treturn getInstanceMode() === \"platform\";\n}\n\n/** True when the active mode is `\"oss\"` (self-hosted). */\nexport function isOssMode(): boolean {\n\treturn getInstanceMode() === \"oss\";\n}\n"
6
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;AAcA,IAAM,cAAuC,CAAC,OAAO,UAAU;AAOxD,SAAS,eAAe,GAAiB;AAAA,EAC/C,MAAM,MAAM,QAAQ,IAAI,eAAe,KAAK,EAAE,YAAY;AAAA,EAC1D,IAAI,OAAQ,YAAkC,SAAS,GAAG,GAAG;AAAA,IAC5D,OAAO;AAAA,EACR;AAAA,EACA,OAAO;AAAA;AAID,SAAS,cAAc,GAAY;AAAA,EACzC,OAAO,gBAAgB,MAAM;AAAA;AAIvB,SAAS,SAAS,GAAY;AAAA,EACpC,OAAO,gBAAgB,MAAM;AAAA;",
8
- "debugId": "B04DA9673CE8B2EF64756E2164756E21",
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAkBA,IAAM,cAA+C;AAAA,EACpD;AAAA,EACA;AAAA,EACA;AACD;AAEA,SAAS,YAAY,GAAyB;AAAA,EAC7C,MAAM,MAAM,QAAQ,IAAI,eAAe,KAAK,EAAE,YAAY;AAAA,EAC1D,IAAI,OAAQ,YAAkC,SAAS,GAAG,GAAG;AAAA,IAC5D,OAAO;AAAA,EACR;AAAA,EACA,OAAO;AAAA;AAUD,SAAS,eAAe,GAAiB;AAAA,EAC/C,MAAM,WAAW,aAAa;AAAA,EAC9B,OAAO,aAAa,YAAY,aAAa;AAAA;AAIvC,SAAS,uBAAuB,GAAyB;AAAA,EAC/D,OAAO,aAAa;AAAA;AASd,SAAS,cAAc,GAAY;AAAA,EACzC,MAAM,WAAW,QAAQ,IAAI,eAAe,KAAK,EAAE,YAAY;AAAA,EAC/D,IAAI,aAAa;AAAA,IAAQ,OAAO;AAAA,EAChC,IAAI,aAAa;AAAA,IAAS,OAAO;AAAA,EACjC,OAAO,gBAAgB,MAAM;AAAA;AAIvB,SAAS,cAAc,GAAY;AAAA,EACzC,OAAO,gBAAgB,MAAM;AAAA;AAIvB,SAAS,SAAS,GAAY;AAAA,EACpC,OAAO,gBAAgB,MAAM;AAAA;",
8
+ "debugId": "F90A93497EE7AEC664756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -18,6 +18,7 @@ declare const FAILURE_CLASSES: readonly ["omission", "version", "digest_mismatch
18
18
  type FailureClass = (typeof FAILURE_CLASSES)[number];
19
19
  declare const RETRY_STATES: readonly ["open", "retrying", "halted", "resolved"];
20
20
  type RetryState = (typeof RETRY_STATES)[number];
21
+ type BootstrapSource = "archive" | "genesis" | "import";
21
22
  interface BlocksTable {
22
23
  height: number;
23
24
  hash: string;
@@ -223,11 +224,9 @@ interface AccountsTable {
223
224
  ghost: Generated<boolean>;
224
225
  /** Stacks principal owning a wallet-ghost account (x402-paid deploys). */
225
226
  wallet_principal: string | null;
226
- plan: Generated<string>;
227
227
  display_name: string | null;
228
228
  bio: string | null;
229
229
  avatar_url: string | null;
230
- slug: string | null;
231
230
  stripe_customer_id: string | null;
232
231
  /** Opt-out toggle for the subgraph reindex-completion email. Defaults true. */
233
232
  notify_reindex_complete: Generated<boolean>;
@@ -244,19 +243,6 @@ interface SessionsTable {
244
243
  last_used_at: Date | null;
245
244
  created_at: Generated<Date>;
246
245
  }
247
- /**
248
- * One-time claim tokens for ghost accounts. The raw token only ever appears in
249
- * the claim URL returned at mint time; we store its sha256. A used token marks
250
- * the account as claimed (or merged into an existing account).
251
- */
252
- interface ClaimTokensTable {
253
- id: Generated<string>;
254
- account_id: string;
255
- token_hash: string;
256
- created_at: Generated<Date>;
257
- expires_at: Date;
258
- used_at: Date | null;
259
- }
260
246
  interface MagicLinksTable {
261
247
  id: Generated<string>;
262
248
  email: string;
@@ -267,47 +253,6 @@ interface MagicLinksTable {
267
253
  failed_attempts: Generated<number>;
268
254
  created_at: Generated<Date>;
269
255
  }
270
- interface UsageDailyTable {
271
- account_id: string;
272
- tenant_id: string | null;
273
- date: string;
274
- api_requests: Generated<number>;
275
- deliveries: Generated<number>;
276
- streams_events_returned: Generated<number>;
277
- index_decoded_events_returned: Generated<number>;
278
- }
279
- interface UsageSnapshotsTable {
280
- id: Generated<string>;
281
- account_id: string;
282
- measured_at: Generated<Date>;
283
- storage_bytes: Generated<number>;
284
- }
285
- interface AccountInsightsTable {
286
- id: Generated<string>;
287
- account_id: string;
288
- category: string;
289
- insight_type: string;
290
- resource_id: string | null;
291
- severity: string;
292
- title: string;
293
- body: string;
294
- data: unknown;
295
- dismissed_at: Date | null;
296
- expires_at: Date | null;
297
- created_at: Generated<Date>;
298
- }
299
- interface AccountAgentRunsTable {
300
- id: Generated<string>;
301
- account_id: string;
302
- started_at: Generated<Date>;
303
- completed_at: Date | null;
304
- status: Generated<string>;
305
- input_tokens: Generated<number>;
306
- output_tokens: Generated<number>;
307
- cost_usd: Generated<number>;
308
- insights_created: Generated<number>;
309
- error: string | null;
310
- }
311
256
  interface SubgraphProcessingStatsTable {
312
257
  id: Generated<string>;
313
258
  subgraph_name: string;
@@ -340,41 +285,6 @@ interface SubgraphHealthSnapshotsTable {
340
285
  last_processed_block: number | null;
341
286
  captured_at: Generated<Date>;
342
287
  }
343
- interface SubgraphUsageDailyTable {
344
- subgraph_id: string;
345
- date: string;
346
- query_count: Generated<number>;
347
- }
348
- interface ProjectsTable {
349
- id: Generated<string>;
350
- name: string;
351
- slug: string;
352
- account_id: string;
353
- settings: Generated<Record<string, unknown>>;
354
- network: Generated<string>;
355
- node_rpc: string | null;
356
- created_at: Generated<Date>;
357
- updated_at: Generated<Date>;
358
- }
359
- interface TeamMembersTable {
360
- id: Generated<string>;
361
- project_id: string;
362
- account_id: string;
363
- role: Generated<string>;
364
- invited_by: string | null;
365
- created_at: Generated<Date>;
366
- }
367
- interface TeamInvitationsTable {
368
- id: Generated<string>;
369
- project_id: string;
370
- email: string;
371
- role: Generated<string>;
372
- token: string;
373
- invited_by: string | null;
374
- expires_at: Date;
375
- accepted_at: Date | null;
376
- created_at: Generated<Date>;
377
- }
378
288
  interface ProcessedStripeEventsTable {
379
289
  event_id: string;
380
290
  event_type: string;
@@ -811,6 +721,20 @@ interface StageFailuresTable {
811
721
  resolved_at: Date | null;
812
722
  retain_until: Generated<Date>;
813
723
  }
724
+ /**
725
+ * The instance's declared scope — one row per network. `start_height` is what
726
+ * makes missing history below it deliberate rather than a gap.
727
+ */
728
+ interface SyncScopesTable {
729
+ network: string;
730
+ start_height: number;
731
+ target_height: number | null;
732
+ bootstrap_source: BootstrapSource;
733
+ bootstrap_manifest_digest: string | null;
734
+ genesis_hash: string | null;
735
+ created_at: Generated<Date>;
736
+ updated_at: Generated<Date>;
737
+ }
814
738
  interface Database {
815
739
  blocks: BlocksTable;
816
740
  transactions: TransactionsTable;
@@ -827,27 +751,14 @@ interface Database {
827
751
  accounts: AccountsTable;
828
752
  sessions: SessionsTable;
829
753
  magic_links: MagicLinksTable;
830
- claim_tokens: ClaimTokensTable;
831
- usage_daily: UsageDailyTable;
832
- usage_snapshots: UsageSnapshotsTable;
833
- account_insights: AccountInsightsTable;
834
- account_agent_runs: AccountAgentRunsTable;
835
754
  subgraph_health_snapshots: SubgraphHealthSnapshotsTable;
836
755
  subgraph_processing_stats: SubgraphProcessingStatsTable;
837
756
  subgraph_table_snapshots: SubgraphTableSnapshotsTable;
838
757
  subgraph_gaps: SubgraphGapsTable;
839
758
  subgraph_operations: SubgraphOperationsTable;
840
- subgraph_usage_daily: SubgraphUsageDailyTable;
841
- projects: ProjectsTable;
842
- team_members: TeamMembersTable;
843
- team_invitations: TeamInvitationsTable;
844
759
  processed_stripe_events: ProcessedStripeEventsTable;
845
- tenants: TenantsTable;
846
- tenant_usage_monthly: TenantUsageMonthlyTable;
847
- tenant_compute_addons: TenantComputeAddonsTable;
848
760
  account_spend_caps: AccountSpendCapsTable;
849
761
  account_credits: AccountCreditsTable;
850
- provisioning_audit_log: ProvisioningAuditLogTable;
851
762
  subscriptions: SubscriptionsTable;
852
763
  subscription_outbox: SubscriptionOutboxTable;
853
764
  subscription_deliveries: SubscriptionDeliveriesTable;
@@ -876,6 +787,7 @@ interface Database {
876
787
  chain_read_cache: ChainReadCacheTable;
877
788
  pending_fork_blocks: PendingForkBlocksTable;
878
789
  observer_journal: ObserverJournalTable;
790
+ sync_scopes: SyncScopesTable;
879
791
  stage_registry: StageRegistryTable;
880
792
  stage_runs: StageRunsTable;
881
793
  stage_block_receipts: StageBlockReceiptsTable;
@@ -922,57 +834,6 @@ interface X402PaymentsTable {
922
834
  * reconciler's heal path can never double-credit them. */
923
835
  credited_at: Generated<Date> | null;
924
836
  }
925
- type TenantStatus = "provisioning" | "active" | "limit_warning" | "paused_limit" | "suspended" | "error" | "deleted";
926
- interface TenantsTable {
927
- id: Generated<string>;
928
- account_id: string;
929
- slug: string;
930
- status: ColumnType<TenantStatus, TenantStatus | undefined, TenantStatus>;
931
- plan: string;
932
- cpus: ColumnType<number, number | string, number | string>;
933
- memory_mb: number;
934
- storage_limit_mb: number;
935
- storage_used_mb: number | null;
936
- pg_container_id: string | null;
937
- api_container_id: string | null;
938
- processor_container_id: string | null;
939
- target_database_url_enc: Buffer;
940
- tenant_jwt_secret_enc: Buffer;
941
- anon_key_enc: Buffer;
942
- service_key_enc: Buffer;
943
- api_url_internal: string;
944
- api_url_public: string;
945
- suspended_at: Date | null;
946
- last_health_check_at: Date | null;
947
- last_active_at: Generated<Date>;
948
- service_gen: Generated<number>;
949
- anon_gen: Generated<number>;
950
- project_id: string | null;
951
- created_at: Generated<Date>;
952
- updated_at: Generated<Date>;
953
- }
954
- interface TenantUsageMonthlyTable {
955
- id: Generated<string>;
956
- tenant_id: string;
957
- period_month: Date;
958
- storage_peak_mb: Generated<number>;
959
- storage_avg_mb: Generated<number>;
960
- storage_last_mb: Generated<number>;
961
- measurements: Generated<number>;
962
- first_at: Generated<Date>;
963
- last_at: Generated<Date>;
964
- }
965
- interface TenantComputeAddonsTable {
966
- id: Generated<string>;
967
- tenant_id: string;
968
- memory_mb_delta: Generated<number>;
969
- cpu_delta: Generated<number | string>;
970
- storage_mb_delta: Generated<number>;
971
- effective_from: Generated<Date>;
972
- effective_until: Date | null;
973
- stripe_subscription_item_id: string | null;
974
- created_at: Generated<Date>;
975
- }
976
837
  interface AccountSpendCapsTable {
977
838
  account_id: string;
978
839
  monthly_cap_cents: number | null;
@@ -996,20 +857,6 @@ interface AccountCreditsTable {
996
857
  refill_last_at: Date | null;
997
858
  updated_at: Generated<Date>;
998
859
  }
999
- type ProvisioningAuditEvent = "provision.start" | "provision.success" | "provision.failure" | "suspend" | "resume" | "resize" | "keys.rotate" | "bastion.key.upload" | "bastion.key.revoke" | "teardown";
1000
- type ProvisioningAuditStatus = "ok" | "error";
1001
- interface ProvisioningAuditLogTable {
1002
- id: Generated<string>;
1003
- tenant_id: string | null;
1004
- tenant_slug: string | null;
1005
- account_id: string | null;
1006
- actor: string;
1007
- event: ProvisioningAuditEvent;
1008
- status: ProvisioningAuditStatus;
1009
- detail: unknown | null;
1010
- error: string | null;
1011
- created_at: Generated<Date>;
1012
- }
1013
860
  type SubscriptionStatus = "active" | "paused" | "error";
1014
861
  /** Polymorphic subscription mode: `subgraph` reacts to processed table rows;
1015
862
  * `chain` reacts to raw chain events matched directly off the Index/Streams
@@ -155,13 +155,11 @@ declare function reportRuntimeStatus(input: {
155
155
  coverage?: CoverageState | string
156
156
  }): RuntimeStatusReport;
157
157
  declare function actionFor(plane: StatusPlane, state: string): string;
158
- /**
159
- * Backup bundle — consistent DB, pinned config, encrypted keys, handler
160
- * manifests, and scope. Restore onto a wiped host must deep-verify green.
161
- */
158
+ declare const BACKUP_MANIFEST_VERSION = 1;
162
159
  declare const BACKUP_PARTS: readonly ["db", "config", "keys", "handlers", "scope"];
163
160
  type BackupPart = (typeof BACKUP_PARTS)[number];
164
161
  type BackupManifest = {
162
+ schema_version: number
165
163
  created_at: string
166
164
  network: string
167
165
  parts: BackupPart[]
@@ -170,34 +168,90 @@ type BackupManifest = {
170
168
  from_height: number
171
169
  to_height: number | null
172
170
  }
171
+ db: {
172
+ file: string
173
+ sha256: string
174
+ bytes: number
175
+ format: string
176
+ } | null
177
+ /** Never the secrets themselves — only how to check them. */
178
+ secrets: {
179
+ file: string
180
+ encrypted: boolean
181
+ canary: string
182
+ } | null
183
+ signature?: string
184
+ key_id?: string
173
185
  };
174
186
  type BackupPlan = {
175
- ok: boolean
187
+ ok: true
176
188
  manifest: BackupManifest
189
+ } | {
190
+ ok: false
177
191
  reason: string
178
192
  };
193
+ /**
194
+ * Validate a backup before any bytes are written. Refusing early is the whole
195
+ * point: a bundle that omits the keys looks like a backup and is not one.
196
+ */
179
197
  declare function planBackup(input: {
180
198
  network: string
181
- encryptedKeys: boolean
182
199
  fromHeight: number
183
200
  toHeight?: number | null
201
+ includeSecrets: boolean
202
+ secretsEncrypted: boolean
203
+ canary?: string
184
204
  now?: string
185
205
  }): BackupPlan;
186
- type RestoreResult = {
206
+ /**
207
+ * Seal the canary under an EXPLICIT key.
208
+ *
209
+ * Deliberately not reusing `crypto/secrets.ts`: that module resolves the key
210
+ * from the ambient environment and, in OSS mode, generates and persists one as
211
+ * a side effect when it is missing. Calling it here would mean a backup could
212
+ * mint the very key it is supposed to be preserving.
213
+ */
214
+ declare function sealKeyCanary(secretsKeyHex: string): string;
215
+ /** True only when `secretsKeyHex` is the key the canary was sealed with. */
216
+ declare function keyMatchesCanary(canaryBase64: string, secretsKeyHex: string): boolean;
217
+ /**
218
+ * Encrypt the secrets bundle under an operator passphrase.
219
+ * Layout: `salt(16) || iv(12) || authTag(16) || ciphertext`.
220
+ */
221
+ declare function encryptBundle(plaintext: string, passphrase: string): Buffer;
222
+ declare function decryptBundle(envelope: Buffer, passphrase: string): string;
223
+ type RestorePrecheck = {
187
224
  ok: true
188
- applied: boolean
189
- deep_green: boolean
190
225
  } | {
191
226
  ok: false
192
227
  reason: string
228
+ fatal: boolean
193
229
  };
194
- declare function restoreBackup(plan: BackupPlan, opts?: {
195
- apply?: boolean
196
- deepVerify?: boolean
197
- }): RestoreResult;
230
+ /**
231
+ * Everything that must hold before a restore writes anything.
232
+ *
233
+ * `fatal` distinguishes "this bundle can never restore here" from "this needs
234
+ * an explicit override" — the caller surfaces them differently.
235
+ */
236
+ declare function precheckRestore(input: {
237
+ manifest: BackupManifest
238
+ targetNetwork: string
239
+ targetIsEmpty: boolean
240
+ force: boolean
241
+ secretsKeyHex?: string
242
+ }): RestorePrecheck;
198
243
  /**
199
244
  * Upgrade contract — pin image, preflight schema/disk, backup first,
200
245
  * migrate, health/verify, document rollback limits.
246
+ *
247
+ * PLANNER ONLY — `applyUpgrade` returns `{applied:true}` without pulling an
248
+ * image, running a preflight, or migrating anything. Nothing in the product
249
+ * calls it. The upgrade operators actually perform is `docker compose pull &&
250
+ * up -d`, with migrations applied at boot by the runtime entrypoint.
251
+ *
252
+ * Same caution as the sibling backup planner: this step list was published as
253
+ * an operator procedure in the self-host docs until 2026-08-15. Make it do the
254
+ * work before presenting it as one.
201
255
  */
202
256
  declare const UPGRADE_STEPS: readonly ["pin", "preflight", "backup", "migrate", "health", "verify"];
203
257
  type UpgradeStep = (typeof UPGRADE_STEPS)[number];
@@ -227,6 +281,13 @@ declare function applyUpgrade(plan: UpgradePlan, opts?: {
227
281
  /**
228
282
  * Resource guardrails — preflight RAM/disk/Postgres and estimate growth.
229
283
  * Constrained fixtures fail early.
284
+ *
285
+ * The disk numbers here were wrong by 3-6x until 2026-08-15: they promised a
286
+ * full-history mainnet index would fit in 80 GB, and estimated growth at 1 GB
287
+ * per 100k blocks. The reference index measured 504 GB at height 8,771,873.
288
+ * An operator who sized a box from these figures would have filled the disk
289
+ * partway through their first bootstrap, so every constant below now cites what
290
+ * it was measured against.
230
291
  */
231
292
  type ResourceSnapshot = {
232
293
  ramMb: number
@@ -234,23 +295,81 @@ type ResourceSnapshot = {
234
295
  postgresMaxConnections: number
235
296
  postgresSharedBuffersMb?: number
236
297
  };
298
+ type DiskEstimates = {
299
+ /** blocks + transactions + events, no decoded plane. */
300
+ diskGbPer100kBlocks: number
301
+ /** Same, plus a broad decoder set writing `decoded_events`. */
302
+ diskGbPer100kBlocksDecoded: number
303
+ };
237
304
  type GuardrailResult = {
238
305
  ok: true
239
- estimates: {
240
- diskGbPer100kBlocks: number
241
- }
306
+ estimates: DiskEstimates
242
307
  } | {
243
308
  ok: false
244
309
  errors: string[]
245
310
  };
311
+ type GuardrailNetwork = "mainnet" | "testnet" | "devnet";
246
312
  declare const FLOORS: {
247
313
  readonly appRamMb: 4096
248
314
  readonly fullRamMb: 98304
315
+ /**
316
+ * Mainnet full history: 504 GB measured today, growing ~0.5 GB/day at the
317
+ * observed block rate. 600 leaves roughly six months of headroom, which is
318
+ * the point of a floor — a box that fits exactly today fails within weeks.
319
+ */
320
+ readonly mainnetAppDiskGb: 600
321
+ /**
322
+ * Testnet/devnet carry a fraction of mainnet's history. Unmeasured; retained
323
+ * as the long-standing default rather than replaced with a fresh guess.
324
+ */
249
325
  readonly appDiskGb: 80
326
+ /**
327
+ * Bundled node on mainnet. The Stacks chainstate alone measured 1.3 TB on
328
+ * the reference node (2026-08-15), and the index adds ~500 GB; bitcoind is
329
+ * additional and not measured here. The previous 1.5 TB floor was below the
330
+ * two components we HAVE measured.
331
+ */
332
+ readonly mainnetFullDiskGb: 2500
333
+ /** Bundled node, non-mainnet. Unmeasured; retained default. */
250
334
  readonly fullDiskGb: 1500
251
335
  readonly postgresMaxConnections: 50
252
336
  };
253
- declare function preflightResources(snap: ResourceSnapshot, mode: "external" | "stacks" | "full"): GuardrailResult;
337
+ /** The disk floor that applies to a given mode and network. */
338
+ declare function diskFloorGb(mode: "external" | "stacks" | "full", network: GuardrailNetwork): number;
339
+ /**
340
+ * A dimension the caller could not measure is absent, not zero. Skipping it
341
+ * keeps an unreadable `statfs` from presenting as a 0 GB disk and refusing a
342
+ * perfectly adequate box.
343
+ */
344
+ declare function preflightResources(snap: Partial<ResourceSnapshot>, mode: "external" | "stacks" | "full", network?: GuardrailNetwork): GuardrailResult;
345
+ type MeasuredResources = {
346
+ snapshot: Partial<ResourceSnapshot>
347
+ /** Dimensions we could not read, with why. Never guessed at. */
348
+ unknown: string[]
349
+ };
350
+ declare function measureResources(input: {
351
+ dataDir: string
352
+ query?: (sql: string) => Promise<Array<Record<string, unknown>>>
353
+ }): Promise<MeasuredResources>;
354
+ declare const UNDERSIZED_OVERRIDE = "SECONDLAYER_ALLOW_UNDERSIZED";
355
+ type PreflightDecision = {
356
+ action: "pass" | "warn" | "refuse"
357
+ messages: string[]
358
+ };
359
+ declare function decidePreflight(input: {
360
+ measured: MeasuredResources
361
+ mode: "external" | "stacks" | "full"
362
+ network: GuardrailNetwork
363
+ env?: Record<string, string | undefined>
364
+ }): PreflightDecision;
365
+ /** Measure this box and decide. Returns the decision; the caller exits. */
366
+ declare function runPreflight(input: {
367
+ dataDir: string
368
+ mode: "external" | "stacks" | "full"
369
+ network: GuardrailNetwork
370
+ query?: (sql: string) => Promise<Array<Record<string, unknown>>>
371
+ env?: Record<string, string | undefined>
372
+ }): Promise<PreflightDecision>;
254
373
  declare const MODULE_COMMANDS: Record<ModuleId, readonly string[]>;
255
374
  declare function commandFor(id: ModuleId): readonly string[];
256
- export { restoreBackup, reportRuntimeStatus, preflightResources, planUpgrade, planBackup, parseRuntimeConfig, migrateEmbedded, isolateHandler, isModuleId, emptyHealth, createSupervisor, createMemoryModule, createMemoryMigrationRunner, commandFor, applyUpgrade, actionFor, UpgradeStep, UpgradePlan, UPGRADE_STEPS, SupervisorHealth, Supervisor, StatusPlane, STATUS_PLANES, SECRET_KEYS, RuntimeStatusReport, RuntimeNetwork, RuntimeModule, RuntimeConfig, RestoreResult, ResourceSnapshot, RequiredConfigKey, REQUIRED_KEYS, PlaneStatus, PUBLISHER_PROFILE, OPTIONAL_KEYS, NodeMode, NODE_MODES, NETWORKS, ModuleState, ModuleId, ModuleHealth, MigrationRunner, MODULE_STATES, MODULE_IDS, MODULE_COMMANDS, MIGRATION_LOCK_KEY, IsolationResult, IsolationOomError, IsolationNetworkError, IsolationLimits, IsolationKillError, IsolationFault, ISOLATION_FAULTS, GuardrailResult, FLOORS, EmbeddedMigration, DEFAULT_PROFILE, ConfigResult, BackupPlan, BackupPart, BackupManifest, BACKUP_PARTS };
375
+ export { sealKeyCanary, runPreflight, reportRuntimeStatus, preflightResources, precheckRestore, planUpgrade, planBackup, parseRuntimeConfig, migrateEmbedded, measureResources, keyMatchesCanary, isolateHandler, isModuleId, encryptBundle, emptyHealth, diskFloorGb, decryptBundle, decidePreflight, createSupervisor, createMemoryModule, createMemoryMigrationRunner, commandFor, applyUpgrade, actionFor, UpgradeStep, UpgradePlan, UPGRADE_STEPS, UNDERSIZED_OVERRIDE, SupervisorHealth, Supervisor, StatusPlane, STATUS_PLANES, SECRET_KEYS, RuntimeStatusReport, RuntimeNetwork, RuntimeModule, RuntimeConfig, RestorePrecheck, ResourceSnapshot, RequiredConfigKey, REQUIRED_KEYS, PreflightDecision, PlaneStatus, PUBLISHER_PROFILE, OPTIONAL_KEYS, NodeMode, NODE_MODES, NETWORKS, ModuleState, ModuleId, ModuleHealth, MigrationRunner, MeasuredResources, MODULE_STATES, MODULE_IDS, MODULE_COMMANDS, MIGRATION_LOCK_KEY, IsolationResult, IsolationOomError, IsolationNetworkError, IsolationLimits, IsolationKillError, IsolationFault, ISOLATION_FAULTS, GuardrailResult, GuardrailNetwork, FLOORS, EmbeddedMigration, DiskEstimates, DEFAULT_PROFILE, ConfigResult, BackupPlan, BackupPart, BackupManifest, BACKUP_PARTS, BACKUP_MANIFEST_VERSION };