unlimit-keys 0.1.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/README.md +64 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +41 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/schema/getLeastUsedKey.d.ts +9 -0
- package/dist/schema/getLeastUsedKey.d.ts.map +1 -0
- package/dist/schema/getLeastUsedKey.js +45 -0
- package/dist/schema/getLeastUsedKey.js.map +1 -0
- package/dist/schema/redis.d.ts +3 -0
- package/dist/schema/redis.d.ts.map +1 -0
- package/dist/schema/redis.js +12 -0
- package/dist/schema/redis.js.map +1 -0
- package/dist/scripts/sync-api-keys.d.ts +2 -0
- package/dist/scripts/sync-api-keys.d.ts.map +1 -0
- package/dist/scripts/sync-api-keys.js +62 -0
- package/dist/scripts/sync-api-keys.js.map +1 -0
- package/package.json +68 -0
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# unlimit-keys
|
|
2
|
+
|
|
3
|
+
A generic, distributed API key rotator that uses Redis to select the least recently used (LRU) key from a pool. Ideal for distributing load across multiple API keys to avoid rate limits, regardless of the provider (Google, OpenAI, Anthropic, etc.).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install unlimit-keys
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Setup
|
|
12
|
+
|
|
13
|
+
### 1. Environment Variables
|
|
14
|
+
|
|
15
|
+
Create a `.env.local` file with your Redis credentials and API keys:
|
|
16
|
+
|
|
17
|
+
```env
|
|
18
|
+
# Upstash Redis credentials
|
|
19
|
+
REDIS_URL=https://your-redis-url.upstash.io
|
|
20
|
+
REDIS_TOKEN=your-token
|
|
21
|
+
|
|
22
|
+
# Comma-separated or newline-separated API keys
|
|
23
|
+
RU_API_KEYS="key1,key2,key3"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Sync Keys to Redis
|
|
27
|
+
|
|
28
|
+
Run the sync script to load your API keys into the global Redis pool:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npx unlimit-keys sync
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Programmatic API
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { getLeastUsedKey } from 'unlimit-keys';
|
|
40
|
+
|
|
41
|
+
// Get the least recently used key
|
|
42
|
+
const apiKey = await getLeastUsedKey();
|
|
43
|
+
console.log(apiKey);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### CLI
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Get the least recently used key via CLI
|
|
50
|
+
npx unlimit-keys get-key
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## How It Works
|
|
54
|
+
|
|
55
|
+
1. **Key Pool**: Keys are stored in a single Redis Sorted Set (`ru_api_keys`).
|
|
56
|
+
2. **LRU Rotation**: When you request a key, the library atomically:
|
|
57
|
+
* Finds the key with the lowest score (oldest usage timestamp).
|
|
58
|
+
* Updates that key's score to the current timestamp.
|
|
59
|
+
* Returns the key.
|
|
60
|
+
3. **Concurrency**: Atomic Lua scripts ensure no race conditions, even with high concurrency across serverless functions.
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
ISC
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
4
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
5
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
6
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
7
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
8
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
9
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
|
+
});
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
const commander_1 = require("commander");
|
|
14
|
+
const getLeastUsedKey_1 = require("./schema/getLeastUsedKey");
|
|
15
|
+
const program = new commander_1.Command();
|
|
16
|
+
program
|
|
17
|
+
.name('unlimit-keys')
|
|
18
|
+
.description('Distributed LRU API key rotation using Redis')
|
|
19
|
+
.version('0.1.0');
|
|
20
|
+
program
|
|
21
|
+
.command('get-key')
|
|
22
|
+
.description('Get the least recently used API key')
|
|
23
|
+
.action(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
+
try {
|
|
25
|
+
const key = yield (0, getLeastUsedKey_1.getLeastUsedKey)();
|
|
26
|
+
console.log(key);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
program
|
|
34
|
+
.command('sync')
|
|
35
|
+
.description('Sync API keys from RU_API_KEYS env var to Redis')
|
|
36
|
+
.action(() => {
|
|
37
|
+
console.log('Please run: npx unlimit-keys sync');
|
|
38
|
+
console.log('Or: node dist/scripts/sync-api-keys.js');
|
|
39
|
+
});
|
|
40
|
+
program.parse();
|
|
41
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,yCAAoC;AACpC,8DAA2D;AAE3D,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,cAAc,CAAC;KACpB,WAAW,CAAC,8CAA8C,CAAC;KAC3D,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,qCAAqC,CAAC;KAClD,MAAM,CAAC,GAAS,EAAE;IACjB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,IAAA,iCAAe,GAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAA,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,iDAAiD,CAAC;KAC9D,MAAM,CAAC,GAAG,EAAE;IACX,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,wCAAwC,CAAC,CAAC;AACxD,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.redis = exports.getLeastUsedKey = void 0;
|
|
4
|
+
var getLeastUsedKey_1 = require("./schema/getLeastUsedKey");
|
|
5
|
+
Object.defineProperty(exports, "getLeastUsedKey", { enumerable: true, get: function () { return getLeastUsedKey_1.getLeastUsedKey; } });
|
|
6
|
+
var redis_1 = require("./schema/redis");
|
|
7
|
+
Object.defineProperty(exports, "redis", { enumerable: true, get: function () { return redis_1.redis; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,4DAA2D;AAAlD,kHAAA,eAAe,OAAA;AACxB,wCAAuC;AAA9B,8FAAA,KAAK,OAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetches the least recently used API key from the global pool.
|
|
3
|
+
* Automatically updates the key's usage timestamp.
|
|
4
|
+
*
|
|
5
|
+
* @returns The API key to be used.
|
|
6
|
+
* @throws Will throw an error if no keys are found.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getLeastUsedKey(): Promise<string>;
|
|
9
|
+
//# sourceMappingURL=getLeastUsedKey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLeastUsedKey.d.ts","sourceRoot":"","sources":["../../src/schema/getLeastUsedKey.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAwBvD"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getLeastUsedKey = getLeastUsedKey;
|
|
13
|
+
const redis_1 = require("./redis");
|
|
14
|
+
const KEY_SET = 'ru_api_keys';
|
|
15
|
+
/**
|
|
16
|
+
* Fetches the least recently used API key from the global pool.
|
|
17
|
+
* Automatically updates the key's usage timestamp.
|
|
18
|
+
*
|
|
19
|
+
* @returns The API key to be used.
|
|
20
|
+
* @throws Will throw an error if no keys are found.
|
|
21
|
+
*/
|
|
22
|
+
function getLeastUsedKey() {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const currentTime = Date.now() / 1000;
|
|
25
|
+
// Atomic Lua script:
|
|
26
|
+
// 1. Get the key with the lowest score (least recently used)
|
|
27
|
+
// 2. If a key exists, update its score to current time
|
|
28
|
+
// 3. Return the key
|
|
29
|
+
const script = `
|
|
30
|
+
local key = redis.call('zrange', KEYS[1], 0, 0)[1]
|
|
31
|
+
if key then
|
|
32
|
+
redis.call('zadd', KEYS[1], ARGV[1], key)
|
|
33
|
+
return key
|
|
34
|
+
else
|
|
35
|
+
return nil
|
|
36
|
+
end
|
|
37
|
+
`;
|
|
38
|
+
const key = yield redis_1.redis.eval(script, [KEY_SET], [currentTime]);
|
|
39
|
+
if (!key) {
|
|
40
|
+
throw new Error('No API keys found in Redis. Please check your RU_API_KEYS environment variable and run the sync script.');
|
|
41
|
+
}
|
|
42
|
+
return key;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=getLeastUsedKey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getLeastUsedKey.js","sourceRoot":"","sources":["../../src/schema/getLeastUsedKey.ts"],"names":[],"mappings":";;;;;;;;;;;AAWA,0CAwBC;AAnCD,mCAAgC;AAEhC,MAAM,OAAO,GAAG,aAAa,CAAC;AAE9B;;;;;;GAMG;AACH,SAAsB,eAAe;;QACjC,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QAEtC,qBAAqB;QACrB,6DAA6D;QAC7D,uDAAuD;QACvD,oBAAoB;QACpB,MAAM,MAAM,GAAG;;;;;;;;KAQd,CAAC;QAEF,MAAM,GAAG,GAAG,MAAM,aAAK,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,CAAC,CAAkB,CAAC;QAEhF,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,yGAAyG,CAAC,CAAC;QAC/H,CAAC;QAED,OAAO,GAAG,CAAC;IACf,CAAC;CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/schema/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAMvC,eAAO,MAAM,KAAK,OAGhB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.redis = void 0;
|
|
4
|
+
const redis_1 = require("@upstash/redis");
|
|
5
|
+
if (!process.env.REDIS_URL || !process.env.REDIS_TOKEN) {
|
|
6
|
+
throw new Error('Missing Redis credentials. Please set REDIS_URL and REDIS_TOKEN.');
|
|
7
|
+
}
|
|
8
|
+
exports.redis = new redis_1.Redis({
|
|
9
|
+
url: process.env.REDIS_URL,
|
|
10
|
+
token: process.env.REDIS_TOKEN,
|
|
11
|
+
});
|
|
12
|
+
//# sourceMappingURL=redis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/schema/redis.ts"],"names":[],"mappings":";;;AAAA,0CAAuC;AAEvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;IACvD,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;AACtF,CAAC;AAEY,QAAA,KAAK,GAAG,IAAI,aAAK,CAAC;IAC7B,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS;IAC1B,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;CAC/B,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-api-keys.d.ts","sourceRoot":"","sources":["../../src/scripts/sync-api-keys.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
require("dotenv/config");
|
|
13
|
+
const redis_1 = require("@upstash/redis");
|
|
14
|
+
// Note: checking for properties on process.env needs type assertions or simply checking existence
|
|
15
|
+
if (!process.env.REDIS_URL || !process.env.REDIS_TOKEN) {
|
|
16
|
+
throw new Error('Missing Upstash Redis credentials in .env file');
|
|
17
|
+
}
|
|
18
|
+
const redis = new redis_1.Redis({
|
|
19
|
+
url: process.env.REDIS_URL,
|
|
20
|
+
token: process.env.REDIS_TOKEN,
|
|
21
|
+
});
|
|
22
|
+
const KEY_SET = 'ru_api_keys';
|
|
23
|
+
function syncApiKeys() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
console.log('Syncing API keys from RU_API_KEYS...');
|
|
26
|
+
const keysString = process.env.RU_API_KEYS || '';
|
|
27
|
+
const keysFromEnv = keysString.split(/[\n,]/).map(k => k.trim()).filter(Boolean);
|
|
28
|
+
if (keysFromEnv.length === 0) {
|
|
29
|
+
console.warn('No RU_API_KEYS found in environment variables.');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const pipeline = redis.pipeline();
|
|
33
|
+
// Get existing keys
|
|
34
|
+
const keysInRedis = yield redis.zrange(KEY_SET, 0, -1);
|
|
35
|
+
// Determine additions and removals
|
|
36
|
+
const keysToAdd = keysFromEnv.filter(k => !keysInRedis.includes(k));
|
|
37
|
+
const keysToRemove = keysInRedis.filter(k => !keysFromEnv.includes(k));
|
|
38
|
+
if (keysToAdd.length > 0) {
|
|
39
|
+
console.log(`Adding ${keysToAdd.length} new keys.`);
|
|
40
|
+
for (const key of keysToAdd) {
|
|
41
|
+
// Add with score 0 (least used)
|
|
42
|
+
pipeline.zadd(KEY_SET, { score: 0, member: key });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (keysToRemove.length > 0) {
|
|
46
|
+
console.log(`Removing ${keysToRemove.length} stale keys.`);
|
|
47
|
+
pipeline.zrem(KEY_SET, ...keysToRemove);
|
|
48
|
+
}
|
|
49
|
+
if (keysToAdd.length === 0 && keysToRemove.length === 0) {
|
|
50
|
+
console.log('Keys are already in sync.');
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
yield pipeline.exec();
|
|
54
|
+
console.log('Sync complete.');
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
syncApiKeys().catch((err) => {
|
|
59
|
+
console.error('Error syncing keys:', err);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=sync-api-keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-api-keys.js","sourceRoot":"","sources":["../../src/scripts/sync-api-keys.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,yBAAuB;AACvB,0CAAuC;AAEvC,kGAAkG;AAClG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;IACrD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,KAAK,GAAG,IAAI,aAAK,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS;IAC1B,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;CACjC,CAAC,CAAC;AAEH,MAAM,OAAO,GAAG,aAAa,CAAC;AAE9B,SAAe,WAAW;;QACtB,OAAO,CAAC,GAAG,CAAC,sCAAsC,CAAC,CAAC;QAEpD,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;QACjD,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEjF,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3B,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC/D,OAAO;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAElC,oBAAoB;QACpB,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAa,CAAC;QAEnE,mCAAmC;QACnC,MAAM,SAAS,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAEvE,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CAAC,UAAU,SAAS,CAAC,MAAM,YAAY,CAAC,CAAC;YACpD,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC1B,gCAAgC;gBAChC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;YACtD,CAAC;QACL,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,YAAY,YAAY,CAAC,MAAM,cAAc,CAAC,CAAC;YAC3D,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,YAAY,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;QAC7C,CAAC;aAAM,CAAC;YACJ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAClC,CAAC;IACL,CAAC;CAAA;AAED,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACxB,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "unlimit-keys",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An API key rotation system using Redis",
|
|
5
|
+
"author": "Anirban Majumder <anirbanmajumder.404@gmail.com>",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/Anirban-Majumder/unlimit-keys.git"
|
|
9
|
+
},
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/Anirban-Majumder/unlimit-keys/issues"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/Anirban-Majumder/unlimit-keys#readme",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"rate-limit",
|
|
17
|
+
"api-key",
|
|
18
|
+
"redis",
|
|
19
|
+
"upstash",
|
|
20
|
+
"key-rotation",
|
|
21
|
+
"lru",
|
|
22
|
+
"keys"
|
|
23
|
+
],
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"require": "./dist/index.js",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"bin": {
|
|
34
|
+
"unlimit-keys": "./dist/cli.js"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "tsc",
|
|
41
|
+
"prepublishOnly": "npm run build",
|
|
42
|
+
"sync": "node dist/scripts/sync-api-keys.js",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"publish-pkg": "npm publish --access public"
|
|
45
|
+
},
|
|
46
|
+
"type": "commonjs",
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@upstash/redis": ">=1.0.0",
|
|
52
|
+
"commander": "^14.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^24.0.15",
|
|
56
|
+
"ts-node": "^10.9.2",
|
|
57
|
+
"typescript": "^5.8.3",
|
|
58
|
+
"vitest": "^4.0.17"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@upstash/redis": ">=1.0.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"@upstash/redis": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|