@secondlayer/shared 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/src/crypto/secrets.d.ts +5 -0
  2. package/dist/src/crypto/secrets.js +69 -0
  3. package/dist/src/crypto/secrets.js.map +10 -0
  4. package/dist/src/db/index.d.ts +91 -6
  5. package/dist/src/db/index.js +53 -29
  6. package/dist/src/db/index.js.map +4 -4
  7. package/dist/src/db/jsonb.js.map +2 -2
  8. package/dist/src/db/queries/accounts.d.ts +59 -2
  9. package/dist/src/db/queries/integrity.d.ts +59 -2
  10. package/dist/src/db/queries/marketplace.d.ts +59 -2
  11. package/dist/src/db/queries/marketplace.js +6 -9
  12. package/dist/src/db/queries/marketplace.js.map +3 -3
  13. package/dist/src/db/queries/projects.d.ts +59 -2
  14. package/dist/src/db/queries/projects.js.map +2 -2
  15. package/dist/src/db/queries/subgraph-gaps.d.ts +59 -2
  16. package/dist/src/db/queries/subgraphs.d.ts +63 -5
  17. package/dist/src/db/queries/subgraphs.js +3 -9
  18. package/dist/src/db/queries/subgraphs.js.map +4 -4
  19. package/dist/src/db/queries/tenants.d.ts +493 -0
  20. package/dist/src/db/queries/tenants.js +194 -0
  21. package/dist/src/db/queries/tenants.js.map +11 -0
  22. package/dist/src/db/queries/usage.d.ts +59 -2
  23. package/dist/src/db/queries/usage.js +3 -3
  24. package/dist/src/db/queries/usage.js.map +3 -3
  25. package/dist/src/db/queries/workflows.d.ts +59 -2
  26. package/dist/src/db/queries/workflows.js +31 -3
  27. package/dist/src/db/queries/workflows.js.map +4 -4
  28. package/dist/src/db/schema.d.ts +69 -3
  29. package/dist/src/env.d.ts +10 -0
  30. package/dist/src/env.js +3 -1
  31. package/dist/src/env.js.map +3 -3
  32. package/dist/src/errors.d.ts +17 -3
  33. package/dist/src/errors.js +34 -3
  34. package/dist/src/errors.js.map +3 -3
  35. package/dist/src/index.d.ts +117 -8
  36. package/dist/src/index.js +88 -31
  37. package/dist/src/index.js.map +6 -6
  38. package/dist/src/logger.js +3 -1
  39. package/dist/src/logger.js.map +3 -3
  40. package/dist/src/mode.d.ts +30 -0
  41. package/dist/src/mode.js +43 -0
  42. package/dist/src/mode.js.map +10 -0
  43. package/dist/src/node/archive-client.js +3 -1
  44. package/dist/src/node/archive-client.js.map +3 -3
  45. package/dist/src/node/hiro-client.js +3 -1
  46. package/dist/src/node/hiro-client.js.map +3 -3
  47. package/dist/src/node/local-client.d.ts +59 -2
  48. package/dist/src/pricing.d.ts +28 -0
  49. package/dist/src/pricing.js +47 -0
  50. package/dist/src/pricing.js.map +10 -0
  51. package/dist/src/queue/listener.d.ts +11 -2
  52. package/dist/src/queue/listener.js +11 -12
  53. package/dist/src/queue/listener.js.map +3 -3
  54. package/dist/src/types.d.ts +10 -0
  55. package/migrations/0033_workflow_steps_memo_key.ts +54 -0
  56. package/migrations/0034_workflow_signer_secrets.ts +42 -0
  57. package/migrations/0035_workflow_budgets.ts +53 -0
  58. package/migrations/0036_tx_confirmed_notify.ts +36 -0
  59. package/migrations/0037_nullable_api_key.ts +35 -0
  60. package/migrations/0038_drop_workflow_tables.ts +46 -0
  61. package/migrations/0039_tenants.ts +66 -0
  62. package/migrations/0040_tenant_key_generations.ts +29 -0
  63. package/migrations/0041_subgraphs_drop_api_key_id.ts +49 -0
  64. package/migrations/0042_tenant_project_id.ts +25 -0
  65. package/package.json +18 -2
