@trendyvideo/billing 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/__tests__/billing-coverage.test.d.ts +2 -0
  2. package/dist/__tests__/billing-coverage.test.d.ts.map +1 -0
  3. package/dist/__tests__/billing-coverage.test.js +170 -0
  4. package/dist/__tests__/billing-coverage.test.js.map +1 -0
  5. package/dist/__tests__/plan-limits.test.d.ts +2 -0
  6. package/dist/__tests__/plan-limits.test.d.ts.map +1 -0
  7. package/dist/__tests__/plan-limits.test.js +139 -0
  8. package/dist/__tests__/plan-limits.test.js.map +1 -0
  9. package/dist/__tests__/pricing.test.d.ts +2 -0
  10. package/dist/__tests__/pricing.test.d.ts.map +1 -0
  11. package/dist/__tests__/pricing.test.js +146 -0
  12. package/dist/__tests__/pricing.test.js.map +1 -0
  13. package/dist/__tests__/usage-tracker.test.d.ts +2 -0
  14. package/dist/__tests__/usage-tracker.test.d.ts.map +1 -0
  15. package/dist/__tests__/usage-tracker.test.js +210 -0
  16. package/dist/__tests__/usage-tracker.test.js.map +1 -0
  17. package/dist/alerts.d.ts +19 -0
  18. package/dist/alerts.d.ts.map +1 -0
  19. package/dist/alerts.js +90 -0
  20. package/dist/alerts.js.map +1 -0
  21. package/dist/guards/project-guard.d.ts +6 -0
  22. package/dist/guards/project-guard.d.ts.map +1 -0
  23. package/dist/guards/project-guard.js +56 -0
  24. package/dist/guards/project-guard.js.map +1 -0
  25. package/dist/guards/resolution-guard.d.ts +6 -0
  26. package/dist/guards/resolution-guard.d.ts.map +1 -0
  27. package/dist/guards/resolution-guard.js +40 -0
  28. package/dist/guards/resolution-guard.js.map +1 -0
  29. package/dist/guards/seat-guard.d.ts +8 -0
  30. package/dist/guards/seat-guard.d.ts.map +1 -0
  31. package/dist/guards/seat-guard.js +55 -0
  32. package/dist/guards/seat-guard.js.map +1 -0
  33. package/dist/guards/social-guard.d.ts +6 -0
  34. package/dist/guards/social-guard.d.ts.map +1 -0
  35. package/dist/guards/social-guard.js +52 -0
  36. package/dist/guards/social-guard.js.map +1 -0
  37. package/dist/guards/storage-guard.d.ts +14 -0
  38. package/dist/guards/storage-guard.d.ts.map +1 -0
  39. package/dist/guards/storage-guard.js +85 -0
  40. package/dist/guards/storage-guard.js.map +1 -0
  41. package/dist/guards/stream-guard.d.ts +7 -0
  42. package/dist/guards/stream-guard.d.ts.map +1 -0
  43. package/dist/guards/stream-guard.js +73 -0
  44. package/dist/guards/stream-guard.js.map +1 -0
  45. package/dist/guards/watch-guard.d.ts +13 -0
  46. package/dist/guards/watch-guard.d.ts.map +1 -0
  47. package/dist/guards/watch-guard.js +71 -0
  48. package/dist/guards/watch-guard.js.map +1 -0
  49. package/dist/index.d.ts +16 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +49 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/plan-limits.d.ts +25 -0
  54. package/dist/plan-limits.d.ts.map +1 -0
  55. package/dist/plan-limits.js +138 -0
  56. package/dist/plan-limits.js.map +1 -0
  57. package/dist/pricing.d.ts +32 -0
  58. package/dist/pricing.d.ts.map +1 -0
  59. package/dist/pricing.js +126 -0
  60. package/dist/pricing.js.map +1 -0
  61. package/dist/types.d.ts +188 -0
  62. package/dist/types.d.ts.map +1 -0
  63. package/dist/types.js +3 -0
  64. package/dist/types.js.map +1 -0
  65. package/dist/usage-checker.d.ts +26 -0
  66. package/dist/usage-checker.d.ts.map +1 -0
  67. package/dist/usage-checker.js +295 -0
  68. package/dist/usage-checker.js.map +1 -0
  69. package/dist/usage-tracker.d.ts +25 -0
  70. package/dist/usage-tracker.d.ts.map +1 -0
  71. package/dist/usage-tracker.js +181 -0
  72. package/dist/usage-tracker.js.map +1 -0
  73. package/package.json +41 -0
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=billing-coverage.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-coverage.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/billing-coverage.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const vitest_1 = require("vitest");
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ /**
40
+ * Meta-test: scan the actual codebase to verify that every known cost point
41
+ * has a `recordUsage` call nearby in the source file.
42
+ *
43
+ * This catches regressions where a developer adds a new AI call but forgets
44
+ * to wire up billing.
45
+ */
46
+ const ROOT = path.resolve(__dirname, '..', '..', '..', '..');
47
+ const COST_POINTS = [
48
+ {
49
+ file: 'trendy-video-agent/src/websocket/connection-handler.ts',
50
+ description: 'Claude/Gemini conversation usage',
51
+ },
52
+ {
53
+ file: 'trendy-video-agent/src/tools/generate-voiceover.ts',
54
+ description: 'Chirp TTS usage',
55
+ },
56
+ {
57
+ file: 'trendy-video-agent/src/tools/check-generation-status.ts',
58
+ description: 'Veo video generation usage',
59
+ },
60
+ {
61
+ file: 'trendy-video-agent/src/tools/web-search.ts',
62
+ description: 'Brave web search usage',
63
+ },
64
+ {
65
+ file: 'trendy-video-agent/src/tools/download-youtube.ts',
66
+ description: 'YouTube download usage',
67
+ },
68
+ {
69
+ file: 'trendy-video-agent/src/tools/download-media.ts',
70
+ description: 'Media download usage',
71
+ },
72
+ {
73
+ file: 'trendy-video-agent/src/tools/screenshot-url.ts',
74
+ description: 'Playwright screenshot usage',
75
+ },
76
+ {
77
+ file: 'trendy-video-agent/src/tools/generate-image.ts',
78
+ description: 'Gemini image generation usage',
79
+ },
80
+ {
81
+ file: 'trendy-video-agent/src/tools/analyze-video.ts',
82
+ description: 'Gemini video analysis usage',
83
+ },
84
+ {
85
+ file: 'trendy-video-agent/src/agent/project-memory.ts',
86
+ description: 'Claude Haiku memory summarization usage',
87
+ },
88
+ {
89
+ file: 'trendy-chunk-analyzer/src/ChunkAnalyzerService.ts',
90
+ description: 'Gemini Flash chunk analysis usage',
91
+ },
92
+ {
93
+ file: 'trendy-chunk-analyzer/src/FileAnalyzerService.ts',
94
+ description: 'Gemini Pro file analysis usage',
95
+ },
96
+ {
97
+ file: 'trendy-chunk-analyzer/src/utils/embeddings.ts',
98
+ description: 'text-embedding-005 usage',
99
+ },
100
+ {
101
+ file: 'trendy-story-planner/src/StoryPlannerService.ts',
102
+ description: 'Gemini story planning usage',
103
+ },
104
+ {
105
+ file: 'trendy-longform-segmenter/src/TopicSegmenterService.ts',
106
+ description: 'Gemini topic segmentation usage',
107
+ },
108
+ {
109
+ file: 'trendy-longform-story-planner/src/LongformStoryPlannerService.ts',
110
+ description: 'Gemini longform story planning usage',
111
+ },
112
+ {
113
+ file: 'trendy-reviral/src/integrations/GeminiClient.ts',
114
+ description: 'ReViral Gemini usage',
115
+ },
116
+ {
117
+ file: 'trendy-reviral/src/integrations/VeoClient.ts',
118
+ description: 'ReViral Veo usage',
119
+ },
120
+ {
121
+ file: 'trendy-reviral/src/integrations/ChirpClient.ts',
122
+ description: 'ReViral Chirp TTS usage',
123
+ },
124
+ {
125
+ file: 'trendy-thumbnail-generator/src/NanoBananaClient.ts',
126
+ description: 'Thumbnail Gemini image generation usage',
127
+ },
128
+ {
129
+ file: 'trendy-thumbnail-generator/src/FrameAnalyzer.ts',
130
+ description: 'Thumbnail frame analysis (Gemini) usage',
131
+ },
132
+ ];
133
+ (0, vitest_1.describe)('billing coverage — recordUsage present at all cost points', () => {
134
+ for (const point of COST_POINTS) {
135
+ (0, vitest_1.it)(`${point.file} — ${point.description}`, () => {
136
+ const fullPath = path.join(ROOT, point.file);
137
+ (0, vitest_1.expect)(fs.existsSync(fullPath), `File must exist: ${point.file}`).toBe(true);
138
+ const content = fs.readFileSync(fullPath, 'utf-8');
139
+ const pattern = point.pattern ?? 'recordUsage';
140
+ if (typeof pattern === 'string') {
141
+ (0, vitest_1.expect)(content.includes(pattern), `${point.file} must contain "${pattern}" for billing tracking (${point.description})`).toBe(true);
142
+ }
143
+ else {
144
+ (0, vitest_1.expect)(pattern.test(content), `${point.file} must match ${pattern} for billing tracking (${point.description})`).toBe(true);
145
+ }
146
+ });
147
+ }
148
+ (0, vitest_1.it)('all cost point files import from @trendy/billing or ./pricing or billing package', () => {
149
+ for (const point of COST_POINTS) {
150
+ const fullPath = path.join(ROOT, point.file);
151
+ if (!fs.existsSync(fullPath))
152
+ continue;
153
+ const content = fs.readFileSync(fullPath, 'utf-8');
154
+ // The file should either:
155
+ // 1. Import recordUsage directly from @trendy/billing
156
+ // 2. Import from a local module that re-exports recordUsage
157
+ // 3. Call recordUsage from an injected/imported reference
158
+ const hasBillingImport = content.includes('@trendy/billing') ||
159
+ content.includes('recordUsage') ||
160
+ content.includes('billing');
161
+ (0, vitest_1.expect)(hasBillingImport, `${point.file} should reference billing/recordUsage`).toBe(true);
162
+ }
163
+ });
164
+ (0, vitest_1.it)('no duplicate cost points in the list', () => {
165
+ const files = COST_POINTS.map((p) => p.file);
166
+ const unique = new Set(files);
167
+ (0, vitest_1.expect)(files.length).toBe(unique.size);
168
+ });
169
+ });
170
+ //# sourceMappingURL=billing-coverage.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billing-coverage.test.js","sourceRoot":"","sources":["../../src/__tests__/billing-coverage.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plan-limits.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-limits.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/plan-limits.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const plan_limits_1 = require("../plan-limits");
5
+ const ALL_PLANS = ['free', 'creator', 'pro', 'agency'];
6
+ (0, vitest_1.describe)('PLAN_LIMITS', () => {
7
+ (0, vitest_1.it)('all 4 plans exist', () => {
8
+ for (const plan of ALL_PLANS) {
9
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS[plan], `${plan} plan must exist`).toBeDefined();
10
+ }
11
+ });
12
+ (0, vitest_1.it)('each plan has all required fields', () => {
13
+ const requiredFields = [
14
+ 'storageBytes',
15
+ 'rendersPerMonth',
16
+ 'streams',
17
+ 'projects',
18
+ 'socialAccounts',
19
+ 'maxResolution',
20
+ 'seats',
21
+ 'watermark',
22
+ 'maxWatches',
23
+ 'includedCredits',
24
+ 'overageCapCredits',
25
+ ];
26
+ for (const plan of ALL_PLANS) {
27
+ const limits = plan_limits_1.PLAN_LIMITS[plan];
28
+ for (const field of requiredFields) {
29
+ (0, vitest_1.expect)(limits[field], `${plan}.${field} must be defined`).toBeDefined();
30
+ }
31
+ }
32
+ });
33
+ (0, vitest_1.it)('free plan has watermark=true', () => {
34
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.free.watermark).toBe(true);
35
+ });
36
+ (0, vitest_1.it)('paid plans have watermark=false', () => {
37
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.creator.watermark).toBe(false);
38
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.pro.watermark).toBe(false);
39
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.agency.watermark).toBe(false);
40
+ });
41
+ (0, vitest_1.it)('credit limits increase with plan tier', () => {
42
+ const tiers = ALL_PLANS;
43
+ for (let i = 1; i < tiers.length; i++) {
44
+ const prev = plan_limits_1.PLAN_LIMITS[tiers[i - 1]];
45
+ const curr = plan_limits_1.PLAN_LIMITS[tiers[i]];
46
+ (0, vitest_1.expect)(curr.includedCredits, `${tiers[i]} includedCredits >= ${tiers[i - 1]}`).toBeGreaterThan(prev.includedCredits);
47
+ }
48
+ });
49
+ (0, vitest_1.it)('storage limits increase with plan tier', () => {
50
+ const tiers = ALL_PLANS;
51
+ for (let i = 1; i < tiers.length; i++) {
52
+ const prev = plan_limits_1.PLAN_LIMITS[tiers[i - 1]];
53
+ const curr = plan_limits_1.PLAN_LIMITS[tiers[i]];
54
+ (0, vitest_1.expect)(curr.storageBytes, `${tiers[i]} storage >= ${tiers[i - 1]}`).toBeGreaterThan(prev.storageBytes);
55
+ }
56
+ });
57
+ (0, vitest_1.it)('renders per month increase with plan tier', () => {
58
+ const tiers = ALL_PLANS;
59
+ for (let i = 1; i < tiers.length; i++) {
60
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS[tiers[i]].rendersPerMonth).toBeGreaterThan(plan_limits_1.PLAN_LIMITS[tiers[i - 1]].rendersPerMonth);
61
+ }
62
+ });
63
+ (0, vitest_1.it)('free plan has zero overage credit cap', () => {
64
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.free.overageCapCredits).toBe(0);
65
+ });
66
+ (0, vitest_1.it)('paid plans have positive overage credit caps', () => {
67
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.creator.overageCapCredits).toBeGreaterThan(0);
68
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.pro.overageCapCredits).toBeGreaterThan(0);
69
+ (0, vitest_1.expect)(plan_limits_1.PLAN_LIMITS.agency.overageCapCredits).toBeGreaterThan(0);
70
+ });
71
+ });
72
+ (0, vitest_1.describe)('normalizePlanName', () => {
73
+ (0, vitest_1.it)('maps legacy "starter" to "creator"', () => {
74
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('starter')).toBe('creator');
75
+ });
76
+ (0, vitest_1.it)('maps legacy "business" to "agency"', () => {
77
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('business')).toBe('agency');
78
+ });
79
+ (0, vitest_1.it)('passes through valid plan names', () => {
80
+ for (const plan of ALL_PLANS) {
81
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)(plan)).toBe(plan);
82
+ }
83
+ });
84
+ (0, vitest_1.it)('is case-insensitive', () => {
85
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('FREE')).toBe('free');
86
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('Creator')).toBe('creator');
87
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('PRO')).toBe('pro');
88
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('AGENCY')).toBe('agency');
89
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('Starter')).toBe('creator');
90
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('BUSINESS')).toBe('agency');
91
+ });
92
+ (0, vitest_1.it)('trims whitespace', () => {
93
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)(' pro ')).toBe('pro');
94
+ });
95
+ (0, vitest_1.it)('falls back to "free" for null/undefined', () => {
96
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)(null)).toBe('free');
97
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)(undefined)).toBe('free');
98
+ });
99
+ (0, vitest_1.it)('falls back to "free" for unknown names', () => {
100
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('enterprise')).toBe('free');
101
+ (0, vitest_1.expect)((0, plan_limits_1.normalizePlanName)('garbage')).toBe('free');
102
+ });
103
+ });
104
+ (0, vitest_1.describe)('getPlanLimits', () => {
105
+ (0, vitest_1.it)('returns correct limits for known plans', () => {
106
+ (0, vitest_1.expect)((0, plan_limits_1.getPlanLimits)('pro')).toEqual(plan_limits_1.PLAN_LIMITS.pro);
107
+ (0, vitest_1.expect)((0, plan_limits_1.getPlanLimits)('agency')).toEqual(plan_limits_1.PLAN_LIMITS.agency);
108
+ });
109
+ (0, vitest_1.it)('falls back to free for null/undefined', () => {
110
+ (0, vitest_1.expect)((0, plan_limits_1.getPlanLimits)(null)).toEqual(plan_limits_1.PLAN_LIMITS.free);
111
+ (0, vitest_1.expect)((0, plan_limits_1.getPlanLimits)(undefined)).toEqual(plan_limits_1.PLAN_LIMITS.free);
112
+ });
113
+ (0, vitest_1.it)('falls back to free for unknown plan', () => {
114
+ (0, vitest_1.expect)((0, plan_limits_1.getPlanLimits)('nonexistent')).toEqual(plan_limits_1.PLAN_LIMITS.free);
115
+ });
116
+ });
117
+ (0, vitest_1.describe)('formatBytes', () => {
118
+ (0, vitest_1.it)('formats zero', () => {
119
+ (0, vitest_1.expect)((0, plan_limits_1.formatBytes)(0)).toBe('0 B');
120
+ });
121
+ (0, vitest_1.it)('formats GB', () => {
122
+ (0, vitest_1.expect)((0, plan_limits_1.formatBytes)(1024 * 1024 * 1024)).toBe('1.0 GB');
123
+ });
124
+ (0, vitest_1.it)('formats TB', () => {
125
+ (0, vitest_1.expect)((0, plan_limits_1.formatBytes)(1024 * 1024 * 1024 * 1024)).toBe('1.0 TB');
126
+ });
127
+ });
128
+ (0, vitest_1.describe)('isResolutionAllowed', () => {
129
+ (0, vitest_1.it)('allows same resolution', () => {
130
+ (0, vitest_1.expect)((0, plan_limits_1.isResolutionAllowed)('1080p', '1080p')).toBe(true);
131
+ });
132
+ (0, vitest_1.it)('allows lower resolution', () => {
133
+ (0, vitest_1.expect)((0, plan_limits_1.isResolutionAllowed)('720p', '1080p')).toBe(true);
134
+ });
135
+ (0, vitest_1.it)('blocks higher resolution', () => {
136
+ (0, vitest_1.expect)((0, plan_limits_1.isResolutionAllowed)('4k', '1080p')).toBe(false);
137
+ });
138
+ });
139
+ //# sourceMappingURL=plan-limits.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-limits.test.js","sourceRoot":"","sources":["../../src/__tests__/plan-limits.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pricing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pricing.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const pricing_1 = require("../pricing");
5
+ (0, vitest_1.describe)('MODEL_PRICING', () => {
6
+ (0, vitest_1.it)('has valid pricing for every model entry', () => {
7
+ for (const [model, pricing] of Object.entries(pricing_1.MODEL_PRICING)) {
8
+ // Token-based models must have input > 0 OR be a flat-rate service
9
+ const isFlatRate = ['chirp-tts', 'veo-video-gen', 'gemini-3-pro-image-preview', 'gemini-3.1-flash-image-preview', 'render-engine', 'storage'].includes(model);
10
+ if (!isFlatRate) {
11
+ (0, vitest_1.expect)(pricing.input, `${model} input should be > 0`).toBeGreaterThan(0);
12
+ }
13
+ // All fields must be non-negative
14
+ (0, vitest_1.expect)(pricing.input).toBeGreaterThanOrEqual(0);
15
+ (0, vitest_1.expect)(pricing.output).toBeGreaterThanOrEqual(0);
16
+ (0, vitest_1.expect)(pricing.cacheRead).toBeGreaterThanOrEqual(0);
17
+ (0, vitest_1.expect)(pricing.cacheWrite).toBeGreaterThanOrEqual(0);
18
+ }
19
+ });
20
+ (0, vitest_1.it)('flat-rate services have zeroed token prices', () => {
21
+ for (const model of ['chirp-tts', 'veo-video-gen']) {
22
+ const p = pricing_1.MODEL_PRICING[model];
23
+ (0, vitest_1.expect)(p, `${model} must exist in MODEL_PRICING`).toBeDefined();
24
+ (0, vitest_1.expect)(p.input).toBe(0);
25
+ (0, vitest_1.expect)(p.output).toBe(0);
26
+ }
27
+ });
28
+ (0, vitest_1.it)('text-embedding-005 has input pricing but no output pricing', () => {
29
+ const p = pricing_1.MODEL_PRICING['text-embedding-005'];
30
+ (0, vitest_1.expect)(p).toBeDefined();
31
+ (0, vitest_1.expect)(p.input).toBeGreaterThan(0);
32
+ (0, vitest_1.expect)(p.output).toBe(0);
33
+ });
34
+ });
35
+ (0, vitest_1.describe)('DEFAULT_PRICING', () => {
36
+ (0, vitest_1.it)('falls back to Claude Sonnet pricing', () => {
37
+ (0, vitest_1.expect)(pricing_1.DEFAULT_PRICING.input).toBe(3);
38
+ (0, vitest_1.expect)(pricing_1.DEFAULT_PRICING.output).toBe(15);
39
+ (0, vitest_1.expect)(pricing_1.DEFAULT_PRICING.cacheRead).toBe(0.30);
40
+ (0, vitest_1.expect)(pricing_1.DEFAULT_PRICING.cacheWrite).toBe(3.75);
41
+ });
42
+ });
43
+ (0, vitest_1.describe)('getPricing', () => {
44
+ (0, vitest_1.it)('returns correct pricing for exact match', () => {
45
+ const p = (0, pricing_1.getPricing)('claude-sonnet-4-6');
46
+ (0, vitest_1.expect)(p.input).toBe(3);
47
+ (0, vitest_1.expect)(p.output).toBe(15);
48
+ });
49
+ (0, vitest_1.it)('returns correct pricing for another exact match', () => {
50
+ const p = (0, pricing_1.getPricing)('gemini-2.5-pro');
51
+ (0, vitest_1.expect)(p.input).toBe(1.25);
52
+ (0, vitest_1.expect)(p.output).toBe(10);
53
+ });
54
+ (0, vitest_1.it)('returns correct pricing for gemini-3.1-pro-preview', () => {
55
+ const p = (0, pricing_1.getPricing)('gemini-3.1-pro-preview');
56
+ (0, vitest_1.expect)(p.input).toBe(2.50);
57
+ (0, vitest_1.expect)(p.output).toBe(15);
58
+ });
59
+ (0, vitest_1.it)('returns correct pricing for gemini-3.1-pro-preview-customtools (same rate as vanilla Pro preview)', () => {
60
+ const p = (0, pricing_1.getPricing)('gemini-3.1-pro-preview-customtools');
61
+ (0, vitest_1.expect)(p.input).toBe(2.50);
62
+ (0, vitest_1.expect)(p.output).toBe(15);
63
+ });
64
+ (0, vitest_1.it)('returns correct pricing for gemini-3-flash-preview', () => {
65
+ const p = (0, pricing_1.getPricing)('gemini-3-flash-preview');
66
+ (0, vitest_1.expect)(p.input).toBe(0.30);
67
+ (0, vitest_1.expect)(p.output).toBe(2.50);
68
+ });
69
+ (0, vitest_1.it)('handles prefix matching (e.g. dated Gemini preview)', () => {
70
+ const p = (0, pricing_1.getPricing)('gemini-2.5-flash-preview-05-20');
71
+ (0, vitest_1.expect)(p.input).toBe(0.15);
72
+ (0, vitest_1.expect)(p.output).toBe(0.60);
73
+ });
74
+ (0, vitest_1.it)('handles prefix matching for Gemini Pro', () => {
75
+ const p = (0, pricing_1.getPricing)('gemini-2.5-pro-preview-06-01');
76
+ (0, vitest_1.expect)(p.input).toBe(1.25);
77
+ (0, vitest_1.expect)(p.output).toBe(10);
78
+ });
79
+ (0, vitest_1.it)('handles date suffix stripping (e.g. claude-sonnet-4-6-20260101)', () => {
80
+ const p = (0, pricing_1.getPricing)('claude-sonnet-4-6-20260101');
81
+ (0, vitest_1.expect)(p.input).toBe(3);
82
+ (0, vitest_1.expect)(p.output).toBe(15);
83
+ });
84
+ (0, vitest_1.it)('falls back to DEFAULT_PRICING for unknown models', () => {
85
+ const p = (0, pricing_1.getPricing)('completely-unknown-model');
86
+ (0, vitest_1.expect)(p).toEqual(pricing_1.DEFAULT_PRICING);
87
+ });
88
+ (0, vitest_1.it)('falls back to DEFAULT_PRICING for empty string', () => {
89
+ const p = (0, pricing_1.getPricing)('');
90
+ (0, vitest_1.expect)(p).toEqual(pricing_1.DEFAULT_PRICING);
91
+ });
92
+ });
93
+ (0, vitest_1.describe)('calculateCostMicrodollars', () => {
94
+ (0, vitest_1.it)('calculates correctly for known models', () => {
95
+ // pricing: input=3, output=15 per 1M tokens
96
+ // 1000 input * 3 = 3000, 500 output * 15 = 7500 => 10500
97
+ const cost = (0, pricing_1.calculateCostMicrodollars)('claude-sonnet-4-6', 1000, 500);
98
+ (0, vitest_1.expect)(cost).toBe(10500);
99
+ });
100
+ (0, vitest_1.it)('calculates correctly for Gemini 2.5 Pro', () => {
101
+ // pricing: input=1.25, output=10 per 1M tokens
102
+ // 1000 * 1.25 = 1250, 500 * 10 = 5000 => 6250
103
+ const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-2.5-pro', 1000, 500);
104
+ (0, vitest_1.expect)(cost).toBe(6250);
105
+ });
106
+ (0, vitest_1.it)('includes cache token costs', () => {
107
+ // claude-sonnet-4-6: cacheRead=0.30, cacheWrite=3.75
108
+ // 1000*3 + 500*15 + 200*0.30 + 100*3.75 = 3000+7500+60+375 = 10935
109
+ const cost = (0, pricing_1.calculateCostMicrodollars)('claude-sonnet-4-6', 1000, 500, 200, 100);
110
+ (0, vitest_1.expect)(cost).toBe(10935);
111
+ });
112
+ (0, vitest_1.it)('respects costMicrodollarsOverride', () => {
113
+ const cost = (0, pricing_1.calculateCostMicrodollars)('claude-sonnet-4-6', 1000, 500, 0, 0, 99999);
114
+ (0, vitest_1.expect)(cost).toBe(99999);
115
+ });
116
+ (0, vitest_1.it)('Chirp TTS: 1000 chars at 30 microdollars/char = 30000 via override', () => {
117
+ const cost = (0, pricing_1.calculateCostMicrodollars)('chirp-tts', 0, 0, 0, 0, 30000);
118
+ (0, vitest_1.expect)(cost).toBe(30000);
119
+ });
120
+ (0, vitest_1.it)('Veo: 8 sec clip at $0.40/sec = 3200000 microdollars via override', () => {
121
+ // $0.40/sec * 8 sec = $3.20 = 3,200,000 microdollars
122
+ const cost = (0, pricing_1.calculateCostMicrodollars)('veo-video-gen', 0, 0, 0, 0, 3_200_000);
123
+ (0, vitest_1.expect)(cost).toBe(3_200_000);
124
+ });
125
+ (0, vitest_1.it)('returns 0 for flat-rate services with no override', () => {
126
+ // chirp-tts has all-zero pricing, so without override it calculates 0
127
+ const cost = (0, pricing_1.calculateCostMicrodollars)('chirp-tts', 1000, 0);
128
+ (0, vitest_1.expect)(cost).toBe(0);
129
+ });
130
+ (0, vitest_1.it)('rounds to nearest integer', () => {
131
+ // gemini-1.5-flash: input=0.075
132
+ // 1 token * 0.075 = 0.075 => rounds to 0
133
+ const cost = (0, pricing_1.calculateCostMicrodollars)('gemini-1.5-flash', 1, 0);
134
+ (0, vitest_1.expect)(cost).toBe(0);
135
+ // 10 tokens * 0.075 = 0.75 => rounds to 1
136
+ const cost2 = (0, pricing_1.calculateCostMicrodollars)('gemini-1.5-flash', 10, 0);
137
+ (0, vitest_1.expect)(cost2).toBe(1);
138
+ });
139
+ (0, vitest_1.it)('uses DEFAULT_PRICING for unknown models', () => {
140
+ // default: input=3, output=15
141
+ // 1000*3 + 500*15 = 10500
142
+ const cost = (0, pricing_1.calculateCostMicrodollars)('unknown-model', 1000, 500);
143
+ (0, vitest_1.expect)(cost).toBe(10500);
144
+ });
145
+ });
146
+ //# sourceMappingURL=pricing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../../src/__tests__/pricing.test.ts"],"names":[],"mappings":";;AAAA,mCAA8C;AAC9C,wCAKoB;AAEpB,IAAA,iBAAQ,EAAC,eAAe,EAAE,GAAG,EAAE;IAC7B,IAAA,WAAE,EAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,uBAAa,CAAC,EAAE,CAAC;YAC7D,mEAAmE;YACnE,MAAM,UAAU,GAAG,CAAC,WAAW,EAAE,eAAe,EAAE,4BAA4B,EAAE,gCAAgC,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;YAC9J,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,IAAA,eAAM,EAAC,OAAO,CAAC,KAAK,EAAE,GAAG,KAAK,sBAAsB,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC3E,CAAC;YACD,kCAAkC;YAClC,IAAA,eAAM,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YAChD,IAAA,eAAM,EAAC,OAAO,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACjD,IAAA,eAAM,EAAC,OAAO,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;YACpD,IAAA,eAAM,EAAC,OAAO,CAAC,UAAU,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,KAAK,MAAM,KAAK,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,EAAE,CAAC;YACnD,MAAM,CAAC,GAAG,uBAAa,CAAC,KAAK,CAAC,CAAC;YAC/B,IAAA,eAAM,EAAC,CAAC,EAAE,GAAG,KAAK,8BAA8B,CAAC,CAAC,WAAW,EAAE,CAAC;YAChE,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACxB,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,GAAG,uBAAa,CAAC,oBAAoB,CAAC,CAAC;QAC9C,IAAA,eAAM,EAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACxB,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACnC,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAA,WAAE,EAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,IAAA,eAAM,EAAC,yBAAe,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACtC,IAAA,eAAM,EAAC,yBAAe,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxC,IAAA,eAAM,EAAC,yBAAe,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,IAAA,eAAM,EAAC,yBAAe,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,IAAA,WAAE,EAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,mBAAmB,CAAC,CAAC;QAC1C,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,gBAAgB,CAAC,CAAC;QACvC,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,wBAAwB,CAAC,CAAC;QAC/C,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mGAAmG,EAAE,GAAG,EAAE;QAC3G,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,oCAAoC,CAAC,CAAC;QAC3D,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,wBAAwB,CAAC,CAAC;QAC/C,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,gCAAgC,CAAC,CAAC;QACvD,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,8BAA8B,CAAC,CAAC;QACrD,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,4BAA4B,CAAC,CAAC;QACnD,IAAA,eAAM,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxB,IAAA,eAAM,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,0BAA0B,CAAC,CAAC;QACjD,IAAA,eAAM,EAAC,CAAC,CAAC,CAAC,OAAO,CAAC,yBAAe,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,IAAA,oBAAU,EAAC,EAAE,CAAC,CAAC;QACzB,IAAA,eAAM,EAAC,CAAC,CAAC,CAAC,OAAO,CAAC,yBAAe,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,IAAA,iBAAQ,EAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,IAAA,WAAE,EAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,4CAA4C;QAC5C,yDAAyD;QACzD,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,mBAAmB,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACvE,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,+CAA+C;QAC/C,8CAA8C;QAC9C,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,gBAAgB,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACpE,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,qDAAqD;QACrD,mEAAmE;QACnE,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,mBAAmB,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACjF,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,mBAAmB,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACpF,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,WAAW,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;QACvE,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,qDAAqD;QACrD,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,eAAe,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;QAC/E,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,sEAAsE;QACtE,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC7D,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,gCAAgC;QAChC,yCAAyC;QACzC,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACjE,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAErB,0CAA0C;QAC1C,MAAM,KAAK,GAAG,IAAA,mCAAyB,EAAC,kBAAkB,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,IAAA,WAAE,EAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,8BAA8B;QAC9B,0BAA0B;QAC1B,MAAM,IAAI,GAAG,IAAA,mCAAyB,EAAC,eAAe,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QACnE,IAAA,eAAM,EAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=usage-tracker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-tracker.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/usage-tracker.test.ts"],"names":[],"mappings":""}