@secondlayer/shared 1.0.0 → 1.1.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.
@@ -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
+ }
@@ -309,6 +309,8 @@ interface WorkflowStepsTable {
309
309
  started_at: Date | null;
310
310
  completed_at: Date | null;
311
311
  duration_ms: number | null;
312
+ memo_key: string | null;
313
+ parent_step_id: string | null;
312
314
  created_at: Generated<Date>;
313
315
  }
314
316
  interface WorkflowQueueTable {
@@ -370,6 +372,32 @@ interface Database {
370
372
  workflow_queue: WorkflowQueueTable;
371
373
  workflow_schedules: WorkflowSchedulesTable;
372
374
  workflow_cursors: WorkflowCursorsTable;
375
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
376
+ workflow_budgets: WorkflowBudgetsTable;
377
+ }
378
+ interface WorkflowBudgetsTable {
379
+ id: Generated<string>;
380
+ workflow_definition_id: string;
381
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
382
+ period: string;
383
+ ai_usd_used: Generated<string>;
384
+ ai_tokens_used: Generated<string>;
385
+ chain_microstx_used: Generated<string>;
386
+ chain_tx_count: Generated<number>;
387
+ run_count: Generated<number>;
388
+ step_count: Generated<number>;
389
+ reset_at: Date;
390
+ created_at: Generated<Date>;
391
+ updated_at: Generated<Date>;
392
+ }
393
+ interface WorkflowSignerSecretsTable {
394
+ id: Generated<string>;
395
+ account_id: string;
396
+ name: string;
397
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
398
+ encrypted_value: Buffer;
399
+ created_at: Generated<Date>;
400
+ updated_at: Generated<Date>;
373
401
  }
374
402
  type Block = Selectable<BlocksTable>;
375
403
  type InsertBlock = Insertable<BlocksTable>;
@@ -422,6 +450,12 @@ type WorkflowSchedule = Selectable<WorkflowSchedulesTable>;
422
450
  type InsertWorkflowSchedule = Insertable<WorkflowSchedulesTable>;
423
451
  type UpdateWorkflowSchedule = Updateable<WorkflowSchedulesTable>;
424
452
  type WorkflowCursor = Selectable<WorkflowCursorsTable>;
453
+ type WorkflowSignerSecret = Selectable<WorkflowSignerSecretsTable>;
454
+ type InsertWorkflowSignerSecret = Insertable<WorkflowSignerSecretsTable>;
455
+ type UpdateWorkflowSignerSecret = Updateable<WorkflowSignerSecretsTable>;
456
+ type WorkflowBudget = Selectable<WorkflowBudgetsTable>;
457
+ type InsertWorkflowBudget = Insertable<WorkflowBudgetsTable>;
458
+ type UpdateWorkflowBudget = Updateable<WorkflowBudgetsTable>;
425
459
  type Project = Selectable<ProjectsTable>;
426
460
  type InsertProject = Insertable<ProjectsTable>;
427
461
  type UpdateProject = Updateable<ProjectsTable>;
@@ -440,4 +474,4 @@ declare function getDb(connectionString?: string): Kysely<Database>;
440
474
  declare function getRawClient(): ReturnType<typeof postgres>;
441
475
  /** Close the DB connection pool. Call in CLI commands to allow process exit. */
442
476
  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 };
477
+ export { sql, parseJsonb, jsonb, 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, 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, InsertWorkflowSignerSecret, InsertWorkflowSchedule, InsertWorkflowRun, InsertWorkflowQueueItem, InsertWorkflowDefinition, InsertWorkflowBudget, 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 };
@@ -296,6 +296,8 @@ interface WorkflowStepsTable {
296
296
  started_at: Date | null;
297
297
  completed_at: Date | null;
298
298
  duration_ms: number | null;
299
+ memo_key: string | null;
300
+ parent_step_id: string | null;
299
301
  created_at: Generated<Date>;
300
302
  }
