@secondlayer/shared 11.4.3 → 11.5.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 (55) hide show
  1. package/README.md +4 -4
  2. package/dist/src/archive/derived-stage-report.d.ts +2 -2
  3. package/dist/src/archive/derived-stage-report.js.map +1 -1
  4. package/dist/src/archive/instance-diagnosis.js +2 -2
  5. package/dist/src/archive/instance-diagnosis.js.map +2 -2
  6. package/dist/src/archive/range-digest.d.ts +25 -25
  7. package/dist/src/archive/semantic-digest-builder.d.ts +25 -25
  8. package/dist/src/coverage/index.d.ts +25 -25
  9. package/dist/src/coverage/index.js.map +1 -1
  10. package/dist/src/crypto/secondlayer-webhook.d.ts +2 -2
  11. package/dist/src/crypto/secondlayer-webhook.js.map +1 -1
  12. package/dist/src/crypto/secrets.js.map +1 -1
  13. package/dist/src/db/index.d.ts +37 -37
  14. package/dist/src/db/index.js +4 -4
  15. package/dist/src/db/index.js.map +3 -3
  16. package/dist/src/db/queries/chain-reorgs.d.ts +25 -25
  17. package/dist/src/db/queries/chain-reorgs.js +4 -4
  18. package/dist/src/db/queries/chain-reorgs.js.map +3 -3
  19. package/dist/src/db/queries/contracts.d.ts +25 -25
  20. package/dist/src/db/queries/instance.d.ts +25 -25
  21. package/dist/src/db/queries/integrity.d.ts +25 -25
  22. package/dist/src/db/queries/subgraph-gaps.d.ts +25 -25
  23. package/dist/src/db/queries/subgraph-operations.d.ts +25 -25
  24. package/dist/src/db/queries/subgraphs.d.ts +25 -25
  25. package/dist/src/db/queries/subgraphs.js +4 -4
  26. package/dist/src/db/queries/subgraphs.js.map +3 -3
  27. package/dist/src/db/queries/sync-scope.d.ts +25 -25
  28. package/dist/src/db/queries/{subscriptions.d.ts → webhooks.d.ts} +58 -58
  29. package/dist/src/db/queries/{subscriptions.js → webhooks.js} +38 -38
  30. package/dist/src/db/queries/webhooks.js.map +13 -0
  31. package/dist/src/db/schema.d.ts +34 -34
  32. package/dist/src/index.d.ts +109 -107
  33. package/dist/src/index.js +51 -54
  34. package/dist/src/index.js.map +6 -6
  35. package/dist/src/leader.d.ts +4 -4
  36. package/dist/src/leader.js +3 -3
  37. package/dist/src/leader.js.map +3 -3
  38. package/dist/src/node/local-client.d.ts +25 -25
  39. package/dist/src/queue/listener.d.ts +2 -2
  40. package/dist/src/queue/listener.js.map +1 -1
  41. package/dist/src/runtime/index.js +2 -6
  42. package/dist/src/runtime/index.js.map +4 -4
  43. package/dist/src/schemas/index.d.ts +61 -61
  44. package/dist/src/schemas/index.js +48 -51
  45. package/dist/src/schemas/index.js.map +5 -5
  46. package/dist/src/schemas/subgraphs.d.ts +2 -2
  47. package/dist/src/schemas/subgraphs.js.map +1 -1
  48. package/dist/src/schemas/{subscriptions.d.ts → webhooks.d.ts} +63 -63
  49. package/dist/src/schemas/{subscriptions.js → webhooks.js} +49 -52
  50. package/dist/src/schemas/webhooks.js.map +10 -0
  51. package/migrations/0126_rename_subscriptions_to_webhooks.ts +96 -0
  52. package/migrations/0127_rename_webhook_catalog_names.ts +55 -0
  53. package/package.json +8 -8
  54. package/dist/src/db/queries/subscriptions.js.map +0 -13
  55. package/dist/src/schemas/subscriptions.js.map +0 -10
