ertk 0.1.0 → 0.1.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.
@@ -5,6 +5,7 @@
5
5
  * Next.js App Router route handlers. Decoupled from any specific
6
6
  * auth or database implementation.
7
7
  */
8
+ import { defaultKeyFn, InMemoryRateLimitAdapter, } from "./rate-limit.js";
8
9
  // ─── Validation Error ─────────────────────────────────────────
9
10
  class ValidationError extends Error {
10
11
  issues;
@@ -82,6 +83,38 @@ function jsonResponse(data, status = 200) {
82
83
  function errorResponse(message, status) {
83
84
  return jsonResponse({ error: message }, status);
84
85
  }
86
+ // ─── Rate Limiting ────────────────────────────────────────────
87
+ let defaultAdapter = null;
88
+ function getDefaultAdapter() {
89
+ if (!defaultAdapter) {
90
+ defaultAdapter = new InMemoryRateLimitAdapter();
91
+ }
92
+ return defaultAdapter;
93
+ }
94
+ async function applyRateLimit(req, user, globalConfig, endpointOverride) {
95
+ if (!globalConfig && !endpointOverride)
96
+ return null;
97
+ const windowMs = endpointOverride?.windowMs ?? globalConfig.windowMs;
98
+ const max = endpointOverride?.max ?? globalConfig.max;
99
+ const keyFn = globalConfig?.keyFn ?? defaultKeyFn;
100
+ const adapter = globalConfig?.adapter ?? getDefaultAdapter();
101
+ const key = keyFn(req, user);
102
+ const result = await adapter.check(key, windowMs, max);
103
+ if (!result.allowed) {
104
+ const retryAfter = Math.ceil((result.resetAt * 1000 - Date.now()) / 1000);
105
+ return new Response(JSON.stringify({ error: "Too many requests" }), {
106
+ status: 429,
107
+ headers: {
108
+ "Content-Type": "application/json",
109
+ "Retry-After": String(Math.max(1, retryAfter)),
110
+ "X-RateLimit-Limit": String(result.limit),
111
+ "X-RateLimit-Remaining": "0",
112
+ "X-RateLimit-Reset": String(result.resetAt),
113
+ },
114
+ });
115
+ }
116
+ return null;
117
+ }
85
118
  // ─── Route Handler Factory ───────────────────────────────────
86
119
  /**
87
120
  * Create a configured route handler factory. Call this once with your
@@ -130,6 +163,12 @@ export function configureHandler(options = {}) {
130
163
  return errorResponse("Unauthorized", 401);
131
164
  }
132
165
  }
166
+ // Rate limiting
167
+ if (options.rateLimit || def.rateLimit) {
168
+ const rateLimitResponse = await applyRateLimit(req, user, options.rateLimit, def.rateLimit);
169
+ if (rateLimitResponse)
170
+ return rateLimitResponse;
171
+ }
133
172
  // Call the endpoint handler
134
173
  if (!def.handler) {
135
174
  return errorResponse("No handler defined for this endpoint", 501);
@@ -1 +1 @@
1
- {"version":3,"file":"route-handler.js","sourceRoot":"","sources":["../../src/next/route-handler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"route-handler.js","sourceRoot":"","sources":["../../src/next/route-handler.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -69,6 +69,22 @@ export interface EndpointDefinition<TResponse = unknown, TArgs = void> {
69
69
  };
70
70
  /** Optimistic update configuration */
71
71
  optimistic?: SingleOptimistic<TArgs> | MultiOptimistic<TArgs>;
72
+ /**
73
+ * Maximum number of retry attempts for transient failures (5xx, network errors, 408, 429).
74
+ * Uses RTK Query's built-in `retry` utility with exponential backoff.
75
+ * 0 or undefined means no retries. A value of 2 means up to 3 total attempts.
76
+ * Client-side only — does not affect server-side route handlers.
77
+ */
78
+ maxRetries?: number;
79
+ /**
80
+ * Per-endpoint rate limit override for the server-side route handler.
81
+ * Overrides the global `rateLimit` config from `configureHandler()`.
82
+ * Only `windowMs` and `max` can be overridden; `keyFn` and `adapter` come from the global config.
83
+ */
84
+ rateLimit?: {
85
+ windowMs: number;
86
+ max: number;
87
+ };
72
88
  /**
73
89
  * Server-side handler. Optional — omit for client-only endpoints
74
90
  * that consume an external API.
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,75 +1,74 @@
1
1
  {
2
- "name": "ertk",
3
- "version": "0.1.0",
4
- "description": "Easy RTK — Define endpoints once, generate RTK Query hooks and route handlers automatically",
5
- "type": "module",
6
- "exports": {
7
- ".": {
8
- "types": "./dist/index.d.ts",
9
- "import": "./dist/index.js"
10
- },
11
- "./next": {
12
- "types": "./dist/next/index.d.ts",
13
- "import": "./dist/next/index.js"
14
- }
15
- },
16
- "bin": {
17
- "ertk": "dist/cli.js"
18
- },
19
- "files": [
20
- "dist"
21
- ],
22
- "scripts": {
23
- "build": "tsc",
24
- "dev": "tsc --watch",
25
- "prepublishOnly": "tsc"
26
- },
27
- "keywords": [
28
- "rtk",
29
- "redux",
30
- "rtk-query",
31
- "codegen",
32
- "next.js",
33
- "api",
34
- "endpoints"
35
- ],
36
- "author": "Amber Cowled",
37
- "license": "MIT",
38
- "repository": {
39
- "type": "git",
40
- "url": "git+https://github.com/AmberCowled/ertk.git"
41
- },
42
- "homepage": "https://github.com/AmberCowled/ertk#readme",
43
- "bugs": {
44
- "url": "https://github.com/AmberCowled/ertk/issues"
45
- },
46
- "dependencies": {
47
- "jiti": "^2.4.2",
48
- "ts-morph": "^27.0.2"
49
- },
50
- "peerDependencies": {
51
- "@reduxjs/toolkit": "^2.0.0",
52
- "next": ">=14.0.0",
53
- "react": ">=18.0.0",
54
- "react-redux": "^9.0.0",
55
- "typescript": "^5.0.0",
56
- "zod": "^3.0.0 || ^4.0.0"
57
- },
58
- "peerDependenciesMeta": {
59
- "next": {
60
- "optional": true
61
- },
62
- "zod": {
63
- "optional": true
64
- }
65
- },
66
- "devDependencies": {
67
- "@reduxjs/toolkit": "^2.5.0",
68
- "@types/node": "^22.0.0",
69
- "next": "^16.0.0",
70
- "react": "^19.0.0",
71
- "react-redux": "^9.2.0",
72
- "typescript": "^5.0.0",
73
- "zod": "^4.0.0"
74
- }
75
- }
2
+ "name": "ertk",
3
+ "version": "0.1.2",
4
+ "description": "Easy RTK — Define endpoints once, generate RTK Query hooks and route handlers automatically",
5
+ "type": "module",
6
+ "exports": {
7
+ ".": {
8
+ "types": "./dist/index.d.ts",
9
+ "import": "./dist/index.js"
10
+ },
11
+ "./next": {
12
+ "types": "./dist/next/index.d.ts",
13
+ "import": "./dist/next/index.js"
14
+ }
15
+ },
16
+ "bin": {
17
+ "ertk": "dist/cli.js"
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "keywords": [
23
+ "rtk",
24
+ "redux",
25
+ "rtk-query",
26
+ "codegen",
27
+ "next.js",
28
+ "api",
29
+ "endpoints"
30
+ ],
31
+ "author": "Amber Cowled",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/AmberCowled/ertk.git"
36
+ },
37
+ "homepage": "https://github.com/AmberCowled/ertk#readme",
38
+ "bugs": {
39
+ "url": "https://github.com/AmberCowled/ertk/issues"
40
+ },
41
+ "dependencies": {
42
+ "jiti": "^2.4.2",
43
+ "ts-morph": "^27.0.2"
44
+ },
45
+ "peerDependencies": {
46
+ "@reduxjs/toolkit": "^2.0.0",
47
+ "next": ">=14.0.0",
48
+ "react": ">=18.0.0",
49
+ "react-redux": "^9.0.0",
50
+ "typescript": "^5.0.0",
51
+ "zod": "^3.0.0 || ^4.0.0"
52
+ },
53
+ "peerDependenciesMeta": {
54
+ "next": {
55
+ "optional": true
56
+ },
57
+ "zod": {
58
+ "optional": true
59
+ }
60
+ },
61
+ "devDependencies": {
62
+ "@reduxjs/toolkit": "^2.5.0",
63
+ "@types/node": "^22.0.0",
64
+ "next": "^16.0.0",
65
+ "react": "^19.0.0",
66
+ "react-redux": "^9.2.0",
67
+ "typescript": "^5.0.0",
68
+ "zod": "^4.0.0"
69
+ },
70
+ "scripts": {
71
+ "build": "tsc",
72
+ "dev": "tsc --watch"
73
+ }
74
+ }