@supaku/agentfactory-nextjs 0.3.0 → 0.4.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.
Files changed (45) hide show
  1. package/dist/src/factory.d.ts +34 -6
  2. package/dist/src/factory.d.ts.map +1 -1
  3. package/dist/src/factory.js +37 -7
  4. package/dist/src/handlers/oauth/callback.d.ts +36 -0
  5. package/dist/src/handlers/oauth/callback.d.ts.map +1 -0
  6. package/dist/src/handlers/oauth/callback.js +92 -0
  7. package/dist/src/index.d.ts +11 -2
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js +11 -2
  10. package/dist/src/linear-client-resolver.d.ts +37 -0
  11. package/dist/src/linear-client-resolver.d.ts.map +1 -0
  12. package/dist/src/linear-client-resolver.js +60 -0
  13. package/dist/src/middleware/factory.d.ts +32 -0
  14. package/dist/src/middleware/factory.d.ts.map +1 -0
  15. package/dist/src/middleware/factory.js +115 -0
  16. package/dist/src/middleware/types.d.ts +35 -0
  17. package/dist/src/middleware/types.d.ts.map +1 -0
  18. package/dist/src/middleware/types.js +4 -0
  19. package/dist/src/orchestrator/error-formatting.d.ts +8 -0
  20. package/dist/src/orchestrator/error-formatting.d.ts.map +1 -0
  21. package/dist/src/orchestrator/error-formatting.js +35 -0
  22. package/dist/src/orchestrator/index.d.ts +4 -0
  23. package/dist/src/orchestrator/index.d.ts.map +1 -0
  24. package/dist/src/orchestrator/index.js +2 -0
  25. package/dist/src/orchestrator/types.d.ts +53 -0
  26. package/dist/src/orchestrator/types.d.ts.map +1 -0
  27. package/dist/src/orchestrator/types.js +4 -0
  28. package/dist/src/orchestrator/webhook-orchestrator.d.ts +32 -0
  29. package/dist/src/orchestrator/webhook-orchestrator.d.ts.map +1 -0
  30. package/dist/src/orchestrator/webhook-orchestrator.js +300 -0
  31. package/dist/src/types.d.ts +16 -0
  32. package/dist/src/types.d.ts.map +1 -1
  33. package/dist/src/webhook/handlers/issue-updated.d.ts +2 -2
  34. package/dist/src/webhook/handlers/issue-updated.d.ts.map +1 -1
  35. package/dist/src/webhook/handlers/session-created.d.ts +2 -2
  36. package/dist/src/webhook/handlers/session-created.d.ts.map +1 -1
  37. package/dist/src/webhook/handlers/session-prompted.d.ts +2 -2
  38. package/dist/src/webhook/handlers/session-prompted.d.ts.map +1 -1
  39. package/dist/src/webhook/handlers/session-updated.d.ts +2 -2
  40. package/dist/src/webhook/handlers/session-updated.d.ts.map +1 -1
  41. package/dist/src/webhook/processor.d.ts +2 -2
  42. package/dist/src/webhook/processor.d.ts.map +1 -1
  43. package/dist/src/webhook/utils.d.ts +5 -5
  44. package/dist/src/webhook/utils.d.ts.map +1 -1
  45. package/package.json +4 -4
@@ -4,8 +4,12 @@
4
4
  * Wires all handlers together from a single configuration object.
5
5
  * Consumers call `createAllRoutes(config)` and get back a nested
6
6
  * route tree that maps 1:1 onto Next.js App Router exports.
7
+ *
8
+ * When optional config fields are omitted, sensible defaults from
9
+ * @supaku/agentfactory-linear are used (defaultGeneratePrompt, etc.).
7
10
  */
8
11
  import type { RouteHandler, WebhookConfig, CronConfig } from './types.js';
