@secondlayer/shared 2.0.0 → 3.0.0-alpha.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 (78) hide show
  1. package/README.md +2 -2
  2. package/dist/src/db/index.d.ts +64 -130
  3. package/dist/src/db/index.js.map +2 -2
  4. package/dist/src/db/jsonb.d.ts +5 -1
  5. package/dist/src/db/jsonb.js.map +2 -2
  6. package/dist/src/db/queries/account-spend-caps.d.ts +379 -0
  7. package/dist/src/db/queries/account-spend-caps.js +60 -0
  8. package/dist/src/db/queries/account-spend-caps.js.map +10 -0
  9. package/dist/src/db/queries/account-usage.d.ts +403 -0
  10. package/dist/src/db/queries/account-usage.js +222 -0
  11. package/dist/src/db/queries/account-usage.js.map +11 -0
  12. package/dist/src/db/queries/accounts.d.ts +61 -108
  13. package/dist/src/db/queries/accounts.js +15 -1
  14. package/dist/src/db/queries/accounts.js.map +3 -3
  15. package/dist/src/db/queries/integrity.d.ts +47 -107
  16. package/dist/src/db/queries/projects.d.ts +47 -107
  17. package/dist/src/db/queries/{workflows.d.ts → provisioning-audit.d.ts} +70 -142
  18. package/dist/src/db/queries/provisioning-audit.js +40 -0
  19. package/dist/src/db/queries/provisioning-audit.js.map +10 -0
  20. package/dist/src/db/queries/subgraph-gaps.d.ts +47 -107
  21. package/dist/src/db/queries/subgraphs.d.ts +47 -108
  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/{marketplace.d.ts → tenant-compute-addons.d.ts} +66 -159
  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 +67 -110
  28. package/dist/src/db/queries/tenants.js +35 -6
  29. package/dist/src/db/queries/tenants.js.map +3 -3
  30. package/dist/src/db/queries/usage.d.ts +48 -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 +59 -129
  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 +98 -212
  38. package/dist/src/index.js +69 -80
  39. package/dist/src/index.js.map +6 -6
  40. package/dist/src/mode.d.ts +4 -5
  41. package/dist/src/mode.js.map +2 -2
  42. package/dist/src/node/local-client.d.ts +47 -107
  43. package/dist/src/pricing.d.ts +20 -1
  44. package/dist/src/pricing.js +58 -1
  45. package/dist/src/pricing.js.map +3 -3
  46. package/dist/src/schemas/accounts.d.ts +14 -0
  47. package/dist/src/schemas/{marketplace.js → accounts.js} +4 -14
  48. package/dist/src/schemas/accounts.js.map +10 -0
  49. package/dist/src/schemas/index.d.ts +28 -77
  50. package/dist/src/schemas/index.js +59 -69
  51. package/dist/src/schemas/index.js.map +4 -4
  52. package/migrations/0043_tenant_usage_monthly.ts +36 -0
  53. package/migrations/0044_provisioning_audit_log.ts +40 -0
  54. package/migrations/0045_drop_marketplace_columns.ts +47 -0
  55. package/migrations/0046_tenant_activity_signal.ts +47 -0
  56. package/migrations/0047_usage_daily_tenant_id.ts +73 -0
  57. package/migrations/0048_tenant_compute_addons.ts +49 -0
  58. package/migrations/0049_accounts_stripe_customer_id.ts +30 -0
  59. package/migrations/0050_account_spend_caps.ts +45 -0
  60. package/migrations/0051_workflow_ai_usage_daily.ts +40 -0
  61. package/migrations/0052_sentries.ts +61 -0
  62. package/migrations/0053_workflow_runtime.ts +88 -0
  63. package/migrations/0054_accounts_plan_hobby.ts +32 -0
  64. package/migrations/0055_ai_usage_account_scope.ts +108 -0
  65. package/migrations/0056_drop_workflow_sentry_residuals.ts +23 -0
  66. package/package.json +33 -21
  67. package/dist/src/db/queries/marketplace.js +0 -139
  68. package/dist/src/db/queries/marketplace.js.map +0 -10
  69. package/dist/src/db/queries/workflows.js +0 -260
  70. package/dist/src/db/queries/workflows.js.map +0 -12
  71. package/dist/src/lib/plans.d.ts +0 -9
  72. package/dist/src/lib/plans.js +0 -37
  73. package/dist/src/lib/plans.js.map +0 -10
  74. package/dist/src/schemas/marketplace.d.ts +0 -63
  75. package/dist/src/schemas/marketplace.js.map +0 -10
  76. package/dist/src/schemas/workflows.d.ts +0 -70
  77. package/dist/src/schemas/workflows.js +0 -43
  78. 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,15 +272,11 @@ 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;