@@ -0,0 +1,5 @@
1
+ declare function encryptSecret(plaintext: string): Buffer;
2
+ declare function decryptSecret(envelope: Buffer): string;
3
+ /** Generate a fresh 32-byte hex key suitable for `SECONDLAYER_SECRETS_KEY`. */
4
+ declare function generateSecretsKey(): string;
5
+ export { generateSecretsKey, encryptSecret, decryptSecret };
@@ -0,0 +1,69 @@
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/crypto/secrets.ts
18
+ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
19
+ var KEY_ENV = "SECONDLAYER_SECRETS_KEY";
20
+ var IV_LEN = 12;
21
+ var TAG_LEN = 16;
22
+ function loadKey() {
23
+ const hex = process.env[KEY_ENV];
24
+ if (!hex) {
25
+ throw new Error(`${KEY_ENV} not set. Generate one with: openssl rand -hex 32`);
26
+ }
27
+ const key = Buffer.from(hex, "hex");
28
+ if (key.length !== 32) {
29
+ throw new Error(`${KEY_ENV} must be 32 bytes hex (got ${key.length})`);
30
+ }
31
+ return key;
32
+ }
33
+ var _cachedKey = null;
34
+ function getKey() {
35
+ if (!_cachedKey)
36
+ _cachedKey = loadKey();
37
+ return _cachedKey;
38
+ }
39
+ function encryptSecret(plaintext) {
40
+ const key = getKey();
41
+ const iv = randomBytes(IV_LEN);
42
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
43
+ const ciphertext = Buffer.concat([
44
+ cipher.update(plaintext, "utf8"),
45
+ cipher.final()
46
+ ]);
47
+ const tag = cipher.getAuthTag();
48
+ return Buffer.concat([iv, tag, ciphertext]);
49
+ }
50
+ function decryptSecret(envelope) {
51
+ const key = getKey();
52
+ const iv = envelope.subarray(0, IV_LEN);
53
+ const tag = envelope.subarray(IV_LEN, IV_LEN + TAG_LEN);
54
+ const ciphertext = envelope.subarray(IV_LEN + TAG_LEN);
55
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
56
+ decipher.setAuthTag(tag);
57
+ return decipher.update(ciphertext).toString("utf8") + decipher.final("utf8");
58
+ }
59
+ function generateSecretsKey() {
60
+ return randomBytes(32).toString("hex");
61
+ }
62
+ export {
63
+ generateSecretsKey,
64
+ encryptSecret,
65
+ decryptSecret
66
+ };
67
+
68
+ //# debugId=0FD7F496A1099A3864756E2164756E21
69
+ //# sourceMappingURL=secrets.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/crypto/secrets.ts"],
4
+ "sourcesContent": [
5
+ "import { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\n\n/**\n * AES-256-GCM symmetric envelope for workflow signer secrets.\n *\n * Ciphertext layout: `iv (12 bytes) || authTag (16 bytes) || ciphertext`\n *\n * The key comes from `SECONDLAYER_SECRETS_KEY` — 32 bytes hex. Callers must\n * load + cache the key once per process. Rotation strategy: when a customer\n * wants to rotate keys, re-encrypt all rows with the new key and swap the\n * env var. Not zero-downtime, but acceptable at v2 scale.\n *\n * For real KMS (AWS KMS, HashiCorp Vault, GCP KMS), wrap the same byte\n * layout behind an `EncryptSecret` / `DecryptSecret` interface in the\n * runner and swap the implementation at startup.\n */\n\nconst KEY_ENV = \"SECONDLAYER_SECRETS_KEY\";\nconst IV_LEN = 12;\nconst TAG_LEN = 16;\n\nfunction loadKey(): Buffer {\n\tconst hex = process.env[KEY_ENV];\n\tif (!hex) {\n\t\tthrow new Error(\n\t\t\t`${KEY_ENV} not set. Generate one with: openssl rand -hex 32`,\n\t\t);\n\t}\n\tconst key = Buffer.from(hex, \"hex\");\n\tif (key.length !== 32) {\n\t\tthrow new Error(`${KEY_ENV} must be 32 bytes hex (got ${key.length})`);\n\t}\n\treturn key;\n}\n\nlet _cachedKey: Buffer | null = null;\nfunction getKey(): Buffer {\n\tif (!_cachedKey) _cachedKey = loadKey();\n\treturn _cachedKey;\n}\n\nexport function encryptSecret(plaintext: string): Buffer {\n\tconst key = getKey();\n\tconst iv = randomBytes(IV_LEN);\n\tconst cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n\tconst ciphertext = Buffer.concat([\n\t\tcipher.update(plaintext, \"utf8\"),\n\t\tcipher.final(),\n\t]);\n\tconst tag = cipher.getAuthTag();\n\treturn Buffer.concat([iv, tag, ciphertext]);\n}\n\nexport function decryptSecret(envelope: Buffer): string {\n\tconst key = getKey();\n\tconst iv = envelope.subarray(0, IV_LEN);\n\tconst tag = envelope.subarray(IV_LEN, IV_LEN + TAG_LEN);\n\tconst ciphertext = envelope.subarray(IV_LEN + TAG_LEN);\n\tconst decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n\tdecipher.setAuthTag(tag);\n\treturn decipher.update(ciphertext).toString(\"utf8\") + decipher.final(\"utf8\");\n}\n\n/** Generate a fresh 32-byte hex key suitable for `SECONDLAYER_SECRETS_KEY`. */\nexport function generateSecretsKey(): string {\n\treturn randomBytes(32).toString(\"hex\");\n}\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAiBA,IAAM,UAAU;AAChB,IAAM,SAAS;AACf,IAAM,UAAU;AAEhB,SAAS,OAAO,GAAW;AAAA,EAC1B,MAAM,MAAM,QAAQ,IAAI;AAAA,EACxB,IAAI,CAAC,KAAK;AAAA,IACT,MAAM,IAAI,MACT,GAAG,0DACJ;AAAA,EACD;AAAA,EACA,MAAM,MAAM,OAAO,KAAK,KAAK,KAAK;AAAA,EAClC,IAAI,IAAI,WAAW,IAAI;AAAA,IACtB,MAAM,IAAI,MAAM,GAAG,qCAAqC,IAAI,SAAS;AAAA,EACtE;AAAA,EACA,OAAO;AAAA;AAGR,IAAI,aAA4B;AAChC,SAAS,MAAM,GAAW;AAAA,EACzB,IAAI,CAAC;AAAA,IAAY,aAAa,QAAQ;AAAA,EACtC,OAAO;AAAA;AAGD,SAAS,aAAa,CAAC,WAA2B;AAAA,EACxD,MAAM,MAAM,OAAO;AAAA,EACnB,MAAM,KAAK,YAAY,MAAM;AAAA,EAC7B,MAAM,SAAS,eAAe,eAAe,KAAK,EAAE;AAAA,EACpD,MAAM,aAAa,OAAO,OAAO;AAAA,IAChC,OAAO,OAAO,WAAW,MAAM;AAAA,IAC/B,OAAO,MAAM;AAAA,EACd,CAAC;AAAA,EACD,MAAM,MAAM,OAAO,WAAW;AAAA,EAC9B,OAAO,OAAO,OAAO,CAAC,IAAI,KAAK,UAAU,CAAC;AAAA;AAGpC,SAAS,aAAa,CAAC,UAA0B;AAAA,EACvD,MAAM,MAAM,OAAO;AAAA,EACnB,MAAM,KAAK,SAAS,SAAS,GAAG,MAAM;AAAA,EACtC,MAAM,MAAM,SAAS,SAAS,QAAQ,SAAS,OAAO;AAAA,EACtD,MAAM,aAAa,SAAS,SAAS,SAAS,OAAO;AAAA,EACrD,MAAM,WAAW,iBAAiB,eAAe,KAAK,EAAE;AAAA,EACxD,SAAS,WAAW,GAAG;AAAA,EACvB,OAAO,SAAS,OAAO,UAAU,EAAE,SAAS,MAAM,IAAI,SAAS,MAAM,MAAM;AAAA;AAIrE,SAAS,kBAAkB,GAAW;AAAA,EAC5C,OAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AAAA;",
8
+ "debugId": "0FD7F496A1099A3864756E2164756E21",
9
+ "names": []
10
+ }
@@ -13,7 +13,7 @@ declare function jsonb(value: unknown): RawBuilder<unknown>;
13
13
  declare function parseJsonb<T = unknown>(value: unknown): T;
