@secondlayer/shared 2.1.0 → 3.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/README.md +2 -2
  2. package/dist/src/crypto/secrets.js +47 -3
  3. package/dist/src/crypto/secrets.js.map +5 -4
  4. package/dist/src/db/index.d.ts +112 -137
  5. package/dist/src/db/index.js.map +2 -2
  6. package/dist/src/db/jsonb.d.ts +5 -1
  7. package/dist/src/db/jsonb.js.map +2 -2
  8. package/dist/src/db/queries/account-spend-caps.d.ts +444 -0
  9. package/dist/src/db/queries/account-spend-caps.js +60 -0
  10. package/dist/src/db/queries/account-spend-caps.js.map +10 -0
  11. package/dist/src/db/queries/account-usage.d.ts +468 -0
  12. package/dist/src/db/queries/account-usage.js +222 -0
  13. package/dist/src/db/queries/account-usage.js.map +11 -0
  14. package/dist/src/db/queries/accounts.d.ts +100 -109
  15. package/dist/src/db/queries/accounts.js +15 -1
  16. package/dist/src/db/queries/accounts.js.map +3 -3
  17. package/dist/src/db/queries/integrity.d.ts +85 -107
  18. package/dist/src/db/queries/projects.d.ts +87 -109
  19. package/dist/src/db/queries/provisioning-audit.d.ts +85 -107
  20. package/dist/src/db/queries/subgraph-gaps.d.ts +85 -107
  21. package/dist/src/db/queries/subgraphs.d.ts +86 -109
  22. package/dist/src/db/queries/subgraphs.js +2 -3
  23. package/dist/src/db/queries/subgraphs.js.map +4 -4
  24. package/dist/src/db/queries/{workflows.d.ts → tenant-compute-addons.d.ts} +108 -142
  25. package/dist/src/db/queries/tenant-compute-addons.js +47 -0
  26. package/dist/src/db/queries/tenant-compute-addons.js.map +10 -0
  27. package/dist/src/db/queries/tenants.d.ts +98 -110
  28. package/dist/src/db/queries/tenants.js +55 -8
  29. package/dist/src/db/queries/tenants.js.map +6 -5
  30. package/dist/src/db/queries/usage.d.ts +86 -132
  31. package/dist/src/db/queries/usage.js +5 -64
  32. package/dist/src/db/queries/usage.js.map +4 -5
  33. package/dist/src/db/schema.d.ts +107 -136
  34. package/dist/src/errors.d.ts +8 -7
  35. package/dist/src/errors.js +11 -12
  36. package/dist/src/errors.js.map +3 -3
  37. package/dist/src/index.d.ts +119 -143
  38. package/dist/src/index.js +11 -12
  39. package/dist/src/index.js.map +4 -4
  40. package/dist/src/node/local-client.d.ts +85 -107
  41. package/dist/src/pricing.d.ts +20 -1
  42. package/dist/src/pricing.js +58 -1
  43. package/dist/src/pricing.js.map +3 -3
  44. package/migrations/0045_drop_marketplace_columns.ts +47 -0
  45. package/migrations/0046_tenant_activity_signal.ts +47 -0
  46. package/migrations/0047_usage_daily_tenant_id.ts +73 -0
  47. package/migrations/0048_tenant_compute_addons.ts +49 -0
  48. package/migrations/0049_accounts_stripe_customer_id.ts +30 -0
  49. package/migrations/0050_account_spend_caps.ts +45 -0
  50. package/migrations/0051_workflow_ai_usage_daily.ts +40 -0
  51. package/migrations/0052_sentries.ts +61 -0
  52. package/migrations/0053_workflow_runtime.ts +88 -0
  53. package/migrations/0054_accounts_plan_hobby.ts +32 -0
  54. package/migrations/0055_ai_usage_account_scope.ts +108 -0
  55. package/migrations/0056_drop_workflow_sentry_residuals.ts +23 -0
  56. package/migrations/0057_subscriptions.ts +137 -0
  57. package/package.json +26 -14
  58. package/dist/src/db/queries/workflows.js +0 -260
  59. package/dist/src/db/queries/workflows.js.map +0 -12
  60. package/dist/src/lib/plans.d.ts +0 -9
  61. package/dist/src/lib/plans.js +0 -37
  62. package/dist/src/lib/plans.js.map +0 -10
  63. package/dist/src/schemas/workflows.d.ts +0 -70
  64. package/dist/src/schemas/workflows.js +0 -43
  65. package/dist/src/schemas/workflows.js.map +0 -10
