@barqel/barq-rate-limit 0.0.0-stage → 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.
@@ -0,0 +1,7 @@
1
+ import type { App } from "@barqel/barq";
2
+ import type { RateLimitOptions } from "./types";
3
+ export * from "./middleware";
4
+ export * from "./store";
5
+ export * from "./types";
6
+ export declare function rateLimiter(options?: RateLimitOptions): (app: App<any>) => void;
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,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAExC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAEhD,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AAExB,wBAAgB,WAAW,CAAC,OAAO,GAAE,gBAAqB,IAEjD,KAAK,GAAG,CAAC,GAAG,CAAC,UAGrB"}
package/dist/index.js ADDED
@@ -0,0 +1,153 @@
1
+ // src/middleware.ts
2
+ import { json } from "@barqel/barq";
3
+
4
+ // src/store.ts
5
+ class MemoryStore {
6
+ hits = new Map;
7
+ sweepInterval = null;
8
+ constructor(sweepMs = 30000) {
9
+ this.sweepInterval = setInterval(() => this.sweep(), sweepMs);
10
+ if (typeof this.sweepInterval.unref === "function") {
11
+ this.sweepInterval.unref();
12
+ }
13
+ }
14
+ increment(key, windowMs) {
15
+ const now = Date.now();
16
+ let entry = this.hits.get(key);
17
+ if (!entry || entry.expiresAt <= now) {
18
+ entry = { count: 1, expiresAt: now + windowMs };
19
+ this.hits.set(key, entry);
20
+ } else {
21
+ entry.count++;
22
+ }
23
+ const timeToResetMs = Math.max(0, entry.expiresAt - now);
24
+ return {
25
+ totalHits: entry.count,
26
+ timeToResetMs,
27
+ resetTime: Math.ceil(entry.expiresAt / 1000)
28
+ };
29
+ }
30
+ decrement(key) {
31
+ const entry = this.hits.get(key);
32
+ if (entry && entry.count > 0) {
33
+ entry.count--;
34
+ }
35
+ }
36
+ reset(key) {
37
+ this.hits.delete(key);
38
+ }
39
+ clear() {
40
+ this.hits.clear();
41
+ }
42
+ destroy() {
43
+ if (this.sweepInterval) {
44
+ clearInterval(this.sweepInterval);
45
+ this.sweepInterval = null;
46
+ }
47
+ this.clear();
48
+ }
49
+ sweep() {
50
+ const now = Date.now();
51
+ for (const [key, entry] of this.hits.entries()) {
52
+ if (entry.expiresAt <= now) {
53
+ this.hits.delete(key);
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ // src/middleware.ts
60
+ var defaultStore = new MemoryStore;
61
+ function rateLimit(options = {}) {
62
+ const windowMs = options.windowMs ?? 60000;
63
+ const maxOption = options.max ?? 100;
64
+ const statusCode = options.statusCode ?? 429;
65
+ const standardHeaders = options.standardHeaders ?? true;
66
+ const legacyHeaders = options.legacyHeaders ?? true;
67
+ const store = options.store ?? defaultStore;
68
+ const keyGenerator = options.keyGenerator ?? ((ctx) => {
69
+ return ctx.ip || ctx.req.headers.get("x-forwarded-for") || "127.0.0.1";
70
+ });
71
+ return {
72
+ async before(ctx) {
73
+ if (options.skip && await options.skip(ctx)) {
74
+ return;
75
+ }
76
+ const key = await keyGenerator(ctx);
77
+ const maxLimit = typeof maxOption === "function" ? await maxOption(ctx) : maxOption;
78
+ const { totalHits, timeToResetMs, resetTime } = await store.increment(key, windowMs);
79
+ const remaining = Math.max(0, maxLimit - totalHits);
80
+ const retryAfter = Math.ceil(timeToResetMs / 1000);
81
+ const info = {
82
+ limit: maxLimit,
83
+ current: totalHits,
84
+ remaining,
85
+ resetTime,
86
+ retryAfter
87
+ };
88
+ const state = ctx.state;
89
+ state._rateLimitInfo = info;
90
+ const headersToSet = new Headers;
91
+ if (standardHeaders) {
92
+ headersToSet.set("RateLimit-Limit", String(maxLimit));
93
+ headersToSet.set("RateLimit-Remaining", String(remaining));
94
+ headersToSet.set("RateLimit-Reset", String(retryAfter));
95
+ }
96
+ if (legacyHeaders) {
97
+ headersToSet.set("X-RateLimit-Limit", String(maxLimit));
98
+ headersToSet.set("X-RateLimit-Remaining", String(remaining));
99
+ headersToSet.set("X-RateLimit-Reset", String(resetTime));
100
+ }
101
+ state._rateLimitHeaders = headersToSet;
102
+ if (totalHits > maxLimit) {
103
+ headersToSet.set("Retry-After", String(retryAfter));
104
+ if (options.onRateLimit) {
105
+ return options.onRateLimit(ctx, info);
106
+ }
107
+ const body = options.message !== undefined ? options.message : {
108
+ error: "Too Many Requests",
109
+ message: `Rate limit exceeded, retry in ${retryAfter} seconds`,
110
+ retryAfter
111
+ };
112
+ const response = typeof body === "string" ? new Response(body, { status: statusCode }) : json(body, statusCode);
113
+ for (const [k, v] of headersToSet.entries()) {
114
+ response.headers.set(k, v);
115
+ }
116
+ return response;
117
+ }
118
+ },
119
+ after(ctx, res) {
120
+ const state = ctx.state;
121
+ const rlHeaders = state._rateLimitHeaders;
122
+ if (rlHeaders) {
123
+ const headers = new Headers(res.headers);
124
+ for (const [k, v] of rlHeaders.entries()) {
125
+ if (!headers.has(k)) {
126
+ headers.set(k, v);
127
+ }
128
+ }
129
+ return new Response(res.body, {
130
+ status: res.status,
131
+ statusText: res.statusText,
132
+ headers
133
+ });
134
+ }
135
+ return res;
136
+ }
137
+ };
138
+ }
139
+
140
+ // src/index.ts
141
+ function rateLimiter(options = {}) {
142
+ const mw = rateLimit(options);
143
+ return (app) => {
144
+ app.use(mw);
145
+ };
146
+ }
147
+ export {
148
+ MemoryStore,
149
+ rateLimit,
150
+ rateLimiter
151
+ };
152
+
153
+ //# debugId=119AA4BA8ADA270964756E2164756E21
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/middleware.ts", "../src/store.ts", "../src/index.ts"],
4
+ "sourcesContent": [
5
+ "import { type Context, json, type Middleware } from \"@barqel/barq\";\nimport { MemoryStore } from \"./store\";\nimport type { RateLimitInfo, RateLimitOptions, RateLimitStore } from \"./types\";\n\nconst defaultStore = new MemoryStore();\n\nexport function rateLimit(options: RateLimitOptions = {}): Middleware {\n\tconst windowMs = options.windowMs ?? 60_000;\n\tconst maxOption = options.max ?? 100;\n\tconst statusCode = options.statusCode ?? 429;\n\tconst standardHeaders = options.standardHeaders ?? true;\n\tconst legacyHeaders = options.legacyHeaders ?? true;\n\tconst store: RateLimitStore = options.store ?? defaultStore;\n\n\tconst keyGenerator =\n\t\toptions.keyGenerator ??\n\t\t((ctx: Context) => {\n\t\t\treturn ctx.ip || ctx.req.headers.get(\"x-forwarded-for\") || \"127.0.0.1\";\n\t\t});\n\n\treturn {\n\t\tasync before(ctx: Context) {\n\t\t\tif (options.skip && (await options.skip(ctx))) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst key = await keyGenerator(ctx);\n\t\t\tconst maxLimit =\n\t\t\t\ttypeof maxOption === \"function\" ? await maxOption(ctx) : maxOption;\n\t\t\tconst { totalHits, timeToResetMs, resetTime } = await store.increment(\n\t\t\t\tkey,\n\t\t\t\twindowMs,\n\t\t\t);\n\n\t\t\tconst remaining = Math.max(0, maxLimit - totalHits);\n\t\t\tconst retryAfter = Math.ceil(timeToResetMs / 1000);\n\n\t\t\tconst info: RateLimitInfo = {\n\t\t\t\tlimit: maxLimit,\n\t\t\t\tcurrent: totalHits,\n\t\t\t\tremaining,\n\t\t\t\tresetTime,\n\t\t\t\tretryAfter,\n\t\t\t};\n\n\t\t\tconst state = ctx.state as Record<string, unknown>;\n\t\t\tstate._rateLimitInfo = info;\n\n\t\t\tconst headersToSet = new Headers();\n\t\t\tif (standardHeaders) {\n\t\t\t\theadersToSet.set(\"RateLimit-Limit\", String(maxLimit));\n\t\t\t\theadersToSet.set(\"RateLimit-Remaining\", String(remaining));\n\t\t\t\theadersToSet.set(\"RateLimit-Reset\", String(retryAfter));\n\t\t\t}\n\t\t\tif (legacyHeaders) {\n\t\t\t\theadersToSet.set(\"X-RateLimit-Limit\", String(maxLimit));\n\t\t\t\theadersToSet.set(\"X-RateLimit-Remaining\", String(remaining));\n\t\t\t\theadersToSet.set(\"X-RateLimit-Reset\", String(resetTime));\n\t\t\t}\n\n\t\t\tstate._rateLimitHeaders = headersToSet;\n\n\t\t\tif (totalHits > maxLimit) {\n\t\t\t\theadersToSet.set(\"Retry-After\", String(retryAfter));\n\n\t\t\t\tif (options.onRateLimit) {\n\t\t\t\t\treturn options.onRateLimit(ctx, info);\n\t\t\t\t}\n\n\t\t\t\tconst body =\n\t\t\t\t\toptions.message !== undefined\n\t\t\t\t\t\t? options.message\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\terror: \"Too Many Requests\",\n\t\t\t\t\t\t\t\tmessage: `Rate limit exceeded, retry in ${retryAfter} seconds`,\n\t\t\t\t\t\t\t\tretryAfter,\n\t\t\t\t\t\t\t};\n\n\t\t\t\tconst response =\n\t\t\t\t\ttypeof body === \"string\"\n\t\t\t\t\t\t? new Response(body, { status: statusCode })\n\t\t\t\t\t\t: json(body, statusCode);\n\n\t\t\t\tfor (const [k, v] of headersToSet.entries()) {\n\t\t\t\t\tresponse.headers.set(k, v);\n\t\t\t\t}\n\n\t\t\t\treturn response;\n\t\t\t}\n\t\t},\n\n\t\tafter(ctx: Context, res: Response) {\n\t\t\tconst state = ctx.state as Record<string, unknown>;\n\t\t\tconst rlHeaders = state._rateLimitHeaders as Headers | undefined;\n\n\t\t\tif (rlHeaders) {\n\t\t\t\tconst headers = new Headers(res.headers);\n\t\t\t\tfor (const [k, v] of rlHeaders.entries()) {\n\t\t\t\t\tif (!headers.has(k)) {\n\t\t\t\t\t\theaders.set(k, v);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn new Response(res.body, {\n\t\t\t\t\tstatus: res.status,\n\t\t\t\t\tstatusText: res.statusText,\n\t\t\t\t\theaders,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn res;\n\t\t},\n\t};\n}\n",
6
+ "import type { RateLimitStore, StoreIncrementResult } from \"./types\";\n\ninterface MemoryEntry {\n\tcount: number;\n\texpiresAt: number;\n}\n\nexport class MemoryStore implements RateLimitStore {\n\tprivate readonly hits = new Map<string, MemoryEntry>();\n\tprivate sweepInterval: ReturnType<typeof setInterval> | null = null;\n\n\tconstructor(sweepMs = 30_000) {\n\t\tthis.sweepInterval = setInterval(() => this.sweep(), sweepMs);\n\t\tif (typeof this.sweepInterval.unref === \"function\") {\n\t\t\tthis.sweepInterval.unref();\n\t\t}\n\t}\n\n\tincrement(key: string, windowMs: number): StoreIncrementResult {\n\t\tconst now = Date.now();\n\t\tlet entry = this.hits.get(key);\n\n\t\tif (!entry || entry.expiresAt <= now) {\n\t\t\tentry = { count: 1, expiresAt: now + windowMs };\n\t\t\tthis.hits.set(key, entry);\n\t\t} else {\n\t\t\tentry.count++;\n\t\t}\n\n\t\tconst timeToResetMs = Math.max(0, entry.expiresAt - now);\n\t\treturn {\n\t\t\ttotalHits: entry.count,\n\t\t\ttimeToResetMs,\n\t\t\tresetTime: Math.ceil(entry.expiresAt / 1000),\n\t\t};\n\t}\n\n\tdecrement(key: string): void {\n\t\tconst entry = this.hits.get(key);\n\t\tif (entry && entry.count > 0) {\n\t\t\tentry.count--;\n\t\t}\n\t}\n\n\treset(key: string): void {\n\t\tthis.hits.delete(key);\n\t}\n\n\tclear(): void {\n\t\tthis.hits.clear();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.sweepInterval) {\n\t\t\tclearInterval(this.sweepInterval);\n\t\t\tthis.sweepInterval = null;\n\t\t}\n\t\tthis.clear();\n\t}\n\n\tprivate sweep(): void {\n\t\tconst now = Date.now();\n\t\tfor (const [key, entry] of this.hits.entries()) {\n\t\t\tif (entry.expiresAt <= now) {\n\t\t\t\tthis.hits.delete(key);\n\t\t\t}\n\t\t}\n\t}\n}\n",
7
+ "import type { App } from \"@barqel/barq\";\nimport { rateLimit } from \"./middleware\";\nimport type { RateLimitOptions } from \"./types\";\n\nexport * from \"./middleware\";\nexport * from \"./store\";\nexport * from \"./types\";\n\nexport function rateLimiter(options: RateLimitOptions = {}) {\n\tconst mw = rateLimit(options);\n\treturn (app: App<any>) => {\n\t\tapp.use(mw);\n\t};\n}\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "119AA4BA8ADA270964756E2164756E21",
11
+ "names": []
12
+ }
@@ -0,0 +1,4 @@
1
+ import { type Middleware } from "@barqel/barq";
2
+ import type { RateLimitOptions } from "./types";
3
+ export declare function rateLimit(options?: RateLimitOptions): Middleware;
4
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEnE,OAAO,KAAK,EAAiB,gBAAgB,EAAkB,MAAM,SAAS,CAAC;AAI/E,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,UAAU,CA2GpE"}
@@ -0,0 +1,13 @@
1
+ import type { RateLimitStore, StoreIncrementResult } from "./types";
2
+ export declare class MemoryStore implements RateLimitStore {
3
+ private readonly hits;
4
+ private sweepInterval;
5
+ constructor(sweepMs?: number);
6
+ increment(key: string, windowMs: number): StoreIncrementResult;
7
+ decrement(key: string): void;
8
+ reset(key: string): void;
9
+ clear(): void;
10
+ destroy(): void;
11
+ private sweep;
12
+ }
13
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAOpE,qBAAa,WAAY,YAAW,cAAc;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAkC;IACvD,OAAO,CAAC,aAAa,CAA+C;gBAExD,OAAO,SAAS;IAO5B,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,oBAAoB;IAmB9D,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAO5B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIxB,KAAK,IAAI,IAAI;IAIb,OAAO,IAAI,IAAI;IAQf,OAAO,CAAC,KAAK;CAQb"}
@@ -0,0 +1,32 @@
1
+ import type { Context } from "@barqel/barq";
2
+ export interface RateLimitInfo {
3
+ limit: number;
4
+ current: number;
5
+ remaining: number;
6
+ resetTime: number;
7
+ retryAfter: number;
8
+ }
9
+ export interface StoreIncrementResult {
10
+ totalHits: number;
11
+ timeToResetMs: number;
12
+ resetTime: number;
13
+ }
14
+ export interface RateLimitStore {
15
+ increment(key: string, windowMs: number): Promise<StoreIncrementResult> | StoreIncrementResult;
16
+ decrement?(key: string): Promise<void> | void;
17
+ reset(key: string): Promise<void> | void;
18
+ clear(): Promise<void> | void;
19
+ }
20
+ export interface RateLimitOptions {
21
+ windowMs?: number;
22
+ max?: number | ((ctx: Context) => number | Promise<number>);
23
+ keyGenerator?: (ctx: Context) => string | Promise<string>;
24
+ skip?: (ctx: Context) => boolean | Promise<boolean>;
25
+ standardHeaders?: boolean;
26
+ legacyHeaders?: boolean;
27
+ statusCode?: number;
28
+ message?: unknown;
29
+ store?: RateLimitStore;
30
+ onRateLimit?: (ctx: Context, info: RateLimitInfo) => Response | Promise<Response>;
31
+ }
32
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,oBAAoB;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC9B,SAAS,CACR,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC,oBAAoB,CAAC,GAAG,oBAAoB,CAAC;IACxD,SAAS,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAC9C,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,WAAW,CAAC,EAAE,CACb,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE,aAAa,KACf,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAClC"}
package/package.json CHANGED
@@ -1,6 +1,37 @@
1
1
  {
2
- "name": "@barqel/barq-rate-limit",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@barqel/barq-rate-limit",
3
+ "version": "1.0.0",
4
+ "description": "Zero-dependency, high-performance rate limiting plugin for Barq",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "scripts": {
18
+ "format": "biome format --write .",
19
+ "lint": "biome lint .",
20
+ "check": "biome check .",
21
+ "build": "rm -rf dist && bun build src/index.ts --external @barqel/barq --target=node --format=esm --sourcemap=external --outdir dist && tsc --emitDeclarationOnly --declaration --outDir dist",
22
+ "test": "bun test",
23
+ "prepublishOnly": "bun run check && bun test && bun run build"
24
+ },
25
+ "files": [
26
+ "dist"
27
+ ],
28
+ "peerDependencies": {
29
+ "@barqel/barq": ">=1.0.0"
30
+ },
31
+ "devDependencies": {
32
+ "@biomejs/biome": "^2.5.15",
33
+ "@types/bun": "^1.2.0",
34
+ "@types/node": "^20.0.0",
35
+ "typescript": "^5.0.0"
36
+ }
37
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.