14
14
  import { Kysely } from "kysely";
15
15
  import postgres from "postgres";
16
- import { Generated, Insertable, Selectable, Updateable } from "kysely";
16
+ import { ColumnType, Generated, Insertable, Selectable, Updateable } from "kysely";
17
17
  interface BlocksTable {
18
18
  height: number;
19
19
  hash: string;
@@ -70,7 +70,6 @@ interface SubgraphsTable {
70
70
  last_error_at: Date | null;
71
71
  total_processed: Generated<number>;
72
72
  total_errors: Generated<number>;
73
- api_key_id: string | null;
74
73
  account_id: string;
75
74
  handler_code: string | null;
76
75
  source_code: string | null;
@@ -309,6 +308,8 @@ interface WorkflowStepsTable {
309
308
  started_at: Date | null;
310
309
  completed_at: Date | null;
311
310
  duration_ms: number | null;
311
+ memo_key: string | null;
312
+ parent_step_id: string | null;
312
313
  created_at: Generated<Date>;
313
314
  }
314
315
  interface WorkflowQueueTable {
@@ -370,6 +371,65 @@ interface Database {
370
371
  workflow_queue: WorkflowQueueTable;
371
372
  workflow_schedules: WorkflowSchedulesTable;
372
373
  workflow_cursors: WorkflowCursorsTable;
374
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
375
+ workflow_budgets: WorkflowBudgetsTable;
376
+ tenants: TenantsTable;
377
+ }
378
+ type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
379
+ interface TenantsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ slug: string;
383
+ status: ColumnType<TenantStatus, TenantStatus | undefined, TenantStatus>;
384
+ plan: string;
385
+ cpus: ColumnType<number, number | string, number | string>;
386
+ memory_mb: number;
387
+ storage_limit_mb: number;
388
+ storage_used_mb: number | null;
389
+ pg_container_id: string | null;
390
+ api_container_id: string | null;
391
+ processor_container_id: string | null;
392
+ target_database_url_enc: Buffer;
393
+ tenant_jwt_secret_enc: Buffer;
394
+ anon_key_enc: Buffer;
395
+ service_key_enc: Buffer;
396
+ api_url_internal: string;
397
+ api_url_public: string;
398
+ trial_ends_at: Date;
399
+ suspended_at: Date | null;
400
+ last_health_check_at: Date | null;
401
+ service_gen: Generated<number>;
402
+ anon_gen: Generated<number>;
403
+ project_id: string | null;
404
+ created_at: Generated<Date>;
405
+ updated_at: Generated<Date>;
406
+ }
407
+ type Tenant = Selectable<TenantsTable>;
408
+ type InsertTenant = Insertable<TenantsTable>;
409
+ type UpdateTenant = Updateable<TenantsTable>;
410
+ interface WorkflowBudgetsTable {
411
+ id: Generated<string>;
412
+ workflow_definition_id: string;
413
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
414
+ period: string;
415
+ ai_usd_used: Generated<string>;
416
+ ai_tokens_used: Generated<string>;
417
+ chain_microstx_used: Generated<string>;
418
+ chain_tx_count: Generated<number>;
419
+ run_count: Generated<number>;
420
+ step_count: Generated<number>;
421
+ reset_at: Date;
422
+ created_at: Generated<Date>;
423
+ updated_at: Generated<Date>;
424
+ }
425
+ interface WorkflowSignerSecretsTable {
426
+ id: Generated<string>;
427
+ account_id: string;
428
+ name: string;
429
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
430
+ encrypted_value: Buffer;
431
+ created_at: Generated<Date>;
432
+ updated_at: Generated<Date>;
373
433
  }
374
434
  type Block = Selectable<BlocksTable>;
375
435
  type InsertBlock = Insertable<BlocksTable>;
@@ -422,6 +482,12 @@ type WorkflowSchedule = Selectable<WorkflowSchedulesTable>;
422
482
  type InsertWorkflowSchedule = Insertable<WorkflowSchedulesTable>;
423
483
  type UpdateWorkflowSchedule = Updateable<WorkflowSchedulesTable>;
424
484
  type WorkflowCursor = Selectable<WorkflowCursorsTable>;
485
+ type WorkflowSignerSecret = Selectable<WorkflowSignerSecretsTable>;
486
+ type InsertWorkflowSignerSecret = Insertable<WorkflowSignerSecretsTable>;
487
+ type UpdateWorkflowSignerSecret = Updateable<WorkflowSignerSecretsTable>;
488
+ type WorkflowBudget = Selectable<WorkflowBudgetsTable>;
489
+ type InsertWorkflowBudget = Insertable<WorkflowBudgetsTable>;
490
+ type UpdateWorkflowBudget = Updateable<WorkflowBudgetsTable>;
425
491
  type Project = Selectable<ProjectsTable>;
426
492
  type InsertProject = Insertable<ProjectsTable>;
427
493
  type UpdateProject = Updateable<ProjectsTable>;
@@ -435,9 +501,28 @@ type UpdateChatSession = Updateable<ChatSessionsTable>;
435
501
  type ChatMessage = Selectable<ChatMessagesTable>;
436
502
  type InsertChatMessage = Insertable<ChatMessagesTable>;
437
503
  import { sql } from "kysely";
504
+ /**
505
+ * Kysely instance for the SOURCE DB (block/tx/event reads from the shared
506
+ * indexer). Resolution: `SOURCE_DATABASE_URL || DATABASE_URL`.
507
+ */
508
+ declare function getSourceDb(): Kysely<Database>;
509
+ /**
510
+ * Kysely instance for the TARGET DB (subgraph schemas, subgraphs table,
511
+ * account-scoped data — tenant-side writes). Resolution:
512
+ * `TARGET_DATABASE_URL || DATABASE_URL`.
513
+ */
514
+ declare function getTargetDb(): Kysely<Database>;
515
+ /**
516
+ * Backward-compat alias for `getTargetDb()`. Accepts an optional
517
+ * `connectionString` override used by seed/test helpers — when supplied,
518
+ * bypasses env resolution and uses the provided URL directly (still cached).
519
+ */
438
520
  declare function getDb(connectionString?: string): Kysely<Database>;
439
- /** Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.) */
440
- declare function getRawClient(): ReturnType<typeof postgres>;
441
- /** Close the DB connection pool. Call in CLI commands to allow process exit. */
521
+ /**
522
+ * Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.).
523
+ * Defaults to the target role (tenant schemas live in the target DB).
524
+ */
525
+ declare function getRawClient(role?: "source" | "target"): ReturnType<typeof postgres>;
526
+ /** Close all DB connection pools. Call in CLI commands to allow process exit. */
442
527
  declare function closeDb(): Promise<void>;
443
- export { sql, parseJsonb, jsonb, getRawClient, getDb, closeDb, WorkflowStepsTable, WorkflowStep, WorkflowSchedulesTable, WorkflowSchedule, WorkflowRunsTable, WorkflowRun, WorkflowQueueTable, WorkflowQueueItem, WorkflowDefinitionsTable, WorkflowDefinition, WorkflowCursorsTable, WorkflowCursor, WaitlistTable, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateWorkflowStep, UpdateWorkflowSchedule, UpdateWorkflowRun, UpdateWorkflowDefinition, UpdateTransaction, UpdateSubgraph, UpdateProject, UpdateIndexProgress, UpdateEvent, UpdateChatSession, UpdateBlock, UpdateApiKey, TransactionsTable, Transaction, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphProcessingStatsTable, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGap, Subgraph, SessionsTable, Session, ProjectsTable, Project, MagicLinksTable, MagicLink, InsertWorkflowStep, InsertWorkflowSchedule, InsertWorkflowRun, InsertWorkflowQueueItem, InsertWorkflowDefinition, InsertTransaction, InsertTeamMember, InsertTeamInvitation, InsertSubgraphUsageDaily, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProject, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertChatSession, InsertChatMessage, InsertBlock, InsertApiKey, InsertAccountInsight, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, EventsTable, Event, Database, ChatSessionsTable, ChatSession, ChatMessagesTable, ChatMessage, BlocksTable, Block, ApiKeysTable, ApiKey, AccountsTable, AccountInsightsTable, AccountInsight, AccountAgentRunsTable, AccountAgentRun, Account };
528
+ export { sql, parseJsonb, jsonb, getTargetDb, getSourceDb, getRawClient, getDb, closeDb, WorkflowStepsTable, WorkflowStep, WorkflowSignerSecretsTable, WorkflowSignerSecret, WorkflowSchedulesTable, WorkflowSchedule, WorkflowRunsTable, WorkflowRun, WorkflowQueueTable, WorkflowQueueItem, WorkflowDefinitionsTable, WorkflowDefinition, WorkflowCursorsTable, WorkflowCursor, WorkflowBudgetsTable, WorkflowBudget, WaitlistTable, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateWorkflowStep, UpdateWorkflowSignerSecret, UpdateWorkflowSchedule, UpdateWorkflowRun, UpdateWorkflowDefinition, UpdateWorkflowBudget, UpdateTransaction, UpdateTenant, UpdateSubgraph, UpdateProject, UpdateIndexProgress, UpdateEvent, UpdateChatSession, UpdateBlock, UpdateApiKey, TransactionsTable, Transaction, TenantsTable, TenantStatus, Tenant, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphProcessingStatsTable, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGap, Subgraph, SessionsTable, Session, ProjectsTable, Project, MagicLinksTable, MagicLink, InsertWorkflowStep, InsertWorkflowSignerSecret, InsertWorkflowSchedule, InsertWorkflowRun, InsertWorkflowQueueItem, InsertWorkflowDefinition, InsertWorkflowBudget, InsertTransaction, InsertTenant, InsertTeamMember, InsertTeamInvitation, InsertSubgraphUsageDaily, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProject, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertChatSession, InsertChatMessage, InsertBlock, InsertApiKey, InsertAccountInsight, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, EventsTable, Event, Database, ChatSessionsTable, ChatSession, ChatMessagesTable, ChatMessage, BlocksTable, Block, ApiKeysTable, ApiKey, AccountsTable, AccountInsightsTable, AccountInsight, AccountAgentRunsTable, AccountAgentRun, Account };
@@ -36,48 +36,72 @@ import { Kysely } from "kysely";
36
36
  import { PostgresJSDialect } from "kysely-postgres-js";
37
37
  import postgres from "postgres";
38
38
  import { sql as sql2 } from "kysely";
39
- var db = null;
40
- var rawClient = null;
39
+ var DEFAULT_URL = "postgres://postgres:postgres@localhost:5432/secondlayer_dev";
40
+ var pools = new Map;
41
+ function resolveSourceUrl() {
42
+ return process.env.SOURCE_DATABASE_URL || process.env.DATABASE_URL || DEFAULT_URL;
43
+ }
44
+ function resolveTargetUrl() {
45
+ return process.env.TARGET_DATABASE_URL || process.env.DATABASE_URL || DEFAULT_URL;
46
+ }
47
+ function getOrCreatePool(url) {
48
+ const existing = pools.get(url);
49
+ if (existing)
50
+ return existing;
51
+ const host = (() => {
52
+ try {
53
+ return new URL(url).hostname;
54
+ } catch {
55
+ return "";
56
+ }
57
+ })();
58
+ const isLocal = host === "localhost" || host === "127.0.0.1" || !host.includes(".");
59
+ const poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? "20", 10);
60
+ const rawClient = postgres(url, {
61
+ max: poolMax,
62
+ ssl: isLocal ? undefined : {
63
+ rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0"
64
+ }
65
+ });
66
+ const db = new Kysely({
67
+ dialect: new PostgresJSDialect({ postgres: rawClient })
68
+ });
69
+ const entry = { db, rawClient };
70
+ pools.set(url, entry);
71
+ return entry;
72
+ }
73
+ function getSourceDb() {
74
+ return getOrCreatePool(resolveSourceUrl()).db;
75
+ }
76
+ function getTargetDb() {
77
+ return getOrCreatePool(resolveTargetUrl()).db;
78
+ }
41
79
  function getDb(connectionString) {
42
- if (!db) {
43
- const url = connectionString || process.env.DATABASE_URL || "postgres://postgres:postgres@localhost:5432/secondlayer_dev";
44
- const isLocal = url.includes("localhost") || url.includes("127.0.0.1") || url.includes("@postgres:");
45
- const poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? "20", 10);
46
- rawClient = postgres(url, {
47
- max: poolMax,
48
- ssl: isLocal ? undefined : {
49
- rejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0"
50
- }
51
- });
52
- db = new Kysely({
53
- dialect: new PostgresJSDialect({ postgres: rawClient })
54
- });
55
- }
56
- return db;
80
+ if (connectionString)
81
+ return getOrCreatePool(connectionString).db;
82
+ return getTargetDb();
57
83
  }
