@secondlayer/shared 6.4.5 → 6.6.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.
@@ -1,47 +0,0 @@
1
- import { createRequire } from "node:module";
2
- var __defProp = Object.defineProperty;
3
- var __returnValue = (v) => v;
4
- function __exportSetter(name, newValue) {
5
- this[name] = __returnValue.bind(null, newValue);
6
- }
7
- var __export = (target, all) => {
8
- for (var name in all)
9
- __defProp(target, name, {
10
- get: all[name],
11
- enumerable: true,
12
- configurable: true,
13
- set: __exportSetter.bind(all, name)
14
- });
15
- };
16
-
17
- // src/db/queries/tenant-compute-addons.ts
18
- import { sql } from "kysely";
19
- async function listActiveAddonsForTenant(db, tenantId, now = new Date) {
20
- return db.selectFrom("tenant_compute_addons").selectAll().where("tenant_id", "=", tenantId).where("effective_from", "<=", now).where((eb) => eb.or([
21
- eb("effective_until", "is", null),
22
- eb("effective_until", ">", now)
23
- ])).execute();
24
- }
25
- async function computeEffectiveCompute(db, tenantId, base, now = new Date) {
26
- const row = await db.selectFrom("tenant_compute_addons").select([
27
- sql`coalesce(sum(memory_mb_delta), 0)`.as("mem_delta"),
28
- sql`coalesce(sum(cpu_delta), 0)`.as("cpu_delta"),
29
- sql`coalesce(sum(storage_mb_delta), 0)`.as("stor_delta")
30
- ]).where("tenant_id", "=", tenantId).where("effective_from", "<=", now).where((eb) => eb.or([
31
- eb("effective_until", "is", null),
32
- eb("effective_until", ">", now)
33
- ])).executeTakeFirst();
34
- if (!row)
35
- return base;
36
- const cpus = base.cpus + Number(row.cpu_delta ?? 0);
37
- const memoryMb = base.memoryMb + Number(row.mem_delta ?? 0);
38
- const storageLimitMb = base.storageLimitMb === -1 ? -1 : base.storageLimitMb + Number(row.stor_delta ?? 0);
39
- return { cpus, memoryMb, storageLimitMb };
40
- }
41
- export {
42
- listActiveAddonsForTenant,
43
- computeEffectiveCompute
44
- };
45
-
46
- //# debugId=70D8508BE398EADC64756E2164756E21
47
- //# sourceMappingURL=tenant-compute-addons.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/db/queries/tenant-compute-addons.ts"],
4
- "sourcesContent": [
5
- "import { type Kysely, sql } from \"kysely\";\nimport type { Database, TenantComputeAddon } from \"../types.ts\";\n\n/**\n * Compute add-ons — extras on top of a plan's base spec.\n *\n * Effective compute is NEVER derived from just the `tenants.plan`\n * column — always run `computeEffectiveCompute(tenantId, planBase)`\n * to fold in active add-ons. Provisioning, resize, and Stripe metering\n * all share this source of truth.\n */\n\n/** Active = open-ended (effective_until IS NULL) OR not yet expired. */\nexport async function listActiveAddonsForTenant(\n\tdb: Kysely<Database>,\n\ttenantId: string,\n\tnow: Date = new Date(),\n): Promise<TenantComputeAddon[]> {\n\treturn db\n\t\t.selectFrom(\"tenant_compute_addons\")\n\t\t.selectAll()\n\t\t.where(\"tenant_id\", \"=\", tenantId)\n\t\t.where(\"effective_from\", \"<=\", now)\n\t\t.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"effective_until\", \"is\", null),\n\t\t\t\teb(\"effective_until\", \">\", now),\n\t\t\t]),\n\t\t)\n\t\t.execute();\n}\n\nexport interface ComputeSpec {\n\tcpus: number;\n\tmemoryMb: number;\n\tstorageLimitMb: number;\n}\n\n/**\n * Apply active add-ons on top of a base spec. `storageLimitMb` of -1\n * (enterprise unlimited) passes through unchanged — add-ons don't\n * further modify unlimited storage.\n */\nexport async function computeEffectiveCompute(\n\tdb: Kysely<Database>,\n\ttenantId: string,\n\tbase: ComputeSpec,\n\tnow: Date = new Date(),\n): Promise<ComputeSpec> {\n\tconst row = await db\n\t\t.selectFrom(\"tenant_compute_addons\")\n\t\t.select([\n\t\t\tsql<number>`coalesce(sum(memory_mb_delta), 0)`.as(\"mem_delta\"),\n\t\t\tsql<string>`coalesce(sum(cpu_delta), 0)`.as(\"cpu_delta\"),\n\t\t\tsql<number>`coalesce(sum(storage_mb_delta), 0)`.as(\"stor_delta\"),\n\t\t])\n\t\t.where(\"tenant_id\", \"=\", tenantId)\n\t\t.where(\"effective_from\", \"<=\", now)\n\t\t.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"effective_until\", \"is\", null),\n\t\t\t\teb(\"effective_until\", \">\", now),\n\t\t\t]),\n\t\t)\n\t\t.executeTakeFirst();\n\n\tif (!row) return base;\n\n\tconst cpus = base.cpus + Number(row.cpu_delta ?? 0);\n\tconst memoryMb = base.memoryMb + Number(row.mem_delta ?? 0);\n\tconst storageLimitMb =\n\t\tbase.storageLimitMb === -1\n\t\t\t? -1\n\t\t\t: base.storageLimitMb + Number(row.stor_delta ?? 0);\n\n\treturn { cpus, memoryMb, storageLimitMb };\n}\n"
6
- ],
7
- "mappings": ";;;;;;;;;;;;;;;;;AAAA;AAaA,eAAsB,yBAAyB,CAC9C,IACA,UACA,MAAY,IAAI,MACgB;AAAA,EAChC,OAAO,GACL,WAAW,uBAAuB,EAClC,UAAU,EACV,MAAM,aAAa,KAAK,QAAQ,EAChC,MAAM,kBAAkB,MAAM,GAAG,EACjC,MAAM,CAAC,OACP,GAAG,GAAG;AAAA,IACL,GAAG,mBAAmB,MAAM,IAAI;AAAA,IAChC,GAAG,mBAAmB,KAAK,GAAG;AAAA,EAC/B,CAAC,CACF,EACC,QAAQ;AAAA;AAcX,eAAsB,uBAAuB,CAC5C,IACA,UACA,MACA,MAAY,IAAI,MACO;AAAA,EACvB,MAAM,MAAM,MAAM,GAChB,WAAW,uBAAuB,EAClC,OAAO;AAAA,IACP,uCAA+C,GAAG,WAAW;AAAA,IAC7D,iCAAyC,GAAG,WAAW;AAAA,IACvD,wCAAgD,GAAG,YAAY;AAAA,EAChE,CAAC,EACA,MAAM,aAAa,KAAK,QAAQ,EAChC,MAAM,kBAAkB,MAAM,GAAG,EACjC,MAAM,CAAC,OACP,GAAG,GAAG;AAAA,IACL,GAAG,mBAAmB,MAAM,IAAI;AAAA,IAChC,GAAG,mBAAmB,KAAK,GAAG;AAAA,EAC/B,CAAC,CACF,EACC,iBAAiB;AAAA,EAEnB,IAAI,CAAC;AAAA,IAAK,OAAO;AAAA,EAEjB,MAAM,OAAO,KAAK,OAAO,OAAO,IAAI,aAAa,CAAC;AAAA,EAClD,MAAM,WAAW,KAAK,WAAW,OAAO,IAAI,aAAa,CAAC;AAAA,EAC1D,MAAM,iBACL,KAAK,mBAAmB,KACrB,KACA,KAAK,iBAAiB,OAAO,IAAI,cAAc,CAAC;AAAA,EAEpD,OAAO,EAAE,MAAM,UAAU,eAAe;AAAA;",
8
- "debugId": "70D8508BE398EADC64756E2164756E21",
9
- "names": []
10
- }
@@ -1,60 +0,0 @@
1
- /**
2
- * Single source of truth for plan tiers — capacity, price, display copy,
3
- * Stripe binding, and container allocations.
4
- *
5
- * Consumed by:
6
- * - Provisioner (`packages/provisioner/src/plans.ts` re-exports)
7
- * - API (`/api/accounts/usage` for allowance math + display)
8
- * - Web app (`/billing` page renders plan cards from this)
9
- *
10
- * Adding a tier? Add an entry to PLANS. Removing one? Drop here, run
11
- * the Stripe-side cleanup (archive lookup_key), and update env vars.
12
- */
13
- declare const BYTES_PER_GB: number;
14
- type AccountPlanId = "none" | PlanId;
15
- type PlanId = "launch" | "scale" | "enterprise";
16
- interface ContainerAlloc {
17
- memoryMb: number;
18
- cpus: number;
19
- }
20
- interface Plan {
21
- id: PlanId;
22
- displayName: string;
23
- /** Monthly subscription price in cents. null = custom (Enterprise). */
24
- monthlyPriceCents: number | null;
25
- /** Annual subscription price in cents. null = no self-serve annual price. */
26
- annualPriceCents: number | null;
27
- totalCpus: number;
28
- totalMemoryMb: number;
29
- /** Hard cap. -1 = unlimited (Enterprise). Storage overage bills past this. */
30
- storageLimitMb: number;
31
- containers: {
32
- postgres: ContainerAlloc
33
- api: ContainerAlloc
34
- processor: ContainerAlloc
35
- };
36
- /** Display-only. Marketing/short pitch. */
37
- tagline: string;
38
- /** Display-only. Bullet list on the plan card. */
39
- features: string[];
40
- /** Stripe `lookup_key` for monthly recurring tier price. null for enterprise. */
41
- stripeLookupKey: string | null;
42
- /** Stripe `lookup_key` for annual recurring tier price. null for enterprise. */
43
- stripeAnnualLookupKey: string | null;
44
- }
45
- /**
46
- * Split a compute envelope across (postgres, processor, api) containers.
47
- * Auto-biases PG-heavy (60/25/15) for sub-1GB totals.
48
- */
49
- declare function allocForTotals(totalMemoryMb: number, totalCpus: number): Plan["containers"];
50
- declare const PLANS: Record<PlanId, Plan>;
51
- declare const PLAN_IDS: readonly PlanId[];
52
- declare function getPlan(id: string): Plan;
53
- declare function isValidPlanId(id: string): id is PlanId;
54
- declare function getComputeAllowanceHours(_plan: string): number;
55
- declare function getStorageAllowanceBytes(plan: string): number;
56
- /** Paid tiers bill $2/GB over allowance. Accounts with no plan do not accrue overage. */
57
- declare function hasStorageOverage(plan: string): boolean;
58
- declare function getBasePriceCents(plan: string): number;
59
- declare function getPlanDisplayName(plan: string): string;
60
- export { isValidPlanId, hasStorageOverage, getStorageAllowanceBytes, getPlanDisplayName, getPlan, getComputeAllowanceHours, getBasePriceCents, allocForTotals, PlanId, Plan, PLAN_IDS, PLANS, ContainerAlloc, BYTES_PER_GB, AccountPlanId };
@@ -1,164 +0,0 @@
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 BYTES_PER_GB = 1024 ** 3;
19
- function alloc(totalMb, totalCpus) {
20
- return {
21
- postgres: {
22
- memoryMb: Math.floor(totalMb * 0.25),
23
- cpus: round2(totalCpus * 0.25)
24
- },
25
- processor: {
26
- memoryMb: Math.floor(totalMb * 0.55),
27
- cpus: round2(totalCpus * 0.55)
28
- },
29
- api: {
30
- memoryMb: Math.floor(totalMb * 0.2),
31
- cpus: round2(totalCpus * 0.2)
32
- }
33
- };
34
- }
35
- function allocTight(totalMb, totalCpus) {
36
- return {
37
- postgres: {
38
- memoryMb: Math.floor(totalMb * 0.6),
39
- cpus: round2(totalCpus * 0.6)
40
- },
41
- processor: {
42
- memoryMb: Math.floor(totalMb * 0.25),
43
- cpus: round2(totalCpus * 0.25)
44
- },
45
- api: {
46
- memoryMb: Math.floor(totalMb * 0.15),
47
- cpus: round2(totalCpus * 0.15)
48
- }
49
- };
50
- }
51
- function round2(n) {
52
- return Math.round(n * 100) / 100;
53
- }
54
- function allocForTotals(totalMemoryMb, totalCpus) {
55
- return totalMemoryMb < 1024 ? allocTight(totalMemoryMb, totalCpus) : alloc(totalMemoryMb, totalCpus);
56
- }
57
- var PLANS = {
58
- launch: {
59
- id: "launch",
60
- displayName: "Launch",
61
- monthlyPriceCents: 9900,
62
- annualPriceCents: 99000,
63
- totalCpus: 2,
64
- totalMemoryMb: 6144,
65
- storageLimitMb: 102400,
66
- containers: alloc(6144, 2),
67
- tagline: "Real product",
68
- features: [
69
- "2 vCPU · 6 GB RAM",
70
- "100 GB storage · always-on",
71
- "3-5 contracts",
72
- "Production reindex windows",
73
- "Spend caps + alerts",
74
- "Email support"
75
- ],
76
- stripeLookupKey: "secondlayer_launch_monthly",
77
- stripeAnnualLookupKey: "secondlayer_launch_yearly"
78
- },
79
- scale: {
80
- id: "scale",
81
- displayName: "Scale",
82
- monthlyPriceCents: 29900,
83
- annualPriceCents: 299000,
84
- totalCpus: 8,
85
- totalMemoryMb: 24576,
86
- storageLimitMb: 512000,
87
- containers: alloc(24576, 8),
88
- tagline: "Full indexing",
89
- features: [
90
- "8 vCPU · 24 GB RAM",
91
- "500 GB storage · always-on",
92
- "Heavy history + replay",
93
- "24h SLA · priority support"
94
- ],
95
- stripeLookupKey: "secondlayer_scale_monthly",
96
- stripeAnnualLookupKey: "secondlayer_scale_yearly"
97
- },
98
- enterprise: {
99
- id: "enterprise",
100
- displayName: "Enterprise",
101
- monthlyPriceCents: null,
102
- annualPriceCents: null,
103
- totalCpus: 16,
104
- totalMemoryMb: 65536,
105
- storageLimitMb: -1,
106
- containers: alloc(65536, 16),
107
- tagline: "Whatever needed",
108
- features: [
109
- "Custom compute + storage",
110
- "SLAs · regions · SSO",
111
- "Dedicated success engineer"
112
- ],
113
- stripeLookupKey: null,
114
- stripeAnnualLookupKey: null
115
- }
116
- };
117
- var PLAN_IDS = ["launch", "scale", "enterprise"];
118
- function getPlan(id) {
119
- const plan = PLANS[id];
120
- if (!plan)
121
- throw new Error(`Unknown plan: ${id}`);
122
- return plan;
123
- }
124
- function isValidPlanId(id) {
125
- return id in PLANS;
126
- }
127
- function getComputeAllowanceHours(_plan) {
128
- return Number.POSITIVE_INFINITY;
129
- }
130
- function getStorageAllowanceBytes(plan) {
131
- const planDef = PLANS[plan];
132
- if (!planDef)
133
- return 0;
134
- if (planDef.storageLimitMb < 0)
135
- return Number.POSITIVE_INFINITY;
136
- return planDef.storageLimitMb * 1024 * 1024;
137
- }
138
- function hasStorageOverage(plan) {
139
- return plan !== "none" && plan !== "enterprise";
140
- }
141
- function getBasePriceCents(plan) {
142
- const planDef = PLANS[plan];
143
- return planDef?.monthlyPriceCents ?? 0;
144
- }
145
- function getPlanDisplayName(plan) {
146
- const planDef = PLANS[plan];
147
- return planDef?.displayName ?? plan.charAt(0).toUpperCase() + plan.slice(1);
148
- }
149
- export {
150
- isValidPlanId,
151
- hasStorageOverage,
152
- getStorageAllowanceBytes,
153
- getPlanDisplayName,
154
- getPlan,
155
- getComputeAllowanceHours,
156
- getBasePriceCents,
157
- allocForTotals,
158
- PLAN_IDS,
159
- PLANS,
160
- BYTES_PER_GB
161
- };
162
-
163
- //# debugId=E8AD34879BFF76E564756E2164756E21
164
- //# sourceMappingURL=pricing.js.map
@@ -1,10 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/pricing.ts"],
4
- "sourcesContent": [
5
- "/**\n * Single source of truth for plan tiers — capacity, price, display copy,\n * Stripe binding, and container allocations.\n *\n * Consumed by:\n * - Provisioner (`packages/provisioner/src/plans.ts` re-exports)\n * - API (`/api/accounts/usage` for allowance math + display)\n * - Web app (`/billing` page renders plan cards from this)\n *\n * Adding a tier? Add an entry to PLANS. Removing one? Drop here, run\n * the Stripe-side cleanup (archive lookup_key), and update env vars.\n */\n\nconst BYTES_PER_GB: number = 1024 ** 3;\n\nexport type AccountPlanId = \"none\" | PlanId;\nexport type PlanId = \"launch\" | \"scale\" | \"enterprise\";\n\nexport interface ContainerAlloc {\n\tmemoryMb: number;\n\tcpus: number;\n}\n\nexport interface Plan {\n\tid: PlanId;\n\tdisplayName: string;\n\t/** Monthly subscription price in cents. null = custom (Enterprise). */\n\tmonthlyPriceCents: number | null;\n\t/** Annual subscription price in cents. null = no self-serve annual price. */\n\tannualPriceCents: number | null;\n\ttotalCpus: number;\n\ttotalMemoryMb: number;\n\t/** Hard cap. -1 = unlimited (Enterprise). Storage overage bills past this. */\n\tstorageLimitMb: number;\n\tcontainers: {\n\t\tpostgres: ContainerAlloc;\n\t\tapi: ContainerAlloc;\n\t\tprocessor: ContainerAlloc;\n\t};\n\t/** Display-only. Marketing/short pitch. */\n\ttagline: string;\n\t/** Display-only. Bullet list on the plan card. */\n\tfeatures: string[];\n\t/** Stripe `lookup_key` for monthly recurring tier price. null for enterprise. */\n\tstripeLookupKey: string | null;\n\t/** Stripe `lookup_key` for annual recurring tier price. null for enterprise. */\n\tstripeAnnualLookupKey: string | null;\n}\n\n// ── Allocation helpers ──────────────────────────────────────────────\n//\n// Allocation within a plan (3 containers per tenant):\n// Default split (paid tiers) — PG 25% / proc 55% / api 20%\n// Sub-1GB total — PG 60% / proc 25% / api 15%\n//\n// Why proc-heavy: the subgraph processor is CPU-bound during backfill\n// (event decode + handler exec + DB writes), while PG idles at <1% CPU\n// observed during steady-state indexing on Launch tier. The 2026-05-13\n// rebalance shifts CPU from idle PG to active proc to recover backfill\n// throughput regressed by the move from shared infra to per-tenant\n// containers — Launch went from 5 blocks/min → ~100 blocks/min just by\n// raising the proc's `--cpus` allotment.\n//\n// Docker memory limit is a hard cap (OOM kill on overage). CPU is a soft\n// cap via `--cpus` (throttling, not killing). Storage is monitored\n// separately and billed as overage — PG crashes if we hard-cap it.\n\nfunction alloc(totalMb: number, totalCpus: number): Plan[\"containers\"] {\n\treturn {\n\t\tpostgres: {\n\t\t\tmemoryMb: Math.floor(totalMb * 0.25),\n\t\t\tcpus: round2(totalCpus * 0.25),\n\t\t},\n\t\tprocessor: {\n\t\t\tmemoryMb: Math.floor(totalMb * 0.55),\n\t\t\tcpus: round2(totalCpus * 0.55),\n\t\t},\n\t\tapi: {\n\t\t\tmemoryMb: Math.floor(totalMb * 0.2),\n\t\t\tcpus: round2(totalCpus * 0.2),\n\t\t},\n\t};\n}\n\nfunction allocTight(totalMb: number, totalCpus: number): Plan[\"containers\"] {\n\treturn {\n\t\tpostgres: {\n\t\t\tmemoryMb: Math.floor(totalMb * 0.6),\n\t\t\tcpus: round2(totalCpus * 0.6),\n\t\t},\n\t\tprocessor: {\n\t\t\tmemoryMb: Math.floor(totalMb * 0.25),\n\t\t\tcpus: round2(totalCpus * 0.25),\n\t\t},\n\t\tapi: {\n\t\t\tmemoryMb: Math.floor(totalMb * 0.15),\n\t\t\tcpus: round2(totalCpus * 0.15),\n\t\t},\n\t};\n}\n\nfunction round2(n: number): number {\n\treturn Math.round(n * 100) / 100;\n}\n\n/**\n * Split a compute envelope across (postgres, processor, api) containers.\n * Auto-biases PG-heavy (60/25/15) for sub-1GB totals.\n */\nexport function allocForTotals(\n\ttotalMemoryMb: number,\n\ttotalCpus: number,\n): Plan[\"containers\"] {\n\treturn totalMemoryMb < 1024\n\t\t? allocTight(totalMemoryMb, totalCpus)\n\t\t: alloc(totalMemoryMb, totalCpus);\n}\n\n// ── Canonical plan data ─────────────────────────────────────────────\n\nexport const PLANS: Record<PlanId, Plan> = {\n\tlaunch: {\n\t\tid: \"launch\",\n\t\tdisplayName: \"Launch\",\n\t\tmonthlyPriceCents: 9_900, // $99\n\t\tannualPriceCents: 99_000, // 2 months free\n\t\ttotalCpus: 2,\n\t\ttotalMemoryMb: 6_144,\n\t\tstorageLimitMb: 102_400, // 100 GB\n\t\tcontainers: alloc(6_144, 2),\n\t\ttagline: \"Real product\",\n\t\tfeatures: [\n\t\t\t\"2 vCPU · 6 GB RAM\",\n\t\t\t\"100 GB storage · always-on\",\n\t\t\t\"3-5 contracts\",\n\t\t\t\"Production reindex windows\",\n\t\t\t\"Spend caps + alerts\",\n\t\t\t\"Email support\",\n\t\t],\n\t\tstripeLookupKey: \"secondlayer_launch_monthly\",\n\t\tstripeAnnualLookupKey: \"secondlayer_launch_yearly\",\n\t},\n\tscale: {\n\t\tid: \"scale\",\n\t\tdisplayName: \"Scale\",\n\t\tmonthlyPriceCents: 29_900, // $299\n\t\tannualPriceCents: 299_000, // 2 months free\n\t\ttotalCpus: 8,\n\t\ttotalMemoryMb: 24_576,\n\t\tstorageLimitMb: 512_000, // 500 GB\n\t\tcontainers: alloc(24_576, 8),\n\t\ttagline: \"Full indexing\",\n\t\tfeatures: [\n\t\t\t\"8 vCPU · 24 GB RAM\",\n\t\t\t\"500 GB storage · always-on\",\n\t\t\t\"Heavy history + replay\",\n\t\t\t\"24h SLA · priority support\",\n\t\t],\n\t\tstripeLookupKey: \"secondlayer_scale_monthly\",\n\t\tstripeAnnualLookupKey: \"secondlayer_scale_yearly\",\n\t},\n\tenterprise: {\n\t\tid: \"enterprise\",\n\t\tdisplayName: \"Enterprise\",\n\t\tmonthlyPriceCents: null,\n\t\tannualPriceCents: null,\n\t\ttotalCpus: 16,\n\t\ttotalMemoryMb: 65_536,\n\t\tstorageLimitMb: -1,\n\t\tcontainers: alloc(65_536, 16),\n\t\ttagline: \"Whatever needed\",\n\t\tfeatures: [\n\t\t\t\"Custom compute + storage\",\n\t\t\t\"SLAs · regions · SSO\",\n\t\t\t\"Dedicated success engineer\",\n\t\t],\n\t\tstripeLookupKey: null,\n\t\tstripeAnnualLookupKey: null,\n\t},\n};\n\nexport const PLAN_IDS: readonly PlanId[] = [\"launch\", \"scale\", \"enterprise\"];\n\nexport function getPlan(id: string): Plan {\n\tconst plan = (PLANS as Record<string, Plan | undefined>)[id];\n\tif (!plan) throw new Error(`Unknown plan: ${id}`);\n\treturn plan;\n}\n\nexport function isValidPlanId(id: string): id is PlanId {\n\treturn id in PLANS;\n}\n\n// ── Allowance helpers (used by /api/accounts/usage display) ─────────\n//\n// Compute is hard-capped by Docker `--cpus`, so there's no compute\n// overage billing. The function below returns ∞ for paid plans (display-\n// only — no metering).\n//\n// Storage IS metered and billed past the plan's allowance via the\n// `storage_gb_months` Stripe meter at $2/GB-mo.\n\nexport function getComputeAllowanceHours(_plan: string): number {\n\t// Compute overage was killed when we removed the `compute_hours` meter.\n\t// All plans are now hard-capped by Docker `--cpus`. ∞ here means \"no\n\t// overage tracked\" for display purposes.\n\treturn Number.POSITIVE_INFINITY;\n}\n\nexport function getStorageAllowanceBytes(plan: string): number {\n\tconst planDef = (PLANS as Record<string, Plan | undefined>)[plan];\n\tif (!planDef) return 0;\n\tif (planDef.storageLimitMb < 0) return Number.POSITIVE_INFINITY;\n\treturn planDef.storageLimitMb * 1024 * 1024;\n}\n\n/** Paid tiers bill $2/GB over allowance. Accounts with no plan do not accrue overage. */\nexport function hasStorageOverage(plan: string): boolean {\n\treturn plan !== \"none\" && plan !== \"enterprise\";\n}\n\nexport function getBasePriceCents(plan: string): number {\n\tconst planDef = (PLANS as Record<string, Plan | undefined>)[plan];\n\treturn planDef?.monthlyPriceCents ?? 0;\n}\n\nexport function getPlanDisplayName(plan: string): string {\n\tconst planDef = (PLANS as Record<string, Plan | undefined>)[plan];\n\treturn planDef?.displayName ?? plan.charAt(0).toUpperCase() + plan.slice(1);\n}\n\n// Re-export bytes-per-GB constant for callers that compute display values.\nexport { BYTES_PER_GB };\n"
6
- ],
7
- "mappings": "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",
8
- "debugId": "E8AD34879BFF76E564756E2164756E21",
9
- "names": []
10
- }