@@ -789,9 +789,9 @@ interface Database {
789
789
  account_spend_caps: AccountSpendCapsTable;
790
790
  account_credits: AccountCreditsTable;
791
791
  hosted_meter_days: HostedMeterDaysTable;
792
- subscriptions: SubscriptionsTable;
793
- subscription_outbox: SubscriptionOutboxTable;
794
- subscription_deliveries: SubscriptionDeliveriesTable;
792
+ webhooks: WebhooksTable;
793
+ webhook_outbox: WebhookOutboxTable;
794
+ webhook_deliveries: WebhookDeliveriesTable;
795
795
  trigger_evaluator_state: TriggerEvaluatorStateTable;
796
796
  decoded_events: DecodedEventsTable;
797
797
  decoder_checkpoints: DecoderCheckpointsTable;
@@ -911,31 +911,31 @@ interface ArchiveFetchesTable {
911
911
  via_allowance: Generated<boolean>;
912
912
  charged_at: Generated<Date>;
913
913
  }
914
- type SubscriptionStatus = "active" | "paused" | "error";
915
- /** Polymorphic subscription mode: `subgraph` reacts to processed table rows;
914
+ type WebhookStatus = "active" | "paused" | "error";
915
+ /** Polymorphic webhook mode: `subgraph` reacts to processed table rows;
916
916
  * `chain` reacts to raw chain events matched directly off the Index/Streams
917
917
  * clock (no subgraph). See migration 0088. */
918
- type SubscriptionKind = "subgraph" | "chain";
919
- type SubscriptionFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
920
- type SubscriptionRuntime = "inngest" | "trigger" | "cloudflare" | "node";
921
- interface SubscriptionsTable {
918
+ type WebhookKind = "subgraph" | "chain";
919
+ type WebhookFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
920
+ type WebhookRuntime = "inngest" | "trigger" | "cloudflare" | "node";
921
+ interface WebhooksTable {
922
922
  id: Generated<string>;
923
923
  account_id: string;
924
924
  project_id: string | null;
925
925
  name: string;
926
- status: ColumnType<SubscriptionStatus, SubscriptionStatus | undefined, SubscriptionStatus>;
927
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
928
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
926
+ status: ColumnType<WebhookStatus, WebhookStatus | undefined, WebhookStatus>;
927
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
928
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
929
929
  subgraph_name: string | null;
930
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
930
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
931
931
  table_name: string | null;
932
932
  /** Chain-trigger filter array (the `SubgraphFilter` shape, JSON). Null for
933
- * subgraph subscriptions. Typed loosely here to avoid a shared→subgraphs
934
- * import cycle; the Zod schema in schemas/subscriptions.ts owns the shape. */
933
+ * subgraph webhooks. Typed loosely here to avoid a shared→subgraphs
934
+ * import cycle; the Zod schema in schemas/webhooks.ts owns the shape. */
935
935
  triggers: unknown | null;
936
936
  filter: Generated<unknown>;
937
- format: ColumnType<SubscriptionFormat, SubscriptionFormat | undefined, SubscriptionFormat>;
938
- runtime: SubscriptionRuntime | null;
937
+ format: ColumnType<WebhookFormat, WebhookFormat | undefined, WebhookFormat>;
938
+ runtime: WebhookRuntime | null;
939
939
  url: string;
940
940
  signing_secret_enc: Buffer;
941
941
  auth_config: Generated<unknown>;
@@ -951,13 +951,13 @@ interface SubscriptionsTable {
951
951
  updated_at: Generated<Date>;
952
952
  }
953
953
  type OutboxStatus = "pending" | "delivered" | "dead";
954
- interface SubscriptionOutboxTable {
954
+ interface WebhookOutboxTable {
955
955
  id: Generated<string>;
956
- subscription_id: string;
957
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
958
- /** Null for chain-subscription rows. */
956
+ webhook_id: string;
957
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
958
+ /** Null for chain-webhook rows. */
959
959
  subgraph_name: string | null;
960
- /** Null for chain-subscription rows. */
960
+ /** Null for chain-webhook rows. */
961
961
  table_name: string | null;
962
962
  block_height: number | bigint;
963
963
  tx_id: string | null;
@@ -975,12 +975,12 @@ interface SubscriptionOutboxTable {
975
975
  locked_until: Date | null;
976
976
  created_at: Generated<Date>;
977
977
  }
978
- interface SubscriptionDeliveriesTable {
978
+ interface WebhookDeliveriesTable {
979
979
  id: Generated<string>;
980
980
  /** Nullable after migration 0077 — outbox row may be cleaned up while
981
981
  * delivery telemetry is retained. */
982
982
  outbox_id: string | null;
983
- subscription_id: string;
983
+ webhook_id: string;
984
984
  attempt: number;
985
985
  status_code: number | null;
986
986
  response_headers: unknown | null;
@@ -990,7 +990,7 @@ interface SubscriptionDeliveriesTable {
990
990
  dispatched_at: Generated<Date>;
991
991
  }
992
992
  /** Single-row (id always TRUE) high-water mark for the chain-trigger evaluator.
993
- * One loop serves all chain subscriptions, so the cursor is global. */
993
+ * One loop serves all chain webhooks, so the cursor is global. */
994
994
  interface TriggerEvaluatorStateTable {
995
995
  id: Generated<boolean>;
996
996
  last_processed_block: ColumnType<bigint, bigint | number | undefined, bigint | number>;
@@ -789,9 +789,9 @@ interface Database {
789
789
  account_spend_caps: AccountSpendCapsTable;
790
790
  account_credits: AccountCreditsTable;
791
791
  hosted_meter_days: HostedMeterDaysTable;
792
- subscriptions: SubscriptionsTable;
793
- subscription_outbox: SubscriptionOutboxTable;
794
- subscription_deliveries: SubscriptionDeliveriesTable;
792
+ webhooks: WebhooksTable;
793
+ webhook_outbox: WebhookOutboxTable;
794
+ webhook_deliveries: WebhookDeliveriesTable;
795
795
  trigger_evaluator_state: TriggerEvaluatorStateTable;
796
796
  decoded_events: DecodedEventsTable;
797
797
  decoder_checkpoints: DecoderCheckpointsTable;
@@ -912,31 +912,31 @@ interface ArchiveFetchesTable {
912
912
  charged_at: Generated<Date>;
913
913
  }
914
914
  type SubgraphOperation = Selectable<SubgraphOperationsTable>;
915
- type SubscriptionStatus = "active" | "paused" | "error";
916
- /** Polymorphic subscription mode: `subgraph` reacts to processed table rows;
915
+ type WebhookStatus = "active" | "paused" | "error";
916
+ /** Polymorphic webhook mode: `subgraph` reacts to processed table rows;
917
917
  * `chain` reacts to raw chain events matched directly off the Index/Streams
918
918
  * clock (no subgraph). See migration 0088. */
919
- type SubscriptionKind = "subgraph" | "chain";
920
- type SubscriptionFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
921
- type SubscriptionRuntime = "inngest" | "trigger" | "cloudflare" | "node";
922
- interface SubscriptionsTable {
919
+ type WebhookKind = "subgraph" | "chain";
920
+ type WebhookFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
921
+ type WebhookRuntime = "inngest" | "trigger" | "cloudflare" | "node";
922
+ interface WebhooksTable {
923
923
  id: Generated<string>;
924
924
  account_id: string;
925
925
  project_id: string | null;
926
926
  name: string;
927
- status: ColumnType<SubscriptionStatus, SubscriptionStatus | undefined, SubscriptionStatus>;
928
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
929
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
927
+ status: ColumnType<WebhookStatus, WebhookStatus | undefined, WebhookStatus>;
928
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
929
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
930
930
  subgraph_name: string | null;
931
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
931
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
932
932
  table_name: string | null;
933
933
  /** Chain-trigger filter array (the `SubgraphFilter` shape, JSON). Null for
934
- * subgraph subscriptions. Typed loosely here to avoid a shared→subgraphs
935
- * import cycle; the Zod schema in schemas/subscriptions.ts owns the shape. */
934
+ * subgraph webhooks. Typed loosely here to avoid a shared→subgraphs
935
+ * import cycle; the Zod schema in schemas/webhooks.ts owns the shape. */
936
936
  triggers: unknown | null;
937
937
  filter: Generated<unknown>;
938
- format: ColumnType<SubscriptionFormat, SubscriptionFormat | undefined, SubscriptionFormat>;
939
- runtime: SubscriptionRuntime | null;
938
+ format: ColumnType<WebhookFormat, WebhookFormat | undefined, WebhookFormat>;
939
+ runtime: WebhookRuntime | null;
940
940
  url: string;
941
941
  signing_secret_enc: Buffer;
942
942
  auth_config: Generated<unknown>;
@@ -952,13 +952,13 @@ interface SubscriptionsTable {
952
952
  updated_at: Generated<Date>;
953
953
  }
954
954
  type OutboxStatus = "pending" | "delivered" | "dead";
955
- interface SubscriptionOutboxTable {
955
+ interface WebhookOutboxTable {
956
956
  id: Generated<string>;
957
- subscription_id: string;
958
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
959
- /** Null for chain-subscription rows. */
957
+ webhook_id: string;
958
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
959
+ /** Null for chain-webhook rows. */
960
960
  subgraph_name: string | null;
961
- /** Null for chain-subscription rows. */
961
+ /** Null for chain-webhook rows. */
962
962
  table_name: string | null;
963
963
  block_height: number | bigint;
964
964
  tx_id: string | null;
@@ -976,12 +976,12 @@ interface SubscriptionOutboxTable {
976
976
  locked_until: Date | null;
977
977
  created_at: Generated<Date>;
978
978
  }
979
- interface SubscriptionDeliveriesTable {
979
+ interface WebhookDeliveriesTable {
980
980
  id: Generated<string>;
981
981
  /** Nullable after migration 0077 — outbox row may be cleaned up while
982
982
  * delivery telemetry is retained. */
983
983
  outbox_id: string | null;
984
- subscription_id: string;
984
+ webhook_id: string;
985
985
  attempt: number;
986
986
  status_code: number | null;
987
987
  response_headers: unknown | null;
@@ -991,7 +991,7 @@ interface SubscriptionDeliveriesTable {
991
991
  dispatched_at: Generated<Date>;
992
992
  }
993
993
  /** Single-row (id always TRUE) high-water mark for the chain-trigger evaluator.
994
- * One loop serves all chain subscriptions, so the cursor is global. */
994
+ * One loop serves all chain webhooks, so the cursor is global. */
995
995
  interface TriggerEvaluatorStateTable {
996
996
  id: Generated<boolean>;
997
997
  last_processed_block: ColumnType<bigint, bigint | number | undefined, bigint | number>;
@@ -789,9 +789,9 @@ interface Database {
789
789
  account_spend_caps: AccountSpendCapsTable;
790
790
  account_credits: AccountCreditsTable;
791
791
  hosted_meter_days: HostedMeterDaysTable;
792
- subscriptions: SubscriptionsTable;
793
- subscription_outbox: SubscriptionOutboxTable;
794
- subscription_deliveries: SubscriptionDeliveriesTable;
792
+ webhooks: WebhooksTable;
793
+ webhook_outbox: WebhookOutboxTable;
794
+ webhook_deliveries: WebhookDeliveriesTable;
795
795
  trigger_evaluator_state: TriggerEvaluatorStateTable;
796
796
  decoded_events: DecodedEventsTable;
797
797
  decoder_checkpoints: DecoderCheckpointsTable;
@@ -912,31 +912,31 @@ interface ArchiveFetchesTable {
912
912
  charged_at: Generated<Date>;
913
913
  }
914
914
  type Subgraph = Selectable<SubgraphsTable>;
915
- type SubscriptionStatus = "active" | "paused" | "error";
916
- /** Polymorphic subscription mode: `subgraph` reacts to processed table rows;
915
+ type WebhookStatus = "active" | "paused" | "error";
916
+ /** Polymorphic webhook mode: `subgraph` reacts to processed table rows;
917
917
  * `chain` reacts to raw chain events matched directly off the Index/Streams
918
918
  * clock (no subgraph). See migration 0088. */
919
- type SubscriptionKind = "subgraph" | "chain";
920
- type SubscriptionFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
921
- type SubscriptionRuntime = "inngest" | "trigger" | "cloudflare" | "node";
922
- interface SubscriptionsTable {
919
+ type WebhookKind = "subgraph" | "chain";
920
+ type WebhookFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
921
+ type WebhookRuntime = "inngest" | "trigger" | "cloudflare" | "node";
922
+ interface WebhooksTable {
923
923
  id: Generated<string>;
924
924
  account_id: string;
925
925
  project_id: string | null;
926
926
  name: string;
927
- status: ColumnType<SubscriptionStatus, SubscriptionStatus | undefined, SubscriptionStatus>;
928
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
929
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
927
+ status: ColumnType<WebhookStatus, WebhookStatus | undefined, WebhookStatus>;
928
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
929
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
930
930
  subgraph_name: string | null;
931
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
931
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
932
932
  table_name: string | null;
933
933
  /** Chain-trigger filter array (the `SubgraphFilter` shape, JSON). Null for
934
- * subgraph subscriptions. Typed loosely here to avoid a shared→subgraphs
935
- * import cycle; the Zod schema in schemas/subscriptions.ts owns the shape. */
934
+ * subgraph webhooks. Typed loosely here to avoid a shared→subgraphs
935
+ * import cycle; the Zod schema in schemas/webhooks.ts owns the shape. */
936
936
  triggers: unknown | null;
937
937
  filter: Generated<unknown>;
938
- format: ColumnType<SubscriptionFormat, SubscriptionFormat | undefined, SubscriptionFormat>;
939
- runtime: SubscriptionRuntime | null;
938
+ format: ColumnType<WebhookFormat, WebhookFormat | undefined, WebhookFormat>;
939
+ runtime: WebhookRuntime | null;
940
940
  url: string;
941
941
  signing_secret_enc: Buffer;
942
942
  auth_config: Generated<unknown>;
@@ -952,13 +952,13 @@ interface SubscriptionsTable {
952
952
  updated_at: Generated<Date>;
953
953
  }
954
954
  type OutboxStatus = "pending" | "delivered" | "dead";
955
- interface SubscriptionOutboxTable {
955
+ interface WebhookOutboxTable {
956
956
  id: Generated<string>;
957
- subscription_id: string;
958
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
959
- /** Null for chain-subscription rows. */
957
+ webhook_id: string;
958
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
959
+ /** Null for chain-webhook rows. */
960
960
  subgraph_name: string | null;
961
- /** Null for chain-subscription rows. */
961
+ /** Null for chain-webhook rows. */
962
962
  table_name: string | null;
963
963
  block_height: number | bigint;
964
964
  tx_id: string | null;
@@ -976,12 +976,12 @@ interface SubscriptionOutboxTable {
976
976
  locked_until: Date | null;
977
977
  created_at: Generated<Date>;
978
978
  }
979
- interface SubscriptionDeliveriesTable {
979
+ interface WebhookDeliveriesTable {
980
980
  id: Generated<string>;
981
981
  /** Nullable after migration 0077 — outbox row may be cleaned up while
982
982
  * delivery telemetry is retained. */
983
983
  outbox_id: string | null;
984
- subscription_id: string;
984
+ webhook_id: string;
985
985
  attempt: number;
986
986
  status_code: number | null;
987
987
  response_headers: unknown | null;
@@ -991,7 +991,7 @@ interface SubscriptionDeliveriesTable {
991
991
  dispatched_at: Generated<Date>;
992
992
  }
993
993
  /** Single-row (id always TRUE) high-water mark for the chain-trigger evaluator.
994
- * One loop serves all chain subscriptions, so the cursor is global. */
994
+ * One loop serves all chain webhooks, so the cursor is global. */
995
995
  interface TriggerEvaluatorStateTable {
996
996
  id: Generated<boolean>;
997
997
  last_processed_block: ColumnType<bigint, bigint | number | undefined, bigint | number>;
@@ -177,12 +177,12 @@ async function deleteSubgraph(db, name, accountId) {
177
177
  if (!subgraph)
178
178
  return null;
179
179
  const schemaName = subgraph.schema_name ?? pgSchemaName(name);
180
- await db.updateTable("subscriptions").set({
180
+ await db.updateTable("webhooks").set({
181
181
  status: "paused",
182
- last_error: `Subgraph "${name}" deleted; subscription auto-paused.`,
182
+ last_error: `Subgraph "${name}" deleted; webhook auto-paused.`,
183
183
  updated_at: new Date
184
184
  }).where("subgraph_name", "=", name).execute();
185
- await db.deleteFrom("subscription_outbox").where("status", "=", "pending").where("subscription_id", "in", (qb) => qb.selectFrom("subscriptions").select("id").where("subgraph_name", "=", name)).execute();
185
+ await db.deleteFrom("webhook_outbox").where("status", "=", "pending").where("webhook_id", "in", (qb) => qb.selectFrom("webhooks").select("id").where("subgraph_name", "=", name)).execute();
186
186
  await sql2`DROP SCHEMA IF EXISTS ${sql2.raw(`"${schemaName}"`)} CASCADE`.execute(db);
187
187
  await db.deleteFrom("subgraphs").where("id", "=", subgraph.id).execute();
188
188
  return subgraph;
@@ -224,5 +224,5 @@ export {
224
224
  deleteSubgraph
225
225
  };
226
226
 
227
- //# debugId=F007CF49F477B67864756E2164756E21
227
+ //# debugId=0C7267DDF02AF5D764756E2164756E21
228
228
  //# sourceMappingURL=subgraphs.js.map
@@ -4,9 +4,9 @@
4
4
  "sourcesContent": [
5
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`: the metered archive deployment. Magic-link auth, API keys,\n * accounts, credits, and metered `/v1` reads (Index + Streams + subgraphs)\n * against a single shared DB. No paid tier ladder — one metered `free`\n * tier plus first-party internal service credentials.\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
  "import { type RawBuilder, sql } from \"kysely\";\n\n/**\n * Safely encode a JS value as a JSONB literal for Kysely inserts/updates.\n * Kysely + postgres.js double-encodes JSON when using parameterized queries\n * with ::jsonb casts. This uses sql.raw to inline a properly escaped literal.\n *\n * Generic parameter lets callers set the RawBuilder's output type so they\n * don't need to cast at the insert site. Default is `unknown` — widen at\n * the call site when the column type is narrower, e.g. `jsonb<MyShape>(...)`.\n */\nexport function jsonb<T = unknown>(value: T): RawBuilder<T> {\n\tconst escaped = JSON.stringify(value, (_k, v) =>\n\t\ttypeof v === \"bigint\" ? v.toString() : v,\n\t).replace(/'/g, \"''\");\n\treturn sql`${sql.raw(`'${escaped}'::jsonb`)}`;\n}\n\n/**\n * Safely parse a JSONB value from the database.\n * Handles double-encoded strings where postgres.js returns a JSON string\n * instead of a parsed object.\n */\nexport function parseJsonb<T = unknown>(value: unknown): T {\n\tif (typeof value === \"string\") {\n\t\ttry {\n\t\t\treturn JSON.parse(value) as T;\n\t\t} catch {\n\t\t\treturn value as T;\n\t\t}\n\t}\n\treturn (value ?? {}) as T;\n}\n",
7
- "import { type Kysely, sql } from \"kysely\";\nimport { isPlatformMode } from \"../../mode.ts\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Database, Subgraph } from \"../types.ts\";\n\n/**\n * Convert a subgraph name to its PostgreSQL schema name (legacy form).\n * Pre shared-rip every tenant DB had its own schema namespace so disambiguation\n * was implicit. Kept for oss mode (single-tenant) and legacy-row fallback.\n * Platform-mode deploys use `pgSchemaNameFor(accountId, name)`.\n */\nexport function pgSchemaName(subgraphName: string): string {\n\tconst safeName = subgraphName.replace(/-/g, \"_\");\n\treturn `subgraph_${safeName}`;\n}\n\n/** OSS writes empty account_id — name is the local unique key. */\nexport function localSubgraphAccountId(accountId?: string): string {\n\tif (!isPlatformMode()) return \"\";\n\treturn accountId ?? \"\";\n}\n\n/**\n * Account-scoped schema name. Matches migration 0028's rename pattern:\n * subgraph_{first8charsOfAccountId, dashes-as-underscores}_{name}\n * Empty accountId falls back to legacy form (oss mode).\n */\nexport function pgSchemaNameFor(\n\taccountId: string,\n\tsubgraphName: string,\n): string {\n\tif (!accountId) return pgSchemaName(subgraphName);\n\tconst accountPrefix = accountId.slice(0, 8).replace(/-/g, \"_\");\n\tconst safeName = subgraphName.replace(/-/g, \"_\");\n\treturn `subgraph_${accountPrefix}_${safeName}`;\n}\n\nexport async function registerSubgraph(\n\tdb: Kysely<Database>,\n\tdata: {\n\t\tname: string;\n\t\tversion: string;\n\t\tdefinition: Record<string, unknown>;\n\t\tschemaHash: string;\n\t\thandlerPath: string;\n\t\tapiKeyId?: string;\n\t\taccountId?: string;\n\t\tschemaName?: string;\n\t\tstartBlock?: number;\n\t\thandlerCode?: string;\n\t\tsourceCode?: string;\n\t},\n): Promise<Subgraph> {\n\tconst accountId = localSubgraphAccountId(data.accountId);\n\tconst values = {\n\t\tname: data.name,\n\t\tversion: data.version,\n\t\tdefinition: jsonb<Record<string, unknown>>(data.definition),\n\t\tschema_hash: data.schemaHash,\n\t\thandler_path: data.handlerPath,\n\t\taccount_id: accountId,\n\t\thandler_code: data.handlerCode ?? null,\n\t\tsource_code: data.sourceCode ?? null,\n\t\tschema_name: data.schemaName ?? null,\n\t\tstart_block: data.startBlock ?? 0,\n\t\tdatabase_url_enc: null,\n\t};\n\tconst updateSet = {\n\t\tversion: data.version,\n\t\tdefinition: jsonb<Record<string, unknown>>(data.definition),\n\t\tschema_hash: data.schemaHash,\n\t\thandler_path: data.handlerPath,\n\t\thandler_code: data.handlerCode ?? null,\n\t\tsource_code: data.sourceCode ?? null,\n\t\tschema_name: data.schemaName ?? null,\n\t\tstart_block: data.startBlock ?? 0,\n\t\tdatabase_url_enc: null,\n\t\tupdated_at: new Date(),\n\t};\n\n\t// OSS: name is unique. Upsert by name so leftover rows with a non-empty\n\t// account_id (pre-local-namespace deploys) don't insert a second row.\n\tif (!isPlatformMode()) {\n\t\tconst existing = await db\n\t\t\t.selectFrom(\"subgraphs\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"name\", \"=\", data.name)\n\t\t\t.executeTakeFirst();\n\t\tif (existing) {\n\t\t\treturn await db\n\t\t\t\t.updateTable(\"subgraphs\")\n\t\t\t\t.set({ ...updateSet, account_id: \"\" })\n\t\t\t\t.where(\"id\", \"=\", existing.id)\n\t\t\t\t.returningAll()\n\t\t\t\t.executeTakeFirstOrThrow();\n\t\t}\n\t\treturn await db\n\t\t\t.insertInto(\"subgraphs\")\n\t\t\t.values(values)\n\t\t\t.returningAll()\n\t\t\t.executeTakeFirstOrThrow();\n\t}\n\n\treturn await db\n\t\t.insertInto(\"subgraphs\")\n\t\t.values(values)\n\t\t.onConflict((oc) =>\n\t\t\toc.columns([\"name\", \"account_id\"]).doUpdateSet(updateSet),\n\t\t)\n\t\t.returningAll()\n\t\t.executeTakeFirstOrThrow();\n}\n\nexport async function getSubgraph(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId?: string,\n): Promise<Subgraph | null> {\n\tlet query = db.selectFrom(\"subgraphs\").selectAll().where(\"name\", \"=\", name);\n\n\tif (isPlatformMode() && accountId !== undefined) {\n\t\tquery = query.where(\"account_id\", \"=\", accountId);\n\t}\n\n\treturn (await query.executeTakeFirst()) ?? null;\n}\n\nexport async function listSubgraphs(\n\tdb: Kysely<Database>,\n\taccountId?: string,\n): Promise<Subgraph[]> {\n\tlet query = db.selectFrom(\"subgraphs\").selectAll();\n\tif (isPlatformMode() && accountId !== undefined) {\n\t\tquery = query.where(\"account_id\", \"=\", accountId);\n\t}\n\treturn query.execute();\n}\n\nexport async function updateSubgraphStatus(\n\tdb: Kysely<Database>,\n\tname: string,\n\tstatus: string,\n\tlastProcessedBlock?: number,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tstatus,\n\t\t\t...(lastProcessedBlock !== undefined\n\t\t\t\t? { last_processed_block: lastProcessedBlock }\n\t\t\t\t: {}),\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n\n/** Account-scoped pause. Only active/reindexing rows flip; name-only\n * {@link updateSubgraphStatus} is unsafe on platform (name, account_id). */\nexport async function pauseSubgraph(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId: string,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ status: \"paused\", updated_at: new Date() })\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"in\", [\"active\", \"reindexing\"])\n\t\t.execute();\n}\n\n/** Resume every paused subgraph for an account (claim / Stripe top-up). */\nexport async function resumePausedSubgraphs(\n\tdb: Kysely<Database>,\n\taccountId: string,\n): Promise<number> {\n\tconst res = await db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ status: \"active\", updated_at: new Date() })\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"=\", \"paused\")\n\t\t.executeTakeFirst();\n\treturn Number(res.numUpdatedRows ?? 0);\n}\n\n/** Live-walk ERROR write (f069): a block whose handlers ALL failed\n * (`processed === 0 && errors > 0`, `block-processor.ts`'s `applyProgress`)\n * is stamped 'error' and its height is recorded as processed, same as\n * `updateSubgraphStatus(db, name, \"error\", blockHeight)` — except the\n * cursor half of that write now goes through the same conditional `<`\n * guard as {@link recordLiveProgress}. Marking a subgraph 'error' is not\n * itself replay-sensitive, but it shares the `last_processed_block` column\n * with the replay guard: an unconditional write here could regress the\n * cursor a racing (successful) writer already advanced past, which is\n * exactly the regress-then-re-walk loop this guard exists to close. In\n * practice `ctx.rollbackTo` (`runner.ts`) means an all-failed block never\n * flushes writes, so a lost race here is always a silent no-op, never a\n * case that needs `CursorRaceLostError`-style tx abort. Returns whether\n * the write applied. Live path only — reindex/backfill's error stamping\n * goes through {@link updateSubgraphStatus} unconditionally, as before. */\nexport async function recordLiveError(\n\tdb: Kysely<Database>,\n\tname: string,\n\tblockHeight: number,\n): Promise<boolean> {\n\tconst result = await db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tstatus: \"error\",\n\t\t\tlast_processed_block: blockHeight,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"last_processed_block\", \"<\", blockHeight)\n\t\t.executeTakeFirst();\n\treturn Number(result.numUpdatedRows ?? 0n) > 0;\n}\n\nexport async function recordSubgraphProcessed(\n\tdb: Kysely<Database>,\n\tname: string,\n\tprocessed: number,\n\terrors: number,\n\tlastError?: string,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\ttotal_processed: sql`total_processed + ${processed}`,\n\t\t\ttotal_errors: sql`total_errors + ${errors}`,\n\t\t\t...(lastError\n\t\t\t\t? { last_error: lastError, last_error_at: new Date() }\n\t\t\t\t: {}),\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n\nexport async function updateSubgraphHandlerPath(\n\tdb: Kysely<Database>,\n\tname: string,\n\thandlerPath: string,\n\topts?: { handlerCode?: string; sourceCode?: string },\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\thandler_path: handlerPath,\n\t\t\t...(opts?.handlerCode != null ? { handler_code: opts.handlerCode } : {}),\n\t\t\t...(opts?.sourceCode != null ? { source_code: opts.sourceCode } : {}),\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n\nexport async function deleteSubgraph(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId?: string,\n): Promise<Subgraph | null> {\n\tconst subgraph = await getSubgraph(db, name, accountId);\n\tif (!subgraph) return null;\n\n\t// Use stored schema_name if available, otherwise compute\n\tconst schemaName = subgraph.schema_name ?? pgSchemaName(name);\n\n\t// Cascade to subscriptions: a subscription pointing at a deleted\n\t// subgraph + table will throw `relation does not exist` on every\n\t// subsequent emission. Pause active subs and purge any pending outbox\n\t// rows so receivers don't get phantom replays. We don't delete the\n\t// subscriptions themselves — operators may want to repoint them at a\n\t// resurrected subgraph; we just stop them firing.\n\tawait db\n\t\t.updateTable(\"subscriptions\")\n\t\t.set({\n\t\t\tstatus: \"paused\",\n\t\t\tlast_error: `Subgraph \"${name}\" deleted; subscription auto-paused.`,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"subgraph_name\", \"=\", name)\n\t\t.execute();\n\tawait db\n\t\t.deleteFrom(\"subscription_outbox\")\n\t\t.where(\"status\", \"=\", \"pending\")\n\t\t.where(\"subscription_id\", \"in\", (qb) =>\n\t\t\tqb\n\t\t\t\t.selectFrom(\"subscriptions\")\n\t\t\t\t.select(\"id\")\n\t\t\t\t.where(\"subgraph_name\", \"=\", name),\n\t\t)\n\t\t.execute();\n\n\t// Drop the subgraph's schema (CASCADE drops all tables within).\n\tawait sql`DROP SCHEMA IF EXISTS ${sql.raw(`\"${schemaName}\"`)} CASCADE`.execute(\n\t\tdb,\n\t);\n\n\t// Remove from registry\n\tawait db.deleteFrom(\"subgraphs\").where(\"id\", \"=\", subgraph.id).execute();\n\n\treturn subgraph;\n}\n\n/** Set or clear a paid subgraph's expiry (NULL = no expiry, e.g. on claim). */\nexport async function updateSubgraphExpiry(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId: string,\n\texpiresAt: Date | null,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ expires_at: expiresAt })\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.execute();\n}\n\n/** Live-walk progress write: advances the cursor and PROMOTES toward\n * 'active' (deploying/error → active keeps reorg eligibility, reorg.ts gates\n * on it) but never overwrites an explicit 'reindexing' park — unconditional\n * status stamping let catch-up flap a parked subgraph back into its own path\n * per block, fighting the queued reindex op.\n *\n * `last_processed_block` is now written CONDITIONALLY — `WHERE\n * last_processed_block < lastProcessedBlock`, mirroring\n * `advanceOperationCursor`'s (`subgraph-operations.ts`) comparison shape —\n * and returns whether THIS call actually advanced it. This used to be\n * unconditional by design, on the premise that the only two writers able to\n * advance/rewind a given subgraph's cursor concurrently (the catch-up walk\n * and the reorg handler) serialize on an in-process per-subgraph lock +\n * reorg epoch guard (`packages/subgraphs/src/runtime/catchup.ts`,\n * `subgraphBlockLockHeld` / `reorgEpoch`; f057). That guard is in-process\n * only. The f068 investigation\n * (`docs/internal/audits/asset-holdings-unreproducible-balances-f068.md`)\n * found a cross-process sequence it does not cover: a catch-up leader that\n * loses its advisory-lock connection mid-walk keeps writing (leadership is\n * checked only at walk entry, not per-iteration) while a new leader takes\n * over and walks the same range — both commit increments for overlapping\n * heights, and every regressed cursor write from the laggard re-triggers a\n * full re-walk, growing per-height application without bound. The\n * conditional advance here (paired with the fast-path replay guard armed on\n * the live path in `block-processor.ts`) is now the cross-process\n * guarantee: a block at/below the current cursor can never re-advance it,\n * so a laggard's commits can no longer regress-then-retrigger.\n *\n * This conditionality is why the reorg rewind can no longer go through this\n * function — a rewind's whole point is to move the cursor *backward*, which\n * the `<` guard would silently refuse. Reorg mode calls\n * {@link rewindLiveProgress} instead, which keeps the old unconditional\n * semantics and is safe specifically because the reorg path takes a\n * transaction-scoped advisory lock (`reorg.ts`) other writers can't cross. */\nexport async function recordLiveProgress(\n\tdb: Kysely<Database>,\n\tname: string,\n\tlastProcessedBlock: number,\n): Promise<boolean> {\n\tconst result = await db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tlast_processed_block: lastProcessedBlock,\n\t\t\tstatus: sql`CASE WHEN status = 'reindexing' THEN status ELSE 'active' END`,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"last_processed_block\", \"<\", lastProcessedBlock)\n\t\t.executeTakeFirst();\n\treturn Number(result.numUpdatedRows ?? 0n) > 0;\n}\n\n/** Reorg-rewind progress write: the OLD unconditional `recordLiveProgress`\n * semantics, verbatim — moves `last_processed_block` to the fork height\n * regardless of its current value, because that is by definition a\n * backward move the conditional `<` guard in `recordLiveProgress` would\n * refuse. Same status-promotion CASE (never unparks an explicit\n * 'reindexing').\n *\n * Callers: exclusively the subgraph-reorg path\n * (`packages/subgraphs/src/runtime/reorg.ts`, via `block-processor.ts`'s\n * `reorgRewind` mode), which is safe from the cross-process race this\n * function reintroduces because it holds a transaction-scoped Postgres\n * advisory lock (`pg_advisory_xact_lock`) for the whole\n * delete+reprocess+rewind sequence — no other writer can interleave a\n * forward write between the rewind and the fork block's reprocess. Do not\n * call this from the live catch-up path. */\nexport async function rewindLiveProgress(\n\tdb: Kysely<Database>,\n\tname: string,\n\tlastProcessedBlock: number,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tlast_processed_block: lastProcessedBlock,\n\t\t\tstatus: sql`CASE WHEN status = 'reindexing' THEN status ELSE 'active' END`,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n"
7
+ "import { type Kysely, sql } from \"kysely\";\nimport { isPlatformMode } from \"../../mode.ts\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Database, Subgraph } from \"../types.ts\";\n\n/**\n * Convert a subgraph name to its PostgreSQL schema name (legacy form).\n * Pre shared-rip every tenant DB had its own schema namespace so disambiguation\n * was implicit. Kept for oss mode (single-tenant) and legacy-row fallback.\n * Platform-mode deploys use `pgSchemaNameFor(accountId, name)`.\n */\nexport function pgSchemaName(subgraphName: string): string {\n\tconst safeName = subgraphName.replace(/-/g, \"_\");\n\treturn `subgraph_${safeName}`;\n}\n\n/** OSS writes empty account_id — name is the local unique key. */\nexport function localSubgraphAccountId(accountId?: string): string {\n\tif (!isPlatformMode()) return \"\";\n\treturn accountId ?? \"\";\n}\n\n/**\n * Account-scoped schema name. Matches migration 0028's rename pattern:\n * subgraph_{first8charsOfAccountId, dashes-as-underscores}_{name}\n * Empty accountId falls back to legacy form (oss mode).\n */\nexport function pgSchemaNameFor(\n\taccountId: string,\n\tsubgraphName: string,\n): string {\n\tif (!accountId) return pgSchemaName(subgraphName);\n\tconst accountPrefix = accountId.slice(0, 8).replace(/-/g, \"_\");\n\tconst safeName = subgraphName.replace(/-/g, \"_\");\n\treturn `subgraph_${accountPrefix}_${safeName}`;\n}\n\nexport async function registerSubgraph(\n\tdb: Kysely<Database>,\n\tdata: {\n\t\tname: string;\n\t\tversion: string;\n\t\tdefinition: Record<string, unknown>;\n\t\tschemaHash: string;\n\t\thandlerPath: string;\n\t\tapiKeyId?: string;\n\t\taccountId?: string;\n\t\tschemaName?: string;\n\t\tstartBlock?: number;\n\t\thandlerCode?: string;\n\t\tsourceCode?: string;\n\t},\n): Promise<Subgraph> {\n\tconst accountId = localSubgraphAccountId(data.accountId);\n\tconst values = {\n\t\tname: data.name,\n\t\tversion: data.version,\n\t\tdefinition: jsonb<Record<string, unknown>>(data.definition),\n\t\tschema_hash: data.schemaHash,\n\t\thandler_path: data.handlerPath,\n\t\taccount_id: accountId,\n\t\thandler_code: data.handlerCode ?? null,\n\t\tsource_code: data.sourceCode ?? null,\n\t\tschema_name: data.schemaName ?? null,\n\t\tstart_block: data.startBlock ?? 0,\n\t\tdatabase_url_enc: null,\n\t};\n\tconst updateSet = {\n\t\tversion: data.version,\n\t\tdefinition: jsonb<Record<string, unknown>>(data.definition),\n\t\tschema_hash: data.schemaHash,\n\t\thandler_path: data.handlerPath,\n\t\thandler_code: data.handlerCode ?? null,\n\t\tsource_code: data.sourceCode ?? null,\n\t\tschema_name: data.schemaName ?? null,\n\t\tstart_block: data.startBlock ?? 0,\n\t\tdatabase_url_enc: null,\n\t\tupdated_at: new Date(),\n\t};\n\n\t// OSS: name is unique. Upsert by name so leftover rows with a non-empty\n\t// account_id (pre-local-namespace deploys) don't insert a second row.\n\tif (!isPlatformMode()) {\n\t\tconst existing = await db\n\t\t\t.selectFrom(\"subgraphs\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"name\", \"=\", data.name)\n\t\t\t.executeTakeFirst();\n\t\tif (existing) {\n\t\t\treturn await db\n\t\t\t\t.updateTable(\"subgraphs\")\n\t\t\t\t.set({ ...updateSet, account_id: \"\" })\n\t\t\t\t.where(\"id\", \"=\", existing.id)\n\t\t\t\t.returningAll()\n\t\t\t\t.executeTakeFirstOrThrow();\n\t\t}\n\t\treturn await db\n\t\t\t.insertInto(\"subgraphs\")\n\t\t\t.values(values)\n\t\t\t.returningAll()\n\t\t\t.executeTakeFirstOrThrow();\n\t}\n\n\treturn await db\n\t\t.insertInto(\"subgraphs\")\n\t\t.values(values)\n\t\t.onConflict((oc) =>\n\t\t\toc.columns([\"name\", \"account_id\"]).doUpdateSet(updateSet),\n\t\t)\n\t\t.returningAll()\n\t\t.executeTakeFirstOrThrow();\n}\n\nexport async function getSubgraph(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId?: string,\n): Promise<Subgraph | null> {\n\tlet query = db.selectFrom(\"subgraphs\").selectAll().where(\"name\", \"=\", name);\n\n\tif (isPlatformMode() && accountId !== undefined) {\n\t\tquery = query.where(\"account_id\", \"=\", accountId);\n\t}\n\n\treturn (await query.executeTakeFirst()) ?? null;\n}\n\nexport async function listSubgraphs(\n\tdb: Kysely<Database>,\n\taccountId?: string,\n): Promise<Subgraph[]> {\n\tlet query = db.selectFrom(\"subgraphs\").selectAll();\n\tif (isPlatformMode() && accountId !== undefined) {\n\t\tquery = query.where(\"account_id\", \"=\", accountId);\n\t}\n\treturn query.execute();\n}\n\nexport async function updateSubgraphStatus(\n\tdb: Kysely<Database>,\n\tname: string,\n\tstatus: string,\n\tlastProcessedBlock?: number,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tstatus,\n\t\t\t...(lastProcessedBlock !== undefined\n\t\t\t\t? { last_processed_block: lastProcessedBlock }\n\t\t\t\t: {}),\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n\n/** Account-scoped pause. Only active/reindexing rows flip; name-only\n * {@link updateSubgraphStatus} is unsafe on platform (name, account_id). */\nexport async function pauseSubgraph(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId: string,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ status: \"paused\", updated_at: new Date() })\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"in\", [\"active\", \"reindexing\"])\n\t\t.execute();\n}\n\n/** Resume every paused subgraph for an account (claim / Stripe top-up). */\nexport async function resumePausedSubgraphs(\n\tdb: Kysely<Database>,\n\taccountId: string,\n): Promise<number> {\n\tconst res = await db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ status: \"active\", updated_at: new Date() })\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"=\", \"paused\")\n\t\t.executeTakeFirst();\n\treturn Number(res.numUpdatedRows ?? 0);\n}\n\n/** Live-walk ERROR write (f069): a block whose handlers ALL failed\n * (`processed === 0 && errors > 0`, `block-processor.ts`'s `applyProgress`)\n * is stamped 'error' and its height is recorded as processed, same as\n * `updateSubgraphStatus(db, name, \"error\", blockHeight)` — except the\n * cursor half of that write now goes through the same conditional `<`\n * guard as {@link recordLiveProgress}. Marking a subgraph 'error' is not\n * itself replay-sensitive, but it shares the `last_processed_block` column\n * with the replay guard: an unconditional write here could regress the\n * cursor a racing (successful) writer already advanced past, which is\n * exactly the regress-then-re-walk loop this guard exists to close. In\n * practice `ctx.rollbackTo` (`runner.ts`) means an all-failed block never\n * flushes writes, so a lost race here is always a silent no-op, never a\n * case that needs `CursorRaceLostError`-style tx abort. Returns whether\n * the write applied. Live path only — reindex/backfill's error stamping\n * goes through {@link updateSubgraphStatus} unconditionally, as before. */\nexport async function recordLiveError(\n\tdb: Kysely<Database>,\n\tname: string,\n\tblockHeight: number,\n): Promise<boolean> {\n\tconst result = await db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tstatus: \"error\",\n\t\t\tlast_processed_block: blockHeight,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"last_processed_block\", \"<\", blockHeight)\n\t\t.executeTakeFirst();\n\treturn Number(result.numUpdatedRows ?? 0n) > 0;\n}\n\nexport async function recordSubgraphProcessed(\n\tdb: Kysely<Database>,\n\tname: string,\n\tprocessed: number,\n\terrors: number,\n\tlastError?: string,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\ttotal_processed: sql`total_processed + ${processed}`,\n\t\t\ttotal_errors: sql`total_errors + ${errors}`,\n\t\t\t...(lastError\n\t\t\t\t? { last_error: lastError, last_error_at: new Date() }\n\t\t\t\t: {}),\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n\nexport async function updateSubgraphHandlerPath(\n\tdb: Kysely<Database>,\n\tname: string,\n\thandlerPath: string,\n\topts?: { handlerCode?: string; sourceCode?: string },\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\thandler_path: handlerPath,\n\t\t\t...(opts?.handlerCode != null ? { handler_code: opts.handlerCode } : {}),\n\t\t\t...(opts?.sourceCode != null ? { source_code: opts.sourceCode } : {}),\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n\nexport async function deleteSubgraph(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId?: string,\n): Promise<Subgraph | null> {\n\tconst subgraph = await getSubgraph(db, name, accountId);\n\tif (!subgraph) return null;\n\n\t// Use stored schema_name if available, otherwise compute\n\tconst schemaName = subgraph.schema_name ?? pgSchemaName(name);\n\n\t// Cascade to webhooks: a webhook pointing at a deleted\n\t// subgraph + table will throw `relation does not exist` on every\n\t// subsequent emission. Pause active subs and purge any pending outbox\n\t// rows so receivers don't get phantom replays. We don't delete the\n\t// webhooks themselves — operators may want to repoint them at a\n\t// resurrected subgraph; we just stop them firing.\n\tawait db\n\t\t.updateTable(\"webhooks\")\n\t\t.set({\n\t\t\tstatus: \"paused\",\n\t\t\tlast_error: `Subgraph \"${name}\" deleted; webhook auto-paused.`,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"subgraph_name\", \"=\", name)\n\t\t.execute();\n\tawait db\n\t\t.deleteFrom(\"webhook_outbox\")\n\t\t.where(\"status\", \"=\", \"pending\")\n\t\t.where(\"webhook_id\", \"in\", (qb) =>\n\t\t\tqb.selectFrom(\"webhooks\").select(\"id\").where(\"subgraph_name\", \"=\", name),\n\t\t)\n\t\t.execute();\n\n\t// Drop the subgraph's schema (CASCADE drops all tables within).\n\tawait sql`DROP SCHEMA IF EXISTS ${sql.raw(`\"${schemaName}\"`)} CASCADE`.execute(\n\t\tdb,\n\t);\n\n\t// Remove from registry\n\tawait db.deleteFrom(\"subgraphs\").where(\"id\", \"=\", subgraph.id).execute();\n\n\treturn subgraph;\n}\n\n/** Set or clear a paid subgraph's expiry (NULL = no expiry, e.g. on claim). */\nexport async function updateSubgraphExpiry(\n\tdb: Kysely<Database>,\n\tname: string,\n\taccountId: string,\n\texpiresAt: Date | null,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ expires_at: expiresAt })\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.execute();\n}\n\n/** Live-walk progress write: advances the cursor and PROMOTES toward\n * 'active' (deploying/error → active keeps reorg eligibility, reorg.ts gates\n * on it) but never overwrites an explicit 'reindexing' park — unconditional\n * status stamping let catch-up flap a parked subgraph back into its own path\n * per block, fighting the queued reindex op.\n *\n * `last_processed_block` is now written CONDITIONALLY — `WHERE\n * last_processed_block < lastProcessedBlock`, mirroring\n * `advanceOperationCursor`'s (`subgraph-operations.ts`) comparison shape —\n * and returns whether THIS call actually advanced it. This used to be\n * unconditional by design, on the premise that the only two writers able to\n * advance/rewind a given subgraph's cursor concurrently (the catch-up walk\n * and the reorg handler) serialize on an in-process per-subgraph lock +\n * reorg epoch guard (`packages/subgraphs/src/runtime/catchup.ts`,\n * `subgraphBlockLockHeld` / `reorgEpoch`; f057). That guard is in-process\n * only. The f068 investigation\n * (`docs/internal/audits/asset-holdings-unreproducible-balances-f068.md`)\n * found a cross-process sequence it does not cover: a catch-up leader that\n * loses its advisory-lock connection mid-walk keeps writing (leadership is\n * checked only at walk entry, not per-iteration) while a new leader takes\n * over and walks the same range — both commit increments for overlapping\n * heights, and every regressed cursor write from the laggard re-triggers a\n * full re-walk, growing per-height application without bound. The\n * conditional advance here (paired with the fast-path replay guard armed on\n * the live path in `block-processor.ts`) is now the cross-process\n * guarantee: a block at/below the current cursor can never re-advance it,\n * so a laggard's commits can no longer regress-then-retrigger.\n *\n * This conditionality is why the reorg rewind can no longer go through this\n * function — a rewind's whole point is to move the cursor *backward*, which\n * the `<` guard would silently refuse. Reorg mode calls\n * {@link rewindLiveProgress} instead, which keeps the old unconditional\n * semantics and is safe specifically because the reorg path takes a\n * transaction-scoped advisory lock (`reorg.ts`) other writers can't cross. */\nexport async function recordLiveProgress(\n\tdb: Kysely<Database>,\n\tname: string,\n\tlastProcessedBlock: number,\n): Promise<boolean> {\n\tconst result = await db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tlast_processed_block: lastProcessedBlock,\n\t\t\tstatus: sql`CASE WHEN status = 'reindexing' THEN status ELSE 'active' END`,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.where(\"last_processed_block\", \"<\", lastProcessedBlock)\n\t\t.executeTakeFirst();\n\treturn Number(result.numUpdatedRows ?? 0n) > 0;\n}\n\n/** Reorg-rewind progress write: the OLD unconditional `recordLiveProgress`\n * semantics, verbatim — moves `last_processed_block` to the fork height\n * regardless of its current value, because that is by definition a\n * backward move the conditional `<` guard in `recordLiveProgress` would\n * refuse. Same status-promotion CASE (never unparks an explicit\n * 'reindexing').\n *\n * Callers: exclusively the subgraph-reorg path\n * (`packages/subgraphs/src/runtime/reorg.ts`, via `block-processor.ts`'s\n * `reorgRewind` mode), which is safe from the cross-process race this\n * function reintroduces because it holds a transaction-scoped Postgres\n * advisory lock (`pg_advisory_xact_lock`) for the whole\n * delete+reprocess+rewind sequence — no other writer can interleave a\n * forward write between the rewind and the fork block's reprocess. Do not\n * call this from the live catch-up path. */\nexport async function rewindLiveProgress(\n\tdb: Kysely<Database>,\n\tname: string,\n\tlastProcessedBlock: number,\n): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({\n\t\t\tlast_processed_block: lastProcessedBlock,\n\t\t\tstatus: sql`CASE WHEN status = 'reindexing' THEN status ELSE 'active' END`,\n\t\t\tupdated_at: new Date(),\n\t\t})\n\t\t.where(\"name\", \"=\", name)\n\t\t.execute();\n}\n"
8
8
  ],
9
- "mappings": "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",
10
- "debugId": "F007CF49F477B67864756E2164756E21",
9
+ "mappings": "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",
10
+ "debugId": "0C7267DDF02AF5D764756E2164756E21",
11
11
  "names": []
12
12
  }
@@ -799,9 +799,9 @@ interface Database {
799
799
  account_spend_caps: AccountSpendCapsTable;
800
800
  account_credits: AccountCreditsTable;
801
801
  hosted_meter_days: HostedMeterDaysTable;
802
- subscriptions: SubscriptionsTable;
803
- subscription_outbox: SubscriptionOutboxTable;
804
- subscription_deliveries: SubscriptionDeliveriesTable;
802
+ webhooks: WebhooksTable;
803
+ webhook_outbox: WebhookOutboxTable;
804
+ webhook_deliveries: WebhookDeliveriesTable;
805
805
  trigger_evaluator_state: TriggerEvaluatorStateTable;
806
806
  decoded_events: DecodedEventsTable;
807
807
  decoder_checkpoints: DecoderCheckpointsTable;
@@ -921,31 +921,31 @@ interface ArchiveFetchesTable {
921
921
  via_allowance: Generated<boolean>;
922
922
  charged_at: Generated<Date>;
923
923
  }
924
- type SubscriptionStatus = "active" | "paused" | "error";
925
- /** Polymorphic subscription mode: `subgraph` reacts to processed table rows;
924
+ type WebhookStatus = "active" | "paused" | "error";
925
+ /** Polymorphic webhook mode: `subgraph` reacts to processed table rows;
926
926
  * `chain` reacts to raw chain events matched directly off the Index/Streams
927
927
  * clock (no subgraph). See migration 0088. */
928
- type SubscriptionKind = "subgraph" | "chain";
929
- type SubscriptionFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
930
- type SubscriptionRuntime = "inngest" | "trigger" | "cloudflare" | "node";
931
- interface SubscriptionsTable {
928
+ type WebhookKind = "subgraph" | "chain";
929
+ type WebhookFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
930
+ type WebhookRuntime = "inngest" | "trigger" | "cloudflare" | "node";
931
+ interface WebhooksTable {
932
932
  id: Generated<string>;
933
933
  account_id: string;
934
934
  project_id: string | null;
935
935
  name: string;
936
- status: ColumnType<SubscriptionStatus, SubscriptionStatus | undefined, SubscriptionStatus>;
937
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
938
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
936
+ status: ColumnType<WebhookStatus, WebhookStatus | undefined, WebhookStatus>;
937
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
938
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
939
939
  subgraph_name: string | null;
940
- /** Null for chain subscriptions (CHECK subscriptions_kind_shape). */
940
+ /** Null for chain webhooks (CHECK webhooks_kind_shape). */
941
941
  table_name: string | null;
942
942
  /** Chain-trigger filter array (the `SubgraphFilter` shape, JSON). Null for
943
- * subgraph subscriptions. Typed loosely here to avoid a shared→subgraphs
944
- * import cycle; the Zod schema in schemas/subscriptions.ts owns the shape. */
943
+ * subgraph webhooks. Typed loosely here to avoid a shared→subgraphs
944
+ * import cycle; the Zod schema in schemas/webhooks.ts owns the shape. */
945
945
  triggers: unknown | null;
946
946
  filter: Generated<unknown>;
947
- format: ColumnType<SubscriptionFormat, SubscriptionFormat | undefined, SubscriptionFormat>;
948
- runtime: SubscriptionRuntime | null;
947
+ format: ColumnType<WebhookFormat, WebhookFormat | undefined, WebhookFormat>;
948
+ runtime: WebhookRuntime | null;
949
949
  url: string;
950
950
  signing_secret_enc: Buffer;
951
951
  auth_config: Generated<unknown>;
@@ -961,13 +961,13 @@ interface SubscriptionsTable {
961
961
  updated_at: Generated<Date>;
962
962
  }
963
963
  type OutboxStatus = "pending" | "delivered" | "dead";
964
- interface SubscriptionOutboxTable {
964
+ interface WebhookOutboxTable {
965
965
  id: Generated<string>;
966
- subscription_id: string;
967
- kind: ColumnType<SubscriptionKind, SubscriptionKind | undefined, SubscriptionKind>;
968
- /** Null for chain-subscription rows. */
966
+ webhook_id: string;
967
+ kind: ColumnType<WebhookKind, WebhookKind | undefined, WebhookKind>;
968
+ /** Null for chain-webhook rows. */
969
969
  subgraph_name: string | null;
970
- /** Null for chain-subscription rows. */
970
+ /** Null for chain-webhook rows. */
971
971
  table_name: string | null;
972
972
  block_height: number | bigint;
973
973
  tx_id: string | null;
@@ -985,12 +985,12 @@ interface SubscriptionOutboxTable {
985
985
  locked_until: Date | null;
986
986
  created_at: Generated<Date>;
987
987
  }
988
- interface SubscriptionDeliveriesTable {
988
+ interface WebhookDeliveriesTable {
989
989
  id: Generated<string>;
990
990
  /** Nullable after migration 0077 — outbox row may be cleaned up while
991
991
  * delivery telemetry is retained. */
992
992
  outbox_id: string | null;
993
- subscription_id: string;
993
+ webhook_id: string;
994
994
  attempt: number;
995
995
  status_code: number | null;
996
996
  response_headers: unknown | null;
@@ -1000,7 +1000,7 @@ interface SubscriptionDeliveriesTable {
1000
1000
  dispatched_at: Generated<Date>;
1001
1001
  }
1002
1002
  /** Single-row (id always TRUE) high-water mark for the chain-trigger evaluator.
1003
- * One loop serves all chain subscriptions, so the cursor is global. */
1003
+ * One loop serves all chain webhooks, so the cursor is global. */
1004
1004
  interface TriggerEvaluatorStateTable {
1005
1005
  id: Generated<boolean>;
1006
1006
  last_processed_block: ColumnType<bigint, bigint | number | undefined, bigint | number>;