@pioneer-platform/markets 8.12.0 → 8.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,226 @@
1
+ "use strict";
2
+ /*
3
+ Token Bucket Refill Scheduler
4
+
5
+ Schedules daily token bucket refills at midnight UTC
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
41
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
42
+ return new (P || (P = Promise))(function (resolve, reject) {
43
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
44
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
45
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
46
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
47
+ });
48
+ };
49
+ var __generator = (this && this.__generator) || function (thisArg, body) {
50
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
51
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
52
+ function verb(n) { return function (v) { return step([n, v]); }; }
53
+ function step(op) {
54
+ if (f) throw new TypeError("Generator is already executing.");
55
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
56
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
57
+ if (y = 0, t) op = [op[0] & 2, t.value];
58
+ switch (op[0]) {
59
+ case 0: case 1: t = op; break;
60
+ case 4: _.label++; return { value: op[1], done: false };
61
+ case 5: _.label++; y = op[1]; op = [0]; continue;
62
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
63
+ default:
64
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
65
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
66
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
67
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
68
+ if (t[2]) _.ops.pop();
69
+ _.trys.pop(); continue;
70
+ }
71
+ op = body.call(thisArg, _);
72
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
73
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
74
+ }
75
+ };
76
+ Object.defineProperty(exports, "__esModule", { value: true });
77
+ exports.scheduleDailyRefill = scheduleDailyRefill;
78
+ exports.manualRefill = manualRefill;
79
+ exports.cancelRefillSchedule = cancelRefillSchedule;
80
+ exports.getNextRefillTime = getNextRefillTime;
81
+ exports.isRefillScheduled = isRefillScheduled;
82
+ var schedule = __importStar(require("node-schedule"));
83
+ var log = require('@pioneer-platform/loggerdog')();
84
+ var TAG = ' | RefillScheduler | ';
85
+ var refillJob = null;
86
+ /**
87
+ * Schedule daily token bucket refill at midnight UTC
88
+ */
89
+ function scheduleDailyRefill(manager, metricsLogger) {
90
+ var _this = this;
91
+ var tag = TAG + ' | scheduleDailyRefill | ';
92
+ // Cancel existing job if any
93
+ if (refillJob) {
94
+ refillJob.cancel();
95
+ log.info(tag, 'Cancelled existing refill job');
96
+ }
97
+ // Schedule for midnight UTC (0 0 * * *)
98
+ refillJob = schedule.scheduleJob('0 0 * * *', function () { return __awaiter(_this, void 0, void 0, function () {
99
+ var status_1, error_1;
100
+ return __generator(this, function (_a) {
101
+ switch (_a.label) {
102
+ case 0:
103
+ log.info(tag, '🔄 Daily token bucket refill starting...');
104
+ _a.label = 1;
105
+ case 1:
106
+ _a.trys.push([1, 6, , 9]);
107
+ return [4 /*yield*/, manager.refillAll()];
108
+ case 2:
109
+ _a.sent();
110
+ if (!metricsLogger) return [3 /*break*/, 4];
111
+ return [4 /*yield*/, metricsLogger.logAPICall({
112
+ apiName: 'system',
113
+ endpoint: '/refill',
114
+ success: true,
115
+ timestamp: new Date()
116
+ })];
117
+ case 3:
118
+ _a.sent();
119
+ _a.label = 4;
120
+ case 4: return [4 /*yield*/, manager.getAllStatus()];
121
+ case 5:
122
+ status_1 = _a.sent();
123
+ log.info(tag, '✅ Daily token bucket refill complete!');
124
+ log.info(tag, 'Bucket status:', status_1);
125
+ return [3 /*break*/, 9];
126
+ case 6:
127
+ error_1 = _a.sent();
128
+ log.error(tag, 'Failed to refill token buckets:', error_1);
129
+ if (!metricsLogger) return [3 /*break*/, 8];
130
+ return [4 /*yield*/, metricsLogger.logAPICall({
131
+ apiName: 'system',
132
+ endpoint: '/refill',
133
+ success: false,
134
+ error: error_1.message,
135
+ timestamp: new Date()
136
+ })];
137
+ case 7:
138
+ _a.sent();
139
+ _a.label = 8;
140
+ case 8: return [3 /*break*/, 9];
141
+ case 9: return [2 /*return*/];
142
+ }
143
+ });
144
+ }); });
145
+ log.info(tag, '✅ Scheduled daily token bucket refill at midnight UTC (cron: 0 0 * * *)');
146
+ // Log next refill time
147
+ var nextRun = refillJob.nextInvocation();
148
+ if (nextRun) {
149
+ log.info(tag, "Next refill scheduled for: ".concat(nextRun.toString()));
150
+ }
151
+ }
152
+ /**
153
+ * Manual refill trigger (for admin use)
154
+ */
155
+ function manualRefill(manager, metricsLogger) {
156
+ return __awaiter(this, void 0, void 0, function () {
157
+ var tag, error_2;
158
+ return __generator(this, function (_a) {
159
+ switch (_a.label) {
160
+ case 0:
161
+ tag = TAG + ' | manualRefill | ';
162
+ log.info(tag, 'Manual token bucket refill triggered');
163
+ _a.label = 1;
164
+ case 1:
165
+ _a.trys.push([1, 5, , 8]);
166
+ return [4 /*yield*/, manager.refillAll()];
167
+ case 2:
168
+ _a.sent();
169
+ if (!metricsLogger) return [3 /*break*/, 4];
170
+ return [4 /*yield*/, metricsLogger.logAPICall({
171
+ apiName: 'system',
172
+ endpoint: '/refill/manual',
173
+ success: true,
174
+ timestamp: new Date()
175
+ })];
176
+ case 3:
177
+ _a.sent();
178
+ _a.label = 4;
179
+ case 4:
180
+ log.info(tag, '✅ Manual refill complete');
181
+ return [3 /*break*/, 8];
182
+ case 5:
183
+ error_2 = _a.sent();
184
+ log.error(tag, 'Manual refill failed:', error_2);
185
+ if (!metricsLogger) return [3 /*break*/, 7];
186
+ return [4 /*yield*/, metricsLogger.logAPICall({
187
+ apiName: 'system',
188
+ endpoint: '/refill/manual',
189
+ success: false,
190
+ error: error_2.message,
191
+ timestamp: new Date()
192
+ })];
193
+ case 6:
194
+ _a.sent();
195
+ _a.label = 7;
196
+ case 7: throw error_2;
197
+ case 8: return [2 /*return*/];
198
+ }
199
+ });
200
+ });
201
+ }
202
+ /**
203
+ * Cancel scheduled refill job
204
+ */
205
+ function cancelRefillSchedule() {
206
+ if (refillJob) {
207
+ refillJob.cancel();
208
+ refillJob = null;
209
+ log.info(TAG, 'Cancelled refill schedule');
210
+ }
211
+ }
212
+ /**
213
+ * Get next refill time
214
+ */
215
+ function getNextRefillTime() {
216
+ if (refillJob) {
217
+ return refillJob.nextInvocation();
218
+ }
219
+ return null;
220
+ }
221
+ /**
222
+ * Check if refill is scheduled
223
+ */
224
+ function isRefillScheduled() {
225
+ return refillJob !== null;
226
+ }
@@ -0,0 +1,47 @@
1
+ import { Db } from 'mongodb';
2
+ export declare class TokenBucketManager {
3
+ private buckets;
4
+ private db;
5
+ private initialized;
6
+ constructor(db: Db);
7
+ /**
8
+ * Initialize all API buckets
9
+ */
10
+ initialize(): Promise<void>;
11
+ /**
12
+ * Check if manager is initialized
13
+ */
14
+ isInitialized(): boolean;
15
+ /**
16
+ * Try to consume tokens from specific API
17
+ */
18
+ tryConsume(apiName: string, count?: number): Promise<boolean>;
19
+ /**
20
+ * Get status of all buckets
21
+ */
22
+ getAllStatus(): Promise<Record<string, any>>;
23
+ /**
24
+ * Get status of specific bucket
25
+ */
26
+ getBucketStatus(apiName: string): Promise<any>;
27
+ /**
28
+ * Refill all buckets (scheduled job runs at midnight UTC)
29
+ */
30
+ refillAll(): Promise<void>;
31
+ /**
32
+ * Refill specific bucket
33
+ */
34
+ refillBucket(apiName: string): Promise<void>;
35
+ /**
36
+ * Get remaining tokens for API
37
+ */
38
+ getRemainingTokens(apiName: string): Promise<number>;
39
+ /**
40
+ * Get bucket configurations
41
+ */
42
+ getBucketConfigs(): Record<string, any>;
43
+ /**
44
+ * Get daily budget summary
45
+ */
46
+ getDailyBudgetSummary(): Promise<any>;
47
+ }
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ /*
3
+ Token Bucket Manager
4
+
5
+ Manages all API token buckets with realistic daily budgets
6
+ based on monthly cost targets
7
+ */
8
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
9
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
10
+ return new (P || (P = Promise))(function (resolve, reject) {
11
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
12
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
13
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
14
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
15
+ });
16
+ };
17
+ var __generator = (this && this.__generator) || function (thisArg, body) {
18
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
19
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
20
+ function verb(n) { return function (v) { return step([n, v]); }; }
21
+ function step(op) {
22
+ if (f) throw new TypeError("Generator is already executing.");
23
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
24
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
25
+ if (y = 0, t) op = [op[0] & 2, t.value];
26
+ switch (op[0]) {
27
+ case 0: case 1: t = op; break;
28
+ case 4: _.label++; return { value: op[1], done: false };
29
+ case 5: _.label++; y = op[1]; op = [0]; continue;
30
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
31
+ default:
32
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
33
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
34
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
35
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
36
+ if (t[2]) _.ops.pop();
37
+ _.trys.pop(); continue;
38
+ }
39
+ op = body.call(thisArg, _);
40
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
41
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
42
+ }
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.TokenBucketManager = void 0;
46
+ var token_bucket_1 = require("./token-bucket");
47
+ var log = require('@pioneer-platform/loggerdog')();
48
+ var TAG = ' | TokenBucketManager | ';
49
+ // REALISTIC daily allocations based on budget
50
+ // To stay within monthly budget limits
51
+ var REALISTIC_DAILY_BUDGETS = {
52
+ coingecko: 167, // To stay within $100/month ($0.02/call)
53
+ coinmarketcap: 111, // To stay within $50/month ($0.015/call)
54
+ coincap: 100 // To stay within $30/month ($0.01/call)
55
+ };
56
+ var TokenBucketManager = /** @class */ (function () {
57
+ function TokenBucketManager(db) {
58
+ this.initialized = false;
59
+ this.buckets = new Map();
60
+ this.db = db;
61
+ }
62
+ /**
63
+ * Initialize all API buckets
64
+ */
65
+ TokenBucketManager.prototype.initialize = function () {
66
+ return __awaiter(this, void 0, void 0, function () {
67
+ var tag, coingeckoBucket, cmcBucket, coincapBucket;
68
+ return __generator(this, function (_a) {
69
+ switch (_a.label) {
70
+ case 0:
71
+ tag = TAG + ' | initialize | ';
72
+ log.info(tag, 'Initializing token buckets for all APIs...');
73
+ coingeckoBucket = new token_bucket_1.TokenBucket({
74
+ apiName: 'coingecko',
75
+ capacity: REALISTIC_DAILY_BUDGETS.coingecko,
76
+ refillAmount: REALISTIC_DAILY_BUDGETS.coingecko,
77
+ refillInterval: 86400000, // 24 hours
78
+ tokensPerRequest: 1,
79
+ costPerToken: 0.02, // $0.02 per call
80
+ monthlyBudget: 100 // $100/month
81
+ }, this.db);
82
+ return [4 /*yield*/, coingeckoBucket.initialize()];
83
+ case 1:
84
+ _a.sent();
85
+ this.buckets.set('coingecko', coingeckoBucket);
86
+ cmcBucket = new token_bucket_1.TokenBucket({
87
+ apiName: 'coinmarketcap',
88
+ capacity: REALISTIC_DAILY_BUDGETS.coinmarketcap,
89
+ refillAmount: REALISTIC_DAILY_BUDGETS.coinmarketcap,
90
+ refillInterval: 86400000,
91
+ tokensPerRequest: 1,
92
+ costPerToken: 0.015, // $0.015 per call
93
+ monthlyBudget: 50 // $50/month
94
+ }, this.db);
95
+ return [4 /*yield*/, cmcBucket.initialize()];
96
+ case 2:
97
+ _a.sent();
98
+ this.buckets.set('coinmarketcap', cmcBucket);
99
+ coincapBucket = new token_bucket_1.TokenBucket({
100
+ apiName: 'coincap',
101
+ capacity: REALISTIC_DAILY_BUDGETS.coincap,
102
+ refillAmount: REALISTIC_DAILY_BUDGETS.coincap,
103
+ refillInterval: 86400000,
104
+ tokensPerRequest: 1,
105
+ costPerToken: 0.01, // $0.01 per call
106
+ monthlyBudget: 30 // $30/month
107
+ }, this.db);
108
+ return [4 /*yield*/, coincapBucket.initialize()];
109
+ case 3:
110
+ _a.sent();
111
+ this.buckets.set('coincap', coincapBucket);
112
+ this.initialized = true;
113
+ log.info(tag, "\u2705 Initialized ".concat(this.buckets.size, " token buckets"));
114
+ log.info(tag, "Daily budgets: CoinGecko=".concat(REALISTIC_DAILY_BUDGETS.coingecko, ", CMC=").concat(REALISTIC_DAILY_BUDGETS.coinmarketcap, ", CoinCap=").concat(REALISTIC_DAILY_BUDGETS.coincap));
115
+ log.info(tag, "Monthly target cost: $180 total ($100 + $50 + $30)");
116
+ return [2 /*return*/];
117
+ }
118
+ });
119
+ });
120
+ };
121
+ /**
122
+ * Check if manager is initialized
123
+ */
124
+ TokenBucketManager.prototype.isInitialized = function () {
125
+ return this.initialized;
126
+ };
127
+ /**
128
+ * Try to consume tokens from specific API
129
+ */
130
+ TokenBucketManager.prototype.tryConsume = function (apiName_1) {
131
+ return __awaiter(this, arguments, void 0, function (apiName, count) {
132
+ var bucket;
133
+ if (count === void 0) { count = 1; }
134
+ return __generator(this, function (_a) {
135
+ switch (_a.label) {
136
+ case 0:
137
+ if (!this.initialized) {
138
+ log.warn(TAG, 'TokenBucketManager not initialized, allowing request');
139
+ return [2 /*return*/, true]; // Allow requests if not initialized yet
140
+ }
141
+ bucket = this.buckets.get(apiName);
142
+ if (!bucket) {
143
+ log.error(TAG, "Unknown API: ".concat(apiName));
144
+ return [2 /*return*/, false];
145
+ }
146
+ return [4 /*yield*/, bucket.tryConsume(count)];
147
+ case 1: return [2 /*return*/, _a.sent()];
148
+ }
149
+ });
150
+ });
151
+ };
152
+ /**
153
+ * Get status of all buckets
154
+ */
155
+ TokenBucketManager.prototype.getAllStatus = function () {
156
+ return __awaiter(this, void 0, void 0, function () {
157
+ var status, _i, _a, _b, apiName, bucket, _c, _d;
158
+ return __generator(this, function (_e) {
159
+ switch (_e.label) {
160
+ case 0:
161
+ status = {};
162
+ _i = 0, _a = Array.from(this.buckets.entries());
163
+ _e.label = 1;
164
+ case 1:
165
+ if (!(_i < _a.length)) return [3 /*break*/, 4];
166
+ _b = _a[_i], apiName = _b[0], bucket = _b[1];
167
+ _c = status;
168
+ _d = apiName;
169
+ return [4 /*yield*/, bucket.getStatus()];
170
+ case 2:
171
+ _c[_d] = _e.sent();
172
+ _e.label = 3;
173
+ case 3:
174
+ _i++;
175
+ return [3 /*break*/, 1];
176
+ case 4: return [2 /*return*/, status];
177
+ }
178
+ });
179
+ });
180
+ };
181
+ /**
182
+ * Get status of specific bucket
183
+ */
184
+ TokenBucketManager.prototype.getBucketStatus = function (apiName) {
185
+ return __awaiter(this, void 0, void 0, function () {
186
+ var bucket;
187
+ return __generator(this, function (_a) {
188
+ switch (_a.label) {
189
+ case 0:
190
+ bucket = this.buckets.get(apiName);
191
+ if (!bucket) {
192
+ throw new Error("Unknown API: ".concat(apiName));
193
+ }
194
+ return [4 /*yield*/, bucket.getStatus()];
195
+ case 1: return [2 /*return*/, _a.sent()];
196
+ }
197
+ });
198
+ });
199
+ };
200
+ /**
201
+ * Refill all buckets (scheduled job runs at midnight UTC)
202
+ */
203
+ TokenBucketManager.prototype.refillAll = function () {
204
+ return __awaiter(this, void 0, void 0, function () {
205
+ var tag, _i, _a, _b, apiName, bucket;
206
+ return __generator(this, function (_c) {
207
+ switch (_c.label) {
208
+ case 0:
209
+ tag = TAG + ' | refillAll | ';
210
+ log.info(tag, 'Refilling all token buckets...');
211
+ _i = 0, _a = Array.from(this.buckets.entries());
212
+ _c.label = 1;
213
+ case 1:
214
+ if (!(_i < _a.length)) return [3 /*break*/, 4];
215
+ _b = _a[_i], apiName = _b[0], bucket = _b[1];
216
+ return [4 /*yield*/, bucket.refill()];
217
+ case 2:
218
+ _c.sent();
219
+ log.info(tag, "Refilled ".concat(apiName));
220
+ _c.label = 3;
221
+ case 3:
222
+ _i++;
223
+ return [3 /*break*/, 1];
224
+ case 4:
225
+ log.info(tag, '✅ All token buckets refilled');
226
+ return [2 /*return*/];
227
+ }
228
+ });
229
+ });
230
+ };
231
+ /**
232
+ * Refill specific bucket
233
+ */
234
+ TokenBucketManager.prototype.refillBucket = function (apiName) {
235
+ return __awaiter(this, void 0, void 0, function () {
236
+ var bucket;
237
+ return __generator(this, function (_a) {
238
+ switch (_a.label) {
239
+ case 0:
240
+ bucket = this.buckets.get(apiName);
241
+ if (!bucket) {
242
+ throw new Error("Unknown API: ".concat(apiName));
243
+ }
244
+ return [4 /*yield*/, bucket.refill()];
245
+ case 1:
246
+ _a.sent();
247
+ log.info(TAG, "Refilled ".concat(apiName));
248
+ return [2 /*return*/];
249
+ }
250
+ });
251
+ });
252
+ };
253
+ /**
254
+ * Get remaining tokens for API
255
+ */
256
+ TokenBucketManager.prototype.getRemainingTokens = function (apiName) {
257
+ return __awaiter(this, void 0, void 0, function () {
258
+ var bucket;
259
+ return __generator(this, function (_a) {
260
+ switch (_a.label) {
261
+ case 0:
262
+ bucket = this.buckets.get(apiName);
263
+ if (!bucket) {
264
+ throw new Error("Unknown API: ".concat(apiName));
265
+ }
266
+ return [4 /*yield*/, bucket.getRemainingTokens()];
267
+ case 1: return [2 /*return*/, _a.sent()];
268
+ }
269
+ });
270
+ });
271
+ };
272
+ /**
273
+ * Get bucket configurations
274
+ */
275
+ TokenBucketManager.prototype.getBucketConfigs = function () {
276
+ return {
277
+ coingecko: {
278
+ dailyBudget: REALISTIC_DAILY_BUDGETS.coingecko,
279
+ monthlyCost: 100,
280
+ costPerCall: 0.02
281
+ },
282
+ coinmarketcap: {
283
+ dailyBudget: REALISTIC_DAILY_BUDGETS.coinmarketcap,
284
+ monthlyCost: 50,
285
+ costPerCall: 0.015
286
+ },
287
+ coincap: {
288
+ dailyBudget: REALISTIC_DAILY_BUDGETS.coincap,
289
+ monthlyCost: 30,
290
+ costPerCall: 0.01
291
+ }
292
+ };
293
+ };
294
+ /**
295
+ * Get daily budget summary
296
+ */
297
+ TokenBucketManager.prototype.getDailyBudgetSummary = function () {
298
+ return __awaiter(this, void 0, void 0, function () {
299
+ var status, configs, totalAllocated, totalUsed, totalCostToday, summary, _i, _a, _b, apiName, apiStatus, config, used, cost;
300
+ return __generator(this, function (_c) {
301
+ switch (_c.label) {
302
+ case 0: return [4 /*yield*/, this.getAllStatus()];
303
+ case 1:
304
+ status = _c.sent();
305
+ configs = this.getBucketConfigs();
306
+ totalAllocated = 0;
307
+ totalUsed = 0;
308
+ totalCostToday = 0;
309
+ summary = {};
310
+ for (_i = 0, _a = Object.entries(status); _i < _a.length; _i++) {
311
+ _b = _a[_i], apiName = _b[0], apiStatus = _b[1];
312
+ config = configs[apiName];
313
+ used = config.dailyBudget - apiStatus.available;
314
+ cost = used * config.costPerCall;
315
+ summary[apiName] = {
316
+ allocated: config.dailyBudget,
317
+ used: used,
318
+ remaining: apiStatus.available,
319
+ utilizationRate: apiStatus.utilizationRate,
320
+ costToday: cost,
321
+ exhausted: apiStatus.exhausted
322
+ };
323
+ totalAllocated += config.dailyBudget;
324
+ totalUsed += used;
325
+ totalCostToday += cost;
326
+ }
327
+ summary.total = {
328
+ allocated: totalAllocated,
329
+ used: totalUsed,
330
+ remaining: totalAllocated - totalUsed,
331
+ utilizationRate: totalUsed / totalAllocated,
332
+ costToday: totalCostToday,
333
+ projectedMonthly: totalCostToday * 30
334
+ };
335
+ return [2 /*return*/, summary];
336
+ }
337
+ });
338
+ });
339
+ };
340
+ return TokenBucketManager;
341
+ }());
342
+ exports.TokenBucketManager = TokenBucketManager;