@supaku/agentfactory-nextjs 0.4.2 → 0.4.3

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.
@@ -1,11 +1,12 @@
1
1
  /**
2
- * Middleware Factory
2
+ * Middleware Factory — Edge Runtime Compatible
3
3
  *
4
4
  * Creates a Next.js middleware function that handles authentication,
5
5
  * rate limiting, and security for AgentFactory API routes.
6
6
  *
7
- * Uses the rate limiter and worker auth from @supaku/agentfactory-server
8
- * for proper LRU eviction and crypto.timingSafeEqual.
7
+ * IMPORTANT: This module runs in the Edge Runtime. It MUST NOT import
8
+ * from @supaku/agentfactory-server (which uses Node.js crypto/ioredis).
9
+ * All utilities are inlined for Edge compatibility.
9
10
  */
10
11
  import { NextRequest, NextResponse } from 'next/server';
11
12
  import type { MiddlewareConfig } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/middleware/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAOvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAQlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,CAAC,EAAE,gBAAgB;0BAO3C,WAAW,KAAG,YAAY,GAAG,SAAS;;;;EA8GpE"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/middleware/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AA0GlD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,CAAC,EAAE,gBAAgB;0BAO3C,WAAW,KAAG,YAAY,GAAG,SAAS;;;;EA8GpE"}
@@ -1,14 +1,80 @@
1
1
  /**
2
- * Middleware Factory
2
+ * Middleware Factory — Edge Runtime Compatible
3
3
  *
4
4
  * Creates a Next.js middleware function that handles authentication,
5
5
  * rate limiting, and security for AgentFactory API routes.
6
6
  *
7
- * Uses the rate limiter and worker auth from @supaku/agentfactory-server
8
- * for proper LRU eviction and crypto.timingSafeEqual.
7
+ * IMPORTANT: This module runs in the Edge Runtime. It MUST NOT import
8
+ * from @supaku/agentfactory-server (which uses Node.js crypto/ioredis).
9
+ * All utilities are inlined for Edge compatibility.
9
10
  */
10
11
  import { NextResponse } from 'next/server';
11
- import { checkRateLimit, getClientIP, buildRateLimitHeaders, verifyApiKey, } from '@supaku/agentfactory-server';
12
+ const RATE_LIMITS = {
13
+ public: { limit: 60, windowMs: 60_000 },
14
+ webhook: { limit: 10, windowMs: 1_000 },
15
+ dashboard: { limit: 30, windowMs: 60_000 },
16
+ };
17
+ const caches = new Map();
18
+ function checkRateLimit(type, key) {
19
+ const config = RATE_LIMITS[type];
20
+ let cache = caches.get(type);
21
+ if (!cache) {
22
+ cache = new Map();
23
+ caches.set(type, cache);
24
+ }
25
+ const now = Date.now();
26
+ const windowStart = now - config.windowMs;
27
+ let entry = cache.get(key);
28
+ if (!entry) {
29
+ entry = { timestamps: [], lastAccess: now };
30
+ }
31
+ entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);
32
+ entry.lastAccess = now;
33
+ const allowed = entry.timestamps.length < config.limit;
34
+ if (allowed)
35
+ entry.timestamps.push(now);
36
+ cache.set(key, entry);
37
+ // LRU eviction at 10k entries
38
+ if (cache.size > 10_000) {
39
+ const entries = Array.from(cache.entries()).sort((a, b) => a[1].lastAccess - b[1].lastAccess);
40
+ const toRemove = Math.ceil(10_000 * 0.1);
41
+ for (let i = 0; i < toRemove && i < entries.length; i++) {
42
+ cache.delete(entries[i][0]);
43
+ }
44
+ }
45
+ const remaining = Math.max(0, config.limit - entry.timestamps.length);
46
+ const oldestTs = entry.timestamps[0];
47
+ const resetIn = oldestTs ? Math.max(0, oldestTs + config.windowMs - now) : 0;
48
+ return { allowed, remaining, resetIn, limit: config.limit };
49
+ }
50
+ // === Edge-compatible utilities ===
51
+ function getClientIP(headers) {
52
+ return (headers.get('x-forwarded-for')?.split(',')[0].trim() ||
53
+ headers.get('cf-connecting-ip') ||
54
+ headers.get('x-real-ip') ||
55
+ 'unknown');
56
+ }
57
+ function buildRateLimitHeaders(result) {
58
+ return {
59
+ 'X-RateLimit-Limit': result.limit.toString(),
60
+ 'X-RateLimit-Remaining': result.remaining.toString(),
61
+ 'X-RateLimit-Reset': Math.ceil(result.resetIn / 1000).toString(),
62
+ };
63
+ }
64
+ /**
65
+ * Timing-safe string comparison using XOR (Edge-compatible).
66
+ * Does NOT use Node.js crypto.timingSafeEqual.
67
+ */
68
+ function timingSafeEqual(a, b) {
69
+ if (a.length !== b.length)
70
+ return false;
71
+ let result = 0;
72
+ for (let i = 0; i < a.length; i++) {
73
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
74
+ }
75
+ return result === 0;
76
+ }
77
+ // === Route defaults ===
12
78
  const DEFAULT_PUBLIC_ROUTES = ['/api/public/', '/dashboard', '/'];
13
79
  const DEFAULT_PROTECTED_ROUTES = ['/api/sessions', '/api/workers'];
14
80
  const DEFAULT_SESSION_PAGES = ['/sessions/'];
@@ -90,7 +156,7 @@ export function createAgentFactoryMiddleware(userConfig) {
90
156
  return new NextResponse(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing API key' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
91
157
  }
92
158
  const token = authHeader.slice(7);
93
- if (!verifyApiKey(token, workerApiKey)) {
159
+ if (!timingSafeEqual(token, workerApiKey)) {
94
160
  return new NextResponse(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing API key' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
95
161
  }
96
162
  return NextResponse.next();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supaku/agentfactory-nextjs",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "type": "module",
5
5
  "description": "Next.js API route handlers for AgentFactory — webhook processor, worker/session management, public stats",
6
6
  "author": "Supaku (https://supaku.com)",
@@ -43,9 +43,9 @@
43
43
  "LICENSE"
44
44
  ],
45
45
  "dependencies": {
46
- "@supaku/agentfactory-linear": "0.4.2",
47
- "@supaku/agentfactory-server": "0.4.2",
48
- "@supaku/agentfactory": "0.4.2"
46
+ "@supaku/agentfactory-linear": "0.4.3",
47
+ "@supaku/agentfactory-server": "0.4.3",
48
+ "@supaku/agentfactory": "0.4.3"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "next": ">=14.0.0"