276
+ tenant_usage_monthly: TenantUsageMonthlyTable;
277
+ tenant_compute_addons: TenantComputeAddonsTable;
278
+ account_spend_caps: AccountSpendCapsTable;
279
+ provisioning_audit_log: ProvisioningAuditLogTable;
363
280
  }
364
281
  type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
365
282
  interface TenantsTable {
@@ -381,92 +298,82 @@ interface TenantsTable {
381
298
  service_key_enc: Buffer;
382
299
  api_url_internal: string;
383
300
  api_url_public: string;
384
- trial_ends_at: Date;
385
301
  suspended_at: Date | null;
386
302
  last_health_check_at: Date | null;
303
+ last_active_at: Generated<Date>;
387
304
  service_gen: Generated<number>;
388
305
  anon_gen: Generated<number>;
389
306
  project_id: string | null;
390
307
  created_at: Generated<Date>;
391
308
  updated_at: Generated<Date>;
392
309
  }
393
- interface WorkflowBudgetsTable {
310
+ interface TenantUsageMonthlyTable {
394
311
  id: Generated<string>;
395
- workflow_definition_id: string;
396
- /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
397
- period: string;
398
- ai_usd_used: Generated<string>;
399
- ai_tokens_used: Generated<string>;
400
- chain_microstx_used: Generated<string>;
401
- chain_tx_count: Generated<number>;
402
- run_count: Generated<number>;
403
- step_count: Generated<number>;
404
- reset_at: Date;
312
+ tenant_id: string;
313
+ period_month: Date;
314
+ storage_peak_mb: Generated<number>;
315
+ storage_avg_mb: Generated<number>;
316
+ storage_last_mb: Generated<number>;
317
+ measurements: Generated<number>;
318
+ first_at: Generated<Date>;
319
+ last_at: Generated<Date>;
320
+ }
321
+ interface TenantComputeAddonsTable {
322
+ id: Generated<string>;
323
+ tenant_id: string;
324
+ memory_mb_delta: Generated<number>;
325
+ cpu_delta: Generated<number | string>;
326
+ storage_mb_delta: Generated<number>;
327
+ effective_from: Generated<Date>;
328
+ effective_until: Date | null;
329
+ stripe_subscription_item_id: string | null;
405
330
  created_at: Generated<Date>;
331
+ }
332
+ type TenantComputeAddon = Selectable<TenantComputeAddonsTable>;
333
+ interface AccountSpendCapsTable {
334
+ account_id: string;
335
+ monthly_cap_cents: number | null;
336
+ compute_cap_cents: number | null;
337
+ storage_cap_cents: number | null;
338
+ ai_cap_cents: number | null;
339
+ alert_threshold_pct: Generated<number>;
340
+ alert_sent_at: Date | null;
341
+ frozen_at: Date | null;
406
342
  updated_at: Generated<Date>;
407
343
  }
408
- interface WorkflowSignerSecretsTable {
344
+ type ProvisioningAuditEvent = "provision.start" | "provision.success" | "provision.failure" | "suspend" | "resume" | "resize" | "keys.rotate" | "bastion.key.upload" | "bastion.key.revoke" | "teardown";
345
+ type ProvisioningAuditStatus = "ok" | "error";
346
+ interface ProvisioningAuditLogTable {
409
347
  id: Generated<string>;
410
- account_id: string;
411
- name: string;
412
- /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
413
- encrypted_value: Buffer;
348
+ tenant_id: string | null;
349
+ tenant_slug: string | null;
350
+ account_id: string | null;
351
+ actor: string;
352
+ event: ProvisioningAuditEvent;
353
+ status: ProvisioningAuditStatus;
354
+ detail: unknown | null;
355
+ error: string | null;
414
356
  created_at: Generated<Date>;
415
- updated_at: Generated<Date>;
416
357
  }
417
- type Subgraph = Selectable<SubgraphsTable>;
418
358
  /**
419
- * List public subgraphs with creator info and usage stats.
359
+ * Compute add-ons extras on top of a plan's base spec.
360
+ *
361
+ * Effective compute is NEVER derived from just the `tenants.plan`
362
+ * column — always run `computeEffectiveCompute(tenantId, planBase)`
363
+ * to fold in active add-ons. Provisioning, resize, and Stripe metering
364
+ * all share this source of truth.
420
365
  */
421
- declare function listPublicSubgraphs(db: Kysely<Database>, opts?: {
422
- limit?: number
423
- offset?: number
424
- tags?: string[]
425
- search?: string
426
- sort?: "recent" | "popular" | "name"
427
- }): Promise<{
428
- data: any[]
429
- meta: {
430
- total: number
431
- limit: number
432
- offset: number
433
- }
434
- }>;
435
- /**
436
- * Get a single public subgraph by name with creator info.
437
- */
438
- declare function getPublicSubgraph(db: Kysely<Database>, name: string): Promise<any | undefined>;
439
- /**
440
- * Get a creator profile by slug with their public subgraphs.
441
- */
442
- declare function getCreatorProfile(db: Kysely<Database>, slug: string): Promise<{
443
- account: any
444
- subgraphs: any[]
445
- } | null>;
446
- /**
447
- * Publish a subgraph (set is_public = true).
448
- */
449
- declare function publishSubgraph(db: Kysely<Database>, subgraphId: string, opts?: {
450
- tags?: string[]
451
- description?: string
452
- }): Promise<Subgraph>;
453
- /**
454
- * Unpublish a subgraph (set is_public = false).
455
- */
456
- declare function unpublishSubgraph(db: Kysely<Database>, subgraphId: string): Promise<Subgraph>;
457
- /**
458
- * Increment per-subgraph query count for today. Fire-and-forget safe.
459
- */
460
- declare function incrementSubgraphQueryCount(db: Kysely<Database>, subgraphId: string): Promise<void>;
461
- /**
462
- * Get daily usage history for a subgraph.
463
- */
464
- declare function getSubgraphUsageHistory(db: Kysely<Database>, subgraphId: string, days: number): Promise<Array<{
465
- date: string
466
- query_count: number
467
- }>>;
366
+ /** Active = open-ended (effective_until IS NULL) OR not yet expired. */
367
+ declare function listActiveAddonsForTenant(db: Kysely<Database>, tenantId: string, now?: Date): Promise<TenantComputeAddon[]>;
368
+ interface ComputeSpec {
369
+ cpus: number;
370
+ memoryMb: number;
371
+ storageLimitMb: number;
372
+ }
468
373
  /**
469
- * Get total query count for a subgraph over last N days.
374
+ * Apply active add-ons on top of a base spec. `storageLimitMb` of -1
375
+ * (enterprise unlimited) passes through unchanged — add-ons don't
376
+ * further modify unlimited storage.
470
377
  */
471
- declare function getSubgraphQueryTotal(db: Kysely<Database>, subgraphId: string, days: number): Promise<number>;
472
- export { unpublishSubgraph, publishSubgraph, listPublicSubgraphs, incrementSubgraphQueryCount, getSubgraphUsageHistory, getSubgraphQueryTotal, getPublicSubgraph, getCreatorProfile };
378
+ declare function computeEffectiveCompute(db: Kysely<Database>, tenantId: string, base: ComputeSpec, now?: Date): Promise<ComputeSpec>;
379
+ export { listActiveAddonsForTenant, computeEffectiveCompute, ComputeSpec };
@@ -0,0 +1,47 @@
1
+ import { createRequire } from "node:module";
2
+ var __defProp = Object.defineProperty;
3
+ var __returnValue = (v) => v;
4
+ function __exportSetter(name, newValue) {
5
+ this[name] = __returnValue.bind(null, newValue);
6
+ }
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, {
10
+ get: all[name],
11
+ enumerable: true,
12
+ configurable: true,
13
+ set: __exportSetter.bind(all, name)
14
+ });
15
+ };
16
+
17
+ // src/db/queries/tenant-compute-addons.ts
18
+ import { sql } from "kysely";
19
+ async function listActiveAddonsForTenant(db, tenantId, now = new Date) {
20
+ return db.selectFrom("tenant_compute_addons").selectAll().where("tenant_id", "=", tenantId).where("effective_from", "<=", now).where((eb) => eb.or([
21
+ eb("effective_until", "is", null),
22
+ eb("effective_until", ">", now)
23
+ ])).execute();
24
+ }
25
+ async function computeEffectiveCompute(db, tenantId, base, now = new Date) {
26
+ const row = await db.selectFrom("tenant_compute_addons").select([
27
+ sql`coalesce(sum(memory_mb_delta), 0)`.as("mem_delta"),
28
+ sql`coalesce(sum(cpu_delta), 0)`.as("cpu_delta"),
29
+ sql`coalesce(sum(storage_mb_delta), 0)`.as("stor_delta")
30
+ ]).where("tenant_id", "=", tenantId).where("effective_from", "<=", now).where((eb) => eb.or([
31
+ eb("effective_until", "is", null),
32
+ eb("effective_until", ">", now)
33
+ ])).executeTakeFirst();
34
+ if (!row)
35
+ return base;
36
+ const cpus = base.cpus + Number(row.cpu_delta ?? 0);
37
+ const memoryMb = base.memoryMb + Number(row.mem_delta ?? 0);
38
+ const storageLimitMb = base.storageLimitMb === -1 ? -1 : base.storageLimitMb + Number(row.stor_delta ?? 0);
39
+ return { cpus, memoryMb, storageLimitMb };
40
+ }
41
+ export {
42
+ listActiveAddonsForTenant,
43
+ computeEffectiveCompute
44
+ };
45
+
46
+ //# debugId=70D8508BE398EADC64756E2164756E21
47
+ //# sourceMappingURL=tenant-compute-addons.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/db/queries/tenant-compute-addons.ts"],
4
+ "sourcesContent": [
5
+ "import { type Kysely, sql } from \"kysely\";\nimport type { Database, TenantComputeAddon } from \"../types.ts\";\n\n/**\n * Compute add-ons — extras on top of a plan's base spec.\n *\n * Effective compute is NEVER derived from just the `tenants.plan`\n * column — always run `computeEffectiveCompute(tenantId, planBase)`\n * to fold in active add-ons. Provisioning, resize, and Stripe metering\n * all share this source of truth.\n */\n\n/** Active = open-ended (effective_until IS NULL) OR not yet expired. */\nexport async function listActiveAddonsForTenant(\n\tdb: Kysely<Database>,\n\ttenantId: string,\n\tnow: Date = new Date(),\n): Promise<TenantComputeAddon[]> {\n\treturn db\n\t\t.selectFrom(\"tenant_compute_addons\")\n\t\t.selectAll()\n\t\t.where(\"tenant_id\", \"=\", tenantId)\n\t\t.where(\"effective_from\", \"<=\", now)\n\t\t.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"effective_until\", \"is\", null),\n\t\t\t\teb(\"effective_until\", \">\", now),\n\t\t\t]),\n\t\t)\n\t\t.execute();\n}\n\nexport interface ComputeSpec {\n\tcpus: number;\n\tmemoryMb: number;\n\tstorageLimitMb: number;\n}\n\n/**\n * Apply active add-ons on top of a base spec. `storageLimitMb` of -1\n * (enterprise unlimited) passes through unchanged — add-ons don't\n * further modify unlimited storage.\n */\nexport async function computeEffectiveCompute(\n\tdb: Kysely<Database>,\n\ttenantId: string,\n\tbase: ComputeSpec,\n\tnow: Date = new Date(),\n): Promise<ComputeSpec> {\n\tconst row = await db\n\t\t.selectFrom(\"tenant_compute_addons\")\n\t\t.select([\n\t\t\tsql<number>`coalesce(sum(memory_mb_delta), 0)`.as(\"mem_delta\"),\n\t\t\tsql<string>`coalesce(sum(cpu_delta), 0)`.as(\"cpu_delta\"),\n\t\t\tsql<number>`coalesce(sum(storage_mb_delta), 0)`.as(\"stor_delta\"),\n\t\t])\n\t\t.where(\"tenant_id\", \"=\", tenantId)\n\t\t.where(\"effective_from\", \"<=\", now)\n\t\t.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"effective_until\", \"is\", null),\n\t\t\t\teb(\"effective_until\", \">\", now),\n\t\t\t]),\n\t\t)\n\t\t.executeTakeFirst();\n\n\tif (!row) return base;\n\n\tconst cpus = base.cpus + Number(row.cpu_delta ?? 0);\n\tconst memoryMb = base.memoryMb + Number(row.mem_delta ?? 0);\n\tconst storageLimitMb =\n\t\tbase.storageLimitMb === -1\n\t\t\t? -1\n\t\t\t: base.storageLimitMb + Number(row.stor_delta ?? 0);\n\n\treturn { cpus, memoryMb, storageLimitMb };\n}\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAaA,eAAsB,yBAAyB,CAC9C,IACA,UACA,MAAY,IAAI,MACgB;AAAA,EAChC,OAAO,GACL,WAAW,uBAAuB,EAClC,UAAU,EACV,MAAM,aAAa,KAAK,QAAQ,EAChC,MAAM,kBAAkB,MAAM,GAAG,EACjC,MAAM,CAAC,OACP,GAAG,GAAG;AAAA,IACL,GAAG,mBAAmB,MAAM,IAAI;AAAA,IAChC,GAAG,mBAAmB,KAAK,GAAG;AAAA,EAC/B,CAAC,CACF,EACC,QAAQ;AAAA;AAcX,eAAsB,uBAAuB,CAC5C,IACA,UACA,MACA,MAAY,IAAI,MACO;AAAA,EACvB,MAAM,MAAM,MAAM,GAChB,WAAW,uBAAuB,EAClC,OAAO;AAAA,IACP,uCAA+C,GAAG,WAAW;AAAA,IAC7D,iCAAyC,GAAG,WAAW;AAAA,IACvD,wCAAgD,GAAG,YAAY;AAAA,EAChE,CAAC,EACA,MAAM,aAAa,KAAK,QAAQ,EAChC,MAAM,kBAAkB,MAAM,GAAG,EACjC,MAAM,CAAC,OACP,GAAG,GAAG;AAAA,IACL,GAAG,mBAAmB,MAAM,IAAI;AAAA,IAChC,GAAG,mBAAmB,KAAK,GAAG;AAAA,EAC/B,CAAC,CACF,EACC,iBAAiB;AAAA,EAEnB,IAAI,CAAC;AAAA,IAAK,OAAO;AAAA,EAEjB,MAAM,OAAO,KAAK,OAAO,OAAO,IAAI,aAAa,CAAC;AAAA,EAClD,MAAM,WAAW,KAAK,WAAW,OAAO,IAAI,aAAa,CAAC;AAAA,EAC1D,MAAM,iBACL,KAAK,mBAAmB,KACrB,KACA,KAAK,iBAAiB,OAAO,IAAI,cAAc,CAAC;AAAA,EAEpD,OAAO,EAAE,MAAM,UAAU,eAAe;AAAA;",
8
+ "debugId": "70D8508BE398EADC64756E2164756E21",
9
+ "names": []
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,15 +272,11 @@ 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;
276
+ tenant_usage_monthly: TenantUsageMonthlyTable;
277
+ tenant_compute_addons: TenantComputeAddonsTable;
278
+ account_spend_caps: AccountSpendCapsTable;
279
+ provisioning_audit_log: ProvisioningAuditLogTable;
363
280
  }
364
281
  type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
365
282
  interface TenantsTable {
@@ -381,9 +298,9 @@ interface TenantsTable {
381
298
  service_key_enc: Buffer;
382
299
  api_url_internal: string;
383
300
  api_url_public: string;
384
- trial_ends_at: Date;
385
301
  suspended_at: Date | null;
386
302
  last_health_check_at: Date | null;
303
+ last_active_at: Generated<Date>;
387
304
  service_gen: Generated<number>;
388
305
  anon_gen: Generated<number>;
389
306
  project_id: string | null;
@@ -391,29 +308,52 @@ interface TenantsTable {
391
308
  updated_at: Generated<Date>;
392
309
  }
393
310
  type Tenant = Selectable<TenantsTable>;
394
- interface WorkflowBudgetsTable {
311
+ interface TenantUsageMonthlyTable {
312
+ id: Generated<string>;
313
+ tenant_id: string;
314
+ period_month: Date;
315
+ storage_peak_mb: Generated<number>;
316
+ storage_avg_mb: Generated<number>;
317
+ storage_last_mb: Generated<number>;
318
+ measurements: Generated<number>;
319
+ first_at: Generated<Date>;
320
+ last_at: Generated<Date>;
321
+ }
322
+ interface TenantComputeAddonsTable {
395
323
  id: Generated<string>;
396
- workflow_definition_id: string;
397
- /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
398
- period: string;
399
- ai_usd_used: Generated<string>;
400
- ai_tokens_used: Generated<string>;
401
- chain_microstx_used: Generated<string>;
402
- chain_tx_count: Generated<number>;
403
- run_count: Generated<number>;
404
- step_count: Generated<number>;
405
- reset_at: Date;
324
+ tenant_id: string;
325
+ memory_mb_delta: Generated<number>;
326
+ cpu_delta: Generated<number | string>;
327
+ storage_mb_delta: Generated<number>;
328
+ effective_from: Generated<Date>;
329
+ effective_until: Date | null;
330
+ stripe_subscription_item_id: string | null;
406
331
  created_at: Generated<Date>;
332
+ }
333
+ interface AccountSpendCapsTable {
334
+ account_id: string;
335
+ monthly_cap_cents: number | null;
336
+ compute_cap_cents: number | null;
337
+ storage_cap_cents: number | null;
338
+ ai_cap_cents: number | null;
339
+ alert_threshold_pct: Generated<number>;
340
+ alert_sent_at: Date | null;
341
+ frozen_at: Date | null;
407
342
  updated_at: Generated<Date>;
408
343
  }
409
- interface WorkflowSignerSecretsTable {
344
+ type ProvisioningAuditEvent = "provision.start" | "provision.success" | "provision.failure" | "suspend" | "resume" | "resize" | "keys.rotate" | "bastion.key.upload" | "bastion.key.revoke" | "teardown";
345
+ type ProvisioningAuditStatus = "ok" | "error";
346
+ interface ProvisioningAuditLogTable {
410
347
  id: Generated<string>;
411
- account_id: string;
412
- name: string;
413
- /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
414
- encrypted_value: Buffer;
348
+ tenant_id: string | null;
349
+ tenant_slug: string | null;
350
+ account_id: string | null;
351
+ actor: string;
352
+ event: ProvisioningAuditEvent;
353
+ status: ProvisioningAuditStatus;
354
+ detail: unknown | null;
355
+ error: string | null;
415
356
  created_at: Generated<Date>;
416
- updated_at: Generated<Date>;
417
357
  }
418
358
  /**
419
359
  * Tenant registry queries. Encrypted columns are stored as `bytea` and
@@ -439,17 +379,34 @@ interface NewTenantInput {
439
379
  serviceKey: string;
440
380
  apiUrlInternal: string;
441
381
  apiUrlPublic: string;
442
- trialEndsAt: Date;
443
382
  projectId?: string;
444
383
  }
445
384
  declare function insertTenant(db: Kysely<Database>, input: NewTenantInput): Promise<Tenant>;
446
385
  declare function getTenantByAccount(db: Kysely<Database>, accountId: string): Promise<Tenant | null>;
447
386
  declare function getTenantBySlug(db: Kysely<Database>, slug: string): Promise<Tenant | null>;
448
387
  declare function listTenantsByStatus(db: Kysely<Database>, status: TenantStatus): Promise<Tenant[]>;
449
- declare function listExpiredTrials(db: Kysely<Database>, now?: Date): Promise<Tenant[]>;
388
+ /**
389
+ * Tenants considered "idle" for auto-pause on the Hobby tier. Active = any
390
+ * successful tenant-API query OR workflow run wrote `last_active_at` within
391
+ * the threshold.
392
+ */
393
+ declare function listIdleHobbyTenants(db: Kysely<Database>, idleSince: Date): Promise<Tenant[]>;
394
+ /**
395
+ * Bump `last_active_at` for a tenant. Callers are expected to throttle
396
+ * (don't hammer on every request) — the activity middleware + workflow-
397
+ * runner enforce a 60s per-tenant min between writes.
398
+ */
399
+ declare function bumpTenantActivity(db: Kysely<Database>, slug: string): Promise<void>;
450
400
  declare function listSuspendedOlderThan(db: Kysely<Database>, olderThan: Date): Promise<Tenant[]>;
451
401
  declare function setTenantStatus(db: Kysely<Database>, slug: string, status: TenantStatus): Promise<void>;
452
402
  declare function recordHealthCheck(db: Kysely<Database>, slug: string, storageUsedMb: number | null): Promise<void>;
403
+ /**
404
+ * Record a storage measurement into the current calendar month's bucket.
405
+ * Maintains peak, running average, and the most recent value in a single
406
+ * upsert. Billing will consume this later; for now the table just gives
407
+ * us evidence of usage over time.
408
+ */
409
+ declare function recordMonthlyUsage(db: Kysely<Database>, tenantId: string, storageMb: number): Promise<void>;
453
410
  declare function updateTenantPlan(db: Kysely<Database>, slug: string, plan: string, cpus: number, memoryMb: number, storageLimitMb: number): Promise<void>;
454
411
  type RotateType = "service" | "anon" | "both";
455
412
  /**
@@ -490,4 +447,4 @@ interface TenantCredentials {
490
447
  * CLI). Never log the returned object.
491
448
  */
492
449
  declare function getTenantCredentials(db: Kysely<Database>, slug: string): Promise<TenantCredentials | null>;
493
- export { updateTenantPlan, updateTenantKeys, setTenantStatus, recordHealthCheck, listTenantsByStatus, listSuspendedOlderThan, listExpiredTrials, insertTenant, getTenantCredentials, getTenantBySlug, getTenantByAccount, deleteTenant, bumpTenantKeyGen, TenantCredentials, RotateType, NewTenantInput };
450
+ export { updateTenantPlan, updateTenantKeys, setTenantStatus, recordMonthlyUsage, recordHealthCheck, listTenantsByStatus, listSuspendedOlderThan, listIdleHobbyTenants, insertTenant, getTenantCredentials, getTenantBySlug, getTenantByAccount, deleteTenant, bumpTenantKeyGen, bumpTenantActivity, TenantCredentials, RotateType, NewTenantInput };
@@ -61,6 +61,7 @@ function generateSecretsKey() {
61
61
  }
62
62
 
63
63
  // src/db/queries/tenants.ts
64
+ import { sql } from "kysely";
64
65
  async function insertTenant(db, input) {
65
66
  const row = {
66
67
  account_id: input.accountId,
@@ -79,7 +80,6 @@ async function insertTenant(db, input) {
79
80
  service_key_enc: encryptSecret(input.serviceKey),
80
81
  api_url_internal: input.apiUrlInternal,
81
82
  api_url_public: input.apiUrlPublic,
82
- trial_ends_at: input.trialEndsAt,
83
83
  project_id: input.projectId ?? null
84
84
  };
85
85
  return db.insertInto("tenants").values(row).returningAll().executeTakeFirstOrThrow();
@@ -95,8 +95,11 @@ async function getTenantBySlug(db, slug) {
95
95
  async function listTenantsByStatus(db, status) {
96
96
  return db.selectFrom("tenants").selectAll().where("status", "=", status).execute();
97
97
  }
98
- async function listExpiredTrials(db, now = new Date) {
99
- return db.selectFrom("tenants").selectAll().where("status", "in", ["provisioning", "active"]).where("trial_ends_at", "<", now).execute();
98
+ async function listIdleHobbyTenants(db, idleSince) {
99
+ return db.selectFrom("tenants").selectAll().where("status", "=", "active").where("plan", "=", "hobby").where("last_active_at", "<", idleSince).execute();
100
+ }
101
+ async function bumpTenantActivity(db, slug) {
102
+ await db.updateTable("tenants").set({ last_active_at: new Date }).where("slug", "=", slug).execute();
100
103
  }
101
104
  async function listSuspendedOlderThan(db, olderThan) {
102
105
  return db.selectFrom("tenants").selectAll().where("status", "=", "suspended").where("suspended_at", "<", olderThan).execute();
@@ -119,6 +122,30 @@ async function recordHealthCheck(db, slug, storageUsedMb) {
119
122
  updated_at: new Date
120
123
  }).where("slug", "=", slug).execute();
121
124
  }
125
+ async function recordMonthlyUsage(db, tenantId, storageMb) {
126
+ const now = new Date;
127
+ const periodMonth = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), 1));
128
+ await sql`
129
+ INSERT INTO tenant_usage_monthly (
130
+ tenant_id, period_month,
131
+ storage_peak_mb, storage_avg_mb, storage_last_mb,
132
+ measurements, first_at, last_at
133
+ ) VALUES (
134
+ ${tenantId}, ${periodMonth},
135
+ ${storageMb}, ${storageMb}, ${storageMb},
136
+ 1, now(), now()
137
+ )
138
+ ON CONFLICT (tenant_id, period_month) DO UPDATE SET
139
+ storage_peak_mb = GREATEST(tenant_usage_monthly.storage_peak_mb, EXCLUDED.storage_last_mb),
140
+ storage_avg_mb = (
141
+ (tenant_usage_monthly.storage_avg_mb * tenant_usage_monthly.measurements + EXCLUDED.storage_last_mb)
142
+ / (tenant_usage_monthly.measurements + 1)
143
+ ),
144
+ storage_last_mb = EXCLUDED.storage_last_mb,
145
+ measurements = tenant_usage_monthly.measurements + 1,
146
+ last_at = now()
147
+ `.execute(db);
148
+ }
122
149
  async function updateTenantPlan(db, slug, plan, cpus, memoryMb, storageLimitMb) {
123
150
  await db.updateTable("tenants").set({
124
151
  plan,
@@ -178,17 +205,19 @@ export {
178
205
  updateTenantPlan,
179
206
  updateTenantKeys,
180
207
  setTenantStatus,
208
+ recordMonthlyUsage,
181
209
  recordHealthCheck,
182
210
  listTenantsByStatus,
183
211
  listSuspendedOlderThan,
184
- listExpiredTrials,
212
+ listIdleHobbyTenants,
185
213
  insertTenant,
186
214
  getTenantCredentials,
187
215
  getTenantBySlug,
188
216
  getTenantByAccount,
189
217
  deleteTenant,
190
- bumpTenantKeyGen
218
+ bumpTenantKeyGen,
219
+ bumpTenantActivity
191
220
  };
192
221
 
193
- //# debugId=1D0DA0A21FCE7D7664756E2164756E21
222
+ //# debugId=D0CC1ED1445094FE64756E2164756E21
194
223
  //# sourceMappingURL=tenants.js.map