@@ -60,10 +60,6 @@ interface SubgraphsTable {
60
60
  handler_code: string | null;
61
61
  source_code: string | null;
62
62
  project_id: string | null;
63
- is_public: Generated<boolean>;
64
- tags: Generated<string[]>;
65
- description: string | null;
66
- forked_from_id: string | null;
67
63
  created_at: Generated<Date>;
68
64
  updated_at: Generated<Date>;
69
65
  }
@@ -98,6 +94,7 @@ interface AccountsTable {
98
94
  bio: string | null;
99
95
  avatar_url: string | null;
100
96
  slug: string | null;
97
+ stripe_customer_id: string | null;
101
98
  created_at: Generated<Date>;
102
99
  }
103
100
  interface SessionsTable {
@@ -123,6 +120,7 @@ interface MagicLinksTable {
123
120
  }
124
121
  interface UsageDailyTable {
125
122
  account_id: string;
123
+ tenant_id: string | null;
126
124
  date: string;
127
125
  api_requests: Generated<number>;
128
126
  deliveries: Generated<number>;
@@ -249,83 +247,6 @@ interface ChatMessagesTable {
249
247
  metadata: unknown | null;
250
248
  created_at: Generated<Date>;
251
249
  }
252
- interface WorkflowDefinitionsTable {
253
- id: Generated<string>;
254
- name: string;
255
- version: Generated<string>;
256
- status: Generated<string>;
257
- trigger_type: string;
258
- trigger_config: unknown;
259
- handler_path: string;
260
- source_code: string | null;
261
- retries_config: unknown | null;
262
- timeout_ms: number | null;
263
- api_key_id: string;
264
- project_id: string | null;
265
- created_at: Generated<Date>;
266
- updated_at: Generated<Date>;
267
- }
268
- interface WorkflowRunsTable {
269
- id: Generated<string>;
270
- definition_id: string;
271
- status: Generated<string>;
272
- trigger_type: string;
273
- trigger_data: unknown | null;
274
- dedup_key: string | null;
275
- error: string | null;
276
- started_at: Date | null;
277
- completed_at: Date | null;
278
- duration_ms: number | null;
279
- total_ai_tokens: Generated<number>;
280
- created_at: Generated<Date>;
281
- }
282
- interface WorkflowStepsTable {
283
- id: Generated<string>;
284
- run_id: string;
285
- step_index: number;
286
- step_id: string;
287
- step_type: string;
288
- status: Generated<string>;
289
- input: unknown | null;
290
- output: unknown | null;
291
- error: string | null;
292
- retry_count: Generated<number>;
293
- ai_tokens_used: Generated<number>;
294
- started_at: Date | null;
295
- completed_at: Date | null;
296
- duration_ms: number | null;
297
- memo_key: string | null;
298
- parent_step_id: string | null;
299
- created_at: Generated<Date>;
300
- }
301
- interface WorkflowQueueTable {
302
- id: Generated<string>;
303
- run_id: string;
304
- status: Generated<string>;
305
- attempts: Generated<number>;
306
- max_attempts: Generated<number>;
307
- scheduled_for: Generated<Date>;
308
- locked_at: Date | null;
309
- locked_by: string | null;
310
- error: string | null;
311
- created_at: Generated<Date>;
312
- completed_at: Date | null;
313
- }
314
- interface WorkflowSchedulesTable {
315
- id: Generated<string>;
316
- definition_id: string;
317
- cron_expr: string;
318
- timezone: Generated<string>;
319
- next_run_at: Date;
320
- last_run_at: Date | null;
321
- enabled: Generated<boolean>;
322
- created_at: Generated<Date>;
323
- }
324
- interface WorkflowCursorsTable {
325
- name: string;
326
- block_height: Generated<number>;
327
- updated_at: Generated<Date>;
328
- }
329
250
  interface Database {
330
251
  blocks: BlocksTable;
331
252
  transactions: TransactionsTable;
@@ -351,17 +272,14 @@ interface Database {
351
272
  team_invitations: TeamInvitationsTable;
352
273
  chat_sessions: ChatSessionsTable;
353
274
  chat_messages: ChatMessagesTable;
354
- workflow_definitions: WorkflowDefinitionsTable;
355
- workflow_runs: WorkflowRunsTable;
356
- workflow_steps: WorkflowStepsTable;
357
- workflow_queue: WorkflowQueueTable;
358
- workflow_schedules: WorkflowSchedulesTable;
359
- workflow_cursors: WorkflowCursorsTable;
360
- workflow_signer_secrets: WorkflowSignerSecretsTable;
361
- workflow_budgets: WorkflowBudgetsTable;
362
275
  tenants: TenantsTable;
363
276
  tenant_usage_monthly: TenantUsageMonthlyTable;
277
+ tenant_compute_addons: TenantComputeAddonsTable;
278
+ account_spend_caps: AccountSpendCapsTable;
364
279
  provisioning_audit_log: ProvisioningAuditLogTable;
280
+ subscriptions: SubscriptionsTable;
281
+ subscription_outbox: SubscriptionOutboxTable;
282
+ subscription_deliveries: SubscriptionDeliveriesTable;
365
283
  }
366
284
  type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
367
285
  interface TenantsTable {
@@ -383,9 +301,9 @@ interface TenantsTable {
383
301
  service_key_enc: Buffer;
384
302
  api_url_internal: string;
385
303
  api_url_public: string;
386
- trial_ends_at: Date;
387
304
  suspended_at: Date | null;
388
305
  last_health_check_at: Date | null;
306
+ last_active_at: Generated<Date>;
389
307
  service_gen: Generated<number>;
390
308
  anon_gen: Generated<number>;
391
309
  project_id: string | null;
@@ -403,6 +321,28 @@ interface TenantUsageMonthlyTable {
403
321
  first_at: Generated<Date>;
404
322
  last_at: Generated<Date>;
405
323
  }
324
+ interface TenantComputeAddonsTable {
325
+ id: Generated<string>;
326
+ tenant_id: string;
327
+ memory_mb_delta: Generated<number>;
328
+ cpu_delta: Generated<number | string>;
329
+ storage_mb_delta: Generated<number>;
330
+ effective_from: Generated<Date>;
331
+ effective_until: Date | null;
332
+ stripe_subscription_item_id: string | null;
333
+ created_at: Generated<Date>;
334
+ }
335
+ interface AccountSpendCapsTable {
336
+ account_id: string;
337
+ monthly_cap_cents: number | null;
338
+ compute_cap_cents: number | null;
339
+ storage_cap_cents: number | null;
340
+ ai_cap_cents: number | null;
341
+ alert_threshold_pct: Generated<number>;
342
+ alert_sent_at: Date | null;
343
+ frozen_at: Date | null;
344
+ updated_at: Generated<Date>;
345
+ }
406
346
  type ProvisioningAuditEvent = "provision.start" | "provision.success" | "provision.failure" | "suspend" | "resume" | "resize" | "keys.rotate" | "bastion.key.upload" | "bastion.key.revoke" | "teardown";
407
347
  type ProvisioningAuditStatus = "ok" | "error";
408
348
  interface ProvisioningAuditLogTable {
@@ -417,31 +357,69 @@ interface ProvisioningAuditLogTable {
417
357
  error: string | null;
418
358
  created_at: Generated<Date>;
419
359
  }
420
- interface WorkflowBudgetsTable {
360
+ type Subgraph = Selectable<SubgraphsTable>;
361
+ type SubscriptionStatus = "active" | "paused" | "error";
362
+ type SubscriptionFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
363
+ type SubscriptionRuntime = "inngest" | "trigger" | "cloudflare" | "node";
364
+ interface SubscriptionsTable {
421
365
  id: Generated<string>;
422
- workflow_definition_id: string;
423
- /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
424
- period: string;
425
- ai_usd_used: Generated<string>;
426
- ai_tokens_used: Generated<string>;
427
- chain_microstx_used: Generated<string>;
428
- chain_tx_count: Generated<number>;
429
- run_count: Generated<number>;
430
- step_count: Generated<number>;
431
- reset_at: Date;
366
+ account_id: string;
367
+ project_id: string | null;
368
+ name: string;
369
+ status: ColumnType<SubscriptionStatus, SubscriptionStatus | undefined, SubscriptionStatus>;
370
+ subgraph_name: string;
371
+ table_name: string;
372
+ filter: Generated<unknown>;
373
+ format: ColumnType<SubscriptionFormat, SubscriptionFormat | undefined, SubscriptionFormat>;
374
+ runtime: SubscriptionRuntime | null;
375
+ url: string;
376
+ signing_secret_enc: Buffer;
377
+ auth_config: Generated<unknown>;
378
+ max_retries: Generated<number>;
379
+ timeout_ms: Generated<number>;
380
+ concurrency: Generated<number>;
381
+ circuit_failures: Generated<number>;
382
+ circuit_opened_at: Date | null;
383
+ last_delivery_at: Date | null;
384
+ last_success_at: Date | null;
385
+ last_error: string | null;
432
386
  created_at: Generated<Date>;
433
387
  updated_at: Generated<Date>;
434
388
  }
435
- interface WorkflowSignerSecretsTable {
389
+ type OutboxStatus = "pending" | "delivered" | "dead";
390
+ interface SubscriptionOutboxTable {
436
391
  id: Generated<string>;
437
- account_id: string;
438
- name: string;
439
- /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
440
- encrypted_value: Buffer;
392
+ subscription_id: string;
393
+ subgraph_name: string;
394
+ table_name: string;
395
+ block_height: number | bigint;
396
+ tx_id: string | null;
397
+ row_pk: unknown;
398
+ event_type: string;
399
+ payload: unknown;
400
+ dedup_key: string;
401
+ attempt: Generated<number>;
402
+ next_attempt_at: Generated<Date>;
403
+ status: ColumnType<OutboxStatus, OutboxStatus | undefined, OutboxStatus>;
404
+ is_replay: Generated<boolean>;
405
+ delivered_at: Date | null;
406
+ failed_at: Date | null;
407
+ locked_by: string | null;
408
+ locked_until: Date | null;
441
409
  created_at: Generated<Date>;
442
- updated_at: Generated<Date>;
443
410
  }
444
- type Subgraph = Selectable<SubgraphsTable>;
411
+ interface SubscriptionDeliveriesTable {
412
+ id: Generated<string>;
413
+ outbox_id: string;
414
+ subscription_id: string;
415
+ attempt: number;
416
+ status_code: number | null;
417
+ response_headers: unknown | null;
418
+ response_body: string | null;
419
+ error_message: string | null;
420
+ duration_ms: number | null;
421
+ dispatched_at: Generated<Date>;
422
+ }
445
423
  /**
446
424
  * Convert a subgraph name to its PostgreSQL schema name.
447
425
  * Every tenant DB has its own isolated schema namespace, so there's no
@@ -459,7 +437,6 @@ declare function registerSubgraph(db: Kysely<Database>, data: {
459
437
  accountId?: string
460
438
  schemaName?: string
461
439
  startBlock?: number
462
- forkedFromId?: string
463
440
  handlerCode?: string
464
441
  sourceCode?: string
465
442
  }): Promise<Subgraph>;
@@ -48,8 +48,7 @@ async function registerSubgraph(db, data) {
48
48
  handler_code: data.handlerCode ?? null,
49
49
  source_code: data.sourceCode ?? null,
50
50
  schema_name: data.schemaName ?? null,
51
- start_block: data.startBlock ?? 0,
52
- forked_from_id: data.forkedFromId ?? null
51
+ start_block: data.startBlock ?? 0
53
52
  }).onConflict((oc) => oc.columns(["name", "account_id"]).doUpdateSet({
54
53
  version: data.version,
55
54
  definition: jsonb(data.definition),
@@ -114,5 +113,5 @@ export {
114
113
  deleteSubgraph
115
114
  };
116
115
 
117
- //# debugId=AE963057007E387C64756E2164756E21
116
+ //# debugId=D8D245F7C02FE78964756E2164756E21
118
117
  //# sourceMappingURL=subgraphs.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/db/jsonb.ts", "../src/db/queries/subgraphs.ts"],
4
4
  "sourcesContent": [
5
- "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 */\nexport function jsonb(value: unknown): RawBuilder<unknown> {\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",
6
- "import { type Kysely, sql } from \"kysely\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Database, Subgraph } from \"../types.ts\";\n\n/**\n * Convert a subgraph name to its PostgreSQL schema name.\n * Every tenant DB has its own isolated schema namespace, so there's no\n * account-prefix disambiguation needed — every subgraph within a tenant\n * just maps to `subgraph_{safeName}`.\n */\nexport function pgSchemaName(subgraphName: string): string {\n\tconst safeName = subgraphName.replace(/-/g, \"_\");\n\treturn `subgraph_${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\tforkedFromId?: string;\n\t\thandlerCode?: string;\n\t\tsourceCode?: string;\n\t},\n): Promise<Subgraph> {\n\treturn await db\n\t\t.insertInto(\"subgraphs\")\n\t\t.values({\n\t\t\tname: data.name,\n\t\t\tversion: data.version,\n\t\t\tdefinition: jsonb(data.definition) as any,\n\t\t\tschema_hash: data.schemaHash,\n\t\t\thandler_path: data.handlerPath,\n\t\t\taccount_id: data.accountId ?? \"\",\n\t\t\thandler_code: data.handlerCode ?? null,\n\t\t\tsource_code: data.sourceCode ?? null,\n\t\t\tschema_name: data.schemaName ?? null,\n\t\t\tstart_block: data.startBlock ?? 0,\n\t\t\tforked_from_id: data.forkedFromId ?? null,\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\toc.columns([\"name\", \"account_id\"]).doUpdateSet({\n\t\t\t\tversion: data.version,\n\t\t\t\tdefinition: jsonb(data.definition) as any,\n\t\t\t\tschema_hash: data.schemaHash,\n\t\t\t\thandler_path: data.handlerPath,\n\t\t\t\thandler_code: data.handlerCode ?? null,\n\t\t\t\tsource_code: data.sourceCode ?? null,\n\t\t\t\tschema_name: data.schemaName ?? null,\n\t\t\t\tstart_block: data.startBlock ?? 0,\n\t\t\t\tupdated_at: new Date(),\n\t\t\t}),\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 (accountId) {\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 (accountId) {\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\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): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ handler_path: handlerPath, updated_at: new Date() })\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// 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"
5
+ "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",
6
+ "import { type Kysely, sql } from \"kysely\";\nimport { jsonb } from \"../jsonb.ts\";\nimport type { Database, Subgraph } from \"../types.ts\";\n\n/**\n * Convert a subgraph name to its PostgreSQL schema name.\n * Every tenant DB has its own isolated schema namespace, so there's no\n * account-prefix disambiguation needed — every subgraph within a tenant\n * just maps to `subgraph_{safeName}`.\n */\nexport function pgSchemaName(subgraphName: string): string {\n\tconst safeName = subgraphName.replace(/-/g, \"_\");\n\treturn `subgraph_${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\treturn await db\n\t\t.insertInto(\"subgraphs\")\n\t\t.values({\n\t\t\tname: data.name,\n\t\t\tversion: data.version,\n\t\t\tdefinition: jsonb<Record<string, unknown>>(data.definition),\n\t\t\tschema_hash: data.schemaHash,\n\t\t\thandler_path: data.handlerPath,\n\t\t\taccount_id: data.accountId ?? \"\",\n\t\t\thandler_code: data.handlerCode ?? null,\n\t\t\tsource_code: data.sourceCode ?? null,\n\t\t\tschema_name: data.schemaName ?? null,\n\t\t\tstart_block: data.startBlock ?? 0,\n\t\t})\n\t\t.onConflict((oc) =>\n\t\t\toc.columns([\"name\", \"account_id\"]).doUpdateSet({\n\t\t\t\tversion: data.version,\n\t\t\t\tdefinition: jsonb<Record<string, unknown>>(data.definition),\n\t\t\t\tschema_hash: data.schemaHash,\n\t\t\t\thandler_path: data.handlerPath,\n\t\t\t\thandler_code: data.handlerCode ?? null,\n\t\t\t\tsource_code: data.sourceCode ?? null,\n\t\t\t\tschema_name: data.schemaName ?? null,\n\t\t\t\tstart_block: data.startBlock ?? 0,\n\t\t\t\tupdated_at: new Date(),\n\t\t\t}),\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 (accountId) {\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 (accountId) {\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\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): Promise<void> {\n\tawait db\n\t\t.updateTable(\"subgraphs\")\n\t\t.set({ handler_path: handlerPath, updated_at: new Date() })\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// 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"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "AE963057007E387C64756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "D8D245F7C02FE78964756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -60,10 +60,6 @@ interface SubgraphsTable {
60
60
  handler_code: string | null;
61
61
  source_code: string | null;
62
62
  project_id: string | null;
63
- is_public: Generated<boolean>;
64
- tags: Generated<string[]>;
65
- description: string | null;
66
- forked_from_id: string | null;
67
63
  created_at: Generated<Date>;
68
64
  updated_at: Generated<Date>;
69
65
  }
@@ -98,6 +94,7 @@ interface AccountsTable {
98
94
  bio: string | null;
99
95
  avatar_url: string | null;
100
96
  slug: string | null;
97
+ stripe_customer_id: string | null;
101
98
  created_at: Generated<Date>;
102
99
  }
103
100
  interface SessionsTable {
@@ -123,6 +120,7 @@ interface MagicLinksTable {
123
120
  }
124
121
  interface UsageDailyTable {
125
122
  account_id: string;
123
+ tenant_id: string | null;
126
124
  date: string;
127
125
  api_requests: Generated<number>;
128
126
  deliveries: Generated<number>;
@@ -249,83 +247,6 @@ interface ChatMessagesTable {
249
247
  metadata: unknown | null;
250
248
  created_at: Generated<Date>;
251
249
  }
252
- interface WorkflowDefinitionsTable {
253
- id: Generated<string>;
254
- name: string;
255
- version: Generated<string>;
256
- status: Generated<string>;
257
- trigger_type: string;
258
- trigger_config: unknown;
259
- handler_path: string;
260
- source_code: string | null;
261
- retries_config: unknown | null;
262
- timeout_ms: number | null;
263
- api_key_id: string;
264
- project_id: string | null;
265
- created_at: Generated<Date>;
266
- updated_at: Generated<Date>;
267
- }
268
- interface WorkflowRunsTable {
269
- id: Generated<string>;
270
- definition_id: string;
271
- status: Generated<string>;
272
- trigger_type: string;
273
- trigger_data: unknown | null;
274
- dedup_key: string | null;
275
- error: string | null;
276
- started_at: Date | null;
277
- completed_at: Date | null;
278
- duration_ms: number | null;
279
- total_ai_tokens: Generated<number>;
280
- created_at: Generated<Date>;
281
- }
282
- interface WorkflowStepsTable {
283
- id: Generated<string>;
284
- run_id: string;
285
- step_index: number;
286
- step_id: string;
287
- step_type: string;
288
- status: Generated<string>;
289
- input: unknown | null;
290
- output: unknown | null;
291
- error: string | null;
292
- retry_count: Generated<number>;
293
- ai_tokens_used: Generated<number>;
294
- started_at: Date | null;
295
- completed_at: Date | null;
296
- duration_ms: number | null;
297
- memo_key: string | null;
298
- parent_step_id: string | null;
299
- created_at: Generated<Date>;
300
- }
301
- interface WorkflowQueueTable {
302
- id: Generated<string>;
303
- run_id: string;
304
- status: Generated<string>;
305
- attempts: Generated<number>;
306
- max_attempts: Generated<number>;
307
- scheduled_for: Generated<Date>;
308
- locked_at: Date | null;
309
- locked_by: string | null;
310
- error: string | null;
311
- created_at: Generated<Date>;
312
- completed_at: Date | null;
313
- }
314
- interface WorkflowSchedulesTable {
315
- id: Generated<string>;
316
- definition_id: string;
317
- cron_expr: string;
318
- timezone: Generated<string>;
319
- next_run_at: Date;
320
- last_run_at: Date | null;
321
- enabled: Generated<boolean>;
322
- created_at: Generated<Date>;
323
- }
324
- interface WorkflowCursorsTable {
325
- name: string;
326
- block_height: Generated<number>;
327
- updated_at: Generated<Date>;
328
- }
329
250
  interface Database {
330
251
  blocks: BlocksTable;
331
252
  transactions: TransactionsTable;
@@ -351,17 +272,14 @@ interface Database {
351
272
  team_invitations: TeamInvitationsTable;
352
273
  chat_sessions: ChatSessionsTable;
353
274
  chat_messages: ChatMessagesTable;
354
- workflow_definitions: WorkflowDefinitionsTable;
355
- workflow_runs: WorkflowRunsTable;
356
- workflow_steps: WorkflowStepsTable;
357
- workflow_queue: WorkflowQueueTable;
358
- workflow_schedules: WorkflowSchedulesTable;
359
- workflow_cursors: WorkflowCursorsTable;
360
- workflow_signer_secrets: WorkflowSignerSecretsTable;
361
- workflow_budgets: WorkflowBudgetsTable;
362
275
  tenants: TenantsTable;
363
276
  tenant_usage_monthly: TenantUsageMonthlyTable;
277
+ tenant_compute_addons: TenantComputeAddonsTable;
278
+ account_spend_caps: AccountSpendCapsTable;
364
279
  provisioning_audit_log: ProvisioningAuditLogTable;
280
+ subscriptions: SubscriptionsTable;
281
+ subscription_outbox: SubscriptionOutboxTable;
282
+ subscription_deliveries: SubscriptionDeliveriesTable;
365
283
  }
366
284
  type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
367
285
  interface TenantsTable {
@@ -383,9 +301,9 @@ interface TenantsTable {
383
301
  service_key_enc: Buffer;
384
302
  api_url_internal: string;
385
303
  api_url_public: string;
386
- trial_ends_at: Date;
387
304
  suspended_at: Date | null;
388
305
  last_health_check_at: Date | null;
306
+ last_active_at: Generated<Date>;
389
307
  service_gen: Generated<number>;
390
308
  anon_gen: Generated<number>;
391
309
  project_id: string | null;
@@ -403,6 +321,29 @@ interface TenantUsageMonthlyTable {
403
321
  first_at: Generated<Date>;
404
322
  last_at: Generated<Date>;
405
323
  }
324
+ interface TenantComputeAddonsTable {
325
+ id: Generated<string>;
326
+ tenant_id: string;
327
+ memory_mb_delta: Generated<number>;
328
+ cpu_delta: Generated<number | string>;
329
+ storage_mb_delta: Generated<number>;
330
+ effective_from: Generated<Date>;
331
+ effective_until: Date | null;
332
+ stripe_subscription_item_id: string | null;
333
+ created_at: Generated<Date>;
334
+ }
335
+ type TenantComputeAddon = Selectable<TenantComputeAddonsTable>;
336
+ interface AccountSpendCapsTable {
337
+ account_id: string;
338
+ monthly_cap_cents: number | null;
339
+ compute_cap_cents: number | null;
340
+ storage_cap_cents: number | null;
341
+ ai_cap_cents: number | null;
342
+ alert_threshold_pct: Generated<number>;
343
+ alert_sent_at: Date | null;
344
+ frozen_at: Date | null;
345
+ updated_at: Generated<Date>;
346
+ }
406
347
  type ProvisioningAuditEvent = "provision.start" | "provision.success" | "provision.failure" | "suspend" | "resume" | "resize" | "keys.rotate" | "bastion.key.upload" | "bastion.key.revoke" | "teardown";
407
348
  type ProvisioningAuditStatus = "ok" | "error";
408
349
  interface ProvisioningAuditLogTable {
@@ -417,62 +358,87 @@ interface ProvisioningAuditLogTable {
417
358
  error: string | null;
418
359
  created_at: Generated<Date>;
419
360
  }
420
- interface WorkflowBudgetsTable {
361
+ type SubscriptionStatus = "active" | "paused" | "error";
362
+ type SubscriptionFormat = "standard-webhooks" | "inngest" | "trigger" | "cloudflare" | "cloudevents" | "raw";
363
+ type SubscriptionRuntime = "inngest" | "trigger" | "cloudflare" | "node";
364
+ interface SubscriptionsTable {
421
365
  id: Generated<string>;
422
- workflow_definition_id: string;
423
- /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
424
- period: string;
425
- ai_usd_used: Generated<string>;
426
- ai_tokens_used: Generated<string>;
427
- chain_microstx_used: Generated<string>;
428
- chain_tx_count: Generated<number>;
429
- run_count: Generated<number>;
430
- step_count: Generated<number>;
431
- reset_at: Date;
366
+ account_id: string;
367
+ project_id: string | null;
368
+ name: string;
369
+ status: ColumnType<SubscriptionStatus, SubscriptionStatus | undefined, SubscriptionStatus>;
370
+ subgraph_name: string;
371
+ table_name: string;
372
+ filter: Generated<unknown>;
373
+ format: ColumnType<SubscriptionFormat, SubscriptionFormat | undefined, SubscriptionFormat>;
374
+ runtime: SubscriptionRuntime | null;
375
+ url: string;
376
+ signing_secret_enc: Buffer;
377
+ auth_config: Generated<unknown>;
378
+ max_retries: Generated<number>;
379
+ timeout_ms: Generated<number>;
380
+ concurrency: Generated<number>;
381
+ circuit_failures: Generated<number>;
382
+ circuit_opened_at: Date | null;
383
+ last_delivery_at: Date | null;
384
+ last_success_at: Date | null;
385
+ last_error: string | null;
432
386
  created_at: Generated<Date>;
433
387
  updated_at: Generated<Date>;
434
388
  }
435
- interface WorkflowSignerSecretsTable {
389
+ type OutboxStatus = "pending" | "delivered" | "dead";
390
+ interface SubscriptionOutboxTable {
436
391
  id: Generated<string>;
437
- account_id: string;
438
- name: string;
439
- /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
440
- encrypted_value: Buffer;
392
+ subscription_id: string;
393
+ subgraph_name: string;
394
+ table_name: string;
395
+ block_height: number | bigint;
396
+ tx_id: string | null;
397
+ row_pk: unknown;
398
+ event_type: string;
399
+ payload: unknown;
400
+ dedup_key: string;
401
+ attempt: Generated<number>;
402
+ next_attempt_at: Generated<Date>;
403
+ status: ColumnType<OutboxStatus, OutboxStatus | undefined, OutboxStatus>;
404
+ is_replay: Generated<boolean>;
405
+ delivered_at: Date | null;
406
+ failed_at: Date | null;
407
+ locked_by: string | null;
408
+ locked_until: Date | null;
441
409
  created_at: Generated<Date>;
442
- updated_at: Generated<Date>;
443
410
  }
444
- type WorkflowDefinition = Selectable<WorkflowDefinitionsTable>;
445
- type WorkflowRun = Selectable<WorkflowRunsTable>;
446
- type WorkflowStep = Selectable<WorkflowStepsTable>;
447
- /** Bump the patch digit of a semver string. Falls back to "1.0.1" on malformed input. */
448
- declare function bumpPatch(version: string): string;
449
- declare function listWorkflowDefinitions(db: Kysely<Database>, apiKeyIds?: string[]): Promise<WorkflowDefinition[]>;
450
- declare function getWorkflowDefinition(db: Kysely<Database>, name: string, apiKeyIds?: string[]): Promise<WorkflowDefinition | null>;
451
- declare function upsertWorkflowDefinition(db: Kysely<Database>, data: {
452
- name: string
453
- triggerType: string
454
- triggerConfig: Record<string, unknown>
455
- handlerPath: string
456
- apiKeyId: string
457
- projectId?: string
458
- retriesConfig?: Record<string, unknown>
459
- timeoutMs?: number
460
- sourceCode?: string
461
- expectedVersion?: string
462
- }): Promise<WorkflowDefinition>;
463
- declare function updateWorkflowStatus(db: Kysely<Database>, name: string, apiKeyId: string, status: string): Promise<void>;
464
- declare function deleteWorkflowDefinition(db: Kysely<Database>, name: string, apiKeyId: string): Promise<void>;
465
- declare function createWorkflowRun(db: Kysely<Database>, data: {
466
- definitionId: string
467
- triggerType: string
468
- triggerData?: Record<string, unknown>
469
- dedupKey?: string
470
- }): Promise<WorkflowRun>;
471
- declare function getWorkflowRun(db: Kysely<Database>, runId: string): Promise<WorkflowRun | null>;
472
- declare function listWorkflowRuns(db: Kysely<Database>, definitionId: string, params?: {
473
- status?: string
474
- limit?: number
475
- offset?: number
476
- }): Promise<WorkflowRun[]>;
477
- declare function getWorkflowSteps(db: Kysely<Database>, runId: string): Promise<WorkflowStep[]>;
478
- export { upsertWorkflowDefinition, updateWorkflowStatus, listWorkflowRuns, listWorkflowDefinitions, getWorkflowSteps, getWorkflowRun, getWorkflowDefinition, deleteWorkflowDefinition, createWorkflowRun, bumpPatch };
411
+ interface SubscriptionDeliveriesTable {
412
+ id: Generated<string>;
413
+ outbox_id: string;
414
+ subscription_id: string;
415
+ attempt: number;
416
+ status_code: number | null;
417
+ response_headers: unknown | null;
418
+ response_body: string | null;
419
+ error_message: string | null;
420
+ duration_ms: number | null;
421
+ dispatched_at: Generated<Date>;
422
+ }
423
+ /**
424
+ * Compute add-ons — extras on top of a plan's base spec.
425
+ *
426
+ * Effective compute is NEVER derived from just the `tenants.plan`
427
+ * column — always run `computeEffectiveCompute(tenantId, planBase)`
428
+ * to fold in active add-ons. Provisioning, resize, and Stripe metering
429
+ * all share this source of truth.
430
+ */
431
+ /** Active = open-ended (effective_until IS NULL) OR not yet expired. */
432
+ declare function listActiveAddonsForTenant(db: Kysely<Database>, tenantId: string, now?: Date): Promise<TenantComputeAddon[]>;
433
+ interface ComputeSpec {
434
+ cpus: number;
435
+ memoryMb: number;
436
+ storageLimitMb: number;
437
+ }
438
+ /**
439
+ * Apply active add-ons on top of a base spec. `storageLimitMb` of -1
440
+ * (enterprise unlimited) passes through unchanged — add-ons don't
441
+ * further modify unlimited storage.
442
+ */
443
+ declare function computeEffectiveCompute(db: Kysely<Database>, tenantId: string, base: ComputeSpec, now?: Date): Promise<ComputeSpec>;
444
+ export { listActiveAddonsForTenant, computeEffectiveCompute, ComputeSpec };