@splashcodex/api-key-manager 4.1.0 → 5.0.2
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/README.md +129 -201
- package/bin/cli.js +50 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.js +16 -4
- package/dist/index.js.map +1 -1
- package/dist/persistence/file.d.ts +43 -0
- package/dist/persistence/file.js +82 -0
- package/dist/persistence/file.js.map +1 -0
- package/dist/persistence/index.d.ts +7 -0
- package/dist/persistence/index.js +12 -0
- package/dist/persistence/index.js.map +1 -0
- package/dist/persistence/memory.d.ts +30 -0
- package/dist/persistence/memory.js +43 -0
- package/dist/persistence/memory.js.map +1 -0
- package/dist/presets/base.d.ts +138 -0
- package/dist/presets/base.js +227 -0
- package/dist/presets/base.js.map +1 -0
- package/dist/presets/gemini.d.ts +60 -0
- package/dist/presets/gemini.js +77 -0
- package/dist/presets/gemini.js.map +1 -0
- package/dist/presets/index.d.ts +10 -0
- package/dist/presets/index.js +16 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/presets/multi.d.ts +120 -0
- package/dist/presets/multi.js +210 -0
- package/dist/presets/multi.js.map +1 -0
- package/dist/presets/openai.d.ts +45 -0
- package/dist/presets/openai.js +62 -0
- package/dist/presets/openai.js.map +1 -0
- package/package.json +88 -5
- package/src/index.ts +24 -3
- package/src/persistence/file.ts +89 -0
- package/src/persistence/index.ts +7 -0
- package/src/persistence/memory.ts +43 -0
- package/src/presets/base.ts +323 -0
- package/src/presets/gemini.ts +84 -0
- package/src/presets/index.ts +10 -0
- package/src/presets/multi.ts +280 -0
- package/src/presets/openai.ts +69 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BasePreset — Shared foundation for all provider presets
|
|
4
|
+
*
|
|
5
|
+
* Provides the "batteries included" pattern:
|
|
6
|
+
* - Singleton lifecycle management
|
|
7
|
+
* - Environment variable parsing (single key or JSON array)
|
|
8
|
+
* - File-based persistence (survives restarts)
|
|
9
|
+
* - Event-to-logger wiring
|
|
10
|
+
* - Health check scheduling
|
|
11
|
+
* - Result<T> pattern for safe initialization
|
|
12
|
+
*
|
|
13
|
+
* @module presets/base
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.BasePreset = void 0;
|
|
17
|
+
const index_1 = require("../index");
|
|
18
|
+
const file_1 = require("../persistence/file");
|
|
19
|
+
const path_1 = require("path");
|
|
20
|
+
const os_1 = require("os");
|
|
21
|
+
// ─── Base Preset Class ──────────────────────────────────────────────────────
|
|
22
|
+
/**
|
|
23
|
+
* Abstract base class for provider presets.
|
|
24
|
+
* Subclasses only need to define `getDefaultOptions()` with provider-specific
|
|
25
|
+
* defaults (env var name, health check function, etc.).
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* ```ts
|
|
29
|
+
* // Creating a custom preset:
|
|
30
|
+
* class MyProviderPreset extends BasePreset {
|
|
31
|
+
* protected static getDefaultOptions(): Partial<PresetOptions> {
|
|
32
|
+
* return {
|
|
33
|
+
* envKeys: ['MY_PROVIDER_API_KEY'],
|
|
34
|
+
* provider: 'my-provider',
|
|
35
|
+
* };
|
|
36
|
+
* }
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
class BasePreset {
|
|
41
|
+
static instances = new Map();
|
|
42
|
+
manager;
|
|
43
|
+
logger;
|
|
44
|
+
options;
|
|
45
|
+
constructor(apiKeys, options) {
|
|
46
|
+
this.logger = options.logger || console;
|
|
47
|
+
this.options = {
|
|
48
|
+
provider: options.provider || 'default',
|
|
49
|
+
concurrency: options.concurrency ?? 20,
|
|
50
|
+
healthCheckIntervalMs: options.healthCheckIntervalMs ?? 300_000,
|
|
51
|
+
...options,
|
|
52
|
+
};
|
|
53
|
+
const stateFile = this.options.stateFilePath ||
|
|
54
|
+
(0, path_1.join)((0, os_1.tmpdir)(), `codedex_${this.options.provider}_state.json`);
|
|
55
|
+
const storage = new file_1.FileStorage({
|
|
56
|
+
filePath: stateFile,
|
|
57
|
+
clearOnInit: true, // Fresh start each session to clear stale DEAD keys
|
|
58
|
+
});
|
|
59
|
+
this.manager = new index_1.ApiKeyManager(apiKeys, {
|
|
60
|
+
storage,
|
|
61
|
+
strategy: this.options.strategy || new index_1.LatencyStrategy(),
|
|
62
|
+
fallbackFn: this.options.fallbackFn,
|
|
63
|
+
concurrency: this.options.concurrency,
|
|
64
|
+
semanticCache: this.options.semanticCache,
|
|
65
|
+
});
|
|
66
|
+
this.wireEvents();
|
|
67
|
+
if (this.options.healthCheckFn && this.options.healthCheckIntervalMs > 0) {
|
|
68
|
+
this.manager.setHealthCheck(this.options.healthCheckFn);
|
|
69
|
+
this.manager.startHealthChecks(this.options.healthCheckIntervalMs);
|
|
70
|
+
}
|
|
71
|
+
this.logger.info(`[${this.options.provider}] ApiKeyManager initialized with ${apiKeys.length} keys ` +
|
|
72
|
+
`(Strategy: ${this.options.strategy?.constructor.name || 'LatencyStrategy'}, ` +
|
|
73
|
+
`Concurrency: ${this.options.concurrency}, ` +
|
|
74
|
+
`HealthChecks: ${this.options.healthCheckIntervalMs > 0 ? `every ${this.options.healthCheckIntervalMs / 1000}s` : 'disabled'})`);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Wire all manager events to the logger.
|
|
78
|
+
*/
|
|
79
|
+
wireEvents() {
|
|
80
|
+
const tag = this.options.provider;
|
|
81
|
+
this.manager.on('keyDead', (key) => this.logger.error(`[${tag}] Key PERMANENTLY DEAD: ...${key.slice(-4)}`));
|
|
82
|
+
this.manager.on('circuitOpen', (key) => this.logger.warn(`[${tag}] Circuit OPEN (cooldown): ...${key.slice(-4)}`));
|
|
83
|
+
this.manager.on('keyRecovered', (key) => this.logger.info(`[${tag}] Key RECOVERED: ...${key.slice(-4)}`));
|
|
84
|
+
this.manager.on('retry', (key, attempt, delay) => this.logger.info(`[${tag}] Retry with ...${key.slice(-4)} (Attempt ${attempt}, Delay ${delay}ms)`));
|
|
85
|
+
this.manager.on('fallback', (reason) => this.logger.warn(`[${tag}] Triggering FALLBACK: ${reason}`));
|
|
86
|
+
this.manager.on('allKeysExhausted', () => this.logger.error(`[${tag}] ALL KEYS EXHAUSTED! No fallback available.`));
|
|
87
|
+
this.manager.on('bulkheadRejected', () => this.logger.warn(`[${tag}] Bulkhead rejected request (concurrency limit reached)`));
|
|
88
|
+
this.manager.on('healthCheckPassed', (key) => this.logger.info(`[${tag}] Health check PASSED: ...${key.slice(-4)}`));
|
|
89
|
+
this.manager.on('healthCheckFailed', (key) => this.logger.warn(`[${tag}] Health check FAILED: ...${key.slice(-4)}`));
|
|
90
|
+
}
|
|
91
|
+
// ─── Public API ─────────────────────────────────────────────────────────
|
|
92
|
+
/**
|
|
93
|
+
* Execute a function with automatic key rotation, retries, timeout, and caching.
|
|
94
|
+
*/
|
|
95
|
+
async execute(fn, options) {
|
|
96
|
+
return this.manager.execute(fn, options);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Execute a streaming function with retry on initial connection failure.
|
|
100
|
+
*/
|
|
101
|
+
async *executeStream(fn, options) {
|
|
102
|
+
yield* this.manager.executeStream(fn, options);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Get the best available API key directly (low-level).
|
|
106
|
+
*/
|
|
107
|
+
getKey() {
|
|
108
|
+
return this.manager.getKey();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get the number of non-dead keys.
|
|
112
|
+
*/
|
|
113
|
+
getKeyCount() {
|
|
114
|
+
return this.manager.getKeyCount();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get pool health statistics.
|
|
118
|
+
*/
|
|
119
|
+
getStats() {
|
|
120
|
+
return this.manager.getStats();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Get the underlying ApiKeyManager instance for advanced use.
|
|
124
|
+
*/
|
|
125
|
+
getManager() {
|
|
126
|
+
return this.manager;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Stop health checks and clean up. Call when shutting down.
|
|
130
|
+
*/
|
|
131
|
+
destroy() {
|
|
132
|
+
this.manager.stopHealthChecks();
|
|
133
|
+
}
|
|
134
|
+
// ─── Static Factory ─────────────────────────────────────────────────────
|
|
135
|
+
/**
|
|
136
|
+
* Parse API keys from environment variables.
|
|
137
|
+
* Supports:
|
|
138
|
+
* - Single key: `"AIza..."`
|
|
139
|
+
* - JSON array: `'["AIza...", "AIzb..."]'`
|
|
140
|
+
* - Comma-separated: `"AIza...,AIzb..."`
|
|
141
|
+
*/
|
|
142
|
+
static parseKeysFromEnv(envKeys) {
|
|
143
|
+
const keys = [];
|
|
144
|
+
for (const envName of envKeys) {
|
|
145
|
+
const envValue = process.env[envName];
|
|
146
|
+
if (!envValue)
|
|
147
|
+
continue;
|
|
148
|
+
const trimmed = envValue.trim();
|
|
149
|
+
if (!trimmed)
|
|
150
|
+
continue;
|
|
151
|
+
// Try JSON array
|
|
152
|
+
if (trimmed.startsWith('[')) {
|
|
153
|
+
try {
|
|
154
|
+
const parsed = JSON.parse(trimmed);
|
|
155
|
+
if (Array.isArray(parsed)) {
|
|
156
|
+
keys.push(...parsed.filter((k) => typeof k === 'string' && k.trim()));
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Not valid JSON, fall through to comma split
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Comma-separated or single key
|
|
165
|
+
keys.push(...trimmed.split(',').map(k => k.trim()).filter(k => k.length > 0));
|
|
166
|
+
}
|
|
167
|
+
return [...new Set(keys)]; // Deduplicate
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get or create the singleton instance for a preset.
|
|
171
|
+
* This is the core factory used by all preset subclasses.
|
|
172
|
+
*
|
|
173
|
+
* @param PresetClass - The preset class to instantiate
|
|
174
|
+
* @param overrides - Optional overrides for preset options
|
|
175
|
+
* @returns Result<T> — either `{ success: true, data: instance }` or `{ success: false, error }`
|
|
176
|
+
*/
|
|
177
|
+
static createInstance(PresetClass, defaultOptions, overrides) {
|
|
178
|
+
const mergedOptions = { ...defaultOptions, ...overrides };
|
|
179
|
+
const instanceKey = mergedOptions.provider || PresetClass.name;
|
|
180
|
+
// Return existing singleton
|
|
181
|
+
const existing = BasePreset.instances.get(instanceKey);
|
|
182
|
+
if (existing) {
|
|
183
|
+
return { success: true, data: existing };
|
|
184
|
+
}
|
|
185
|
+
// Parse keys
|
|
186
|
+
const envKeys = mergedOptions.envKeys || [];
|
|
187
|
+
const keys = BasePreset.parseKeysFromEnv(envKeys);
|
|
188
|
+
if (keys.length === 0) {
|
|
189
|
+
const logger = mergedOptions.logger || console;
|
|
190
|
+
logger.warn(`[${instanceKey}] No API keys found in env vars: ${envKeys.join(', ')}. ` +
|
|
191
|
+
`AI features will be disabled.`);
|
|
192
|
+
// Still create the instance with empty keys — allows graceful degradation
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const instance = new PresetClass(keys, mergedOptions);
|
|
196
|
+
BasePreset.instances.set(instanceKey, instance);
|
|
197
|
+
return { success: true, data: instance };
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
return {
|
|
201
|
+
success: false,
|
|
202
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Reset a singleton instance (primarily for testing).
|
|
208
|
+
*/
|
|
209
|
+
static resetInstance(provider) {
|
|
210
|
+
const existing = BasePreset.instances.get(provider);
|
|
211
|
+
if (existing) {
|
|
212
|
+
existing.destroy();
|
|
213
|
+
BasePreset.instances.delete(provider);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Reset ALL singleton instances (primarily for testing).
|
|
218
|
+
*/
|
|
219
|
+
static resetAll() {
|
|
220
|
+
for (const [, instance] of BasePreset.instances) {
|
|
221
|
+
instance.destroy();
|
|
222
|
+
}
|
|
223
|
+
BasePreset.instances.clear();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.BasePreset = BasePreset;
|
|
227
|
+
//# sourceMappingURL=base.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/presets/base.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini Preset — One-line Gemini API key management
|
|
3
|
+
*
|
|
4
|
+
* Pre-configured singleton with:
|
|
5
|
+
* - Reads `GOOGLE_GEMINI_API_KEY` or `GEMINI_API_KEY` from env
|
|
6
|
+
* - LatencyStrategy for optimal key selection
|
|
7
|
+
* - File persistence (survives restarts)
|
|
8
|
+
* - Health checks every 5 minutes
|
|
9
|
+
* - Concurrency limit of 20
|
|
10
|
+
*
|
|
11
|
+
* @module presets/gemini
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* import { GeminiManager } from '@splashcodex/api-key-manager/presets/gemini';
|
|
16
|
+
*
|
|
17
|
+
* // Initialize once (reads keys from process.env automatically)
|
|
18
|
+
* const result = GeminiManager.getInstance();
|
|
19
|
+
* if (!result.success) throw result.error;
|
|
20
|
+
* const gemini = result.data;
|
|
21
|
+
*
|
|
22
|
+
* // Use the execute() wrapper for automatic key rotation + retries
|
|
23
|
+
* const response = await gemini.execute(async (key) => {
|
|
24
|
+
* const genAI = new GoogleGenerativeAI(key);
|
|
25
|
+
* const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
|
|
26
|
+
* const res = await model.generateContent('Hello, world!');
|
|
27
|
+
* return res.response.text();
|
|
28
|
+
* }, { maxRetries: 3, timeoutMs: 30000 });
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import { BasePreset, PresetOptions, Result } from './base';
|
|
32
|
+
export declare class GeminiManager extends BasePreset {
|
|
33
|
+
private static readonly PROVIDER;
|
|
34
|
+
private constructor();
|
|
35
|
+
/**
|
|
36
|
+
* Default configuration for Gemini presets.
|
|
37
|
+
*/
|
|
38
|
+
private static getDefaultOptions;
|
|
39
|
+
/**
|
|
40
|
+
* Get or create the singleton GeminiManager instance.
|
|
41
|
+
*
|
|
42
|
+
* @param overrides - Optional configuration overrides
|
|
43
|
+
* @returns Result<GeminiManager> — safely check `.success` before using `.data`
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const result = GeminiManager.getInstance();
|
|
48
|
+
* if (result.success) {
|
|
49
|
+
* const gemini = result.data;
|
|
50
|
+
* const text = await gemini.execute(apiCall, { maxRetries: 3 });
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
static getInstance(overrides?: Partial<PresetOptions>): Result<GeminiManager>;
|
|
55
|
+
/**
|
|
56
|
+
* Reset the singleton instance. Primarily for testing.
|
|
57
|
+
*/
|
|
58
|
+
static reset(): void;
|
|
59
|
+
}
|
|
60
|
+
export { Result } from './base';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Gemini Preset — One-line Gemini API key management
|
|
4
|
+
*
|
|
5
|
+
* Pre-configured singleton with:
|
|
6
|
+
* - Reads `GOOGLE_GEMINI_API_KEY` or `GEMINI_API_KEY` from env
|
|
7
|
+
* - LatencyStrategy for optimal key selection
|
|
8
|
+
* - File persistence (survives restarts)
|
|
9
|
+
* - Health checks every 5 minutes
|
|
10
|
+
* - Concurrency limit of 20
|
|
11
|
+
*
|
|
12
|
+
* @module presets/gemini
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { GeminiManager } from '@splashcodex/api-key-manager/presets/gemini';
|
|
17
|
+
*
|
|
18
|
+
* // Initialize once (reads keys from process.env automatically)
|
|
19
|
+
* const result = GeminiManager.getInstance();
|
|
20
|
+
* if (!result.success) throw result.error;
|
|
21
|
+
* const gemini = result.data;
|
|
22
|
+
*
|
|
23
|
+
* // Use the execute() wrapper for automatic key rotation + retries
|
|
24
|
+
* const response = await gemini.execute(async (key) => {
|
|
25
|
+
* const genAI = new GoogleGenerativeAI(key);
|
|
26
|
+
* const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' });
|
|
27
|
+
* const res = await model.generateContent('Hello, world!');
|
|
28
|
+
* return res.response.text();
|
|
29
|
+
* }, { maxRetries: 3, timeoutMs: 30000 });
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
+
exports.GeminiManager = void 0;
|
|
34
|
+
const base_1 = require("./base");
|
|
35
|
+
class GeminiManager extends base_1.BasePreset {
|
|
36
|
+
static PROVIDER = 'gemini';
|
|
37
|
+
constructor(keys, options) {
|
|
38
|
+
super(keys, options);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Default configuration for Gemini presets.
|
|
42
|
+
*/
|
|
43
|
+
static getDefaultOptions() {
|
|
44
|
+
return {
|
|
45
|
+
envKeys: ['GOOGLE_GEMINI_API_KEY', 'GEMINI_API_KEY'],
|
|
46
|
+
provider: GeminiManager.PROVIDER,
|
|
47
|
+
concurrency: 20,
|
|
48
|
+
healthCheckIntervalMs: 300_000, // 5 minutes
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get or create the singleton GeminiManager instance.
|
|
53
|
+
*
|
|
54
|
+
* @param overrides - Optional configuration overrides
|
|
55
|
+
* @returns Result<GeminiManager> — safely check `.success` before using `.data`
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const result = GeminiManager.getInstance();
|
|
60
|
+
* if (result.success) {
|
|
61
|
+
* const gemini = result.data;
|
|
62
|
+
* const text = await gemini.execute(apiCall, { maxRetries: 3 });
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
static getInstance(overrides) {
|
|
67
|
+
return base_1.BasePreset.createInstance(GeminiManager, GeminiManager.getDefaultOptions(), overrides);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Reset the singleton instance. Primarily for testing.
|
|
71
|
+
*/
|
|
72
|
+
static reset() {
|
|
73
|
+
base_1.BasePreset.resetInstance(GeminiManager.PROVIDER);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
exports.GeminiManager = GeminiManager;
|
|
77
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/presets/gemini.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;;AAEH,iCAA2D;AAE3D,MAAa,aAAc,SAAQ,iBAAU;IACjC,MAAM,CAAU,QAAQ,GAAG,QAAQ,CAAC;IAE5C,YAAoB,IAAc,EAAE,OAAsB;QACtD,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzB,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,iBAAiB;QAC5B,OAAO;YACH,OAAO,EAAE,CAAC,uBAAuB,EAAE,gBAAgB,CAAC;YACpD,QAAQ,EAAE,aAAa,CAAC,QAAQ;YAChC,WAAW,EAAE,EAAE;YACf,qBAAqB,EAAE,OAAO,EAAE,YAAY;SAC/C,CAAC;IACN,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,WAAW,CAAC,SAAkC;QACjD,OAAO,iBAAU,CAAC,cAAc,CAC5B,aAAyF,EACzF,aAAa,CAAC,iBAAiB,EAAE,EACjC,SAAS,CACa,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK;QACR,iBAAU,CAAC,aAAa,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;;AA/CL,sCAgDC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Presets — Batteries-included provider managers
|
|
3
|
+
* @module presets
|
|
4
|
+
*/
|
|
5
|
+
export { BasePreset } from './base';
|
|
6
|
+
export type { PresetOptions, PresetLogger, Result } from './base';
|
|
7
|
+
export { GeminiManager } from './gemini';
|
|
8
|
+
export { OpenAIManager } from './openai';
|
|
9
|
+
export { MultiManager } from './multi';
|
|
10
|
+
export type { ProviderConfig, MultiManagerOptions } from './multi';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MultiManager = exports.OpenAIManager = exports.GeminiManager = exports.BasePreset = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Presets — Batteries-included provider managers
|
|
6
|
+
* @module presets
|
|
7
|
+
*/
|
|
8
|
+
var base_1 = require("./base");
|
|
9
|
+
Object.defineProperty(exports, "BasePreset", { enumerable: true, get: function () { return base_1.BasePreset; } });
|
|
10
|
+
var gemini_1 = require("./gemini");
|
|
11
|
+
Object.defineProperty(exports, "GeminiManager", { enumerable: true, get: function () { return gemini_1.GeminiManager; } });
|
|
12
|
+
var openai_1 = require("./openai");
|
|
13
|
+
Object.defineProperty(exports, "OpenAIManager", { enumerable: true, get: function () { return openai_1.OpenAIManager; } });
|
|
14
|
+
var multi_1 = require("./multi");
|
|
15
|
+
Object.defineProperty(exports, "MultiManager", { enumerable: true, get: function () { return multi_1.MultiManager; } });
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/presets/index.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,+BAAoC;AAA3B,kGAAA,UAAU,OAAA;AAEnB,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AACtB,mCAAyC;AAAhC,uGAAA,aAAa,OAAA;AACtB,iCAAuC;AAA9B,qGAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MultiManager Preset — Multi-Provider Key Vault
|
|
3
|
+
*
|
|
4
|
+
* Manages API keys across multiple providers from a single entry point.
|
|
5
|
+
* Aggregates keys from multiple environment variables and routes
|
|
6
|
+
* requests to the correct provider pool.
|
|
7
|
+
*
|
|
8
|
+
* @module presets/multi
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* import { MultiManager } from '@splashcodex/api-key-manager/presets/multi';
|
|
13
|
+
*
|
|
14
|
+
* const result = MultiManager.getInstance({
|
|
15
|
+
* providers: {
|
|
16
|
+
* gemini: { envKeys: ['GOOGLE_GEMINI_API_KEY'] },
|
|
17
|
+
* openai: { envKeys: ['OPENAI_API_KEY'] },
|
|
18
|
+
* }
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* if (result.success) {
|
|
22
|
+
* const vault = result.data;
|
|
23
|
+
*
|
|
24
|
+
* // Route to specific provider
|
|
25
|
+
* const text = await vault.execute(async (key) => {
|
|
26
|
+
* // key is from the gemini pool
|
|
27
|
+
* return callGemini(key, prompt);
|
|
28
|
+
* }, { provider: 'gemini', maxRetries: 3 });
|
|
29
|
+
*
|
|
30
|
+
* // Get stats across all providers
|
|
31
|
+
* const stats = vault.getMultiStats();
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
import { ApiKeyManager, ExecuteOptions, ApiKeyManagerStats, LoadBalancingStrategy, ApiKeyManagerOptions } from '../index';
|
|
36
|
+
export type Result<T> = {
|
|
37
|
+
success: true;
|
|
38
|
+
data: T;
|
|
39
|
+
} | {
|
|
40
|
+
success: false;
|
|
41
|
+
error: Error;
|
|
42
|
+
};
|
|
43
|
+
export interface ProviderConfig {
|
|
44
|
+
/** Environment variable names to read API keys from */
|
|
45
|
+
envKeys: string[];
|
|
46
|
+
/** Strategy override. Default: LatencyStrategy */
|
|
47
|
+
strategy?: LoadBalancingStrategy;
|
|
48
|
+
/** Concurrency limit. Default: 20 */
|
|
49
|
+
concurrency?: number;
|
|
50
|
+
/** Semantic cache configuration. Optional. */
|
|
51
|
+
semanticCache?: ApiKeyManagerOptions['semanticCache'];
|
|
52
|
+
}
|
|
53
|
+
export interface MultiManagerOptions {
|
|
54
|
+
/** Provider configurations keyed by name (e.g., 'gemini', 'openai') */
|
|
55
|
+
providers: Record<string, ProviderConfig>;
|
|
56
|
+
/** Health check interval in ms. Default: 300_000 (5 min). Set to 0 to disable. */
|
|
57
|
+
healthCheckIntervalMs?: number;
|
|
58
|
+
/** Custom logger. Defaults to console. */
|
|
59
|
+
logger?: {
|
|
60
|
+
info(msg: string, ...args: any[]): void;
|
|
61
|
+
warn(msg: string, ...args: any[]): void;
|
|
62
|
+
error(msg: string, ...args: any[]): void;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export declare class MultiManager {
|
|
66
|
+
private static instance;
|
|
67
|
+
private managers;
|
|
68
|
+
private logger;
|
|
69
|
+
private constructor();
|
|
70
|
+
/**
|
|
71
|
+
* Get or create the singleton MultiManager instance.
|
|
72
|
+
*/
|
|
73
|
+
static getInstance(options: MultiManagerOptions): Result<MultiManager>;
|
|
74
|
+
/**
|
|
75
|
+
* Reset the singleton (primarily for testing).
|
|
76
|
+
*/
|
|
77
|
+
static reset(): void;
|
|
78
|
+
/**
|
|
79
|
+
* Execute a function with a specific provider's key pool.
|
|
80
|
+
*
|
|
81
|
+
* @param fn - The function to execute with a key
|
|
82
|
+
* @param options - Must include `provider` to select the pool
|
|
83
|
+
*/
|
|
84
|
+
execute<T>(fn: (key: string, signal?: AbortSignal) => Promise<T>, options: ExecuteOptions & {
|
|
85
|
+
prompt?: string;
|
|
86
|
+
provider: string;
|
|
87
|
+
}): Promise<T>;
|
|
88
|
+
/**
|
|
89
|
+
* Execute a streaming function with a specific provider's key pool.
|
|
90
|
+
*/
|
|
91
|
+
executeStream<T>(fn: (key: string, signal?: AbortSignal) => AsyncGenerator<T, any, unknown>, options: ExecuteOptions & {
|
|
92
|
+
prompt?: string;
|
|
93
|
+
provider: string;
|
|
94
|
+
}): AsyncGenerator<T, any, unknown>;
|
|
95
|
+
/**
|
|
96
|
+
* Get a raw key from a specific provider pool.
|
|
97
|
+
*/
|
|
98
|
+
getKey(provider: string): string | null;
|
|
99
|
+
/**
|
|
100
|
+
* Get stats for a specific provider.
|
|
101
|
+
*/
|
|
102
|
+
getStats(provider: string): ApiKeyManagerStats | null;
|
|
103
|
+
/**
|
|
104
|
+
* Get aggregate stats across ALL providers.
|
|
105
|
+
*/
|
|
106
|
+
getMultiStats(): Record<string, ApiKeyManagerStats>;
|
|
107
|
+
/**
|
|
108
|
+
* Get the list of available provider names.
|
|
109
|
+
*/
|
|
110
|
+
getProviders(): string[];
|
|
111
|
+
/**
|
|
112
|
+
* Get the underlying ApiKeyManager for a specific provider.
|
|
113
|
+
*/
|
|
114
|
+
getManager(provider: string): ApiKeyManager | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* Stop all health checks and clean up.
|
|
117
|
+
*/
|
|
118
|
+
destroy(): void;
|
|
119
|
+
private static parseKeysFromEnv;
|
|
120
|
+
}
|