@secondlayer/shared 2.1.0 → 3.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +2 -2
  2. package/dist/src/db/index.d.ts +39 -137
  3. package/dist/src/db/index.js.map +2 -2
  4. package/dist/src/db/jsonb.d.ts +5 -1
  5. package/dist/src/db/jsonb.js.map +2 -2
  6. package/dist/src/db/queries/account-spend-caps.d.ts +379 -0
  7. package/dist/src/db/queries/account-spend-caps.js +60 -0
  8. package/dist/src/db/queries/account-spend-caps.js.map +10 -0
  9. package/dist/src/db/queries/account-usage.d.ts +403 -0
  10. package/dist/src/db/queries/account-usage.js +222 -0
  11. package/dist/src/db/queries/account-usage.js.map +11 -0
  12. package/dist/src/db/queries/accounts.d.ts +41 -115
  13. package/dist/src/db/queries/accounts.js +15 -1
  14. package/dist/src/db/queries/accounts.js.map +3 -3
  15. package/dist/src/db/queries/integrity.d.ts +27 -114
  16. package/dist/src/db/queries/projects.d.ts +27 -114
  17. package/dist/src/db/queries/provisioning-audit.d.ts +27 -114
  18. package/dist/src/db/queries/subgraph-gaps.d.ts +27 -114
  19. package/dist/src/db/queries/subgraphs.d.ts +27 -115
  20. package/dist/src/db/queries/subgraphs.js +2 -3
  21. package/dist/src/db/queries/subgraphs.js.map +4 -4
  22. package/dist/src/db/queries/{workflows.d.ts → tenant-compute-addons.d.ts} +50 -149
  23. package/dist/src/db/queries/tenant-compute-addons.js +47 -0
  24. package/dist/src/db/queries/tenant-compute-addons.js.map +10 -0
  25. package/dist/src/db/queries/tenants.d.ts +40 -117
  26. package/dist/src/db/queries/tenants.js +9 -6
  27. package/dist/src/db/queries/tenants.js.map +3 -3
  28. package/dist/src/db/queries/usage.d.ts +28 -139
  29. package/dist/src/db/queries/usage.js +5 -64
  30. package/dist/src/db/queries/usage.js.map +4 -5
  31. package/dist/src/db/schema.d.ts +34 -136
  32. package/dist/src/errors.d.ts +8 -7
  33. package/dist/src/errors.js +11 -12
  34. package/dist/src/errors.js.map +3 -3
  35. package/dist/src/index.d.ts +46 -143
  36. package/dist/src/index.js +11 -12
  37. package/dist/src/index.js.map +4 -4
  38. package/dist/src/node/local-client.d.ts +27 -114
  39. package/dist/src/pricing.d.ts +20 -1
  40. package/dist/src/pricing.js +58 -1
  41. package/dist/src/pricing.js.map +3 -3
  42. package/migrations/0045_drop_marketplace_columns.ts +47 -0
  43. package/migrations/0046_tenant_activity_signal.ts +47 -0
  44. package/migrations/0047_usage_daily_tenant_id.ts +73 -0
  45. package/migrations/0048_tenant_compute_addons.ts +49 -0
  46. package/migrations/0049_accounts_stripe_customer_id.ts +30 -0
  47. package/migrations/0050_account_spend_caps.ts +45 -0
  48. package/migrations/0051_workflow_ai_usage_daily.ts +40 -0
  49. package/migrations/0052_sentries.ts +61 -0
  50. package/migrations/0053_workflow_runtime.ts +88 -0
  51. package/migrations/0054_accounts_plan_hobby.ts +32 -0
  52. package/migrations/0055_ai_usage_account_scope.ts +108 -0
  53. package/migrations/0056_drop_workflow_sentry_residuals.ts +23 -0
  54. package/package.json +26 -14
  55. package/dist/src/db/queries/workflows.js +0 -260
  56. package/dist/src/db/queries/workflows.js.map +0 -12
  57. package/dist/src/lib/plans.d.ts +0 -9
  58. package/dist/src/lib/plans.js +0 -37
  59. package/dist/src/lib/plans.js.map +0 -10
  60. package/dist/src/schemas/workflows.d.ts +0 -70
  61. package/dist/src/schemas/workflows.js +0 -43
  62. package/dist/src/schemas/workflows.js.map +0 -10