58
- function getRawClient() {
59
- if (!rawClient)
60
- getDb();
61
- return rawClient;
84
+ function getRawClient(role = "target") {
85
+ const url = role === "source" ? resolveSourceUrl() : resolveTargetUrl();
86
+ return getOrCreatePool(url).rawClient;
62
87
  }
63
88
  async function closeDb() {
64
- if (db) {
65
- await db.destroy();
66
- db = null;
67
- }
68
- if (rawClient) {
69
- await rawClient.end();
70
- rawClient = null;
89
+ for (const entry of pools.values()) {
90
+ await entry.db.destroy();
91
+ await entry.rawClient.end();
71
92
  }
93
+ pools.clear();
72
94
  }
73
95
  export {
74
96
  sql2 as sql,
75
97
  parseJsonb,
76
98
  jsonb,
99
+ getTargetDb,
100
+ getSourceDb,
77
101
  getRawClient,
78
102
  getDb,
79
103
  closeDb
80
104
  };
81
105
 
82
- //# debugId=E1023FA2C43975A264756E2164756E21
106
+ //# debugId=C0DD7408E000897364756E2164756E21
83
107
  //# sourceMappingURL=index.js.map
@@ -2,10 +2,10 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/db/jsonb.ts", "../src/db/index.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) => (typeof v === \"bigint\" ? v.toString() : v)).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 { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nlet db: Kysely<Database> | null = null;\nlet rawClient: ReturnType<typeof postgres> | null = null;\n\nexport function getDb(connectionString?: string): Kysely<Database> {\n\tif (!db) {\n\t\tconst url =\n\t\t\tconnectionString ||\n\t\t\tprocess.env.DATABASE_URL ||\n\t\t\t\"postgres://postgres:postgres@localhost:5432/secondlayer_dev\";\n\n\t\t// Always use SSL for remote databases, just disable cert verification if needed\n\t\tconst isLocal =\n\t\t\turl.includes(\"localhost\") ||\n\t\t\turl.includes(\"127.0.0.1\") ||\n\t\t\turl.includes(\"@postgres:\");\n\t\tconst poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? \"20\", 10);\n\t\trawClient = postgres(url, {\n\t\t\tmax: poolMax,\n\t\t\tssl: isLocal\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\trejectUnauthorized:\n\t\t\t\t\t\t\tprocess.env.NODE_TLS_REJECT_UNAUTHORIZED !== \"0\",\n\t\t\t\t\t},\n\t\t});\n\t\tdb = new Kysely<Database>({\n\t\t\tdialect: new PostgresJSDialect({ postgres: rawClient }),\n\t\t});\n\t}\n\treturn db;\n}\n\n/** Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.) */\nexport function getRawClient(): ReturnType<typeof postgres> {\n\tif (!rawClient) getDb();\n\treturn rawClient!;\n}\n\n/** Close the DB connection pool. Call in CLI commands to allow process exit. */\nexport async function closeDb(): Promise<void> {\n\tif (db) {\n\t\tawait db.destroy();\n\t\tdb = null;\n\t}\n\tif (rawClient) {\n\t\tawait rawClient.end();\n\t\trawClient = null;\n\t}\n}\n\nimport { sql } from \"kysely\";\nexport { sql };\nexport * from \"./types.ts\";\nexport { jsonb, parseJsonb } from \"./jsonb.ts\";\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 */\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 { Kysely } from \"kysely\";\nimport { PostgresJSDialect } from \"kysely-postgres-js\";\nimport postgres from \"postgres\";\nimport type { Database } from \"./types.ts\";\n\nconst DEFAULT_URL =\n\t\"postgres://postgres:postgres@localhost:5432/secondlayer_dev\";\n\ninterface PoolEntry {\n\tdb: Kysely<Database>;\n\trawClient: ReturnType<typeof postgres>;\n}\n\n/**\n * Cache of Kysely + raw postgres.js pools keyed by resolved URL.\n * Two getters resolving to the same URL share one entry (single pool) —\n * this is the single-DB backward-compat contract: when only `DATABASE_URL`\n * is set, `getSourceDb() === getTargetDb()` (zero regression vs. pre-dual-DB).\n */\nconst pools = new Map<string, PoolEntry>();\n\nfunction resolveSourceUrl(): string {\n\treturn (\n\t\tprocess.env.SOURCE_DATABASE_URL || process.env.DATABASE_URL || DEFAULT_URL\n\t);\n}\n\nfunction resolveTargetUrl(): string {\n\treturn (\n\t\tprocess.env.TARGET_DATABASE_URL || process.env.DATABASE_URL || DEFAULT_URL\n\t);\n}\n\nfunction getOrCreatePool(url: string): PoolEntry {\n\tconst existing = pools.get(url);\n\tif (existing) return existing;\n\n\t// \"Local\" = we skip TLS. Any Docker service alias (single-label hostname\n\t// with no dots) is on an internal network and won't serve TLS.\n\tconst host = (() => {\n\t\ttry {\n\t\t\treturn new URL(url).hostname;\n\t\t} catch {\n\t\t\treturn \"\";\n\t\t}\n\t})();\n\tconst isLocal =\n\t\thost === \"localhost\" || host === \"127.0.0.1\" || !host.includes(\".\");\n\tconst poolMax = Number.parseInt(process.env.DATABASE_POOL_MAX ?? \"20\", 10);\n\tconst rawClient = postgres(url, {\n\t\tmax: poolMax,\n\t\tssl: isLocal\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\trejectUnauthorized: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== \"0\",\n\t\t\t\t},\n\t});\n\tconst db = new Kysely<Database>({\n\t\tdialect: new PostgresJSDialect({ postgres: rawClient }),\n\t});\n\tconst entry: PoolEntry = { db, rawClient };\n\tpools.set(url, entry);\n\treturn entry;\n}\n\n/**\n * Kysely instance for the SOURCE DB (block/tx/event reads from the shared\n * indexer). Resolution: `SOURCE_DATABASE_URL || DATABASE_URL`.\n */\nexport function getSourceDb(): Kysely<Database> {\n\treturn getOrCreatePool(resolveSourceUrl()).db;\n}\n\n/**\n * Kysely instance for the TARGET DB (subgraph schemas, subgraphs table,\n * account-scoped data — tenant-side writes). Resolution:\n * `TARGET_DATABASE_URL || DATABASE_URL`.\n */\nexport function getTargetDb(): Kysely<Database> {\n\treturn getOrCreatePool(resolveTargetUrl()).db;\n}\n\n/**\n * Backward-compat alias for `getTargetDb()`. Accepts an optional\n * `connectionString` override used by seed/test helpers — when supplied,\n * bypasses env resolution and uses the provided URL directly (still cached).\n */\nexport function getDb(connectionString?: string): Kysely<Database> {\n\tif (connectionString) return getOrCreatePool(connectionString).db;\n\treturn getTargetDb();\n}\n\n/**\n * Raw postgres.js client for dynamic schema DDL (CREATE SCHEMA, DROP, etc.).\n * Defaults to the target role (tenant schemas live in the target DB).\n */\nexport function getRawClient(\n\trole: \"source\" | \"target\" = \"target\",\n): ReturnType<typeof postgres> {\n\tconst url = role === \"source\" ? resolveSourceUrl() : resolveTargetUrl();\n\treturn getOrCreatePool(url).rawClient;\n}\n\n/** Close all DB connection pools. Call in CLI commands to allow process exit. */\nexport async function closeDb(): Promise<void> {\n\tfor (const entry of pools.values()) {\n\t\tawait entry.db.destroy();\n\t\tawait entry.rawClient.end();\n\t}\n\tpools.clear();\n}\n\nimport { sql } from \"kysely\";\nexport { sql };\nexport * from \"./types.ts\";\nexport { jsonb, parseJsonb } from \"./jsonb.ts\";\n"
7
7
  ],
8
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EAC1D,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,IAAI,MAAO,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CAAE,EAAE,QAAQ,MAAM,IAAI;AAAA,EAC/G,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;ACzBnB;AACA;AACA;AAqDA,gBAAS;AAlDT,IAAI,KAA8B;AAClC,IAAI,YAAgD;AAE7C,SAAS,KAAK,CAAC,kBAA6C;AAAA,EAClE,IAAI,CAAC,IAAI;AAAA,IACR,MAAM,MACL,oBACA,QAAQ,IAAI,gBACZ;AAAA,IAGD,MAAM,UACL,IAAI,SAAS,WAAW,KACxB,IAAI,SAAS,WAAW,KACxB,IAAI,SAAS,YAAY;AAAA,IAC1B,MAAM,UAAU,OAAO,SAAS,QAAQ,IAAI,qBAAqB,MAAM,EAAE;AAAA,IACzE,YAAY,SAAS,KAAK;AAAA,MACzB,KAAK;AAAA,MACL,KAAK,UACF,YACA;AAAA,QACA,oBACC,QAAQ,IAAI,iCAAiC;AAAA,MAC/C;AAAA,IACH,CAAC;AAAA,IACD,KAAK,IAAI,OAAiB;AAAA,MACzB,SAAS,IAAI,kBAAkB,EAAE,UAAU,UAAU,CAAC;AAAA,IACvD,CAAC;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAID,SAAS,YAAY,GAAgC;AAAA,EAC3D,IAAI,CAAC;AAAA,IAAW,MAAM;AAAA,EACtB,OAAO;AAAA;AAIR,eAAsB,OAAO,GAAkB;AAAA,EAC9C,IAAI,IAAI;AAAA,IACP,MAAM,GAAG,QAAQ;AAAA,IACjB,KAAK;AAAA,EACN;AAAA,EACA,IAAI,WAAW;AAAA,IACd,MAAM,UAAU,IAAI;AAAA,IACpB,YAAY;AAAA,EACb;AAAA;",
9
- "debugId": "E1023FA2C43975A264756E2164756E21",
8
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EAC1D,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,IAAI,MAC1C,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CACxC,EAAE,QAAQ,MAAM,IAAI;AAAA,EACpB,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;;;AC3BnB;AACA;AACA;AA8GA,gBAAS;AA3GT,IAAM,cACL;AAaD,IAAM,QAAQ,IAAI;AAElB,SAAS,gBAAgB,GAAW;AAAA,EACnC,OACC,QAAQ,IAAI,uBAAuB,QAAQ,IAAI,gBAAgB;AAAA;AAIjE,SAAS,gBAAgB,GAAW;AAAA,EACnC,OACC,QAAQ,IAAI,uBAAuB,QAAQ,IAAI,gBAAgB;AAAA;AAIjE,SAAS,eAAe,CAAC,KAAwB;AAAA,EAChD,MAAM,WAAW,MAAM,IAAI,GAAG;AAAA,EAC9B,IAAI;AAAA,IAAU,OAAO;AAAA,EAIrB,MAAM,QAAQ,MAAM;AAAA,IACnB,IAAI;AAAA,MACH,OAAO,IAAI,IAAI,GAAG,EAAE;AAAA,MACnB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,KAEN;AAAA,EACH,MAAM,UACL,SAAS,eAAe,SAAS,eAAe,CAAC,KAAK,SAAS,GAAG;AAAA,EACnE,MAAM,UAAU,OAAO,SAAS,QAAQ,IAAI,qBAAqB,MAAM,EAAE;AAAA,EACzE,MAAM,YAAY,SAAS,KAAK;AAAA,IAC/B,KAAK;AAAA,IACL,KAAK,UACF,YACA;AAAA,MACA,oBAAoB,QAAQ,IAAI,iCAAiC;AAAA,IAClE;AAAA,EACH,CAAC;AAAA,EACD,MAAM,KAAK,IAAI,OAAiB;AAAA,IAC/B,SAAS,IAAI,kBAAkB,EAAE,UAAU,UAAU,CAAC;AAAA,EACvD,CAAC;AAAA,EACD,MAAM,QAAmB,EAAE,IAAI,UAAU;AAAA,EACzC,MAAM,IAAI,KAAK,KAAK;AAAA,EACpB,OAAO;AAAA;AAOD,SAAS,WAAW,GAAqB;AAAA,EAC/C,OAAO,gBAAgB,iBAAiB,CAAC,EAAE;AAAA;AAQrC,SAAS,WAAW,GAAqB;AAAA,EAC/C,OAAO,gBAAgB,iBAAiB,CAAC,EAAE;AAAA;AAQrC,SAAS,KAAK,CAAC,kBAA6C;AAAA,EAClE,IAAI;AAAA,IAAkB,OAAO,gBAAgB,gBAAgB,EAAE;AAAA,EAC/D,OAAO,YAAY;AAAA;AAOb,SAAS,YAAY,CAC3B,OAA4B,UACE;AAAA,EAC9B,MAAM,MAAM,SAAS,WAAW,iBAAiB,IAAI,iBAAiB;AAAA,EACtE,OAAO,gBAAgB,GAAG,EAAE;AAAA;AAI7B,eAAsB,OAAO,GAAkB;AAAA,EAC9C,WAAW,SAAS,MAAM,OAAO,GAAG;AAAA,IACnC,MAAM,MAAM,GAAG,QAAQ;AAAA,IACvB,MAAM,MAAM,UAAU,IAAI;AAAA,EAC3B;AAAA,EACA,MAAM,MAAM;AAAA;",
9
+ "debugId": "C0DD7408E000897364756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../src/db/jsonb.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) => (typeof v === \"bigint\" ? v.toString() : v)).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"
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
6
  ],
