@supaku/agentfactory-nextjs 0.4.1 → 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.
package/README.md ADDED
@@ -0,0 +1,139 @@
1
+ # @supaku/agentfactory-nextjs
2
+
3
+ Next.js route handlers, webhook processor, middleware, and OAuth for [AgentFactory](https://github.com/supaku/agentfactory). Drop-in API routes that turn a Next.js app into a full agent fleet server.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @supaku/agentfactory-nextjs
9
+ ```
10
+
11
+ Or scaffold a complete project:
12
+
13
+ ```bash
14
+ npx @supaku/create-agentfactory-app my-agent
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ### 1. Configure routes
20
+
21
+ ```typescript
22
+ // src/lib/config.ts
23
+ import { createAllRoutes, createDefaultLinearClientResolver } from '@supaku/agentfactory-nextjs'
24
+
25
+ export const routes = createAllRoutes({
26
+ linearClient: createDefaultLinearClientResolver(),
27
+ })
28
+ ```
29
+
30
+ ### 2. Add webhook route
31
+
32
+ ```typescript
33
+ // src/app/webhook/route.ts
34
+ import { routes } from '@/lib/config'
35
+ export const POST = routes.webhook.POST
36
+ export const GET = routes.webhook.GET
37
+ ```
38
+
39
+ ### 3. Add middleware
40
+
41
+ ```typescript
42
+ // src/middleware.ts
43
+ import { createAgentFactoryMiddleware } from '@supaku/agentfactory-nextjs'
44
+
45
+ const { middleware } = createAgentFactoryMiddleware()
46
+ export { middleware }
47
+
48
+ export const config = {
49
+ matcher: ['/api/:path*', '/webhook', '/dashboard', '/sessions/:path*', '/'],
50
+ }
51
+ ```
52
+
53
+ ## What's Included
54
+
55
+ `createAllRoutes()` generates 21+ route handlers from a single config:
56
+
57
+ | Route Group | Endpoints | Purpose |
58
+ |-------------|-----------|---------|
59
+ | **Webhook** | `POST /webhook` | Receive Linear events, dispatch agents |
60
+ | **Workers** | `/api/workers/*` | Worker registration, heartbeat, polling |
61
+ | **Sessions** | `/api/sessions/*` | Session management, status, activity |
62
+ | **Public** | `/api/public/*` | Public stats, session list |
63
+ | **Cleanup** | `/api/cleanup` | Orphaned resource cleanup |
64
+ | **OAuth** | `/callback` | Linear OAuth callback |
65
+
66
+ Each route file is a 2-line re-export:
67
+
68
+ ```typescript
69
+ import { routes } from '@/lib/config'
70
+ export const GET = routes.sessions.list.GET
71
+ ```
72
+
73
+ ## Configuration
74
+
75
+ ```typescript
76
+ const routes = createAllRoutes({
77
+ // Required: how to resolve a Linear API client
78
+ linearClient: createDefaultLinearClientResolver(),
79
+
80
+ // Optional: customize prompts, detection, priority
81
+ generatePrompt: (identifier, workType, mentionContext) => string,
82
+ detectWorkTypeFromPrompt: (prompt, validWorkTypes) => AgentWorkType | undefined,
83
+ getPriority: (workType) => number,
84
+
85
+ // Optional: auto-trigger QA/acceptance
86
+ autoTrigger: {
87
+ enableAutoQA: true,
88
+ enableAutoAcceptance: false,
89
+ autoQARequireAgentWorked: true,
90
+ autoAcceptanceRequireAgentWorked: true,
91
+ autoQAProjects: [],
92
+ autoAcceptanceProjects: [],
93
+ autoQAExcludeLabels: [],
94
+ autoAcceptanceExcludeLabels: [],
95
+ },
96
+
97
+ // Optional: OAuth
98
+ oauth: { clientId: '...', clientSecret: '...' },
99
+ })
100
+ ```
101
+
102
+ ## Middleware
103
+
104
+ Handles API key auth, rate limiting, and webhook signature verification:
105
+
106
+ ```typescript
107
+ const { middleware } = createAgentFactoryMiddleware({
108
+ routes: {
109
+ public: ['/api/public/', '/dashboard', '/'],
110
+ protected: ['/api/sessions', '/api/workers'],
111
+ webhook: '/webhook',
112
+ },
113
+ rateLimits: {
114
+ public: { max: 60, windowMs: 60_000 },
115
+ webhook: { max: 10, windowMs: 1_000 },
116
+ },
117
+ })
118
+ ```
119
+
120
+ ## Environment Variables
121
+
122
+ | Variable | Required | Description |
123
+ |----------|----------|-------------|
124
+ | `LINEAR_ACCESS_TOKEN` | Yes | Linear API key |
125
+ | `LINEAR_WEBHOOK_SECRET` | For webhooks | Webhook signature verification |
126
+ | `REDIS_URL` | For distributed | Redis connection URL |
127
+
128
+ ## Related Packages
129
+
130
+ | Package | Description |
131
+ |---------|-------------|
132
+ | [@supaku/agentfactory](https://www.npmjs.com/package/@supaku/agentfactory) | Core orchestrator |
133
+ | [@supaku/agentfactory-linear](https://www.npmjs.com/package/@supaku/agentfactory-linear) | Linear integration |
134
+ | [@supaku/agentfactory-server](https://www.npmjs.com/package/@supaku/agentfactory-server) | Redis infrastructure |
135
+ | [@supaku/agentfactory-cli](https://www.npmjs.com/package/@supaku/agentfactory-cli) | CLI tools |
136
+
137
+ ## License
138
+
139
+ MIT
@@ -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.1",
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": "0.4.1",
47
- "@supaku/agentfactory-server": "0.4.1",
48
- "@supaku/agentfactory-linear": "0.4.1"
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"