301
303
  interface WorkflowQueueTable {
@@ -357,6 +359,32 @@ interface Database {
357
359
  workflow_queue: WorkflowQueueTable;
358
360
  workflow_schedules: WorkflowSchedulesTable;
359
361
  workflow_cursors: WorkflowCursorsTable;
362
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
363
+ workflow_budgets: WorkflowBudgetsTable;
364
+ }
365
+ interface WorkflowBudgetsTable {
366
+ id: Generated<string>;
367
+ workflow_definition_id: string;
368
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
369
+ period: string;
370
+ ai_usd_used: Generated<string>;
371
+ ai_tokens_used: Generated<string>;
372
+ chain_microstx_used: Generated<string>;
373
+ chain_tx_count: Generated<number>;
374
+ run_count: Generated<number>;
375
+ step_count: Generated<number>;
376
+ reset_at: Date;
377
+ created_at: Generated<Date>;
378
+ updated_at: Generated<Date>;
379
+ }
380
+ interface WorkflowSignerSecretsTable {
381
+ id: Generated<string>;
382
+ account_id: string;
383
+ name: string;
384
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
385
+ encrypted_value: Buffer;
386
+ created_at: Generated<Date>;
387
+ updated_at: Generated<Date>;
360
388
  }
361
389
  type Account = Selectable<AccountsTable>;
362
390
  declare function upsertAccount(db: Kysely<Database>, email: string): Promise<Account>;
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  interface Gap {
361
389
  gapStart: number;
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  type Subgraph = Selectable<SubgraphsTable>;
361
389
  /**
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  type Project = Selectable<ProjectsTable>;
361
389
  type TeamInvitation = Selectable<TeamInvitationsTable>;
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  interface GapRange {
361
389
  start: number;
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  type Subgraph = Selectable<SubgraphsTable>;
361
389
  /**
@@ -302,6 +302,8 @@ interface WorkflowStepsTable {
302
302
  started_at: Date | null;
303
303
  completed_at: Date | null;
304
304
  duration_ms: number | null;
305
+ memo_key: string | null;
306
+ parent_step_id: string | null;
305
307
  created_at: Generated<Date>;
306
308
  }
307
309
  interface WorkflowQueueTable {
@@ -363,6 +365,32 @@ interface Database {
363
365
  workflow_queue: WorkflowQueueTable;
364
366
  workflow_schedules: WorkflowSchedulesTable;
365
367
  workflow_cursors: WorkflowCursorsTable;
368
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
369
+ workflow_budgets: WorkflowBudgetsTable;
370
+ }
371
+ interface WorkflowBudgetsTable {
372
+ id: Generated<string>;
373
+ workflow_definition_id: string;
374
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
375
+ period: string;
376
+ ai_usd_used: Generated<string>;
377
+ ai_tokens_used: Generated<string>;
378
+ chain_microstx_used: Generated<string>;
379
+ chain_tx_count: Generated<number>;
380
+ run_count: Generated<number>;
381
+ step_count: Generated<number>;
382
+ reset_at: Date;
383
+ created_at: Generated<Date>;
384
+ updated_at: Generated<Date>;
385
+ }
386
+ interface WorkflowSignerSecretsTable {
387
+ id: Generated<string>;
388
+ account_id: string;
389
+ name: string;
390
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
391
+ encrypted_value: Buffer;
392
+ created_at: Generated<Date>;
393
+ updated_at: Generated<Date>;
366
394
  }
367
395
  /** Increment API request counter for today. Fire-and-forget safe. */
368
396
  declare function incrementApiRequests(db: Kysely<Database>, accountId: string): Promise<void>;
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  type WorkflowDefinition = Selectable<WorkflowDefinitionsTable>;
361
389
  type WorkflowRun = Selectable<WorkflowRunsTable>;
@@ -294,6 +294,8 @@ interface WorkflowStepsTable {
294
294
  started_at: Date | null;
295
295
  completed_at: Date | null;
296
296
  duration_ms: number | null;
297
+ memo_key: string | null;
298
+ parent_step_id: string | null;
297
299
  created_at: Generated<Date>;
298
300
  }
299
301
  interface WorkflowQueueTable {
@@ -355,6 +357,32 @@ interface Database {
355
357
  workflow_queue: WorkflowQueueTable;
356
358
  workflow_schedules: WorkflowSchedulesTable;
357
359
  workflow_cursors: WorkflowCursorsTable;
360
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
361
+ workflow_budgets: WorkflowBudgetsTable;
362
+ }
363
+ interface WorkflowBudgetsTable {
364
+ id: Generated<string>;
365
+ workflow_definition_id: string;
366
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
367
+ period: string;
368
+ ai_usd_used: Generated<string>;
369
+ ai_tokens_used: Generated<string>;
370
+ chain_microstx_used: Generated<string>;
371
+ chain_tx_count: Generated<number>;
372
+ run_count: Generated<number>;
373
+ step_count: Generated<number>;
374
+ reset_at: Date;
375
+ created_at: Generated<Date>;
376
+ updated_at: Generated<Date>;
377
+ }
378
+ interface WorkflowSignerSecretsTable {
379
+ id: Generated<string>;
380
+ account_id: string;
381
+ name: string;
382
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
383
+ encrypted_value: Buffer;
384
+ created_at: Generated<Date>;
385
+ updated_at: Generated<Date>;
358
386
  }
359
387
  type Block = Selectable<BlocksTable>;
360
388
  type InsertBlock = Insertable<BlocksTable>;
@@ -407,6 +435,12 @@ type WorkflowSchedule = Selectable<WorkflowSchedulesTable>;
407
435
  type InsertWorkflowSchedule = Insertable<WorkflowSchedulesTable>;
408
436
  type UpdateWorkflowSchedule = Updateable<WorkflowSchedulesTable>;
409
437
  type WorkflowCursor = Selectable<WorkflowCursorsTable>;
438
+ type WorkflowSignerSecret = Selectable<WorkflowSignerSecretsTable>;
439
+ type InsertWorkflowSignerSecret = Insertable<WorkflowSignerSecretsTable>;
440
+ type UpdateWorkflowSignerSecret = Updateable<WorkflowSignerSecretsTable>;
441
+ type WorkflowBudget = Selectable<WorkflowBudgetsTable>;
442
+ type InsertWorkflowBudget = Insertable<WorkflowBudgetsTable>;
443
+ type UpdateWorkflowBudget = Updateable<WorkflowBudgetsTable>;
410
444
  type Project = Selectable<ProjectsTable>;
411
445
  type InsertProject = Insertable<ProjectsTable>;
412
446
  type UpdateProject = Updateable<ProjectsTable>;
@@ -419,4 +453,4 @@ type InsertChatSession = Insertable<ChatSessionsTable>;
419
453
  type UpdateChatSession = Updateable<ChatSessionsTable>;
420
454
  type ChatMessage = Selectable<ChatMessagesTable>;
421
455
  type InsertChatMessage = Insertable<ChatMessagesTable>;
422
- export { 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 };
456
+ export { 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, 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, InsertWorkflowSignerSecret, InsertWorkflowSchedule, InsertWorkflowRun, InsertWorkflowQueueItem, InsertWorkflowDefinition, InsertWorkflowBudget, 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 };
@@ -294,6 +294,8 @@ interface WorkflowStepsTable {
294
294
  started_at: Date | null;
295
295
  completed_at: Date | null;
296
296
  duration_ms: number | null;
297
+ memo_key: string | null;
298
+ parent_step_id: string | null;
297
299
  created_at: Generated<Date>;
298
300
  }
299
301
  interface WorkflowQueueTable {
@@ -355,6 +357,32 @@ interface Database {
355
357
  workflow_queue: WorkflowQueueTable;
356
358
  workflow_schedules: WorkflowSchedulesTable;
357
359
  workflow_cursors: WorkflowCursorsTable;
360
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
361
+ workflow_budgets: WorkflowBudgetsTable;
362
+ }
363
+ interface WorkflowBudgetsTable {
364
+ id: Generated<string>;
365
+ workflow_definition_id: string;
366
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
367
+ period: string;
368
+ ai_usd_used: Generated<string>;
369
+ ai_tokens_used: Generated<string>;
370
+ chain_microstx_used: Generated<string>;
371
+ chain_tx_count: Generated<number>;
372
+ run_count: Generated<number>;
373
+ step_count: Generated<number>;
374
+ reset_at: Date;
375
+ created_at: Generated<Date>;
376
+ updated_at: Generated<Date>;
377
+ }
378
+ interface WorkflowSignerSecretsTable {
379
+ id: Generated<string>;
380
+ account_id: string;
381
+ name: string;
382
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
383
+ encrypted_value: Buffer;
384
+ created_at: Generated<Date>;
385
+ updated_at: Generated<Date>;
358
386
  }
359
387
  type Block = Selectable<BlocksTable>;
360
388
  type InsertBlock = Insertable<BlocksTable>;
@@ -407,6 +435,12 @@ type WorkflowSchedule = Selectable<WorkflowSchedulesTable>;
407
435
  type InsertWorkflowSchedule = Insertable<WorkflowSchedulesTable>;
408
436
  type UpdateWorkflowSchedule = Updateable<WorkflowSchedulesTable>;
409
437
  type WorkflowCursor = Selectable<WorkflowCursorsTable>;
438
+ type WorkflowSignerSecret = Selectable<WorkflowSignerSecretsTable>;
439
+ type InsertWorkflowSignerSecret = Insertable<WorkflowSignerSecretsTable>;
440
+ type UpdateWorkflowSignerSecret = Updateable<WorkflowSignerSecretsTable>;
441
+ type WorkflowBudget = Selectable<WorkflowBudgetsTable>;
442
+ type InsertWorkflowBudget = Insertable<WorkflowBudgetsTable>;
443
+ type UpdateWorkflowBudget = Updateable<WorkflowBudgetsTable>;
410
444
  type Project = Selectable<ProjectsTable>;
411
445
  type InsertProject = Insertable<ProjectsTable>;
412
446
  type UpdateProject = Updateable<ProjectsTable>;
@@ -819,4 +853,4 @@ declare function createSignatureHeader(payload: string, secret: string, timestam
819
853
  * Returns true if valid, false otherwise
820
854
  */
821
855
  declare function verifySignatureHeader(payload: string, header: string, secret: string, toleranceSeconds?: number): boolean;
822
- export { sql, parseJsonb, logger, jsonb, getRawClient, getErrorMessage, getEnv, getDb, exports_hmac as crypto, closeDb, WorkflowStepsTable, WorkflowStep, WorkflowSchedulesTable, WorkflowSchedule, WorkflowRunsTable, WorkflowRun, WorkflowQueueTable, WorkflowQueueItem, WorkflowDefinitionsTable, WorkflowDefinition, WorkflowCursorsTable, WorkflowCursor, WaitlistTable, VersionConflictError, ValidationError, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateWorkflowStep, UpdateWorkflowSchedule, UpdateWorkflowRun, UpdateWorkflowDefinition, UpdateTransaction, UpdateSubgraph, UpdateProject, UpdateProfileRequestSchema, UpdateProfileRequest, UpdateIndexProgress, UpdateEvent, UpdateChatSession, UpdateBlock, UpdateApiKey, TransactionsTable, Transaction, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphSyncInfo, SubgraphSummary, SubgraphQueryParams, SubgraphProcessingStatsTable, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGapsResponse, SubgraphGapRange, SubgraphGapEntry, SubgraphGap, SubgraphDetail, Subgraph, StxTransferFilterSchema, StxTransferFilter, StxMintFilterSchema, StxMintFilter, StxLockFilterSchema, StxLockFilter, StxBurnFilterSchema, StxBurnFilter, SessionsTable, Session, SecondLayerError, ReindexResponse, RateLimitError, PublishSubgraphRequestSchema, PublishSubgraphRequest, ProjectsTable, Project, PrintEventFilterSchema, PrintEventFilter, NotFoundError, NftTransferFilterSchema, NftTransferFilter, NftMintFilterSchema, NftMintFilter, NftBurnFilterSchema, NftBurnFilter, MarketplaceSubgraphSummary, MarketplaceSubgraphDetail, MarketplaceCreator, 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, FtTransferFilterSchema, FtTransferFilter, FtMintFilterSchema, FtMintFilter, FtBurnFilterSchema, FtBurnFilter, ForkSubgraphRequestSchema, ForkSubgraphRequest, ForbiddenError, EventsTable, EventFilterSchema, EventFilter, Event, ErrorCodes, ErrorCode, Env, DeploySubgraphResponse, DeploySubgraphRequestSchema, DeploySubgraphRequest, DatabaseError, Database, CreatorProfile, ContractDeployFilterSchema, ContractDeployFilter, ContractCallFilterSchema, ContractCallFilter, ChatSessionsTable, ChatSession, ChatMessagesTable, ChatMessage, CODE_TO_STATUS, BlocksTable, Block, AuthorizationError, AuthenticationError, ApiKeysTable, ApiKey, AccountsTable, AccountInsightsTable, AccountInsight, AccountAgentRunsTable, AccountAgentRun, Account };
856
+ export { sql, parseJsonb, logger, jsonb, getRawClient, getErrorMessage, getEnv, getDb, exports_hmac as crypto, closeDb, WorkflowStepsTable, WorkflowStep, WorkflowSignerSecretsTable, WorkflowSignerSecret, WorkflowSchedulesTable, WorkflowSchedule, WorkflowRunsTable, WorkflowRun, WorkflowQueueTable, WorkflowQueueItem, WorkflowDefinitionsTable, WorkflowDefinition, WorkflowCursorsTable, WorkflowCursor, WorkflowBudgetsTable, WorkflowBudget, WaitlistTable, VersionConflictError, ValidationError, UsageSnapshotsTable, UsageSnapshot, UsageDailyTable, UsageDaily, UpdateWorkflowStep, UpdateWorkflowSignerSecret, UpdateWorkflowSchedule, UpdateWorkflowRun, UpdateWorkflowDefinition, UpdateWorkflowBudget, UpdateTransaction, UpdateSubgraph, UpdateProject, UpdateProfileRequestSchema, UpdateProfileRequest, UpdateIndexProgress, UpdateEvent, UpdateChatSession, UpdateBlock, UpdateApiKey, TransactionsTable, Transaction, TeamMembersTable, TeamMember, TeamInvitationsTable, TeamInvitation, SubgraphsTable, SubgraphUsageDailyTable, SubgraphUsageDaily, SubgraphTableSnapshotsTable, SubgraphSyncInfo, SubgraphSummary, SubgraphQueryParams, SubgraphProcessingStatsTable, SubgraphHealthSnapshotsTable, SubgraphHealthSnapshot, SubgraphGapsTable, SubgraphGapsResponse, SubgraphGapRange, SubgraphGapEntry, SubgraphGap, SubgraphDetail, Subgraph, StxTransferFilterSchema, StxTransferFilter, StxMintFilterSchema, StxMintFilter, StxLockFilterSchema, StxLockFilter, StxBurnFilterSchema, StxBurnFilter, SessionsTable, Session, SecondLayerError, ReindexResponse, RateLimitError, PublishSubgraphRequestSchema, PublishSubgraphRequest, ProjectsTable, Project, PrintEventFilterSchema, PrintEventFilter, NotFoundError, NftTransferFilterSchema, NftTransferFilter, NftMintFilterSchema, NftMintFilter, NftBurnFilterSchema, NftBurnFilter, MarketplaceSubgraphSummary, MarketplaceSubgraphDetail, MarketplaceCreator, MagicLinksTable, MagicLink, InsertWorkflowStep, InsertWorkflowSignerSecret, InsertWorkflowSchedule, InsertWorkflowRun, InsertWorkflowQueueItem, InsertWorkflowDefinition, InsertWorkflowBudget, InsertTransaction, InsertTeamMember, InsertTeamInvitation, InsertSubgraphUsageDaily, InsertSubgraphHealthSnapshot, InsertSubgraphGap, InsertSubgraph, InsertSession, InsertProject, InsertMagicLink, InsertIndexProgress, InsertEvent, InsertChatSession, InsertChatMessage, InsertBlock, InsertApiKey, InsertAccountInsight, InsertAccountAgentRun, InsertAccount, IndexProgressTable, IndexProgress, FtTransferFilterSchema, FtTransferFilter, FtMintFilterSchema, FtMintFilter, FtBurnFilterSchema, FtBurnFilter, ForkSubgraphRequestSchema, ForkSubgraphRequest, ForbiddenError, EventsTable, EventFilterSchema, EventFilter, Event, ErrorCodes, ErrorCode, Env, DeploySubgraphResponse, DeploySubgraphRequestSchema, DeploySubgraphRequest, DatabaseError, Database, CreatorProfile, ContractDeployFilterSchema, ContractDeployFilter, ContractCallFilterSchema, ContractCallFilter, ChatSessionsTable, ChatSession, ChatMessagesTable, ChatMessage, CODE_TO_STATUS, BlocksTable, Block, AuthorizationError, AuthenticationError, ApiKeysTable, ApiKey, AccountsTable, AccountInsightsTable, AccountInsight, AccountAgentRunsTable, AccountAgentRun, Account };
@@ -295,6 +295,8 @@ interface WorkflowStepsTable {
295
295
  started_at: Date | null;
296
296
  completed_at: Date | null;
297
297
  duration_ms: number | null;
298
+ memo_key: string | null;
299
+ parent_step_id: string | null;
298
300
  created_at: Generated<Date>;
299
301
  }
300
302
  interface WorkflowQueueTable {
@@ -356,6 +358,32 @@ interface Database {
356
358
  workflow_queue: WorkflowQueueTable;
357
359
  workflow_schedules: WorkflowSchedulesTable;
358
360
  workflow_cursors: WorkflowCursorsTable;
361
+ workflow_signer_secrets: WorkflowSignerSecretsTable;
362
+ workflow_budgets: WorkflowBudgetsTable;
363
+ }
364
+ interface WorkflowBudgetsTable {
365
+ id: Generated<string>;
366
+ workflow_definition_id: string;
367
+ /** Period key: "daily:YYYY-MM-DD" | "weekly:YYYY-Www" | "per-run:<uuid>". */
368
+ period: string;
369
+ ai_usd_used: Generated<string>;
370
+ ai_tokens_used: Generated<string>;
371
+ chain_microstx_used: Generated<string>;
372
+ chain_tx_count: Generated<number>;
373
+ run_count: Generated<number>;
374
+ step_count: Generated<number>;
375
+ reset_at: Date;
376
+ created_at: Generated<Date>;
377
+ updated_at: Generated<Date>;
378
+ }
379
+ interface WorkflowSignerSecretsTable {
380
+ id: Generated<string>;
381
+ account_id: string;
382
+ name: string;
383
+ /** AES-GCM ciphertext bytes produced by the runner's KMS on write. */
384
+ encrypted_value: Buffer;
385
+ created_at: Generated<Date>;
386
+ updated_at: Generated<Date>;
359
387
  }
360
388
  /** Matches the NewBlockPayload shape expected by the indexer's /new_block endpoint */
361
389
  interface ReplayBlockPayload {
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Token → USD pricing constants for internal observability.
3
+ *
4
+ * **Not customer billing.** Tier pricing covers compute; these constants
5
+ * let the dashboard display "~$X spent in AI today" and let us track
6
+ * gross-margin internally. Update manually when providers change prices
7
+ * (roughly twice per year).
8
+ *
9
+ * Source: public provider pricing pages as of 2026-04-17.
10
+ */
11
+ interface ModelPricing {
12
+ /** USD per 1M input tokens */
13
+ inputPerMTokens: number;
14
+ /** USD per 1M output tokens */
15
+ outputPerMTokens: number;
16
+ }
17
+ declare const MODEL_PRICING: Record<string, Record<string, ModelPricing>>;
18
+ interface TokenUsage {
19
+ inputTokens: number;
20
+ outputTokens: number;
21
+ }
22
+ /**
23
+ * Compute approximate USD cost for an AI step. Returns `null` if the
24
+ * (provider, model) pair isn't in the pricing table — the caller should
25
+ * display "-" rather than "$0".
26
+ */
27
+ declare function computeUsdCost(provider: string, modelId: string, usage: TokenUsage): number | null;
28
+ export { computeUsdCost, TokenUsage, ModelPricing, MODEL_PRICING };
@@ -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/pricing.ts
18
+ var MODEL_PRICING = {
19
+ anthropic: {
20
+ "claude-haiku-4-5": { inputPerMTokens: 1, outputPerMTokens: 5 },
21
+ "claude-haiku-4-5-20251001": { inputPerMTokens: 1, outputPerMTokens: 5 },
22
+ "claude-sonnet-4-6": { inputPerMTokens: 3, outputPerMTokens: 15 },
23
+ "claude-opus-4-7": { inputPerMTokens: 15, outputPerMTokens: 75 }
24
+ },
25
+ openai: {
26
+ "gpt-4.1": { inputPerMTokens: 2.5, outputPerMTokens: 10 },
27
+ "gpt-4o": { inputPerMTokens: 2.5, outputPerMTokens: 10 },
28
+ "gpt-4o-mini": { inputPerMTokens: 0.15, outputPerMTokens: 0.6 }
29
+ },
30
+ google: {
31
+ "gemini-2.5-pro": { inputPerMTokens: 1.25, outputPerMTokens: 10 },
32
+ "gemini-2.5-flash": { inputPerMTokens: 0.3, outputPerMTokens: 2.5 }
33
+ }
34
+ };
35
+ function computeUsdCost(provider, modelId, usage) {
36
+ const p = MODEL_PRICING[provider]?.[modelId];
37
+ if (!p)
38
+ return null;
39
+ return usage.inputTokens * p.inputPerMTokens / 1e6 + usage.outputTokens * p.outputPerMTokens / 1e6;
40
+ }
41
+ export {
42
+ computeUsdCost,
43
+ MODEL_PRICING
44
+ };
45
+
46
+ //# debugId=4DD95AFC388E4B9664756E2164756E21
47
+ //# sourceMappingURL=pricing.js.map
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/pricing.ts"],
4
+ "sourcesContent": [
5
+ "/**\n * Token → USD pricing constants for internal observability.\n *\n * **Not customer billing.** Tier pricing covers compute; these constants\n * let the dashboard display \"~$X spent in AI today\" and let us track\n * gross-margin internally. Update manually when providers change prices\n * (roughly twice per year).\n *\n * Source: public provider pricing pages as of 2026-04-17.\n */\n\nexport interface ModelPricing {\n\t/** USD per 1M input tokens */\n\tinputPerMTokens: number;\n\t/** USD per 1M output tokens */\n\toutputPerMTokens: number;\n}\n\nexport const MODEL_PRICING: Record<string, Record<string, ModelPricing>> = {\n\tanthropic: {\n\t\t\"claude-haiku-4-5\": { inputPerMTokens: 1, outputPerMTokens: 5 },\n\t\t\"claude-haiku-4-5-20251001\": { inputPerMTokens: 1, outputPerMTokens: 5 },\n\t\t\"claude-sonnet-4-6\": { inputPerMTokens: 3, outputPerMTokens: 15 },\n\t\t\"claude-opus-4-7\": { inputPerMTokens: 15, outputPerMTokens: 75 },\n\t},\n\topenai: {\n\t\t\"gpt-4.1\": { inputPerMTokens: 2.5, outputPerMTokens: 10 },\n\t\t\"gpt-4o\": { inputPerMTokens: 2.5, outputPerMTokens: 10 },\n\t\t\"gpt-4o-mini\": { inputPerMTokens: 0.15, outputPerMTokens: 0.6 },\n\t},\n\tgoogle: {\n\t\t\"gemini-2.5-pro\": { inputPerMTokens: 1.25, outputPerMTokens: 10 },\n\t\t\"gemini-2.5-flash\": { inputPerMTokens: 0.3, outputPerMTokens: 2.5 },\n\t},\n};\n\nexport interface TokenUsage {\n\tinputTokens: number;\n\toutputTokens: number;\n}\n\n/**\n * Compute approximate USD cost for an AI step. Returns `null` if the\n * (provider, model) pair isn't in the pricing table — the caller should\n * display \"-\" rather than \"$0\".\n */\nexport function computeUsdCost(\n\tprovider: string,\n\tmodelId: string,\n\tusage: TokenUsage,\n): number | null {\n\tconst p = MODEL_PRICING[provider]?.[modelId];\n\tif (!p) return null;\n\treturn (\n\t\t(usage.inputTokens * p.inputPerMTokens) / 1_000_000 +\n\t\t(usage.outputTokens * p.outputPerMTokens) / 1_000_000\n\t);\n}\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;AAkBO,IAAM,gBAA8D;AAAA,EAC1E,WAAW;AAAA,IACV,oBAAoB,EAAE,iBAAiB,GAAG,kBAAkB,EAAE;AAAA,IAC9D,6BAA6B,EAAE,iBAAiB,GAAG,kBAAkB,EAAE;AAAA,IACvE,qBAAqB,EAAE,iBAAiB,GAAG,kBAAkB,GAAG;AAAA,IAChE,mBAAmB,EAAE,iBAAiB,IAAI,kBAAkB,GAAG;AAAA,EAChE;AAAA,EACA,QAAQ;AAAA,IACP,WAAW,EAAE,iBAAiB,KAAK,kBAAkB,GAAG;AAAA,IACxD,UAAU,EAAE,iBAAiB,KAAK,kBAAkB,GAAG;AAAA,IACvD,eAAe,EAAE,iBAAiB,MAAM,kBAAkB,IAAI;AAAA,EAC/D;AAAA,EACA,QAAQ;AAAA,IACP,kBAAkB,EAAE,iBAAiB,MAAM,kBAAkB,GAAG;AAAA,IAChE,oBAAoB,EAAE,iBAAiB,KAAK,kBAAkB,IAAI;AAAA,EACnE;AACD;AAYO,SAAS,cAAc,CAC7B,UACA,SACA,OACgB;AAAA,EAChB,MAAM,IAAI,cAAc,YAAY;AAAA,EACpC,IAAI,CAAC;AAAA,IAAG,OAAO;AAAA,EACf,OACE,MAAM,cAAc,EAAE,kBAAmB,MACzC,MAAM,eAAe,EAAE,mBAAoB;AAAA;",
8
+ "debugId": "4DD95AFC388E4B9664756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,54 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ /**
4
+ * v2 step memoization:
5
+ *
6
+ * 1. `memo_key` — SHA-256 of `(stepId, canonicalJSON(stableInputs))`. Replaces
7
+ * the v1 `(run_id, step_id)` lookup so that editing a prompt in source
8
+ * invalidates the cache on the next run. Partial UNIQUE allows legacy
9
+ * pre-v2 rows with NULL memo_key to coexist.
10
+ *
11
+ * 2. `parent_step_id` — nullable self-FK for sub-step rows. AI tool calls
12
+ * inside `generateText`/`generateObject` persist as children of the
13
+ * parent AI step; on retry, previously successful tool calls return
14
+ * cached results instead of re-invoking `execute`.
15
+ */
16
+ export async function up(db: Kysely<unknown>): Promise<void> {
17
+ await db.schema
18
+ .alterTable("workflow_steps")
19
+ .addColumn("memo_key", "text")
20
+ .addColumn("parent_step_id", "uuid", (c) =>
21
+ c.references("workflow_steps.id").onDelete("cascade"),
22
+ )
23
+ .execute();
24
+
25
+ // Drop v1 composite UNIQUE. Replaced by memo_key-based UNIQUE below.
26
+ await sql`DROP INDEX IF EXISTS workflow_steps_dedup_idx`.execute(db);
27
+
28
+ // Partial UNIQUE: only constrain rows with memo_key set (v2 rows).
29
+ // Legacy NULL memo_key rows coexist without constraint violations.
30
+ await sql`CREATE UNIQUE INDEX workflow_steps_memo_idx ON workflow_steps (run_id, memo_key) WHERE memo_key IS NOT NULL`.execute(
31
+ db,
32
+ );
33
+
34
+ // Fan-out lookup for sub-step tool-call replay.
35
+ await sql`CREATE INDEX workflow_steps_parent_idx ON workflow_steps (parent_step_id) WHERE parent_step_id IS NOT NULL`.execute(
36
+ db,
37
+ );
38
+ }
39
+
40
+ export async function down(db: Kysely<unknown>): Promise<void> {
41
+ await sql`DROP INDEX IF EXISTS workflow_steps_parent_idx`.execute(db);
42
+ await sql`DROP INDEX IF EXISTS workflow_steps_memo_idx`.execute(db);
43
+
44
+ // Restore v1 composite UNIQUE.
45
+ await sql`CREATE UNIQUE INDEX workflow_steps_dedup_idx ON workflow_steps (run_id, step_id)`.execute(
46
+ db,
47
+ );
48
+
49
+ await db.schema
50
+ .alterTable("workflow_steps")
51
+ .dropColumn("parent_step_id")
52
+ .dropColumn("memo_key")
53
+ .execute();
54
+ }
@@ -0,0 +1,42 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ /**
4
+ * Workflow signer secrets — HMAC shared secrets used by the runner to
5
+ * authenticate requests to customer-hosted remote signer endpoints.
6
+ *
7
+ * Stored per-account, keyed by a user-chosen name referenced via
8
+ * `signer.remote({ hmacRef: "<name>" })` in workflow source. The
9
+ * `encrypted_value` column holds the secret encrypted at rest (runner
10
+ * KMS-decrypts on read). This separation lets customers rotate secrets
11
+ * without redeploying every workflow that references them.
12
+ */
13
+ export async function up(db: Kysely<unknown>): Promise<void> {
14
+ await db.schema
15
+ .createTable("workflow_signer_secrets")
16
+ .addColumn("id", "uuid", (c) =>
17
+ c.primaryKey().defaultTo(sql`gen_random_uuid()`),
18
+ )
19
+ .addColumn("account_id", "uuid", (c) =>
20
+ c.notNull().references("accounts.id").onDelete("cascade"),
21
+ )
22
+ .addColumn("name", "text", (c) => c.notNull())
23
+ .addColumn("encrypted_value", "bytea", (c) => c.notNull())
24
+ .addColumn("created_at", "timestamptz", (c) =>
25
+ c.notNull().defaultTo(sql`now()`),
26
+ )
27
+ .addColumn("updated_at", "timestamptz", (c) =>
28
+ c.notNull().defaultTo(sql`now()`),
29
+ )
30
+ .execute();
31
+
32
+ await sql`CREATE UNIQUE INDEX workflow_signer_secrets_account_name_idx ON workflow_signer_secrets (account_id, name)`.execute(
33
+ db,
34
+ );
35
+ }
36
+
37
+ export async function down(db: Kysely<unknown>): Promise<void> {
38
+ await sql`DROP INDEX IF EXISTS workflow_signer_secrets_account_name_idx`.execute(
39
+ db,
40
+ );
41
+ await db.schema.dropTable("workflow_signer_secrets").execute();
42
+ }
@@ -0,0 +1,53 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ /**
4
+ * Workflow budget counters — one row per `(workflow_definition_id, period)`.
5
+ * The runner increments these in `budget/enforcer.ts` after each AI/chain/
6
+ * run event and refuses further work when any configured cap is reached.
7
+ *
8
+ * `period` is a string key derived from the `WorkflowDefinition.budget.reset`
9
+ * setting and the current wall-clock: `"daily:2026-04-17"`,
10
+ * `"weekly:2026-W16"`, or `"per-run:<runId>"`. Old periods are retained for
11
+ * historical observability (budget burn-down view); a weekly TTL cron
12
+ * prunes them past 30 days of history.
13
+ */
14
+ export async function up(db: Kysely<unknown>): Promise<void> {
15
+ await db.schema
16
+ .createTable("workflow_budgets")
17
+ .addColumn("id", "uuid", (c) =>
18
+ c.primaryKey().defaultTo(sql`gen_random_uuid()`),
19
+ )
20
+ .addColumn("workflow_definition_id", "uuid", (c) =>
21
+ c.notNull().references("workflow_definitions.id").onDelete("cascade"),
22
+ )
23
+ .addColumn("period", "text", (c) => c.notNull())
24
+ .addColumn("ai_usd_used", "numeric(12, 4)", (c) => c.notNull().defaultTo(0))
25
+ .addColumn("ai_tokens_used", "bigint", (c) => c.notNull().defaultTo(0))
26
+ .addColumn("chain_microstx_used", "numeric(30, 0)", (c) =>
27
+ c.notNull().defaultTo(0),
28
+ )
29
+ .addColumn("chain_tx_count", "integer", (c) => c.notNull().defaultTo(0))
30
+ .addColumn("run_count", "integer", (c) => c.notNull().defaultTo(0))
31
+ .addColumn("step_count", "integer", (c) => c.notNull().defaultTo(0))
32
+ .addColumn("reset_at", "timestamptz", (c) => c.notNull())
33
+ .addColumn("created_at", "timestamptz", (c) =>
34
+ c.notNull().defaultTo(sql`now()`),
35
+ )
36
+ .addColumn("updated_at", "timestamptz", (c) =>
37
+ c.notNull().defaultTo(sql`now()`),
38
+ )
39
+ .execute();
40
+
41
+ await sql`CREATE UNIQUE INDEX workflow_budgets_def_period_idx ON workflow_budgets (workflow_definition_id, period)`.execute(
42
+ db,
43
+ );
44
+ await sql`CREATE INDEX workflow_budgets_reset_at_idx ON workflow_budgets (reset_at)`.execute(
45
+ db,
46
+ );
47
+ }
48
+
49
+ export async function down(db: Kysely<unknown>): Promise<void> {
50
+ await sql`DROP INDEX IF EXISTS workflow_budgets_reset_at_idx`.execute(db);
51
+ await sql`DROP INDEX IF EXISTS workflow_budgets_def_period_idx`.execute(db);
52
+ await db.schema.dropTable("workflow_budgets").execute();
53
+ }
@@ -0,0 +1,36 @@
1
+ import { type Kysely, sql } from "kysely";
2
+
3
+ /**
4
+ * pg_notify trigger on the core `transactions` table. Fires on INSERT and
5
+ * publishes the txid on the `tx:confirmed` channel. The workflow runner's
6
+ * `confirmation/subgraph.ts` listens on this channel to resolve pending
7
+ * `broadcast({ awaitConfirmation: true })` promises.
8
+ *
9
+ * Payload is just the tx_id — listeners dedupe + look up details
10
+ * themselves. Keeping the payload small keeps pg_notify throughput high.
11
+ */
12
+ export async function up(db: Kysely<unknown>): Promise<void> {
13
+ await sql`
14
+ CREATE OR REPLACE FUNCTION notify_tx_confirmed() RETURNS trigger AS $$
15
+ BEGIN
16
+ PERFORM pg_notify('tx:confirmed', NEW.tx_id);
17
+ RETURN NEW;
18
+ END;
19
+ $$ LANGUAGE plpgsql;
20
+ `.execute(db);
21
+
22
+ await sql`
23
+ DROP TRIGGER IF EXISTS tx_confirmed_notify ON transactions;
24
+ CREATE TRIGGER tx_confirmed_notify
25
+ AFTER INSERT ON transactions
26
+ FOR EACH ROW
27
+ EXECUTE FUNCTION notify_tx_confirmed();
28
+ `.execute(db);
29
+ }
30
+
31
+ export async function down(db: Kysely<unknown>): Promise<void> {
32
+ await sql`DROP TRIGGER IF EXISTS tx_confirmed_notify ON transactions`.execute(
33
+ db,
34
+ );
35
+ await sql`DROP FUNCTION IF EXISTS notify_tx_confirmed()`.execute(db);
36
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/shared",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "main": "./dist/src/index.js",
6
6
  "types": "./dist/src/index.d.ts",
@@ -101,6 +101,10 @@
101
101
  "types": "./dist/src/constants.d.ts",
102
102
  "import": "./dist/src/constants.js"
103
103
  },
104
+ "./pricing": {
105
+ "types": "./dist/src/pricing.d.ts",
106
+ "import": "./dist/src/pricing.js"
107
+ },
104
108
  "./crypto": {
105
109
  "types": "./dist/src/crypto/hmac.d.ts",
106
110
  "import": "./dist/src/crypto/hmac.js"
@@ -109,6 +113,10 @@
109
113
  "types": "./dist/src/crypto/hmac.d.ts",
110
114
  "import": "./dist/src/crypto/hmac.js"
111
115
  },
116
+ "./crypto/secrets": {
117
+ "types": "./dist/src/crypto/secrets.d.ts",
118
+ "import": "./dist/src/crypto/secrets.js"
119
+ },
112
120
  "./node": {
113
121
  "types": "./dist/src/node/client.d.ts",
114
122
  "import": "./dist/src/node/client.js"
@@ -148,7 +156,7 @@
148
156
  "prepublishOnly": "bun run build"
149
157
  },
150
158
  "dependencies": {
151
- "@secondlayer/stacks": "^0.2.2",
159
+ "@secondlayer/stacks": "^0.3.0",
152
160
  "kysely": "0.28.15",
153
161
  "kysely-postgres-js": "3.0.0",
154
162
  "postgres": "^3.4.6",