12
+ import { type OAuthConfig } from './handlers/oauth/callback.js';
9
13
  export interface AllRoutes {
10
14
  workers: {
11
15
  register: {
@@ -84,22 +88,46 @@ export interface AllRoutes {
84
88
  POST: RouteHandler;
85
89
  GET: RouteHandler;
86
90
  };
91
+ oauth: {
92
+ callback: {
93
+ GET: RouteHandler;
94
+ };
95
+ };
96
+ }
97
+ /**
98
+ * Configuration for createAllRoutes.
99
+ * Extends WebhookConfig & CronConfig with optional OAuth config.
100
+ */
101
+ export interface AllRoutesConfig extends WebhookConfig, CronConfig {
102
+ /** OAuth configuration for the callback handler */
103
+ oauth?: OAuthConfig;
87
104
  }
88
105
  /**
89
106
  * Create all route handlers from a single config object.
90
107
  *
108
+ * Optional fields fall back to sensible defaults from @supaku/agentfactory-linear:
109
+ * - `generatePrompt` → `defaultGeneratePrompt`
110
+ * - `detectWorkTypeFromPrompt` → `defaultDetectWorkTypeFromPrompt`
111
+ * - `getPriority` → `defaultGetPriority`
112
+ * - `buildParentQAContext` → `defaultBuildParentQAContext`
113
+ * - `buildParentAcceptanceContext` → `defaultBuildParentAcceptanceContext`
114
+ *
91
115
  * @example
92
116
  * ```typescript
93
- * import { createAllRoutes } from '@supaku/agentfactory-nextjs'
117
+ * import { createAllRoutes, createDefaultLinearClientResolver } from '@supaku/agentfactory-nextjs'
94
118
  *
119
+ * // Minimal — everything uses defaults
95
120
  * const routes = createAllRoutes({
96
- * linearClient: { getClient: async (orgId) => getLinearClient(orgId) },
97
- * generatePrompt: (id, workType) => `Work on ${id}`,
121
+ * linearClient: createDefaultLinearClientResolver(),
98
122
  * })
99
123
  *
100
- * // In app/api/workers/register/route.ts:
101
- * export const POST = routes.workers.register.POST
124
+ * // Custom — override specific callbacks
125
+ * const routes = createAllRoutes({
126
+ * linearClient: createDefaultLinearClientResolver(),
127
+ * generatePrompt: myCustomPromptFn,
128
+ * oauth: { clientId: '...', clientSecret: '...' },
129
+ * })
102
130
  * ```
103
131
  */
104
- export declare function createAllRoutes(config: WebhookConfig & CronConfig): AllRoutes;
132
+ export declare function createAllRoutes(config: AllRoutesConfig): AllRoutes;
105
133
  //# sourceMappingURL=factory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAe,aAAa,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAoCtF,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE;QACP,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC3B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,MAAM,EAAE,YAAY,CAAA;SAAE,CAAA;QACnD,SAAS,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACjC,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KAC5B,CAAA;IACD,QAAQ,EAAE;QACR,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC3B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC7B,KAAK,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAC7B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACjD,WAAW,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACnC,OAAO,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAClD,iBAAiB,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACzC,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,UAAU,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAClC,YAAY,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACpC,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,SAAS,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;KAClC,CAAA;IACD,MAAM,EAAE;QACN,KAAK,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC5B,QAAQ,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC/B,aAAa,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KACrC,CAAA;IACD,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;IAClD,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;CACnD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,CAuC7E"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAe,aAAa,EAAyB,UAAU,EAAE,MAAM,YAAY,CAAA;AA4C7G,OAAO,EAA8B,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAE3F,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE;QACP,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC3B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,MAAM,EAAE,YAAY,CAAA;SAAE,CAAA;QACnD,SAAS,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACjC,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KAC5B,CAAA;IACD,QAAQ,EAAE;QACR,IAAI,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC3B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC7B,KAAK,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAC7B,MAAM,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACjD,WAAW,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACnC,OAAO,EAAE;YAAE,GAAG,EAAE,YAAY,CAAC;YAAC,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAClD,iBAAiB,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACzC,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,UAAU,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAClC,YAAY,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QACpC,QAAQ,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;QAChC,SAAS,EAAE;YAAE,IAAI,EAAE,YAAY,CAAA;SAAE,CAAA;KAClC,CAAA;IACD,MAAM,EAAE;QACN,KAAK,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC5B,QAAQ,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;QAC/B,aAAa,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KACrC,CAAA;IACD,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;IAClD,OAAO,EAAE;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,GAAG,EAAE,YAAY,CAAA;KAAE,CAAA;IAClD,KAAK,EAAE;QACL,QAAQ,EAAE;YAAE,GAAG,EAAE,YAAY,CAAA;SAAE,CAAA;KAChC,CAAA;CACF;AAED;;;GAGG;AACH,MAAM,WAAW,eAAgB,SAAQ,aAAa,EAAE,UAAU;IAChE,mDAAmD;IACnD,KAAK,CAAC,EAAE,WAAW,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAqDlE"}
@@ -4,7 +4,11 @@
4
4
  * Wires all handlers together from a single configuration object.
5
5
  * Consumers call `createAllRoutes(config)` and get back a nested
6
6
  * route tree that maps 1:1 onto Next.js App Router exports.
7
+ *
8
+ * When optional config fields are omitted, sensible defaults from
9
+ * @supaku/agentfactory-linear are used (defaultGeneratePrompt, etc.).
7
10
  */
11
+ import { defaultGeneratePrompt, defaultDetectWorkTypeFromPrompt, defaultGetPriority, defaultBuildParentQAContext, defaultBuildParentAcceptanceContext, } from '@supaku/agentfactory-linear';
8
12
  // Worker handlers
9
13
  import { createWorkerRegisterHandler } from './handlers/workers/register.js';
10
14
  import { createWorkerListHandler } from './handlers/workers/list.js';
@@ -33,29 +37,52 @@ import { createPublicSessionDetailHandler } from './handlers/public/session-deta
33
37
  import { createCleanupHandler } from './handlers/cleanup.js';
34
38
  // Webhook processor
35
39
  import { createWebhookHandler } from './webhook/processor.js';
40
+ // OAuth handler
41
+ import { createOAuthCallbackHandler } from './handlers/oauth/callback.js';
36
42
  /**
37
43
  * Create all route handlers from a single config object.
38
44
  *
45
+ * Optional fields fall back to sensible defaults from @supaku/agentfactory-linear:
46
+ * - `generatePrompt` → `defaultGeneratePrompt`
47
+ * - `detectWorkTypeFromPrompt` → `defaultDetectWorkTypeFromPrompt`
48
+ * - `getPriority` → `defaultGetPriority`
49
+ * - `buildParentQAContext` → `defaultBuildParentQAContext`
50
+ * - `buildParentAcceptanceContext` → `defaultBuildParentAcceptanceContext`
51
+ *
39
52
  * @example
40
53
  * ```typescript
41
- * import { createAllRoutes } from '@supaku/agentfactory-nextjs'
54
+ * import { createAllRoutes, createDefaultLinearClientResolver } from '@supaku/agentfactory-nextjs'
42
55
  *
56
+ * // Minimal — everything uses defaults
43
57
  * const routes = createAllRoutes({
44
- * linearClient: { getClient: async (orgId) => getLinearClient(orgId) },
45
- * generatePrompt: (id, workType) => `Work on ${id}`,
58
+ * linearClient: createDefaultLinearClientResolver(),
46
59
  * })
47
60
  *
48
- * // In app/api/workers/register/route.ts:
49
- * export const POST = routes.workers.register.POST
61
+ * // Custom — override specific callbacks
62
+ * const routes = createAllRoutes({
63
+ * linearClient: createDefaultLinearClientResolver(),
64
+ * generatePrompt: myCustomPromptFn,
65
+ * oauth: { clientId: '...', clientSecret: '...' },
66
+ * })
50
67
  * ```
51
68
  */
52
69
  export function createAllRoutes(config) {
70
+ // Apply defaults for optional webhook config fields
71
+ const webhookConfig = {
72
+ ...config,
73
+ generatePrompt: config.generatePrompt ?? defaultGeneratePrompt,
74
+ detectWorkTypeFromPrompt: config.detectWorkTypeFromPrompt ?? defaultDetectWorkTypeFromPrompt,
75
+ getPriority: config.getPriority ?? defaultGetPriority,
76
+ buildParentQAContext: config.buildParentQAContext ?? defaultBuildParentQAContext,
77
+ buildParentAcceptanceContext: config.buildParentAcceptanceContext ?? defaultBuildParentAcceptanceContext,
78
+ };
53
79
  const routeConfig = {
54
80
  linearClient: config.linearClient,
55
81
  appUrl: config.appUrl,
56
82
  };
57
- const cleanup = createCleanupHandler(config);
58
- const webhook = createWebhookHandler(config);
83
+ const cleanup = createCleanupHandler(webhookConfig);
84
+ const webhook = createWebhookHandler(webhookConfig);
85
+ const oauth = createOAuthCallbackHandler(config.oauth);
59
86
  return {
60
87
  workers: {
61
88
  register: { POST: createWorkerRegisterHandler() },
@@ -85,5 +112,8 @@ export function createAllRoutes(config) {
85
112
  },
86
113
  cleanup: { POST: cleanup.POST, GET: cleanup.GET },
87
114
  webhook: { POST: webhook.POST, GET: webhook.GET },
115
+ oauth: {
116
+ callback: { GET: oauth.GET },
117
+ },
88
118
  };
89
119
  }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * OAuth Callback Handler for Linear
3
+ *
4
+ * Exchanges an authorization code for an access token and stores it
5
+ * in Redis for workspace-specific token resolution.
6
+ *
7
+ * @see https://developers.linear.app/docs/oauth/authentication
8
+ */
9
+ import type { RouteHandler } from '../../types.js';
10
+ /**
11
+ * Configuration for the OAuth callback handler.
12
+ */
13
+ export interface OAuthConfig {
14
+ /** Linear OAuth client ID (defaults to LINEAR_CLIENT_ID env) */
15
+ clientId?: string;
16
+ /** Linear OAuth client secret (defaults to LINEAR_CLIENT_SECRET env) */
17
+ clientSecret?: string;
18
+ /** Application URL for redirect URI (defaults to NEXT_PUBLIC_APP_URL env) */
19
+ appUrl?: string;
20
+ /** Redirect path on success (defaults to '/?oauth=success') */
21
+ successRedirect?: string;
22
+ }
23
+ /**
24
+ * Create an OAuth callback route handler for Linear.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // In app/callback/route.ts:
29
+ * import { createOAuthCallbackHandler } from '@supaku/agentfactory-nextjs'
30
+ * export const { GET } = createOAuthCallbackHandler()
31
+ * ```
32
+ */
33
+ export declare function createOAuthCallbackHandler(config?: OAuthConfig): {
34
+ GET: RouteHandler;
35
+ };
36
+ //# sourceMappingURL=callback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callback.d.ts","sourceRoot":"","sources":["../../../../src/handlers/oauth/callback.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAElD;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAID;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG;IAAE,GAAG,EAAE,YAAY,CAAA;CAAE,CA8FtF"}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * OAuth Callback Handler for Linear
3
+ *
4
+ * Exchanges an authorization code for an access token and stores it
5
+ * in Redis for workspace-specific token resolution.
6
+ *
7
+ * @see https://developers.linear.app/docs/oauth/authentication
8
+ */
9
+ import { NextResponse } from 'next/server';
10
+ import { storeToken, fetchOrganization, isRedisConfigured, createLogger, generateRequestId, } from '@supaku/agentfactory-server';
11
+ const baseLogger = createLogger('oauth-callback');
12
+ /**
13
+ * Create an OAuth callback route handler for Linear.
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * // In app/callback/route.ts:
18
+ * import { createOAuthCallbackHandler } from '@supaku/agentfactory-nextjs'
19
+ * export const { GET } = createOAuthCallbackHandler()
20
+ * ```
21
+ */
22
+ export function createOAuthCallbackHandler(config) {
23
+ return {
24
+ GET: async (request) => {
25
+ const requestId = generateRequestId();
26
+ const log = baseLogger.child({ requestId });
27
+ const clientId = config?.clientId ?? process.env.LINEAR_CLIENT_ID;
28
+ const clientSecret = config?.clientSecret ?? process.env.LINEAR_CLIENT_SECRET;
29
+ const appUrl = config?.appUrl ?? process.env.NEXT_PUBLIC_APP_URL ?? 'http://localhost:3002';
30
+ const successRedirect = config?.successRedirect ?? '/?oauth=success';
31
+ const code = request.nextUrl.searchParams.get('code');
32
+ const error = request.nextUrl.searchParams.get('error');
33
+ const errorDescription = request.nextUrl.searchParams.get('error_description');
34
+ if (error) {
35
+ log.error('OAuth error from Linear', { oauthError: error, errorDescription });
36
+ return NextResponse.json({ error, description: errorDescription, requestId }, { status: 400 });
37
+ }
38
+ if (!code) {
39
+ log.warn('Missing authorization code');
40
+ return NextResponse.json({ error: 'Missing authorization code', requestId }, { status: 400 });
41
+ }
42
+ if (!clientId || !clientSecret) {
43
+ log.error('OAuth credentials not configured');
44
+ return NextResponse.json({ error: 'OAuth not configured', requestId }, { status: 500 });
45
+ }
46
+ try {
47
+ log.debug('Exchanging authorization code for token');
48
+ const tokenResponse = await fetch('https://api.linear.app/oauth/token', {
49
+ method: 'POST',
50
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
51
+ body: new URLSearchParams({
52
+ grant_type: 'authorization_code',
53
+ client_id: clientId,
54
+ client_secret: clientSecret,
55
+ redirect_uri: `${appUrl}/callback`,
56
+ code,
57
+ }),
58
+ });
59
+ if (!tokenResponse.ok) {
60
+ const errorText = await tokenResponse.text();
61
+ log.error('Token exchange failed', {
62
+ statusCode: tokenResponse.status,
63
+ errorDetails: errorText,
64
+ });
65
+ return NextResponse.json({ error: 'Token exchange failed', details: errorText, requestId }, { status: 400 });
66
+ }
67
+ const tokenData = (await tokenResponse.json());
68
+ if (isRedisConfigured()) {
69
+ const organization = await fetchOrganization(tokenData.access_token);
70
+ if (organization) {
71
+ await storeToken(organization.id, tokenData, organization.name);
72
+ log.info('OAuth successful, token stored', {
73
+ workspaceId: organization.id,
74
+ workspaceName: organization.name,
75
+ });
76
+ }
77
+ else {
78
+ log.warn('OAuth successful but could not fetch organization info - token not stored');
79
+ }
80
+ }
81
+ else {
82
+ log.info('OAuth successful, token received (Redis not configured for storage)');
83
+ }
84
+ return NextResponse.redirect(new URL(successRedirect, appUrl));
85
+ }
86
+ catch (err) {
87
+ log.error('OAuth callback error', { error: err });
88
+ return NextResponse.json({ error: 'Internal server error', requestId }, { status: 500 });
89
+ }
90
+ },
91
+ };
92
+ }
@@ -2,11 +2,20 @@
2
2
  * @supaku/agentfactory-nextjs
3
3
  *
4
4
  * Next.js API route handlers for AgentFactory.
5
- * Provides webhook processing, worker/session management, and public stats.
5
+ * Provides webhook processing, worker/session management, public stats,
6
+ * OAuth callback, middleware factory, webhook orchestrator, and Linear client resolver.
6
7
  */
7
8
  export type { LinearClientResolver, RouteConfig, WebhookConfig, AutoTriggerConfig, CronConfig, RouteHandler, } from './types.js';
8
9
  export { createAllRoutes } from './factory.js';
9
- export type { AllRoutes } from './factory.js';
10
+ export type { AllRoutes, AllRoutesConfig } from './factory.js';
11
+ export { createOAuthCallbackHandler } from './handlers/oauth/callback.js';
12
+ export type { OAuthConfig } from './handlers/oauth/callback.js';
13
+ export { createAgentFactoryMiddleware } from './middleware/factory.js';
14
+ export type { MiddlewareConfig } from './middleware/types.js';
15
+ export { createWebhookOrchestrator, formatErrorForComment, } from './orchestrator/index.js';
16
+ export type { WebhookOrchestratorConfig, WebhookOrchestratorHooks, WebhookOrchestratorInstance, } from './orchestrator/index.js';
17
+ export { createDefaultLinearClientResolver } from './linear-client-resolver.js';
18
+ export type { DefaultLinearClientResolverConfig } from './linear-client-resolver.js';
10
19
  export { verifyCronAuth } from './middleware/cron-auth.js';
11
20
  export { verifyWorkerAuth, requireWorkerAuth, unauthorizedResponse, isWorkerAuthConfigured, } from './middleware/worker-auth.js';
12
21
  export { createWebhookHandler } from './webhook/processor.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAG7C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAA;AAGpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAK/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AACpE,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AACpG,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AAGpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AACtE,YAAY,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAO,EAAE,8BAA8B,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAA;AAC7G,OAAO,EAAE,+BAA+B,EAAE,MAAM,qCAAqC,CAAA;AACrF,OAAO,EAAE,8BAA8B,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAA;AAChH,OAAO,EAAE,qCAAqC,EAAE,MAAM,2CAA2C,CAAA;AAGjG,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAA;AAClF,OAAO,EAAE,gCAAgC,EAAE,MAAM,sCAAsC,CAAA;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,6BAA6B,EAAE,MAAM,mCAAmC,CAAA;AAGjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oCAAoC,CAAA;AACpF,YAAY,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,gCAAgC,EAAE,MAAM,qCAAqC,CAAA;AACtF,YAAY,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAA;AAGtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,YAAY,EACV,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,YAAY,GACb,MAAM,YAAY,CAAA;AAGnB,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC9C,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAG9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAA;AACzE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAG/D,OAAO,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAA;AACtE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAG7D,OAAO,EACL,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,yBAAyB,CAAA;AAChC,YAAY,EACV,yBAAyB,EACzB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,yBAAyB,CAAA;AAGhC,OAAO,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAA;AAC/E,YAAY,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAA;AAGpF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAA;AAC1D,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,6BAA6B,CAAA;AAGpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAA;AAK/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AACpE,OAAO,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AACpG,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AAGpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AACtE,YAAY,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAA;AACpE,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAA;AACxE,OAAO,EAAE,8BAA8B,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAA;AAC7G,OAAO,EAAE,+BAA+B,EAAE,MAAM,qCAAqC,CAAA;AACrF,OAAO,EAAE,8BAA8B,EAAE,+BAA+B,EAAE,MAAM,gCAAgC,CAAA;AAChH,OAAO,EAAE,qCAAqC,EAAE,MAAM,2CAA2C,CAAA;AAGjG,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,mCAAmC,CAAA;AAClF,OAAO,EAAE,gCAAgC,EAAE,MAAM,sCAAsC,CAAA;AACvF,OAAO,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,6BAA6B,EAAE,MAAM,mCAAmC,CAAA;AAGjF,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACrE,YAAY,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAA;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oCAAoC,CAAA;AACpF,YAAY,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,gCAAgC,EAAE,MAAM,qCAAqC,CAAA;AACtF,YAAY,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAA;AAGtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAA"}
package/dist/src/index.js CHANGED
@@ -2,11 +2,20 @@
2
2
  * @supaku/agentfactory-nextjs
3
3
  *
4
4
  * Next.js API route handlers for AgentFactory.
5
- * Provides webhook processing, worker/session management, and public stats.
5
+ * Provides webhook processing, worker/session management, public stats,
6
+ * OAuth callback, middleware factory, webhook orchestrator, and Linear client resolver.
6
7
  */
7
8
  // Factory
8
9
  export { createAllRoutes } from './factory.js';
9
- // Middleware
10
+ // OAuth handler
11
+ export { createOAuthCallbackHandler } from './handlers/oauth/callback.js';
12
+ // Middleware factory
13
+ export { createAgentFactoryMiddleware } from './middleware/factory.js';
14
+ // Webhook orchestrator
15
+ export { createWebhookOrchestrator, formatErrorForComment, } from './orchestrator/index.js';
16
+ // Default Linear client resolver
17
+ export { createDefaultLinearClientResolver } from './linear-client-resolver.js';
18
+ // Middleware (existing)
10
19
  export { verifyCronAuth } from './middleware/cron-auth.js';
11
20
  export { verifyWorkerAuth, requireWorkerAuth, unauthorizedResponse, isWorkerAuthConfigured, } from './middleware/worker-auth.js';
12
21
  // Webhook
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Default Linear Client Resolver
3
+ *
4
+ * Provides a generic LinearClientResolver that uses:
5
+ * 1. Workspace-specific OAuth tokens from Redis (if configured)
6
+ * 2. Falls back to a global API key from environment
7
+ *
8
+ * This is the pattern every consumer needs — extracted from Supaku's
9
+ * linear.ts for reuse.
10
+ */
11
+ import type { LinearClientResolver } from './types.js';
12
+ /**
13
+ * Configuration for the default Linear client resolver.
14
+ */
15
+ export interface DefaultLinearClientResolverConfig {
16
+ /** Environment variable name for the API key (default: 'LINEAR_ACCESS_TOKEN') */
17
+ apiKeyEnvVar?: string;
18
+ }
19
+ /**
20
+ * Create a default Linear client resolver.
21
+ *
22
+ * Resolves Linear clients with workspace-aware OAuth token support:
23
+ * - If an organizationId is provided and Redis is configured, attempts to
24
+ * fetch a workspace-specific OAuth token.
25
+ * - Falls back to a global API key from the environment.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * import { createDefaultLinearClientResolver } from '@supaku/agentfactory-nextjs'
30
+ *
31
+ * const resolver = createDefaultLinearClientResolver()
32
+ * // Use in route config:
33
+ * const routes = createAllRoutes({ linearClient: resolver, ... })
34
+ * ```
35
+ */
36
+ export declare function createDefaultLinearClientResolver(config?: DefaultLinearClientResolverConfig): LinearClientResolver;
37
+ //# sourceMappingURL=linear-client-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"linear-client-resolver.d.ts","sourceRoot":"","sources":["../../src/linear-client-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAItD;;GAEG;AACH,MAAM,WAAW,iCAAiC;IAChD,iFAAiF;IACjF,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iCAAiC,CAC/C,MAAM,CAAC,EAAE,iCAAiC,GACzC,oBAAoB,CAwCtB"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Default Linear Client Resolver
3
+ *
4
+ * Provides a generic LinearClientResolver that uses:
5
+ * 1. Workspace-specific OAuth tokens from Redis (if configured)
6
+ * 2. Falls back to a global API key from environment
7
+ *
8
+ * This is the pattern every consumer needs — extracted from Supaku's
9
+ * linear.ts for reuse.
10
+ */
11
+ import { createLinearAgentClient, } from '@supaku/agentfactory-linear';
12
+ import { getAccessToken, isRedisConfigured, createLogger, } from '@supaku/agentfactory-server';
13
+ const log = createLogger('linear-client-resolver');
14
+ /**
15
+ * Create a default Linear client resolver.
16
+ *
17
+ * Resolves Linear clients with workspace-aware OAuth token support:
18
+ * - If an organizationId is provided and Redis is configured, attempts to
19
+ * fetch a workspace-specific OAuth token.
20
+ * - Falls back to a global API key from the environment.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * import { createDefaultLinearClientResolver } from '@supaku/agentfactory-nextjs'
25
+ *
26
+ * const resolver = createDefaultLinearClientResolver()
27
+ * // Use in route config:
28
+ * const routes = createAllRoutes({ linearClient: resolver, ... })
29
+ * ```
30
+ */
31
+ export function createDefaultLinearClientResolver(config) {
32
+ const apiKeyEnvVar = config?.apiKeyEnvVar ?? 'LINEAR_ACCESS_TOKEN';
33
+ let _globalClient = null;
34
+ function getGlobalClient() {
35
+ if (!_globalClient) {
36
+ const apiKey = process.env[apiKeyEnvVar];
37
+ if (!apiKey) {
38
+ throw new Error(`${apiKeyEnvVar} not set - Linear API operations will fail`);
39
+ }
40
+ _globalClient = createLinearAgentClient({ apiKey });
41
+ }
42
+ return _globalClient;
43
+ }
44
+ async function getClientForWorkspace(workspaceId) {
45
+ if (isRedisConfigured()) {
46
+ const accessToken = await getAccessToken(workspaceId);
47
+ if (accessToken) {
48
+ log.debug('Using OAuth token from Redis', { workspaceId });
49
+ return createLinearAgentClient({ apiKey: accessToken });
50
+ }
51
+ log.debug('No OAuth token in Redis, falling back to env var', { workspaceId });
52
+ }
53
+ return getGlobalClient();
54
+ }
55
+ return {
56
+ getClient: async (organizationId) => organizationId
57
+ ? await getClientForWorkspace(organizationId)
58
+ : getGlobalClient(),
59
+ };
60
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Middleware Factory
3
+ *
4
+ * Creates a Next.js middleware function that handles authentication,
5
+ * rate limiting, and security for AgentFactory API routes.
6
+ *
7
+ * Uses the rate limiter and worker auth from @supaku/agentfactory-server
8
+ * for proper LRU eviction and crypto.timingSafeEqual.
9
+ */
10
+ import { NextRequest, NextResponse } from 'next/server';
11
+ import type { MiddlewareConfig } from './types.js';
12
+ /**
13
+ * Create an AgentFactory middleware function with configurable routes
14
+ * and rate limiting.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // In middleware.ts:
19
+ * import { createAgentFactoryMiddleware } from '@supaku/agentfactory-nextjs'
20
+ *
21
+ * const { middleware, matcherConfig } = createAgentFactoryMiddleware()
22
+ * export { middleware }
23
+ * export const config = matcherConfig
24
+ * ```
25
+ */
26
+ export declare function createAgentFactoryMiddleware(userConfig?: MiddlewareConfig): {
27
+ middleware: (request: NextRequest) => NextResponse | undefined;
28
+ matcherConfig: {
29
+ matcher: string[];
30
+ };
31
+ };
32
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Middleware Factory
3
+ *
4
+ * Creates a Next.js middleware function that handles authentication,
5
+ * rate limiting, and security for AgentFactory API routes.
6
+ *
7
+ * Uses the rate limiter and worker auth from @supaku/agentfactory-server
8
+ * for proper LRU eviction and crypto.timingSafeEqual.
9
+ */
10
+ import { NextResponse } from 'next/server';
11
+ import { checkRateLimit, getClientIP, buildRateLimitHeaders, verifyApiKey, } from '@supaku/agentfactory-server';
12
+ const DEFAULT_PUBLIC_ROUTES = ['/api/public/', '/dashboard', '/'];
13
+ const DEFAULT_PROTECTED_ROUTES = ['/api/sessions', '/api/workers'];
14
+ const DEFAULT_SESSION_PAGES = ['/sessions/'];
15
+ const DEFAULT_WEBHOOK_ROUTE = '/webhook';
16
+ const DEFAULT_PASSTHROUGH_ROUTES = ['/api/cleanup'];
17
+ /**
18
+ * Create an AgentFactory middleware function with configurable routes
19
+ * and rate limiting.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * // In middleware.ts:
24
+ * import { createAgentFactoryMiddleware } from '@supaku/agentfactory-nextjs'
25
+ *
26
+ * const { middleware, matcherConfig } = createAgentFactoryMiddleware()
27
+ * export { middleware }
28
+ * export const config = matcherConfig
29
+ * ```
30
+ */
31
+ export function createAgentFactoryMiddleware(userConfig) {
32
+ const publicRoutes = userConfig?.routes?.public ?? DEFAULT_PUBLIC_ROUTES;
33
+ const protectedRoutes = userConfig?.routes?.protected ?? DEFAULT_PROTECTED_ROUTES;
34
+ const sessionPages = userConfig?.routes?.sessionPages ?? DEFAULT_SESSION_PAGES;
35
+ const webhookRoute = userConfig?.routes?.webhook ?? DEFAULT_WEBHOOK_ROUTE;
36
+ const passthroughRoutes = userConfig?.routes?.passthrough ?? DEFAULT_PASSTHROUGH_ROUTES;
37
+ function middleware(request) {
38
+ const { pathname } = request.nextUrl;
39
+ const clientIP = getClientIP(request.headers);
40
+ // === PUBLIC ROUTES ===
41
+ if (publicRoutes.some(route => pathname === route || pathname.startsWith(route))) {
42
+ const result = checkRateLimit('public', clientIP);
43
+ if (!result.allowed) {
44
+ return new NextResponse(JSON.stringify({ error: 'Too many requests' }), {
45
+ status: 429,
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ ...buildRateLimitHeaders(result),
49
+ },
50
+ });
51
+ }
52
+ const response = NextResponse.next();
53
+ const rateLimitHeaders = buildRateLimitHeaders(result);
54
+ for (const [key, value] of Object.entries(rateLimitHeaders)) {
55
+ response.headers.set(key, value);
56
+ }
57
+ return response;
58
+ }
59
+ // === SESSION DETAIL PAGES ===
60
+ if (sessionPages.some(route => pathname.startsWith(route))) {
61
+ return NextResponse.next();
62
+ }
63
+ // === WEBHOOK ROUTE ===
64
+ if (pathname === webhookRoute) {
65
+ const result = checkRateLimit('webhook', clientIP);
66
+ if (!result.allowed) {
67
+ return new NextResponse(JSON.stringify({ error: 'Too many requests' }), {
68
+ status: 429,
69
+ headers: {
70
+ 'Content-Type': 'application/json',
71
+ ...buildRateLimitHeaders(result),
72
+ },
73
+ });
74
+ }
75
+ return NextResponse.next();
76
+ }
77
+ // === PROTECTED INTERNAL APIS ===
78
+ if (protectedRoutes.some(route => pathname.startsWith(route))) {
79
+ const workerApiKey = process.env.WORKER_API_KEY;
80
+ // In development without key, allow access
81
+ if (!workerApiKey && process.env.NODE_ENV !== 'production') {
82
+ return NextResponse.next();
83
+ }
84
+ if (!workerApiKey) {
85
+ console.error('WORKER_API_KEY not configured - blocking protected API access');
86
+ return new NextResponse(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing API key' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
87
+ }
88
+ const authHeader = request.headers.get('authorization');
89
+ if (!authHeader?.startsWith('Bearer ')) {
90
+ return new NextResponse(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing API key' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
91
+ }
92
+ const token = authHeader.slice(7);
93
+ if (!verifyApiKey(token, workerApiKey)) {
94
+ return new NextResponse(JSON.stringify({ error: 'Unauthorized', message: 'Invalid or missing API key' }), { status: 401, headers: { 'Content-Type': 'application/json' } });
95
+ }
96
+ return NextResponse.next();
97
+ }
98
+ // === PASSTHROUGH ROUTES ===
99
+ if (passthroughRoutes.some(route => pathname === route || pathname.startsWith(route))) {
100
+ return NextResponse.next();
101
+ }
102
+ // === ALL OTHER ROUTES ===
103
+ return NextResponse.next();
104
+ }
105
+ const matcherConfig = {
106
+ matcher: [
107
+ '/api/:path*',
108
+ webhookRoute,
109
+ '/dashboard',
110
+ '/sessions/:path*',
111
+ '/',
112
+ ],
113
+ };
114
+ return { middleware, matcherConfig };
115
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Types for the middleware factory.
3
+ */
4
+ /**
5
+ * Configuration for the AgentFactory middleware.
6
+ */
7
+ export interface MiddlewareConfig {
8
+ /** Route path configuration */
9
+ routes?: {
10
+ /** Public routes - no auth, with rate limiting (default: ['/api/public/', '/dashboard', '/']) */
11
+ public?: string[];
12
+ /** Protected routes - require WORKER_API_KEY (default: ['/api/sessions', '/api/workers']) */
13
+ protected?: string[];
14
+ /** Session detail pages - allow public access (default: ['/sessions/']) */
15
+ sessionPages?: string[];
16
+ /** Webhook route (default: '/webhook') */
17
+ webhook?: string;
18
+ /** Routes with custom auth in handler (default: ['/api/cleanup']) */
19
+ passthrough?: string[];
20
+ };
21
+ /** Rate limit configurations */
22
+ rateLimits?: {
23
+ /** Public endpoint rate limit (default: 60/min) */
24
+ public?: {
25
+ max: number;
26
+ windowMs: number;
27
+ };
28
+ /** Webhook endpoint rate limit (default: 10/sec) */
29
+ webhook?: {
30
+ max: number;
31
+ windowMs: number;
32
+ };
33
+ };
34
+ }
35
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/middleware/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,MAAM,CAAC,EAAE;QACP,iGAAiG;QACjG,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;QACjB,6FAA6F;QAC7F,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;QACpB,2EAA2E;QAC3E,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;QACvB,0CAA0C;QAC1C,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,qEAAqE;QACrE,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;KACvB,CAAA;IACD,gCAAgC;IAChC,UAAU,CAAC,EAAE;QACX,mDAAmD;QACnD,MAAM,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAA;QAC1C,oDAAoD;QACpD,OAAO,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAA;KAC5C,CAAA;CACF"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Types for the middleware factory.
3
+ */
4
+ export {};