burnwatch 0.2.0 → 0.4.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.
- package/CHANGELOG.md +24 -0
- package/dist/cli.js +376 -134
- package/dist/cli.js.map +1 -1
- package/dist/cost-impact.d.ts +23 -0
- package/dist/cost-impact.js +281 -0
- package/dist/cost-impact.js.map +1 -0
- package/dist/detector-C4LnLT-O.d.ts +28 -0
- package/dist/hooks/on-file-change.js +324 -6
- package/dist/hooks/on-file-change.js.map +1 -1
- package/dist/hooks/on-prompt.js +2 -1
- package/dist/hooks/on-prompt.js.map +1 -1
- package/dist/hooks/on-session-start.js +114 -27
- package/dist/hooks/on-session-start.js.map +1 -1
- package/dist/hooks/on-stop.js +47 -3
- package/dist/hooks/on-stop.js.map +1 -1
- package/dist/index.d.ts +5 -159
- package/dist/index.js +352 -27
- package/dist/index.js.map +1 -1
- package/dist/interactive-init.d.ts +20 -0
- package/dist/interactive-init.js +239 -0
- package/dist/interactive-init.js.map +1 -0
- package/dist/mcp-server.js +106 -27
- package/dist/mcp-server.js.map +1 -1
- package/dist/types-fDMu4rOd.d.ts +178 -0
- package/package.json +1 -1
- package/registry.json +89 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confidence tiers for spend tracking.
|
|
3
|
+
*
|
|
4
|
+
* LIVE — Real billing API data
|
|
5
|
+
* CALC — Fixed monthly cost, user-entered
|
|
6
|
+
* EST — Estimated from usage signals + pricing formula
|
|
7
|
+
* BLIND — Detected in project, no tracking configured
|
|
8
|
+
*/
|
|
9
|
+
type ConfidenceTier = "live" | "calc" | "est" | "blind" | "excluded";
|
|
10
|
+
declare const CONFIDENCE_BADGES: Record<ConfidenceTier, string>;
|
|
11
|
+
/** How a service charges — determines tracking strategy. */
|
|
12
|
+
type BillingModel = "token_usage" | "credit_pool" | "per_unit" | "percentage" | "flat_monthly" | "tiered" | "compute" | "unknown";
|
|
13
|
+
/** How cost scales — helps the agent reason about future spend. */
|
|
14
|
+
type ScalingShape = "linear" | "linear_burndown" | "tiered_jump" | "percentage" | "fixed" | "unknown";
|
|
15
|
+
/** A plan tier option for a service in the registry. */
|
|
16
|
+
interface PlanTier {
|
|
17
|
+
/** Human-readable plan name */
|
|
18
|
+
name: string;
|
|
19
|
+
/** Plan type: usage (pay-as-you-go), flat (fixed monthly), exclude (don't track) */
|
|
20
|
+
type: "usage" | "flat" | "exclude";
|
|
21
|
+
/** Monthly base cost for flat plans */
|
|
22
|
+
monthlyBase?: number;
|
|
23
|
+
/** Whether this plan requires an API key for tracking */
|
|
24
|
+
requiresKey?: boolean;
|
|
25
|
+
/** Whether this is the default/most common plan */
|
|
26
|
+
default?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** Risk category for service grouping in interactive init. */
|
|
29
|
+
type ServiceRiskCategory = "llm" | "usage" | "infra" | "flat";
|
|
30
|
+
/** A service definition from the registry. */
|
|
31
|
+
interface ServiceDefinition {
|
|
32
|
+
/** Unique service identifier */
|
|
33
|
+
id: string;
|
|
34
|
+
/** Human-readable name */
|
|
35
|
+
name: string;
|
|
36
|
+
/** Package names in npm/pip that indicate this service */
|
|
37
|
+
packageNames: string[];
|
|
38
|
+
/** Env var patterns that indicate this service */
|
|
39
|
+
envPatterns: string[];
|
|
40
|
+
/** Import patterns to scan for (regex strings) */
|
|
41
|
+
importPatterns: string[];
|
|
42
|
+
/** Keywords that indicate mentions in prompts */
|
|
43
|
+
mentionKeywords: string[];
|
|
44
|
+
/** Billing model */
|
|
45
|
+
billingModel: BillingModel;
|
|
46
|
+
/** How cost scales */
|
|
47
|
+
scalingShape: ScalingShape;
|
|
48
|
+
/** What tier of tracking is available */
|
|
49
|
+
apiTier: ConfidenceTier;
|
|
50
|
+
/** Billing API endpoint, if available */
|
|
51
|
+
apiEndpoint?: string;
|
|
52
|
+
/** Pricing details */
|
|
53
|
+
pricing?: {
|
|
54
|
+
/** Human-readable formula */
|
|
55
|
+
formula?: string;
|
|
56
|
+
/** Rate per unit, if applicable */
|
|
57
|
+
unitRate?: number;
|
|
58
|
+
/** Unit name (token, credit, email, session, etc.) */
|
|
59
|
+
unitName?: string;
|
|
60
|
+
/** Monthly base cost, if flat */
|
|
61
|
+
monthlyBase?: number;
|
|
62
|
+
};
|
|
63
|
+
/** Known gotchas that affect cost */
|
|
64
|
+
gotchas?: string[];
|
|
65
|
+
/** Alternative services (free or cheaper) */
|
|
66
|
+
alternatives?: string[];
|
|
67
|
+
/** Documentation URL */
|
|
68
|
+
docsUrl?: string;
|
|
69
|
+
/** Last time pricing was verified */
|
|
70
|
+
lastVerified?: string;
|
|
71
|
+
/** Notes about recent pricing changes */
|
|
72
|
+
pricingNotes?: string;
|
|
73
|
+
/** Available plan tiers for interactive init */
|
|
74
|
+
plans?: PlanTier[];
|
|
75
|
+
/** Whether the plan can be auto-detected from an API key */
|
|
76
|
+
autoDetectPlan?: boolean;
|
|
77
|
+
}
|
|
78
|
+
/** A tracked service instance — a service definition + user config. */
|
|
79
|
+
interface TrackedService {
|
|
80
|
+
/** Service definition ID */
|
|
81
|
+
serviceId: string;
|
|
82
|
+
/** How this service was detected */
|
|
83
|
+
detectedVia: DetectionSource[];
|
|
84
|
+
/** User-configured monthly budget */
|
|
85
|
+
budget?: number;
|
|
86
|
+
/** Whether the user has provided an API/billing key */
|
|
87
|
+
hasApiKey: boolean;
|
|
88
|
+
/** Override confidence tier (e.g., user provided billing key upgrades to LIVE) */
|
|
89
|
+
tierOverride?: ConfidenceTier;
|
|
90
|
+
/** User-entered monthly plan cost (for CALC tier) */
|
|
91
|
+
planCost?: number;
|
|
92
|
+
/** When this service was first detected */
|
|
93
|
+
firstDetected: string;
|
|
94
|
+
/** Explicitly excluded from tracking by user */
|
|
95
|
+
excluded?: boolean;
|
|
96
|
+
/** Plan name selected during interactive init */
|
|
97
|
+
planName?: string;
|
|
98
|
+
}
|
|
99
|
+
type DetectionSource = "package_json" | "env_var" | "import_scan" | "prompt_mention" | "git_diff" | "manual";
|
|
100
|
+
/** A spend snapshot for a single service at a point in time. */
|
|
101
|
+
interface SpendSnapshot {
|
|
102
|
+
serviceId: string;
|
|
103
|
+
/** Current period spend (or estimate) */
|
|
104
|
+
spend: number;
|
|
105
|
+
/** Is the spend figure exact or estimated? */
|
|
106
|
+
isEstimate: boolean;
|
|
107
|
+
/** Confidence tier for this reading */
|
|
108
|
+
tier: ConfidenceTier;
|
|
109
|
+
/** Budget allocated */
|
|
110
|
+
budget?: number;
|
|
111
|
+
/** Percentage of budget consumed */
|
|
112
|
+
budgetPercent?: number;
|
|
113
|
+
/** Budget status */
|
|
114
|
+
status: "healthy" | "caution" | "over" | "unknown";
|
|
115
|
+
/** Human-readable status label */
|
|
116
|
+
statusLabel: string;
|
|
117
|
+
/** Raw data from billing API, if available */
|
|
118
|
+
raw?: Record<string, unknown>;
|
|
119
|
+
/** Timestamp of this snapshot */
|
|
120
|
+
timestamp: string;
|
|
121
|
+
}
|
|
122
|
+
/** The full spend brief, injected at session start. */
|
|
123
|
+
interface SpendBrief {
|
|
124
|
+
projectName: string;
|
|
125
|
+
generatedAt: string;
|
|
126
|
+
period: string;
|
|
127
|
+
services: SpendSnapshot[];
|
|
128
|
+
totalSpend: number;
|
|
129
|
+
totalIsEstimate: boolean;
|
|
130
|
+
estimateMargin: number;
|
|
131
|
+
untrackedCount: number;
|
|
132
|
+
alerts: SpendAlert[];
|
|
133
|
+
}
|
|
134
|
+
interface SpendAlert {
|
|
135
|
+
serviceId: string;
|
|
136
|
+
type: "over_budget" | "near_budget" | "new_service" | "stale_data" | "blind_service";
|
|
137
|
+
message: string;
|
|
138
|
+
severity: "warning" | "critical" | "info";
|
|
139
|
+
}
|
|
140
|
+
/** Ledger entry — one row in spend-ledger.md */
|
|
141
|
+
interface LedgerEntry {
|
|
142
|
+
serviceId: string;
|
|
143
|
+
serviceName: string;
|
|
144
|
+
spend: number;
|
|
145
|
+
isEstimate: boolean;
|
|
146
|
+
tier: ConfidenceTier;
|
|
147
|
+
budget?: number;
|
|
148
|
+
statusLabel: string;
|
|
149
|
+
}
|
|
150
|
+
/** Event logged to events.jsonl */
|
|
151
|
+
interface SpendEvent {
|
|
152
|
+
timestamp: string;
|
|
153
|
+
sessionId: string;
|
|
154
|
+
type: "session_start" | "session_end" | "service_detected" | "service_mentioned" | "spend_polled" | "budget_alert" | "ledger_written" | "cost_impact";
|
|
155
|
+
data: Record<string, unknown>;
|
|
156
|
+
}
|
|
157
|
+
/** A cost impact estimate for a file change. */
|
|
158
|
+
interface CostImpact {
|
|
159
|
+
serviceId: string;
|
|
160
|
+
serviceName: string;
|
|
161
|
+
filePath: string;
|
|
162
|
+
/** Number of SDK call sites found */
|
|
163
|
+
callCount: number;
|
|
164
|
+
/** Detected multipliers (loops, .map(), etc.) */
|
|
165
|
+
multipliers: string[];
|
|
166
|
+
/** Effective multiplier applied to call count */
|
|
167
|
+
multiplierFactor: number;
|
|
168
|
+
/** Estimated monthly invocations */
|
|
169
|
+
monthlyInvocations: number;
|
|
170
|
+
/** Low estimate monthly cost */
|
|
171
|
+
costLow: number;
|
|
172
|
+
/** High estimate monthly cost */
|
|
173
|
+
costHigh: number;
|
|
174
|
+
/** Gotcha-based cost range explanation */
|
|
175
|
+
rangeExplanation?: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export { type BillingModel as B, type CostImpact as C, type DetectionSource as D, type LedgerEntry as L, type PlanTier as P, type ServiceDefinition as S, type TrackedService as T, type SpendSnapshot as a, type SpendBrief as b, type ConfidenceTier as c, type SpendEvent as d, CONFIDENCE_BADGES as e, type ScalingShape as f, type ServiceRiskCategory as g, type SpendAlert as h };
|
package/package.json
CHANGED
package/registry.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./registry.schema.json",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"lastUpdated": "2026-03-24",
|
|
5
5
|
"services": {
|
|
6
6
|
"anthropic": {
|
|
@@ -18,6 +18,13 @@
|
|
|
18
18
|
"formula": "input_tokens * input_rate + output_tokens * output_rate",
|
|
19
19
|
"unitName": "token"
|
|
20
20
|
},
|
|
21
|
+
"plans": [
|
|
22
|
+
{ "name": "API Usage", "type": "usage", "requiresKey": true, "default": true },
|
|
23
|
+
{ "name": "Max ($100/mo)", "type": "flat", "monthlyBase": 100 },
|
|
24
|
+
{ "name": "Max ($200/mo)", "type": "flat", "monthlyBase": 200 },
|
|
25
|
+
{ "name": "Pro ($20/mo)", "type": "flat", "monthlyBase": 20 },
|
|
26
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
27
|
+
],
|
|
21
28
|
"gotchas": [
|
|
22
29
|
"Admin API key required for billing data — standard API key only allows inference",
|
|
23
30
|
"Costs vary significantly by model: Haiku ~$0.25/MTok, Sonnet ~$3/MTok, Opus ~$15/MTok"
|
|
@@ -41,6 +48,13 @@
|
|
|
41
48
|
"formula": "input_tokens * input_rate + output_tokens * output_rate",
|
|
42
49
|
"unitName": "token"
|
|
43
50
|
},
|
|
51
|
+
"plans": [
|
|
52
|
+
{ "name": "API Usage", "type": "usage", "requiresKey": true, "default": true },
|
|
53
|
+
{ "name": "ChatGPT Plus ($20/mo)", "type": "flat", "monthlyBase": 20 },
|
|
54
|
+
{ "name": "ChatGPT Pro ($200/mo)", "type": "flat", "monthlyBase": 200 },
|
|
55
|
+
{ "name": "ChatGPT Team ($25/user/mo)", "type": "flat", "monthlyBase": 25 },
|
|
56
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
57
|
+
],
|
|
44
58
|
"gotchas": [
|
|
45
59
|
"Organization-level API key may be needed for usage data",
|
|
46
60
|
"Image generation (DALL-E) billed per image, not per token"
|
|
@@ -63,6 +77,12 @@
|
|
|
63
77
|
"formula": "input_tokens * input_rate + output_tokens * output_rate",
|
|
64
78
|
"unitName": "token"
|
|
65
79
|
},
|
|
80
|
+
"plans": [
|
|
81
|
+
{ "name": "API Usage (pay-as-you-go)", "type": "usage", "requiresKey": false, "default": true },
|
|
82
|
+
{ "name": "Free tier (rate-limited)", "type": "flat", "monthlyBase": 0 },
|
|
83
|
+
{ "name": "Google One AI Premium ($20/mo)", "type": "flat", "monthlyBase": 20 },
|
|
84
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
85
|
+
],
|
|
66
86
|
"gotchas": [
|
|
67
87
|
"Free tier available with rate limits",
|
|
68
88
|
"No standalone billing API for AI Studio — check Google Cloud Console"
|
|
@@ -85,6 +105,11 @@
|
|
|
85
105
|
"formula": "tokens * rate_per_token",
|
|
86
106
|
"unitName": "token"
|
|
87
107
|
},
|
|
108
|
+
"plans": [
|
|
109
|
+
{ "name": "API Usage (pay-as-you-go)", "type": "usage", "requiresKey": false, "default": true },
|
|
110
|
+
{ "name": "Free tier (50M tokens)", "type": "flat", "monthlyBase": 0 },
|
|
111
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
112
|
+
],
|
|
88
113
|
"gotchas": [
|
|
89
114
|
"Embedding-only service — cost scales with document corpus size"
|
|
90
115
|
],
|
|
@@ -107,6 +132,12 @@
|
|
|
107
132
|
"formula": "base_plan + function_invocations + bandwidth + edge_requests",
|
|
108
133
|
"monthlyBase": 20
|
|
109
134
|
},
|
|
135
|
+
"plans": [
|
|
136
|
+
{ "name": "Hobby (Free)", "type": "flat", "monthlyBase": 0, "default": true },
|
|
137
|
+
{ "name": "Pro ($20/mo)", "type": "flat", "monthlyBase": 20 },
|
|
138
|
+
{ "name": "Enterprise (custom)", "type": "usage", "requiresKey": true },
|
|
139
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
140
|
+
],
|
|
110
141
|
"gotchas": [
|
|
111
142
|
"Pro plan is $20/mo base, but overages on functions, bandwidth, and edge requests can spike",
|
|
112
143
|
"Edge Function pricing differs from Serverless Function pricing",
|
|
@@ -131,6 +162,13 @@
|
|
|
131
162
|
"formula": "plan_base + storage_overage + bandwidth_overage + function_invocations",
|
|
132
163
|
"monthlyBase": 25
|
|
133
164
|
},
|
|
165
|
+
"plans": [
|
|
166
|
+
{ "name": "Free", "type": "flat", "monthlyBase": 0, "default": true },
|
|
167
|
+
{ "name": "Pro ($25/mo)", "type": "flat", "monthlyBase": 25 },
|
|
168
|
+
{ "name": "Team ($599/mo)", "type": "flat", "monthlyBase": 599 },
|
|
169
|
+
{ "name": "Enterprise (custom)", "type": "usage", "requiresKey": true },
|
|
170
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
171
|
+
],
|
|
134
172
|
"gotchas": [
|
|
135
173
|
"Storage charges accumulate even when idle",
|
|
136
174
|
"Database size can grow quickly with unoptimized queries or missing cleanup",
|
|
@@ -156,6 +194,10 @@
|
|
|
156
194
|
"unitRate": 0.029,
|
|
157
195
|
"unitName": "transaction"
|
|
158
196
|
},
|
|
197
|
+
"plans": [
|
|
198
|
+
{ "name": "Standard (2.9% + 30¢)", "type": "usage", "requiresKey": true, "default": true },
|
|
199
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
200
|
+
],
|
|
159
201
|
"gotchas": [
|
|
160
202
|
"2.9% + $0.30 per successful card charge — this is processing fees, not SaaS cost",
|
|
161
203
|
"International cards and currency conversion add extra fees",
|
|
@@ -181,6 +223,15 @@
|
|
|
181
223
|
"unitRate": 0.00015,
|
|
182
224
|
"unitName": "credit"
|
|
183
225
|
},
|
|
226
|
+
"plans": [
|
|
227
|
+
{ "name": "Discovery (Free, 1K credits)", "type": "flat", "monthlyBase": 0 },
|
|
228
|
+
{ "name": "Starter ($30/mo, 200K credits)", "type": "flat", "monthlyBase": 30 },
|
|
229
|
+
{ "name": "Scale ($80/mo, 1M credits)", "type": "flat", "monthlyBase": 80, "default": true },
|
|
230
|
+
{ "name": "Business ($200/mo, 5M credits)", "type": "flat", "monthlyBase": 200 },
|
|
231
|
+
{ "name": "Enterprise (custom)", "type": "usage", "requiresKey": true },
|
|
232
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
233
|
+
],
|
|
234
|
+
"autoDetectPlan": true,
|
|
184
235
|
"gotchas": [
|
|
185
236
|
"Anti-bot bypass options consume 5-25x base credits per request",
|
|
186
237
|
"JavaScript rendering adds extra credit cost",
|
|
@@ -204,6 +255,13 @@
|
|
|
204
255
|
"formula": "sessions * per_session_rate",
|
|
205
256
|
"unitName": "session"
|
|
206
257
|
},
|
|
258
|
+
"plans": [
|
|
259
|
+
{ "name": "Hobby (Free, 100 sessions)", "type": "flat", "monthlyBase": 0, "default": true },
|
|
260
|
+
{ "name": "Startup ($150/mo)", "type": "flat", "monthlyBase": 150 },
|
|
261
|
+
{ "name": "Scale ($600/mo)", "type": "flat", "monthlyBase": 600 },
|
|
262
|
+
{ "name": "Enterprise (custom)", "type": "usage", "requiresKey": false },
|
|
263
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
264
|
+
],
|
|
207
265
|
"gotchas": [
|
|
208
266
|
"Session duration affects cost — long-running browser sessions burn more",
|
|
209
267
|
"Concurrent session limits may cause queuing on lower plans"
|
|
@@ -227,6 +285,12 @@
|
|
|
227
285
|
"unitRate": 0.000002,
|
|
228
286
|
"unitName": "command"
|
|
229
287
|
},
|
|
288
|
+
"plans": [
|
|
289
|
+
{ "name": "Free (10K commands/day)", "type": "flat", "monthlyBase": 0, "default": true },
|
|
290
|
+
{ "name": "Pay-as-you-go", "type": "usage", "requiresKey": false },
|
|
291
|
+
{ "name": "Pro ($280/mo)", "type": "flat", "monthlyBase": 280 },
|
|
292
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
293
|
+
],
|
|
230
294
|
"gotchas": [
|
|
231
295
|
"Free tier includes 10K commands/day",
|
|
232
296
|
"Pay-as-you-go is $0.2 per 100K commands after free tier"
|
|
@@ -249,6 +313,12 @@
|
|
|
249
313
|
"formula": "emails_sent * per_email_rate",
|
|
250
314
|
"unitName": "email"
|
|
251
315
|
},
|
|
316
|
+
"plans": [
|
|
317
|
+
{ "name": "Free (100 emails/day)", "type": "flat", "monthlyBase": 0, "default": true },
|
|
318
|
+
{ "name": "Pro ($20/mo, 50K emails)", "type": "flat", "monthlyBase": 20 },
|
|
319
|
+
{ "name": "Enterprise ($400/mo)", "type": "flat", "monthlyBase": 400 },
|
|
320
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
321
|
+
],
|
|
252
322
|
"gotchas": [
|
|
253
323
|
"Free tier: 100 emails/day, 3000/month",
|
|
254
324
|
"Pro plan: $20/mo for 50K emails",
|
|
@@ -272,6 +342,13 @@
|
|
|
272
342
|
"formula": "plan_base + function_runs_overage",
|
|
273
343
|
"unitName": "function run"
|
|
274
344
|
},
|
|
345
|
+
"plans": [
|
|
346
|
+
{ "name": "Free (5K runs/mo)", "type": "flat", "monthlyBase": 0, "default": true },
|
|
347
|
+
{ "name": "Launch ($50/mo)", "type": "flat", "monthlyBase": 50 },
|
|
348
|
+
{ "name": "Growth ($150/mo)", "type": "flat", "monthlyBase": 150 },
|
|
349
|
+
{ "name": "Enterprise (custom)", "type": "usage", "requiresKey": false },
|
|
350
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
351
|
+
],
|
|
275
352
|
"gotchas": [
|
|
276
353
|
"Free tier: 24hr event history, community support",
|
|
277
354
|
"Cost scales with function step count, not just invocation count"
|
|
@@ -294,6 +371,11 @@
|
|
|
294
371
|
"formula": "events beyond free tier * per_event_rate",
|
|
295
372
|
"unitName": "event"
|
|
296
373
|
},
|
|
374
|
+
"plans": [
|
|
375
|
+
{ "name": "Free (1M events/mo)", "type": "flat", "monthlyBase": 0, "default": true },
|
|
376
|
+
{ "name": "Pay-as-you-go (usage-based)", "type": "usage", "requiresKey": false },
|
|
377
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
378
|
+
],
|
|
297
379
|
"gotchas": [
|
|
298
380
|
"Free tier: 1M events/month — generous but easy to exceed with high-traffic apps",
|
|
299
381
|
"Session replay, feature flags, and surveys have separate pricing",
|
|
@@ -316,6 +398,12 @@
|
|
|
316
398
|
"pricing": {
|
|
317
399
|
"formula": "Varies by service — S3, ECS, Lambda, etc. each have distinct pricing"
|
|
318
400
|
},
|
|
401
|
+
"plans": [
|
|
402
|
+
{ "name": "Pay-as-you-go", "type": "usage", "requiresKey": false, "default": true },
|
|
403
|
+
{ "name": "AWS Free Tier (12 months)", "type": "flat", "monthlyBase": 0 },
|
|
404
|
+
{ "name": "Set custom budget estimate", "type": "usage", "requiresKey": false },
|
|
405
|
+
{ "name": "Don't track for this project", "type": "exclude" }
|
|
406
|
+
],
|
|
319
407
|
"gotchas": [
|
|
320
408
|
"AWS Cost Explorer API exists but requires IAM permissions and is itself billed",
|
|
321
409
|
"Data transfer costs are the most common surprise on AWS bills",
|