7
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EAC1D,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,IAAI,MAAO,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CAAE,EAAE,QAAQ,MAAM,IAAI;AAAA,EAC/G,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;",
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAOO,SAAS,KAAK,CAAC,OAAqC;AAAA,EAC1D,MAAM,UAAU,KAAK,UAAU,OAAO,CAAC,IAAI,MAC1C,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CACxC,EAAE,QAAQ,MAAM,IAAI;AAAA,EACpB,OAAO,MAAM,IAAI,IAAI,IAAI,iBAAiB;AAAA;AAQpC,SAAS,UAAuB,CAAC,OAAmB;AAAA,EAC1D,IAAI,OAAO,UAAU,UAAU;AAAA,IAC9B,IAAI;AAAA,MACH,OAAO,KAAK,MAAM,KAAK;AAAA,MACtB,MAAM;AAAA,MACP,OAAO;AAAA;AAAA,EAET;AAAA,EACA,OAAQ,SAAS,CAAC;AAAA;",
8
8
  "debugId": "DA6ABA81E2ABDC7864756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,6 +1,6 @@
1
1
  import { Kysely } from "kysely";
2
2
  import { Selectable as Selectable2 } from "kysely";
3
- import { Generated, Selectable } from "kysely";
3
+ import { ColumnType, Generated, Selectable } from "kysely";
4
4
  interface BlocksTable {
5
5
  height: number;
6
6
  hash: string;
@@ -57,7 +57,6 @@ interface SubgraphsTable {
57
57
  last_error_at: Date | null;
58
58
  total_processed: Generated<number>;
59
59
  total_errors: Generated<number>;
60
- api_key_id: string | null;
61
60
  account_id: string;
62
61
  handler_code: string | null;
63
62
  source_code: string | null;
@@ -296,6 +295,8 @@ interface WorkflowStepsTable {
296
295
  started_at: Date | null;
297
296
  completed_at: Date | null;
298
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
299
300
  created_at: Generated<Date>;
300
301
  }
301
302
  interface WorkflowQueueTable {
@@ -357,6 +358,62 @@ interface Database {
357
358
  workflow_queue: WorkflowQueueTable;
358
359
  workflow_schedules: WorkflowSchedulesTable;
359
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ tenants: TenantsTable;
364
+ }
365
+ type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
366
+ interface TenantsTable {
367
+ id: Generated<string>;
368
+ account_id: string;
369
+ slug: string;
370
+ status: ColumnType<TenantStatus, TenantStatus | undefined, TenantStatus>;
371
+ plan: string;
372
+ cpus: ColumnType<number, number | string, number | string>;
373
+ memory_mb: number;
374
+ storage_limit_mb: number;
375
+ storage_used_mb: number | null;
376
+ pg_container_id: string | null;
377
+ api_container_id: string | null;
378
+ processor_container_id: string | null;
379
+ target_database_url_enc: Buffer;
380
+ tenant_jwt_secret_enc: Buffer;
381
+ anon_key_enc: Buffer;
382
+ service_key_enc: Buffer;
383
+ api_url_internal: string;
384
+ api_url_public: string;
385
+ trial_ends_at: Date;
386
+ suspended_at: Date | null;
387
+ last_health_check_at: Date | null;
388
+ service_gen: Generated<number>;
389
+ anon_gen: Generated<number>;
390
+ project_id: string | null;
391
+ created_at: Generated<Date>;
392
+ updated_at: Generated<Date>;
393
+ }
394
+ interface WorkflowBudgetsTable {
395
+ 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;
406
+ created_at: Generated<Date>;
407
+ updated_at: Generated<Date>;
408
+ }
409
+ interface WorkflowSignerSecretsTable {
410
+ 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;
415
+ created_at: Generated<Date>;
416
+ updated_at: Generated<Date>;
360
417
  }
361
418
  type Account = Selectable<AccountsTable>;
362
419
  declare function upsertAccount(db: Kysely<Database>, email: string): Promise<Account>;
@@ -1,5 +1,5 @@
1
1
  import { Kysely } from "kysely";
2
- import { Generated } from "kysely";
2
+ import { ColumnType, Generated } from "kysely";
3
3
  interface BlocksTable {
4
4
  height: number;
5
5
  hash: string;
@@ -56,7 +56,6 @@ interface SubgraphsTable {
56
56
  last_error_at: Date | null;
57
57
  total_processed: Generated<number>;
58
58
  total_errors: Generated<number>;
59
- api_key_id: string | null;
60
59
  account_id: string;
61
60
  handler_code: string | null;
62
61
  source_code: string | null;
@@ -295,6 +294,8 @@ interface WorkflowStepsTable {
295
294
  started_at: Date | null;
296
295
  completed_at: Date | null;
297
296
  duration_ms: number | null;
297
+ memo_key: string | null;
298
+ parent_step_id: string | null;
298
299
  created_at: Generated<Date>;
299
300
  }
300
301
  interface WorkflowQueueTable {
@@ -356,6 +357,62 @@ interface Database {
356
357
  workflow_queue: WorkflowQueueTable;
357
358
  workflow_schedules: WorkflowSchedulesTable;
358
359
  workflow_cursors: WorkflowCursorsTable;
360
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
361
+ workflow_budgets: WorkflowBudgetsTable;
362
+ tenants: TenantsTable;
363
+ }
364
+ type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
365
+ interface TenantsTable {
366
+ id: Generated<string>;
367
+ account_id: string;
368
+ slug: string;
369
+ status: ColumnType<TenantStatus, TenantStatus | undefined, TenantStatus>;
370
+ plan: string;
371
+ cpus: ColumnType<number, number | string, number | string>;
372
+ memory_mb: number;
373
+ storage_limit_mb: number;
374
+ storage_used_mb: number | null;
375
+ pg_container_id: string | null;
376
+ api_container_id: string | null;
377
+ processor_container_id: string | null;
378
+ target_database_url_enc: Buffer;
379
+ tenant_jwt_secret_enc: Buffer;
380
+ anon_key_enc: Buffer;
381
+ service_key_enc: Buffer;
382
+ api_url_internal: string;
383
+ api_url_public: string;
384
+ trial_ends_at: Date;
385
+ suspended_at: Date | null;
386
+ last_health_check_at: Date | null;
387
+ service_gen: Generated<number>;
388
+ anon_gen: Generated<number>;
389
+ project_id: string | null;
390
+ created_at: Generated<Date>;
391
+ updated_at: Generated<Date>;
392
+ }
393
+ interface WorkflowBudgetsTable {
394
+ 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;
405
+ created_at: Generated<Date>;
406
+ updated_at: Generated<Date>;
407
+ }
408
+ interface WorkflowSignerSecretsTable {
409
+ 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;
414
+ created_at: Generated<Date>;
415
+ updated_at: Generated<Date>;
359
416
  }
360
417
  interface Gap {
361
418
  gapStart: number;
@@ -1,5 +1,5 @@
1
1
  import { Kysely } from "kysely";
2
- import { Generated, Selectable } from "kysely";
2
+ import { ColumnType, Generated, Selectable } from "kysely";
3
3
  interface BlocksTable {
4
4
  height: number;
5
5
  hash: string;
@@ -56,7 +56,6 @@ interface SubgraphsTable {
56
56
  last_error_at: Date | null;
57
57
  total_processed: Generated<number>;
58
58
  total_errors: Generated<number>;
59
- api_key_id: string | null;
60
59
  account_id: string;
61
60
  handler_code: string | null;
62
61
  source_code: string | null;
@@ -295,6 +294,8 @@ interface WorkflowStepsTable {
295
294
  started_at: Date | null;
296
295
  completed_at: Date | null;
297
296
  duration_ms: number | null;
297
+ memo_key: string | null;
298
+ parent_step_id: string | null;
298
299
  created_at: Generated<Date>;
299
300
  }
300
301
  interface WorkflowQueueTable {
@@ -356,6 +357,62 @@ interface Database {
356
357
  workflow_queue: WorkflowQueueTable;
357
358
  workflow_schedules: WorkflowSchedulesTable;
358
359
  workflow_cursors: WorkflowCursorsTable;
360
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
361
+ workflow_budgets: WorkflowBudgetsTable;
362
+ tenants: TenantsTable;
363
+ }
364
+ type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
365
+ interface TenantsTable {
366
+ id: Generated<string>;
367
+ account_id: string;
368
+ slug: string;
369
+ status: ColumnType<TenantStatus, TenantStatus | undefined, TenantStatus>;
370
+ plan: string;
371
+ cpus: ColumnType<number, number | string, number | string>;
372
+ memory_mb: number;
373
+ storage_limit_mb: number;
374
+ storage_used_mb: number | null;
375
+ pg_container_id: string | null;
376
+ api_container_id: string | null;
377
+ processor_container_id: string | null;
378
+ target_database_url_enc: Buffer;
379
+ tenant_jwt_secret_enc: Buffer;
380
+ anon_key_enc: Buffer;
381
+ service_key_enc: Buffer;
382
+ api_url_internal: string;
383
+ api_url_public: string;
384
+ trial_ends_at: Date;
385
+ suspended_at: Date | null;
386
+ last_health_check_at: Date | null;
387
+ service_gen: Generated<number>;
388
+ anon_gen: Generated<number>;
389
+ project_id: string | null;
390
+ created_at: Generated<Date>;
391
+ updated_at: Generated<Date>;
392
+ }
393
+ interface WorkflowBudgetsTable {
394
+ 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;
405
+ created_at: Generated<Date>;
406
+ updated_at: Generated<Date>;
407
+ }
408
+ interface WorkflowSignerSecretsTable {
409
+ 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;
414
+ created_at: Generated<Date>;
415
+ updated_at: Generated<Date>;
359
416
  }
360
417
  type Subgraph = Selectable<SubgraphsTable>;
361
418
  /**