@@ -0,0 +1,403 @@
1
+ import { Kysely } from "kysely";
2
+ import { ColumnType, Generated } from "kysely";
3
+ interface BlocksTable {
4
+ height: number;
5
+ hash: string;
6
+ parent_hash: string;
7
+ burn_block_height: number;
8
+ timestamp: number;
9
+ canonical: Generated<boolean>;
10
+ created_at: Generated<Date>;
11
+ }
12
+ interface TransactionsTable {
13
+ tx_id: string;
14
+ block_height: number;
15
+ tx_index: Generated<number>;
16
+ type: string;
17
+ sender: string;
18
+ status: string;
19
+ contract_id: string | null;
20
+ function_name: string | null;
21
+ function_args: Generated<unknown | null>;
22
+ raw_result: Generated<string | null>;
23
+ raw_tx: string;
24
+ created_at: Generated<Date>;
25
+ }
26
+ interface EventsTable {
27
+ id: Generated<string>;
28
+ tx_id: string;
29
+ block_height: number;
30
+ event_index: number;
31
+ type: string;
32
+ data: unknown;
33
+ created_at: Generated<Date>;
34
+ }
35
+ interface IndexProgressTable {
36
+ network: string;
37
+ last_indexed_block: Generated<number>;
38
+ last_contiguous_block: Generated<number>;
39
+ highest_seen_block: Generated<number>;
40
+ updated_at: Generated<Date>;
41
+ }
42
+ interface SubgraphsTable {
43
+ id: Generated<string>;
44
+ name: string;
45
+ version: Generated<string>;
46
+ status: Generated<string>;
47
+ definition: Record<string, unknown>;
48
+ schema_hash: string;
49
+ handler_path: string;
50
+ schema_name: string | null;
51
+ start_block: Generated<number>;
52
+ last_processed_block: Generated<number>;
53
+ reindex_from_block: number | null;
54
+ reindex_to_block: number | null;
55
+ last_error: string | null;
56
+ last_error_at: Date | null;
57
+ total_processed: Generated<number>;
58
+ total_errors: Generated<number>;
59
+ account_id: string;
60
+ handler_code: string | null;
61
+ source_code: string | null;
62
+ project_id: string | null;
63
+ created_at: Generated<Date>;
64
+ updated_at: Generated<Date>;
65
+ }
66
+ interface SubgraphGapsTable {
67
+ id: Generated<string>;
68
+ subgraph_id: string;
69
+ subgraph_name: string;
70
+ gap_start: number;
71
+ gap_end: number;
72
+ reason: string;
73
+ detected_at: Generated<Date>;
74
+ resolved_at: Date | null;
75
+ }
76
+ interface ApiKeysTable {
77
+ id: Generated<string>;
78
+ key_hash: string;
79
+ key_prefix: string;
80
+ name: string | null;
81
+ status: Generated<string>;
82
+ rate_limit: Generated<number>;
83
+ ip_address: string;
84
+ account_id: string;
85
+ last_used_at: Date | null;
86
+ revoked_at: Date | null;
87
+ created_at: Generated<Date>;
88
+ }
89
+ interface AccountsTable {
90
+ id: Generated<string>;
91
+ email: string;
92
+ plan: Generated<string>;
93
+ display_name: string | null;
94
+ bio: string | null;
95
+ avatar_url: string | null;
96
+ slug: string | null;
97
+ stripe_customer_id: string | null;
98
+ created_at: Generated<Date>;
99
+ }
100
+ interface SessionsTable {
101
+ id: Generated<string>;
102
+ token_hash: string;
103
+ token_prefix: string;
104
+ account_id: string;
105
+ ip_address: string;
106
+ expires_at: Generated<Date>;
107
+ revoked_at: Date | null;
108
+ last_used_at: Date | null;
109
+ created_at: Generated<Date>;
110
+ }
111
+ interface MagicLinksTable {
112
+ id: Generated<string>;
113
+ email: string;
114
+ token: string;
115
+ code: string | null;
116
+ expires_at: Date;
117
+ used_at: Date | null;
118
+ failed_attempts: Generated<number>;
119
+ created_at: Generated<Date>;
120
+ }
121
+ interface UsageDailyTable {
122
+ account_id: string;
123
+ tenant_id: string | null;
124
+ date: string;
125
+ api_requests: Generated<number>;
126
+ deliveries: Generated<number>;
127
+ }
128
+ interface UsageSnapshotsTable {
129
+ id: Generated<string>;
130
+ account_id: string;
131
+ measured_at: Generated<Date>;
132
+ storage_bytes: Generated<number>;
133
+ }
134
+ interface WaitlistTable {
135
+ id: Generated<string>;
136
+ email: string;
137
+ source: Generated<string>;
138
+ status: Generated<string>;
139
+ created_at: Generated<Date>;
140
+ }
141
+ interface AccountInsightsTable {
142
+ id: Generated<string>;
143
+ account_id: string;
144
+ category: string;
145
+ insight_type: string;
146
+ resource_id: string | null;
147
+ severity: string;
148
+ title: string;
149
+ body: string;
150
+ data: unknown;
151
+ dismissed_at: Date | null;
152
+ expires_at: Date | null;
153
+ created_at: Generated<Date>;
154
+ }
155
+ interface AccountAgentRunsTable {
156
+ id: Generated<string>;
157
+ account_id: string;
158
+ started_at: Generated<Date>;
159
+ completed_at: Date | null;
160
+ status: Generated<string>;
161
+ input_tokens: Generated<number>;
162
+ output_tokens: Generated<number>;
163
+ cost_usd: Generated<number>;
164
+ insights_created: Generated<number>;
165
+ error: string | null;
166
+ }
167
+ interface SubgraphProcessingStatsTable {
168
+ id: Generated<string>;
169
+ subgraph_name: string;
170
+ api_key_id: string | null;
171
+ bucket_start: Date | null;
172
+ bucket_end: Date | null;
173
+ blocks_processed: number | null;
174
+ total_time_ms: number | null;
175
+ handler_time_ms: number | null;
176
+ flush_time_ms: number | null;
177
+ max_block_time_ms: number | null;
178
+ max_handler_time_ms: number | null;
179
+ avg_ops_per_block: number | null;
180
+ is_catchup: Generated<boolean>;
181
+ created_at: Generated<Date>;
182
+ }
183
+ interface SubgraphTableSnapshotsTable {
184
+ id: Generated<string>;
185
+ subgraph_name: string;
186
+ api_key_id: string | null;
187
+ table_name: string;
188
+ row_count: number | null;
189
+ created_at: Generated<Date>;
190
+ }
191
+ interface SubgraphHealthSnapshotsTable {
192
+ id: Generated<string>;
193
+ subgraph_id: string;
194
+ total_processed: number;
195
+ total_errors: number;
196
+ last_processed_block: number | null;
197
+ captured_at: Generated<Date>;
198
+ }
199
+ interface SubgraphUsageDailyTable {
200
+ subgraph_id: string;
201
+ date: string;
202
+ query_count: Generated<number>;
203
+ }
204
+ interface ProjectsTable {
205
+ id: Generated<string>;
206
+ name: string;
207
+ slug: string;
208
+ account_id: string;
209
+ settings: Generated<Record<string, unknown>>;
210
+ network: Generated<string>;
211
+ node_rpc: string | null;
212
+ created_at: Generated<Date>;
213
+ updated_at: Generated<Date>;
214
+ }
215
+ interface TeamMembersTable {
216
+ id: Generated<string>;
217
+ project_id: string;
218
+ account_id: string;
219
+ role: Generated<string>;
220
+ invited_by: string | null;
221
+ created_at: Generated<Date>;
222
+ }
223
+ interface TeamInvitationsTable {
224
+ id: Generated<string>;
225
+ project_id: string;
226
+ email: string;
227
+ role: Generated<string>;
228
+ token: string;
229
+ invited_by: string | null;
230
+ expires_at: Date;
231
+ accepted_at: Date | null;
232
+ created_at: Generated<Date>;
233
+ }
234
+ interface ChatSessionsTable {
235
+ id: Generated<string>;
236
+ account_id: string;
237
+ title: string | null;
238
+ summary: unknown | null;
239
+ created_at: Generated<Date>;
240
+ updated_at: Generated<Date>;
241
+ }
242
+ interface ChatMessagesTable {
243
+ id: Generated<string>;
244
+ chat_session_id: string;
245
+ role: string;
246
+ parts: unknown;
247
+ metadata: unknown | null;
248
+ created_at: Generated<Date>;
249
+ }
250
+ interface Database {
251
+ blocks: BlocksTable;
252
+ transactions: TransactionsTable;
253
+ events: EventsTable;
254
+ index_progress: IndexProgressTable;
255
+ subgraphs: SubgraphsTable;
256
+ api_keys: ApiKeysTable;
257
+ accounts: AccountsTable;
258
+ sessions: SessionsTable;
259
+ magic_links: MagicLinksTable;
260
+ usage_daily: UsageDailyTable;
261
+ usage_snapshots: UsageSnapshotsTable;
262
+ waitlist: WaitlistTable;
263
+ account_insights: AccountInsightsTable;
264
+ account_agent_runs: AccountAgentRunsTable;
265
+ subgraph_health_snapshots: SubgraphHealthSnapshotsTable;
266
+ subgraph_processing_stats: SubgraphProcessingStatsTable;
267
+ subgraph_table_snapshots: SubgraphTableSnapshotsTable;
268
+ subgraph_gaps: SubgraphGapsTable;
269
+ subgraph_usage_daily: SubgraphUsageDailyTable;
270
+ projects: ProjectsTable;
271
+ team_members: TeamMembersTable;
272
+ team_invitations: TeamInvitationsTable;
273
+ chat_sessions: ChatSessionsTable;
274
+ chat_messages: ChatMessagesTable;
275
+ tenants: TenantsTable;
276
+ tenant_usage_monthly: TenantUsageMonthlyTable;
277
+ tenant_compute_addons: TenantComputeAddonsTable;
278
+ account_spend_caps: AccountSpendCapsTable;
279
+ provisioning_audit_log: ProvisioningAuditLogTable;
280
+ }
281
+ type TenantStatus = "provisioning" | "active" | "suspended" | "error" | "deleted";
282
+ interface TenantsTable {
283
+ id: Generated<string>;
284
+ account_id: string;
285
+ slug: string;
286
+ status: ColumnType<TenantStatus, TenantStatus | undefined, TenantStatus>;
287
+ plan: string;
288
+ cpus: ColumnType<number, number | string, number | string>;
289
+ memory_mb: number;
290
+ storage_limit_mb: number;
291
+ storage_used_mb: number | null;
292
+ pg_container_id: string | null;
293
+ api_container_id: string | null;
294
+ processor_container_id: string | null;
295
+ target_database_url_enc: Buffer;
296
+ tenant_jwt_secret_enc: Buffer;
297
+ anon_key_enc: Buffer;
298
+ service_key_enc: Buffer;
299
+ api_url_internal: string;
300
+ api_url_public: string;
301
+ suspended_at: Date | null;
302
+ last_health_check_at: Date | null;
303
+ last_active_at: Generated<Date>;
304
+ service_gen: Generated<number>;
305
+ anon_gen: Generated<number>;
306
+ project_id: string | null;
307
+ created_at: Generated<Date>;
308
+ updated_at: Generated<Date>;
309
+ }
310
+ interface TenantUsageMonthlyTable {
311
+ id: Generated<string>;
312
+ tenant_id: string;
313
+ period_month: Date;
314
+ storage_peak_mb: Generated<number>;
315
+ storage_avg_mb: Generated<number>;
316
+ storage_last_mb: Generated<number>;
317
+ measurements: Generated<number>;
318
+ first_at: Generated<Date>;
319
+ last_at: Generated<Date>;
320
+ }
321
+ interface TenantComputeAddonsTable {
322
+ id: Generated<string>;
323
+ tenant_id: string;
324
+ memory_mb_delta: Generated<number>;
325
+ cpu_delta: Generated<number | string>;
326
+ storage_mb_delta: Generated<number>;
327
+ effective_from: Generated<Date>;
328
+ effective_until: Date | null;
329
+ stripe_subscription_item_id: string | null;
330
+ created_at: Generated<Date>;
331
+ }
332
+ interface AccountSpendCapsTable {
333
+ account_id: string;
334
+ monthly_cap_cents: number | null;
335
+ compute_cap_cents: number | null;
336
+ storage_cap_cents: number | null;
337
+ ai_cap_cents: number | null;
338
+ alert_threshold_pct: Generated<number>;
339
+ alert_sent_at: Date | null;
340
+ frozen_at: Date | null;
341
+ updated_at: Generated<Date>;
342
+ }
343
+ type ProvisioningAuditEvent = "provision.start" | "provision.success" | "provision.failure" | "suspend" | "resume" | "resize" | "keys.rotate" | "bastion.key.upload" | "bastion.key.revoke" | "teardown";
344
+ type ProvisioningAuditStatus = "ok" | "error";
345
+ interface ProvisioningAuditLogTable {
346
+ id: Generated<string>;
347
+ tenant_id: string | null;
348
+ tenant_slug: string | null;
349
+ account_id: string | null;
350
+ actor: string;
351
+ event: ProvisioningAuditEvent;
352
+ status: ProvisioningAuditStatus;
353
+ detail: unknown | null;
354
+ error: string | null;
355
+ created_at: Generated<Date>;
356
+ }
357
+ interface SparklinePoint {
358
+ day: string;
359
+ value: number;
360
+ }
361
+ interface ComputeUsage {
362
+ usedHours: number;
363
+ allowanceHours: number;
364
+ pct: number;
365
+ sparkline: SparklinePoint[];
366
+ }
367
+ interface StorageUsage {
368
+ usedBytes: number;
369
+ allowanceBytes: number;
370
+ pct: number;
371
+ sparkline: SparklinePoint[];
372
+ }
373
+ interface AiUsage {
374
+ todayCount: number;
375
+ periodCount: number;
376
+ dailyCap: number;
377
+ pct: number;
378
+ sparkline: SparklinePoint[];
379
+ }
380
+ interface ProjectRow {
381
+ id: string;
382
+ slug: string;
383
+ name: string;
384
+ status: string;
385
+ subgraphCount: number;
386
+ compute: {
387
+ hours: number
388
+ pct: number
389
+ };
390
+ storage: {
391
+ bytes: number
392
+ pct: number
393
+ };
394
+ aiEvals: {
395
+ todayCount: number
396
+ pct: number
397
+ };
398
+ }
399
+ declare function getComputeUsage(db: Kysely<Database>, accountId: string, plan: string, periodStart: Date, now?: Date): Promise<ComputeUsage>;
400
+ declare function getStorageUsage(db: Kysely<Database>, accountId: string, plan: string, now?: Date): Promise<StorageUsage>;
401
+ declare function getAiUsage(_db: Kysely<Database>, _accountId: string, plan: string, _periodStart: Date, now?: Date): Promise<AiUsage>;
402
+ declare function getProjectBreakdown(db: Kysely<Database>, accountId: string, plan: string, periodStart: Date, now?: Date): Promise<ProjectRow[]>;
403
+ export { getStorageUsage, getProjectBreakdown, getComputeUsage, getAiUsage, StorageUsage, SparklinePoint, ProjectRow, ComputeUsage, AiUsage };
@@ -0,0 +1,222 @@
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
+ var AI_CAP_UNLIMITED = {
42
+ evalsPerDay: Number.POSITIVE_INFINITY,
43
+ overageMeterEventName: "ai_evals"
44
+ };
45
+ var AI_CAPS_BY_PLAN = {
46
+ hobby: { evalsPerDay: 50, overageMeterEventName: "ai_evals" },
47
+ launch: { evalsPerDay: 500, overageMeterEventName: "ai_evals" },
48
+ grow: { evalsPerDay: 1000, overageMeterEventName: "ai_evals" },
49
+ scale: { evalsPerDay: 2500, overageMeterEventName: "ai_evals" },
50
+ enterprise: AI_CAP_UNLIMITED
51
+ };
52
+ function getAiCapForPlan(plan) {
53
+ return AI_CAPS_BY_PLAN[plan] ?? AI_CAPS_BY_PLAN.hobby;
54
+ }
55
+ var BYTES_PER_GB = 1024 ** 3;
56
+ var COMPUTE_ALLOWANCE_BY_PLAN = {
57
+ hobby: Number.POSITIVE_INFINITY,
58
+ launch: 500,
59
+ grow: 1000,
60
+ scale: 2500,
61
+ enterprise: Number.POSITIVE_INFINITY
62
+ };
63
+ var STORAGE_ALLOWANCE_BYTES_BY_PLAN = {
64
+ hobby: 5 * BYTES_PER_GB,
65
+ launch: 50 * BYTES_PER_GB,
66
+ grow: 200 * BYTES_PER_GB,
67
+ scale: 1000 * BYTES_PER_GB,
68
+ enterprise: Number.POSITIVE_INFINITY
69
+ };
70
+ function getComputeAllowanceHours(plan) {
71
+ return COMPUTE_ALLOWANCE_BY_PLAN[plan] ?? COMPUTE_ALLOWANCE_BY_PLAN.hobby;
72
+ }
73
+ function getStorageAllowanceBytes(plan) {
74
+ return STORAGE_ALLOWANCE_BYTES_BY_PLAN[plan] ?? STORAGE_ALLOWANCE_BYTES_BY_PLAN.hobby;
75
+ }
76
+ function hasStorageOverage(plan) {
77
+ return plan !== "hobby";
78
+ }
79
+ var BASE_PRICE_CENTS_BY_PLAN = {
80
+ hobby: 0,
81
+ launch: 14900,
82
+ grow: 34900,
83
+ scale: 79900,
84
+ enterprise: 0
85
+ };
86
+ function getBasePriceCents(plan) {
87
+ return BASE_PRICE_CENTS_BY_PLAN[plan] ?? 0;
88
+ }
89
+ function getPlanDisplayName(plan) {
90
+ return plan.charAt(0).toUpperCase() + plan.slice(1);
91
+ }
92
+
93
+ // src/db/queries/account-usage.ts
94
+ import { sql } from "kysely";
95
+ var IDLE_GRACE_MS = 2 * 60 * 60 * 1000;
96
+ var BYTES_PER_MB = 1024 * 1024;
97
+ function toDayKey(d) {
98
+ return d.toISOString().slice(0, 10);
99
+ }
100
+ function* lastNDays(n, endInclusive) {
101
+ const end = new Date(endInclusive);
102
+ for (let i = n - 1;i >= 0; i--) {
103
+ const d = new Date(end);
104
+ d.setUTCDate(d.getUTCDate() - i);
105
+ yield toDayKey(d);
106
+ }
107
+ }
108
+ function computeActiveHours(periodStart, now, tenant) {
109
+ if (tenant.status !== "active")
110
+ return 0;
111
+ const rangeStart = Math.max(periodStart.getTime(), tenant.created_at.getTime());
112
+ const rangeEnd = Math.min(now.getTime(), tenant.last_active_at.getTime() + IDLE_GRACE_MS);
113
+ if (rangeEnd <= rangeStart)
114
+ return 0;
115
+ return (rangeEnd - rangeStart) / (1000 * 60 * 60);
116
+ }
117
+ function pct(used, allowance) {
118
+ if (!Number.isFinite(allowance) || allowance <= 0)
119
+ return 0;
120
+ return Math.min(used / allowance * 100, 100);
121
+ }
122
+ async function getComputeUsage(db, accountId, plan, periodStart, now = new Date) {
123
+ const tenants = await db.selectFrom("tenants").select(["id", "cpus", "status", "created_at", "last_active_at"]).where("account_id", "=", accountId).where("status", "!=", "deleted").execute();
124
+ let totalHours = 0;
125
+ for (const t of tenants) {
126
+ const hours = computeActiveHours(periodStart, now, {
127
+ created_at: t.created_at,
128
+ last_active_at: t.last_active_at,
129
+ status: String(t.status)
130
+ });
131
+ totalHours += hours * Number(t.cpus);
132
+ }
133
+ const allowance = getComputeAllowanceHours(plan);
134
+ const sparkline = [];
135
+ for (const day of lastNDays(14, now)) {
136
+ const dayStart = new Date(`${day}T00:00:00.000Z`);
137
+ const dayEnd = new Date(`${day}T23:59:59.999Z`);
138
+ let dayHours = 0;
139
+ for (const t of tenants) {
140
+ const hours = computeActiveHours(dayStart, dayEnd, {
141
+ created_at: t.created_at,
142
+ last_active_at: t.last_active_at,
143
+ status: String(t.status)
144
+ });
145
+ dayHours += Math.min(hours, 24) * Number(t.cpus);
146
+ }
147
+ sparkline.push({ day, value: dayHours });
148
+ }
149
+ return {
150
+ usedHours: totalHours,
151
+ allowanceHours: allowance,
152
+ pct: pct(totalHours, allowance),
153
+ sparkline
154
+ };
155
+ }
156
+ async function getStorageUsage(db, accountId, plan, now = new Date) {
157
+ const current = await db.selectFrom("tenants").select(sql`COALESCE(SUM(storage_used_mb), 0)`.as("mb")).where("account_id", "=", accountId).where("status", "!=", "deleted").executeTakeFirst();
158
+ const usedBytes = Number(current?.mb ?? 0) * BYTES_PER_MB;
159
+ const allowance = getStorageAllowanceBytes(plan);
160
+ const sparkline = [];
161
+ for (const day of lastNDays(14, now)) {
162
+ sparkline.push({ day, value: Number(current?.mb ?? 0) });
163
+ }
164
+ return {
165
+ usedBytes,
166
+ allowanceBytes: allowance,
167
+ pct: pct(usedBytes, allowance),
168
+ sparkline
169
+ };
170
+ }
171
+ async function getAiUsage(_db, _accountId, plan, _periodStart, now = new Date) {
172
+ const dailyCap = getAiCapForPlan(plan).evalsPerDay;
173
+ const sparkline = [];
174
+ for (const day of lastNDays(14, now))
175
+ sparkline.push({ day, value: 0 });
176
+ return { todayCount: 0, periodCount: 0, dailyCap, pct: 0, sparkline };
177
+ }
178
+ async function getProjectBreakdown(db, accountId, plan, periodStart, now = new Date) {
179
+ const tenants = await db.selectFrom("tenants").select([
180
+ "id",
181
+ "slug",
182
+ "status",
183
+ "cpus",
184
+ "storage_used_mb",
185
+ "created_at",
186
+ "last_active_at"
187
+ ]).where("account_id", "=", accountId).where("status", "!=", "deleted").orderBy("created_at", "desc").execute();
188
+ if (tenants.length === 0)
189
+ return [];
190
+ const aiByTenant = new Map;
191
+ const computeAllowance = getComputeAllowanceHours(plan);
192
+ const storageAllowance = getStorageAllowanceBytes(plan);
193
+ const aiDailyCap = getAiCapForPlan(plan).evalsPerDay;
194
+ return tenants.map((t) => {
195
+ const hours = computeActiveHours(periodStart, now, {
196
+ created_at: t.created_at,
197
+ last_active_at: t.last_active_at,
198
+ status: String(t.status)
199
+ }) * Number(t.cpus);
200
+ const bytes = Number(t.storage_used_mb ?? 0) * BYTES_PER_MB;
201
+ const todayAi = aiByTenant.get(t.id) ?? 0;
202
+ return {
203
+ id: t.id,
204
+ slug: t.slug,
205
+ name: t.slug,
206
+ status: String(t.status),
207
+ subgraphCount: 0,
208
+ compute: { hours, pct: pct(hours, computeAllowance) },
209
+ storage: { bytes, pct: pct(bytes, storageAllowance) },
210
+ aiEvals: { todayCount: todayAi, pct: pct(todayAi, aiDailyCap) }
211
+ };
212
+ });
213
+ }
214
+ export {
215
+ getStorageUsage,
216
+ getProjectBreakdown,
217
+ getComputeUsage,
218
+ getAiUsage
219
+ };
220
+
221
+ //# debugId=D94D306CAF5E896064756E2164756E21
222
+ //# sourceMappingURL=account-usage.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/pricing.ts", "../src/db/queries/account-usage.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\n// ── Per-tier AI eval caps (workflow-runner) ───────────────────────────\n//\n// Daily `step.ai` budget by tier. Hit the cap → runner throws\n// AI_CAP_REACHED and the step fails cleanly so condition-only paths\n// continue. Overage (past cap) bills to the `ai_evals` Stripe meter on\n// paid tiers.\n//\n// Caps set conservatively so Pro Micro stays margin-positive at\n// realistic AI utilization. Raise based on data, not aspiration.\n\nexport interface AiCap {\n\t/** Max step.ai / generateText / generateObject calls per UTC day. */\n\tevalsPerDay: number;\n\t/** Stripe meter events emitted for overage past this cap. */\n\toverageMeterEventName: \"ai_evals\";\n}\n\nconst AI_CAP_UNLIMITED: AiCap = {\n\tevalsPerDay: Number.POSITIVE_INFINITY,\n\toverageMeterEventName: \"ai_evals\",\n};\n\nconst AI_CAPS_BY_PLAN: Record<string, AiCap> = {\n\thobby: { evalsPerDay: 50, overageMeterEventName: \"ai_evals\" },\n\tlaunch: { evalsPerDay: 500, overageMeterEventName: \"ai_evals\" },\n\tgrow: { evalsPerDay: 1000, overageMeterEventName: \"ai_evals\" },\n\tscale: { evalsPerDay: 2500, overageMeterEventName: \"ai_evals\" },\n\tenterprise: AI_CAP_UNLIMITED,\n};\n\n/** Resolve the daily AI eval cap for a plan. Unknown plans get Hobby's\n * cap so a stray DB value can't accidentally become unlimited. */\nexport function getAiCapForPlan(plan: string): AiCap {\n\treturn AI_CAPS_BY_PLAN[plan] ?? AI_CAPS_BY_PLAN.hobby;\n}\n\n// ── Per-tier compute + storage allowances (usage page) ──────────────\n//\n// \"Included\" amounts per billing period. Actual billing comes from\n// Stripe compute-hours + storage-overage meters; these constants power\n// the dashboard display and the approximation used by `/api/accounts/usage`.\n//\n// Values picked to match `project_supabase_pricing_model.md`:\n// Hobby — 50 h / 5 GB (Nano — free tier)\n// Launch — 500 h / 50 GB ($149/mo)\n// Grow — 1,000 h / 200 GB ($349/mo)\n// Scale — 2,500 h / 1 TB ($799/mo)\n// Enterprise — ∞ / ∞\n\nconst BYTES_PER_GB = 1024 ** 3;\n\n// Hobby has no compute-hour cap — auto-pause after 7d idle is the cap.\n// Paid tiers bill Stripe-metered hours past the included credit; the\n// hour equivalents below are approximate display values. Real billing\n// uses the `compute_hours` meter in Stripe, not these numbers.\nconst COMPUTE_ALLOWANCE_BY_PLAN: Record<string, number> = {\n\thobby: Number.POSITIVE_INFINITY,\n\tlaunch: 500,\n\tgrow: 1000,\n\tscale: 2500,\n\tenterprise: Number.POSITIVE_INFINITY,\n};\n\nconst STORAGE_ALLOWANCE_BYTES_BY_PLAN: Record<string, number> = {\n\thobby: 5 * BYTES_PER_GB,\n\tlaunch: 50 * BYTES_PER_GB,\n\tgrow: 200 * BYTES_PER_GB,\n\tscale: 1000 * BYTES_PER_GB,\n\tenterprise: Number.POSITIVE_INFINITY,\n};\n\n/** Included compute hours per billing period. Unknown → hobby. */\nexport function getComputeAllowanceHours(plan: string): number {\n\treturn COMPUTE_ALLOWANCE_BY_PLAN[plan] ?? COMPUTE_ALLOWANCE_BY_PLAN.hobby;\n}\n\n/** Included storage bytes. Unknown → hobby. */\nexport function getStorageAllowanceBytes(plan: string): number {\n\treturn (\n\t\tSTORAGE_ALLOWANCE_BYTES_BY_PLAN[plan] ??\n\t\tSTORAGE_ALLOWANCE_BYTES_BY_PLAN.hobby\n\t);\n}\n\n/** Whether this plan bills storage overage. Hobby has a hard cap\n * (no overage billing); paid tiers bill $2/GB over allowance. */\nexport function hasStorageOverage(plan: string): boolean {\n\treturn plan !== \"hobby\";\n}\n\n/** Base monthly price for a plan, in cents. Enterprise is custom → 0. */\nconst BASE_PRICE_CENTS_BY_PLAN: Record<string, number> = {\n\thobby: 0,\n\tlaunch: 14900,\n\tgrow: 34900,\n\tscale: 79900,\n\tenterprise: 0,\n};\n\nexport function getBasePriceCents(plan: string): number {\n\treturn BASE_PRICE_CENTS_BY_PLAN[plan] ?? 0;\n}\n\n/** Capitalized display name for a plan tier. */\nexport function getPlanDisplayName(plan: string): string {\n\treturn plan.charAt(0).toUpperCase() + plan.slice(1);\n}\n",
6
+ "import { type Kysely, sql } from \"kysely\";\nimport {\n\tgetAiCapForPlan,\n\tgetComputeAllowanceHours,\n\tgetStorageAllowanceBytes,\n} from \"../../pricing.ts\";\nimport type { Database } from \"../types.ts\";\n\n/**\n * Rollup queries that power the `/platform/usage` page.\n *\n * Compute-hours approximation: each active tenant contributes\n * cpus × hours-in-period-while-active\n * where \"active\" is approximated from `last_active_at`. This undercounts\n * tenants that went idle between cron ticks and overcounts nothing.\n *\n * Actual Stripe billing happens in `packages/worker/src/jobs/compute-metering.ts`\n * — these numbers are for display only. Follow-up work: write-through\n * compute ledger so this query reads truth instead of estimating.\n */\n\nconst IDLE_GRACE_MS = 2 * 60 * 60 * 1000; // 2h\nconst BYTES_PER_MB = 1024 * 1024;\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport interface SparklinePoint {\n\tday: string; // YYYY-MM-DD\n\tvalue: number;\n}\n\nexport interface ComputeUsage {\n\tusedHours: number;\n\tallowanceHours: number;\n\tpct: number;\n\tsparkline: SparklinePoint[];\n}\n\nexport interface StorageUsage {\n\tusedBytes: number;\n\tallowanceBytes: number;\n\tpct: number;\n\tsparkline: SparklinePoint[];\n}\n\nexport interface AiUsage {\n\ttodayCount: number;\n\tperiodCount: number;\n\tdailyCap: number;\n\tpct: number;\n\tsparkline: SparklinePoint[];\n}\n\nexport interface ProjectRow {\n\tid: string;\n\tslug: string;\n\tname: string;\n\tstatus: string;\n\tsubgraphCount: number;\n\tcompute: { hours: number; pct: number };\n\tstorage: { bytes: number; pct: number };\n\taiEvals: { todayCount: number; pct: number };\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction toDayKey(d: Date): string {\n\treturn d.toISOString().slice(0, 10);\n}\n\nfunction* lastNDays(n: number, endInclusive: Date): Generator<string> {\n\tconst end = new Date(endInclusive);\n\tfor (let i = n - 1; i >= 0; i--) {\n\t\tconst d = new Date(end);\n\t\td.setUTCDate(d.getUTCDate() - i);\n\t\tyield toDayKey(d);\n\t}\n}\n\nfunction computeActiveHours(\n\tperiodStart: Date,\n\tnow: Date,\n\ttenant: {\n\t\tcreated_at: Date;\n\t\tlast_active_at: Date;\n\t\tstatus: string;\n\t},\n): number {\n\tif (tenant.status !== \"active\") return 0;\n\tconst rangeStart = Math.max(\n\t\tperiodStart.getTime(),\n\t\ttenant.created_at.getTime(),\n\t);\n\tconst rangeEnd = Math.min(\n\t\tnow.getTime(),\n\t\ttenant.last_active_at.getTime() + IDLE_GRACE_MS,\n\t);\n\tif (rangeEnd <= rangeStart) return 0;\n\treturn (rangeEnd - rangeStart) / (1000 * 60 * 60);\n}\n\nfunction pct(used: number, allowance: number): number {\n\tif (!Number.isFinite(allowance) || allowance <= 0) return 0;\n\treturn Math.min((used / allowance) * 100, 100);\n}\n\n// ── Queries ──────────────────────────────────────────────────────────\n\nexport async function getComputeUsage(\n\tdb: Kysely<Database>,\n\taccountId: string,\n\tplan: string,\n\tperiodStart: Date,\n\tnow: Date = new Date(),\n): Promise<ComputeUsage> {\n\tconst tenants = await db\n\t\t.selectFrom(\"tenants\")\n\t\t.select([\"id\", \"cpus\", \"status\", \"created_at\", \"last_active_at\"])\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"!=\", \"deleted\")\n\t\t.execute();\n\n\tlet totalHours = 0;\n\tfor (const t of tenants) {\n\t\tconst hours = computeActiveHours(periodStart, now, {\n\t\t\tcreated_at: t.created_at,\n\t\t\tlast_active_at: t.last_active_at,\n\t\t\tstatus: String(t.status),\n\t\t});\n\t\ttotalHours += hours * Number(t.cpus);\n\t}\n\n\tconst allowance = getComputeAllowanceHours(plan);\n\n\t// 14-day sparkline: bucket the same formula per-day.\n\tconst sparkline: SparklinePoint[] = [];\n\tfor (const day of lastNDays(14, now)) {\n\t\tconst dayStart = new Date(`${day}T00:00:00.000Z`);\n\t\tconst dayEnd = new Date(`${day}T23:59:59.999Z`);\n\t\tlet dayHours = 0;\n\t\tfor (const t of tenants) {\n\t\t\tconst hours = computeActiveHours(dayStart, dayEnd, {\n\t\t\t\tcreated_at: t.created_at,\n\t\t\t\tlast_active_at: t.last_active_at,\n\t\t\t\tstatus: String(t.status),\n\t\t\t});\n\t\t\tdayHours += Math.min(hours, 24) * Number(t.cpus);\n\t\t}\n\t\tsparkline.push({ day, value: dayHours });\n\t}\n\n\treturn {\n\t\tusedHours: totalHours,\n\t\tallowanceHours: allowance,\n\t\tpct: pct(totalHours, allowance),\n\t\tsparkline,\n\t};\n}\n\nexport async function getStorageUsage(\n\tdb: Kysely<Database>,\n\taccountId: string,\n\tplan: string,\n\tnow: Date = new Date(),\n): Promise<StorageUsage> {\n\t// Current usage: sum of tenants.storage_used_mb for this account.\n\tconst current = await db\n\t\t.selectFrom(\"tenants\")\n\t\t.select(sql<string>`COALESCE(SUM(storage_used_mb), 0)`.as(\"mb\"))\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"!=\", \"deleted\")\n\t\t.executeTakeFirst();\n\n\tconst usedBytes = Number(current?.mb ?? 0) * BYTES_PER_MB;\n\tconst allowance = getStorageAllowanceBytes(plan);\n\n\t// 14-day sparkline: per-month snapshots only — fall back to a flat\n\t// line at the current value. When per-day storage history lands, swap\n\t// this for a real bucket query.\n\tconst sparkline: SparklinePoint[] = [];\n\tfor (const day of lastNDays(14, now)) {\n\t\tsparkline.push({ day, value: Number(current?.mb ?? 0) });\n\t}\n\n\treturn {\n\t\tusedBytes,\n\t\tallowanceBytes: allowance,\n\t\tpct: pct(usedBytes, allowance),\n\t\tsparkline,\n\t};\n}\n\nexport async function getAiUsage(\n\t_db: Kysely<Database>,\n\t_accountId: string,\n\tplan: string,\n\t_periodStart: Date,\n\tnow: Date = new Date(),\n): Promise<AiUsage> {\n\tconst dailyCap = getAiCapForPlan(plan).evalsPerDay;\n\tconst sparkline: SparklinePoint[] = [];\n\tfor (const day of lastNDays(14, now)) sparkline.push({ day, value: 0 });\n\treturn { todayCount: 0, periodCount: 0, dailyCap, pct: 0, sparkline };\n}\n\nexport async function getProjectBreakdown(\n\tdb: Kysely<Database>,\n\taccountId: string,\n\tplan: string,\n\tperiodStart: Date,\n\tnow: Date = new Date(),\n): Promise<ProjectRow[]> {\n\tconst tenants = await db\n\t\t.selectFrom(\"tenants\")\n\t\t.select([\n\t\t\t\"id\",\n\t\t\t\"slug\",\n\t\t\t\"status\",\n\t\t\t\"cpus\",\n\t\t\t\"storage_used_mb\",\n\t\t\t\"created_at\",\n\t\t\t\"last_active_at\",\n\t\t])\n\t\t.where(\"account_id\", \"=\", accountId)\n\t\t.where(\"status\", \"!=\", \"deleted\")\n\t\t.orderBy(\"created_at\", \"desc\")\n\t\t.execute();\n\n\tif (tenants.length === 0) return [];\n\n\tconst aiByTenant = new Map<string, number>();\n\n\tconst computeAllowance = getComputeAllowanceHours(plan);\n\tconst storageAllowance = getStorageAllowanceBytes(plan);\n\tconst aiDailyCap = getAiCapForPlan(plan).evalsPerDay;\n\n\treturn tenants.map((t) => {\n\t\tconst hours =\n\t\t\tcomputeActiveHours(periodStart, now, {\n\t\t\t\tcreated_at: t.created_at,\n\t\t\t\tlast_active_at: t.last_active_at,\n\t\t\t\tstatus: String(t.status),\n\t\t\t}) * Number(t.cpus);\n\t\tconst bytes = Number(t.storage_used_mb ?? 0) * BYTES_PER_MB;\n\t\tconst todayAi = aiByTenant.get(t.id) ?? 0;\n\n\t\treturn {\n\t\t\tid: t.id,\n\t\t\tslug: t.slug,\n\t\t\tname: t.slug,\n\t\t\tstatus: String(t.status),\n\t\t\t// subgraphCount not tracked at account-DB level (subgraphs live on\n\t\t\t// per-tenant DBs). Left at 0; later pass can ping each tenant API.\n\t\t\tsubgraphCount: 0,\n\t\t\tcompute: { hours, pct: pct(hours, computeAllowance) },\n\t\t\tstorage: { bytes, pct: pct(bytes, storageAllowance) },\n\t\t\taiEvals: { todayCount: todayAi, pct: pct(todayAi, aiDailyCap) },\n\t\t};\n\t});\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "D94D306CAF5E896064756E2164756E21",
10
+ "names": []
11
+ }