@ttt-productions/rate-limit-core 0.2.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/dist/error-message.d.ts +23 -0
- package/dist/error-message.d.ts.map +1 -0
- package/dist/error-message.js +18 -0
- package/dist/error-message.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/rate-limiter.d.ts +30 -0
- package/dist/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limiter.js +40 -0
- package/dist/rate-limiter.js.map +1 -0
- package/dist/redis-client.d.ts +28 -0
- package/dist/redis-client.d.ts.map +1 -0
- package/dist/redis-client.js +43 -0
- package/dist/redis-client.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface RateLimitErrorMessageOptions {
|
|
2
|
+
/** Epoch ms when the limit resets (returned by `checkRateLimit`). */
|
|
3
|
+
reset: number;
|
|
4
|
+
/** Optional context shown in the message (e.g. "Upload"). */
|
|
5
|
+
context?: string;
|
|
6
|
+
/** Optional copy overrides — generic defaults are used when omitted. */
|
|
7
|
+
copy?: {
|
|
8
|
+
/** Suffix appended to every message. Default: "" (none). */
|
|
9
|
+
suffix?: string;
|
|
10
|
+
/** Template builder. Receives the formatted time string and context. */
|
|
11
|
+
format?: (args: {
|
|
12
|
+
timeString: string;
|
|
13
|
+
context?: string;
|
|
14
|
+
}) => string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Generate a user-friendly rate-limit error message with relative time.
|
|
19
|
+
* Copy is fully consumer-controlled — TTT supplies its "Early-launch
|
|
20
|
+
* rate limits in place" suffix at the call site.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getRateLimitErrorMessage(opts: RateLimitErrorMessageOptions): string;
|
|
23
|
+
//# sourceMappingURL=error-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-message.d.ts","sourceRoot":"","sources":["../src/error-message.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,4BAA4B;IAC3C,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,IAAI,CAAC,EAAE;QACL,4DAA4D;QAC5D,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,wEAAwE;QACxE,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE;YAAE,UAAU,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,KAAK,MAAM,CAAC;KACrE,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,4BAA4B,GAAG,MAAM,CAcnF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a user-friendly rate-limit error message with relative time.
|
|
3
|
+
* Copy is fully consumer-controlled — TTT supplies its "Early-launch
|
|
4
|
+
* rate limits in place" suffix at the call site.
|
|
5
|
+
*/
|
|
6
|
+
export function getRateLimitErrorMessage(opts) {
|
|
7
|
+
const { reset, context, copy } = opts;
|
|
8
|
+
const minutes = Math.max(1, Math.ceil((reset - Date.now()) / 60_000));
|
|
9
|
+
const timeString = minutes === 1 ? "1 minute" : `${minutes} minutes`;
|
|
10
|
+
if (copy?.format) {
|
|
11
|
+
return copy.format({ timeString, context });
|
|
12
|
+
}
|
|
13
|
+
const base = context
|
|
14
|
+
? `${context} rate limit exceeded. Try again in ${timeString}.`
|
|
15
|
+
: `Rate limit exceeded. Try again in ${timeString}.`;
|
|
16
|
+
return copy?.suffix ? `${base} ${copy.suffix}` : base;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=error-message.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-message.js","sourceRoot":"","sources":["../src/error-message.ts"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAkC;IACzE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IACtE,MAAM,UAAU,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,UAAU,CAAC;IAErE,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,OAAO;QAClB,CAAC,CAAC,GAAG,OAAO,sCAAsC,UAAU,GAAG;QAC/D,CAAC,CAAC,qCAAqC,UAAU,GAAG,CAAC;IAEvD,OAAO,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACxD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createRedisClientFactory } from "./redis-client.js";
|
|
2
|
+
export type { RedisCredentialsProvider, RedisClientFactoryOptions, } from "./redis-client.js";
|
|
3
|
+
export { createRateLimiterFactory } from "./rate-limiter.js";
|
|
4
|
+
export type { RateLimitConfig, RateLimiterFactoryOptions, } from "./rate-limiter.js";
|
|
5
|
+
export { getRateLimitErrorMessage } from "./error-message.js";
|
|
6
|
+
export type { RateLimitErrorMessageOptions } from "./error-message.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EACV,wBAAwB,EACxB,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EACV,eAAe,EACf,yBAAyB,GAC1B,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,YAAY,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAM7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAM7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Ratelimit } from "@upstash/ratelimit";
|
|
2
|
+
import type { Redis } from "@upstash/redis";
|
|
3
|
+
export interface RateLimitConfig {
|
|
4
|
+
/** Unique prefix for this limiter (e.g. "ratelimit:upload"). */
|
|
5
|
+
prefix: string;
|
|
6
|
+
/** Max requests allowed in the window. */
|
|
7
|
+
maxRequests: number;
|
|
8
|
+
/** Window duration (e.g. "1 h", "10 m", "1 d"). */
|
|
9
|
+
window: string;
|
|
10
|
+
}
|
|
11
|
+
export interface RateLimiterFactoryOptions {
|
|
12
|
+
/** Returns the Redis client or null when disabled. */
|
|
13
|
+
getRedis: () => Redis | null;
|
|
14
|
+
/** When true, includes Upstash analytics. Default true. */
|
|
15
|
+
analytics?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Create a memoized Ratelimit factory. Limiters are cached by their `prefix`
|
|
19
|
+
* so repeated calls with the same config return the same instance.
|
|
20
|
+
*/
|
|
21
|
+
export declare function createRateLimiterFactory(options: RateLimiterFactoryOptions): {
|
|
22
|
+
getRateLimiter: (config: RateLimitConfig) => Ratelimit | null;
|
|
23
|
+
checkRateLimit: (key: string, config: RateLimitConfig) => Promise<{
|
|
24
|
+
allowed: true;
|
|
25
|
+
} | {
|
|
26
|
+
allowed: false;
|
|
27
|
+
reset: number;
|
|
28
|
+
}>;
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC9B,gEAAgE;IAChE,MAAM,EAAE,MAAM,CAAC;IACf,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,yBAAyB;IACxC,sDAAsD;IACtD,QAAQ,EAAE,MAAM,KAAK,GAAG,IAAI,CAAC;IAC7B,2DAA2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB;6BAIzC,eAAe,KAAG,SAAS,GAAG,IAAI;0BAsB3D,MAAM,UACH,eAAe,KACtB,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;EASlE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Ratelimit } from "@upstash/ratelimit";
|
|
2
|
+
/**
|
|
3
|
+
* Create a memoized Ratelimit factory. Limiters are cached by their `prefix`
|
|
4
|
+
* so repeated calls with the same config return the same instance.
|
|
5
|
+
*/
|
|
6
|
+
export function createRateLimiterFactory(options) {
|
|
7
|
+
const limiters = new Map();
|
|
8
|
+
const analytics = options.analytics ?? true;
|
|
9
|
+
function getRateLimiter(config) {
|
|
10
|
+
const redis = options.getRedis();
|
|
11
|
+
if (!redis)
|
|
12
|
+
return null;
|
|
13
|
+
const existing = limiters.get(config.prefix);
|
|
14
|
+
if (existing)
|
|
15
|
+
return existing;
|
|
16
|
+
const limiter = new Ratelimit({
|
|
17
|
+
redis,
|
|
18
|
+
limiter: Ratelimit.slidingWindow(config.maxRequests, config.window),
|
|
19
|
+
analytics,
|
|
20
|
+
prefix: config.prefix,
|
|
21
|
+
});
|
|
22
|
+
limiters.set(config.prefix, limiter);
|
|
23
|
+
return limiter;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Check rate limit for a key (e.g. userId). Returns `{ allowed: true }`
|
|
27
|
+
* when Redis is disabled OR the limit isn't exceeded.
|
|
28
|
+
*/
|
|
29
|
+
async function checkRateLimit(key, config) {
|
|
30
|
+
const limiter = getRateLimiter(config);
|
|
31
|
+
if (!limiter)
|
|
32
|
+
return { allowed: true };
|
|
33
|
+
const { success, reset } = await limiter.limit(key);
|
|
34
|
+
if (!success)
|
|
35
|
+
return { allowed: false, reset };
|
|
36
|
+
return { allowed: true };
|
|
37
|
+
}
|
|
38
|
+
return { getRateLimiter, checkRateLimit };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAmB/C;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAkC;IACzE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;IAE5C,SAAS,cAAc,CAAC,MAAuB;QAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC;YAC5B,KAAK;YACL,OAAO,EAAE,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,MAAuD,CAAC;YACpH,SAAS;YACT,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;QACH,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,KAAK,UAAU,cAAc,CAC3B,GAAW,EACX,MAAuB;QAEvB,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QACvC,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC/C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC3B,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Redis } from "@upstash/redis";
|
|
2
|
+
export interface RedisCredentialsProvider {
|
|
3
|
+
/** Lazy URL resolver — invoked only when Redis is first needed. */
|
|
4
|
+
url: () => string | undefined;
|
|
5
|
+
/** Lazy token resolver — invoked only when Redis is first needed. */
|
|
6
|
+
token: () => string | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface RedisClientFactoryOptions {
|
|
9
|
+
credentials: RedisCredentialsProvider;
|
|
10
|
+
/** Optional disable hook (e.g. emulator/local-dev detection). When this returns true on first call, Redis is permanently disabled for this factory instance. */
|
|
11
|
+
disabledWhen?: () => boolean;
|
|
12
|
+
/** Optional logger for "Redis not configured" / "disabled" diagnostics. */
|
|
13
|
+
logger?: {
|
|
14
|
+
info?: (message: string) => void;
|
|
15
|
+
warn?: (message: string) => void;
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Build a lazy, singleton Redis client. The client is constructed on first
|
|
20
|
+
* `get()` and reused thereafter. Returns null when credentials are missing
|
|
21
|
+
* or the disable hook returned true at first access.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createRedisClientFactory(options: RedisClientFactoryOptions): {
|
|
24
|
+
get(): Redis | null;
|
|
25
|
+
/** Test-only: reset cached state. Do not call in production. */
|
|
26
|
+
__reset(): void;
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=redis-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-client.d.ts","sourceRoot":"","sources":["../src/redis-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,MAAM,WAAW,wBAAwB;IACvC,mEAAmE;IACnE,GAAG,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC9B,qEAAqE;IACrE,KAAK,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,wBAAwB,CAAC;IACtC,gKAAgK;IAChK,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;IAC7B,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;QACjC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;KAClC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG;IAC5E,GAAG,IAAI,KAAK,GAAG,IAAI,CAAC;IACpB,gEAAgE;IAChE,OAAO,IAAI,IAAI,CAAC;CACjB,CAoCA"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Redis } from "@upstash/redis";
|
|
2
|
+
/**
|
|
3
|
+
* Build a lazy, singleton Redis client. The client is constructed on first
|
|
4
|
+
* `get()` and reused thereafter. Returns null when credentials are missing
|
|
5
|
+
* or the disable hook returned true at first access.
|
|
6
|
+
*/
|
|
7
|
+
export function createRedisClientFactory(options) {
|
|
8
|
+
let cached = null;
|
|
9
|
+
let disabled = false;
|
|
10
|
+
let resolved = false;
|
|
11
|
+
function resolve() {
|
|
12
|
+
if (resolved)
|
|
13
|
+
return cached;
|
|
14
|
+
resolved = true;
|
|
15
|
+
if (options.disabledWhen?.()) {
|
|
16
|
+
options.logger?.info?.("[rate-limit-core] Redis disabled by disabledWhen hook.");
|
|
17
|
+
disabled = true;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const url = options.credentials.url();
|
|
21
|
+
const token = options.credentials.token();
|
|
22
|
+
if (!url || !token) {
|
|
23
|
+
options.logger?.warn?.("[rate-limit-core] Redis credentials not configured.");
|
|
24
|
+
disabled = true;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
cached = new Redis({ url, token });
|
|
28
|
+
return cached;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
get() {
|
|
32
|
+
if (disabled)
|
|
33
|
+
return null;
|
|
34
|
+
return resolve();
|
|
35
|
+
},
|
|
36
|
+
__reset() {
|
|
37
|
+
cached = null;
|
|
38
|
+
disabled = false;
|
|
39
|
+
resolved = false;
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=redis-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-client.js","sourceRoot":"","sources":["../src/redis-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAoBvC;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAkC;IAKzE,IAAI,MAAM,GAAiB,IAAI,CAAC;IAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,SAAS,OAAO;QACd,IAAI,QAAQ;YAAE,OAAO,MAAM,CAAC;QAC5B,QAAQ,GAAG,IAAI,CAAC;QAEhB,IAAI,OAAO,CAAC,YAAY,EAAE,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,wDAAwD,CAAC,CAAC;YACjF,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC;QACtC,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;QAC1C,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,qDAAqD,CAAC,CAAC;YAC9E,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,GAAG,IAAI,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QACnC,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,OAAO;QACL,GAAG;YACD,IAAI,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAC1B,OAAO,OAAO,EAAE,CAAC;QACnB,CAAC;QACD,OAAO;YACL,MAAM,GAAG,IAAI,CAAC;YACd,QAAQ,GAAG,KAAK,CAAC;YACjB,QAAQ,GAAG,KAAK,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ttt-productions/rate-limit-core",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/ttt-productions/ttt-packages.git",
|
|
7
|
+
"directory": "packages/rate-limit-core"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "dist/index.js",
|
|
11
|
+
"module": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"sideEffects": false,
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
26
|
+
"typecheck": "tsc --noEmit",
|
|
27
|
+
"prepublishOnly": "npm run clean && npm run build"
|
|
28
|
+
},
|
|
29
|
+
"peerDependencies": {
|
|
30
|
+
"@upstash/ratelimit": ">=2.0.0",
|
|
31
|
+
"@upstash/redis": ">=1.34.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@upstash/ratelimit": "^2.0.0",
|
|
35
|
+
"@upstash/redis": "^1.34.0",
|
|
36
|
+
"typescript": "^5.8.3"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=22",
|
|
40
|
+
"npm": ">=10"
|
|
41
|
+
},
|
|
42
|
+
"author": "DJ (TTT Productions)",
|
|
43
|
+
"license": "MIT"
|
|
44
|
+
}
|