@bernierllc/admin-agent-nextjs 0.0.1 → 0.1.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.
- package/README.md +66 -28
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +52 -0
- package/dist/errors.js.map +1 -0
- package/dist/handler.d.ts +49 -0
- package/dist/handler.d.ts.map +1 -0
- package/dist/handler.js +138 -0
- package/dist/handler.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -7
package/README.md
CHANGED
|
@@ -1,45 +1,83 @@
|
|
|
1
1
|
# @bernierllc/admin-agent-nextjs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Thin Next.js App Router adapter that wraps an `AdminAgent` into a streaming SSE POST route handler with auth, validation, and error mapping.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npm install @bernierllc/admin-agent-nextjs @bernierllc/admin-agent-service
|
|
9
|
+
```
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
Peer dependency: `next >= 14.0.0 < 16`.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
1. Configure OIDC trusted publishing for the package name `@bernierllc/admin-agent-nextjs`
|
|
13
|
-
2. Enable secure, token-less publishing from CI/CD workflows
|
|
14
|
-
3. Establish provenance for packages published under this name
|
|
13
|
+
## Usage
|
|
15
14
|
|
|
16
|
-
|
|
15
|
+
```typescript
|
|
16
|
+
// app/api/chat/admin/route.ts
|
|
17
|
+
import { createAdminAgentRouteHandler } from '@bernierllc/admin-agent-nextjs';
|
|
18
|
+
import { adminAgent } from '@/lib/admin-agent';
|
|
19
|
+
import { getServerSession } from 'next-auth';
|
|
20
|
+
import { AdminAgentRouteUnauthorizedError } from '@bernierllc/admin-agent-nextjs';
|
|
17
21
|
|
|
18
|
-
|
|
22
|
+
export const POST = createAdminAgentRouteHandler({
|
|
23
|
+
agent: adminAgent,
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
auth: async (request) => {
|
|
26
|
+
const session = await getServerSession();
|
|
27
|
+
if (!session?.user) {
|
|
28
|
+
throw new AdminAgentRouteUnauthorizedError('Not authenticated');
|
|
29
|
+
}
|
|
30
|
+
return { userId: session.user.id, orgId: session.user.orgId };
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
21
34
|
|
|
22
|
-
|
|
35
|
+
## API
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
2. Configure the trusted publisher (e.g., GitHub Actions)
|
|
26
|
-
3. Specify the repository and workflow that should be allowed to publish
|
|
27
|
-
4. Use the configured workflow to publish your actual package
|
|
37
|
+
### `createAdminAgentRouteHandler(config)`
|
|
28
38
|
|
|
29
|
-
|
|
39
|
+
Returns an `async (request: Request) => Promise<Response>` function suitable for `export const POST` in a Next.js App Router route file.
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
- Contains no executable code
|
|
33
|
-
- Provides no functionality
|
|
34
|
-
- Should not be installed as a dependency
|
|
35
|
-
- Exists only for administrative purposes
|
|
41
|
+
**Config options:**
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
| Field | Type | Description |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `agent` | `AdminAgent` | Agent instance from `@bernierllc/admin-agent-service` |
|
|
46
|
+
| `auth` | `(request: Request) => Promise<AuthContext>` | Extract auth context; throw `AdminAgentRouteUnauthorizedError` for 401 |
|
|
47
|
+
| `validateBody?` | `(body: unknown) => { message: string }` | Custom body validator; default validates `{ message: string }` |
|
|
48
|
+
| `transformEvent?` | `(event: AdminAgentEvent) => AdminAgentEvent \| null` | Filter or transform events; return `null` to suppress |
|
|
38
49
|
|
|
39
|
-
|
|
40
|
-
- [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
|
|
41
|
-
- [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
50
|
+
### Errors
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
- `AdminAgentRouteError` — base error class
|
|
53
|
+
- `AdminAgentRouteUnauthorizedError` — throw from `auth()` to produce a 401
|
|
54
|
+
- `AdminAgentRouteBodyError` — throw from `validateBody()` to produce a 400
|
|
44
55
|
|
|
45
|
-
|
|
56
|
+
### Error-to-HTTP Mapping
|
|
57
|
+
|
|
58
|
+
| Condition | HTTP Status |
|
|
59
|
+
|---|---|
|
|
60
|
+
| Body parse failure | 400 |
|
|
61
|
+
| `validateBody` throws | 400 |
|
|
62
|
+
| `auth` throws `AdminAgentRouteUnauthorizedError` | 401 |
|
|
63
|
+
| `auth` throws any other error | 500 |
|
|
64
|
+
| Agent initialization failure | 500 |
|
|
65
|
+
| `rate-limited` event received | 200 (stream closes with event) |
|
|
66
|
+
| `feature-disabled` event received | 200 (stream closes with event) |
|
|
67
|
+
|
|
68
|
+
### Response Format
|
|
69
|
+
|
|
70
|
+
Streaming `text/plain; charset=utf-8` with `Transfer-Encoding: chunked`. Events are newline-delimited JSON:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
{"type":"text-delta","delta":"Hello"}
|
|
74
|
+
{"type":"done"}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Node.js Only
|
|
78
|
+
|
|
79
|
+
This package requires a Node.js server runtime. It is not browser-safe.
|
|
80
|
+
|
|
81
|
+
## License
|
|
82
|
+
|
|
83
|
+
Copyright (c) 2025 Bernier LLC. All rights reserved.
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base error for all admin-agent-nextjs exceptional conditions.
|
|
3
|
+
*
|
|
4
|
+
* Uses ES2022 `Error.cause` chaining per the BernierLLC error propagation
|
|
5
|
+
* standard — underlying errors are never swallowed.
|
|
6
|
+
*/
|
|
7
|
+
export declare class AdminAgentRouteError extends Error {
|
|
8
|
+
readonly code: string;
|
|
9
|
+
constructor(message: string, options?: {
|
|
10
|
+
cause?: Error;
|
|
11
|
+
code?: string;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Thrown (or to be thrown) from the auth function to produce a 401 response.
|
|
16
|
+
* Consumers throw this from their `auth` callback to signal that the request
|
|
17
|
+
* is not authenticated.
|
|
18
|
+
*/
|
|
19
|
+
export declare class AdminAgentRouteUnauthorizedError extends AdminAgentRouteError {
|
|
20
|
+
constructor(message?: string);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Thrown internally when the request body fails validation.
|
|
24
|
+
* Results in a 400 response.
|
|
25
|
+
*/
|
|
26
|
+
export declare class AdminAgentRouteBodyError extends AdminAgentRouteError {
|
|
27
|
+
constructor(detail: string);
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAQA;;;;;GAKG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGpB,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,KAAK,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;CAOJ;AAED;;;;GAIG;AACH,qBAAa,gCAAiC,SAAQ,oBAAoB;gBAC5D,OAAO,SAAiB;CAKrC;AAED;;;GAGG;AACH,qBAAa,wBAAyB,SAAQ,oBAAoB;gBACpD,MAAM,EAAE,MAAM;CAK3B"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AdminAgentRouteBodyError = exports.AdminAgentRouteUnauthorizedError = exports.AdminAgentRouteError = void 0;
|
|
11
|
+
/**
|
|
12
|
+
* Base error for all admin-agent-nextjs exceptional conditions.
|
|
13
|
+
*
|
|
14
|
+
* Uses ES2022 `Error.cause` chaining per the BernierLLC error propagation
|
|
15
|
+
* standard — underlying errors are never swallowed.
|
|
16
|
+
*/
|
|
17
|
+
class AdminAgentRouteError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
constructor(message, options) {
|
|
20
|
+
super(message, { ...(options?.cause !== undefined ? { cause: options.cause } : {}) });
|
|
21
|
+
this.name = 'AdminAgentRouteError';
|
|
22
|
+
this.code = options?.code ?? 'ROUTE_ERROR';
|
|
23
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.AdminAgentRouteError = AdminAgentRouteError;
|
|
27
|
+
/**
|
|
28
|
+
* Thrown (or to be thrown) from the auth function to produce a 401 response.
|
|
29
|
+
* Consumers throw this from their `auth` callback to signal that the request
|
|
30
|
+
* is not authenticated.
|
|
31
|
+
*/
|
|
32
|
+
class AdminAgentRouteUnauthorizedError extends AdminAgentRouteError {
|
|
33
|
+
constructor(message = 'Unauthorized') {
|
|
34
|
+
super(message, { code: 'UNAUTHORIZED' });
|
|
35
|
+
this.name = 'AdminAgentRouteUnauthorizedError';
|
|
36
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
exports.AdminAgentRouteUnauthorizedError = AdminAgentRouteUnauthorizedError;
|
|
40
|
+
/**
|
|
41
|
+
* Thrown internally when the request body fails validation.
|
|
42
|
+
* Results in a 400 response.
|
|
43
|
+
*/
|
|
44
|
+
class AdminAgentRouteBodyError extends AdminAgentRouteError {
|
|
45
|
+
constructor(detail) {
|
|
46
|
+
super(`Invalid request body: ${detail}`, { code: 'INVALID_BODY' });
|
|
47
|
+
this.name = 'AdminAgentRouteBodyError';
|
|
48
|
+
Error.captureStackTrace?.(this, this.constructor);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.AdminAgentRouteBodyError = AdminAgentRouteBodyError;
|
|
52
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;AAEF;;;;;GAKG;AACH,MAAa,oBAAqB,SAAQ,KAAK;IACpC,IAAI,CAAS;IAEtB,YACE,OAAe,EACf,OAGC;QAED,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACtF,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,IAAI,GAAG,OAAO,EAAE,IAAI,IAAI,aAAa,CAAC;QAC3C,KAAK,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;CACF;AAfD,oDAeC;AAED;;;;GAIG;AACH,MAAa,gCAAiC,SAAQ,oBAAoB;IACxE,YAAY,OAAO,GAAG,cAAc;QAClC,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,GAAG,kCAAkC,CAAC;QAC/C,KAAK,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;CACF;AAND,4EAMC;AAED;;;GAGG;AACH,MAAa,wBAAyB,SAAQ,oBAAoB;IAChE,YAAY,MAAc;QACxB,KAAK,CAAC,yBAAyB,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC;QACnE,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;QACvC,KAAK,CAAC,iBAAiB,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;CACF;AAND,4DAMC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AdminAgent, AuthContext, AdminAgentEvent } from '@bernierllc/admin-agent-service';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration object for the admin-agent route handler factory.
|
|
4
|
+
*/
|
|
5
|
+
export interface AdminAgentRouteConfig {
|
|
6
|
+
/**
|
|
7
|
+
* The AdminAgent instance to delegate chat turns to.
|
|
8
|
+
* Obtained via `createAdminAgent()` from `@bernierllc/admin-agent-service`.
|
|
9
|
+
*/
|
|
10
|
+
agent: AdminAgent;
|
|
11
|
+
/**
|
|
12
|
+
* Extract and validate auth context from the incoming request.
|
|
13
|
+
* Throw `AdminAgentRouteUnauthorizedError` to return a 401.
|
|
14
|
+
* Throw any other error to return a 500.
|
|
15
|
+
*/
|
|
16
|
+
auth(request: Request): Promise<AuthContext>;
|
|
17
|
+
/**
|
|
18
|
+
* Optional body validator. Receives the parsed JSON body and must return
|
|
19
|
+
* `{ message: string }` or throw `AdminAgentRouteBodyError` for a 400.
|
|
20
|
+
* Defaults to a simple `{ message: string }` shape check.
|
|
21
|
+
*/
|
|
22
|
+
validateBody?: (body: unknown) => {
|
|
23
|
+
message: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Optional event transformer. Called for every `AdminAgentEvent` before it
|
|
27
|
+
* is written to the stream. Return `null` to suppress the event.
|
|
28
|
+
*/
|
|
29
|
+
transformEvent?: (event: AdminAgentEvent) => AdminAgentEvent | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Creates a Next.js App Router-compatible POST handler that streams
|
|
33
|
+
* `AdminAgentEvent` objects as newline-delimited JSON.
|
|
34
|
+
*
|
|
35
|
+
* Assign directly to `export const POST` in your route file:
|
|
36
|
+
*
|
|
37
|
+
* ```typescript
|
|
38
|
+
* // app/api/chat/admin/route.ts
|
|
39
|
+
* export const POST = createAdminAgentRouteHandler({
|
|
40
|
+
* agent: adminAgent,
|
|
41
|
+
* auth: async (req) => getAuthContextFromRequest(req),
|
|
42
|
+
* });
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @param config - Route configuration including agent, auth, and optional hooks.
|
|
46
|
+
* @returns An async function `(request: Request) => Promise<Response>`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function createAdminAgentRouteHandler(config: AdminAgentRouteConfig): (request: Request) => Promise<Response>;
|
|
49
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAkBhG;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,EAAE,UAAU,CAAC;IAElB;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE7C;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAEtD;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,eAAe,GAAG,IAAI,CAAC;CACrE;AAgCD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,qBAAqB,GAC5B,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA8GzC"}
|
package/dist/handler.js
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.createAdminAgentRouteHandler = createAdminAgentRouteHandler;
|
|
11
|
+
const logger_1 = require("@bernierllc/logger");
|
|
12
|
+
const errors_1 = require("./errors");
|
|
13
|
+
const log = (0, logger_1.createLogger)();
|
|
14
|
+
const RESPONSE_HEADERS = {
|
|
15
|
+
'Content-Type': 'text/plain; charset=utf-8',
|
|
16
|
+
'Transfer-Encoding': 'chunked',
|
|
17
|
+
};
|
|
18
|
+
const JSON_HEADERS = {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
};
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Default body validator
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
function defaultValidateBody(body) {
|
|
25
|
+
if (body === null ||
|
|
26
|
+
typeof body !== 'object' ||
|
|
27
|
+
Array.isArray(body) ||
|
|
28
|
+
typeof body['message'] !== 'string') {
|
|
29
|
+
throw new errors_1.AdminAgentRouteBodyError('Expected { message: string }');
|
|
30
|
+
}
|
|
31
|
+
return { message: body['message'] };
|
|
32
|
+
}
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Encoder
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
const encoder = new TextEncoder();
|
|
37
|
+
function encodeEvent(event) {
|
|
38
|
+
return encoder.encode(JSON.stringify(event) + '\n');
|
|
39
|
+
}
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Factory
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
/**
|
|
44
|
+
* Creates a Next.js App Router-compatible POST handler that streams
|
|
45
|
+
* `AdminAgentEvent` objects as newline-delimited JSON.
|
|
46
|
+
*
|
|
47
|
+
* Assign directly to `export const POST` in your route file:
|
|
48
|
+
*
|
|
49
|
+
* ```typescript
|
|
50
|
+
* // app/api/chat/admin/route.ts
|
|
51
|
+
* export const POST = createAdminAgentRouteHandler({
|
|
52
|
+
* agent: adminAgent,
|
|
53
|
+
* auth: async (req) => getAuthContextFromRequest(req),
|
|
54
|
+
* });
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @param config - Route configuration including agent, auth, and optional hooks.
|
|
58
|
+
* @returns An async function `(request: Request) => Promise<Response>`.
|
|
59
|
+
*/
|
|
60
|
+
function createAdminAgentRouteHandler(config) {
|
|
61
|
+
const validate = config.validateBody ?? defaultValidateBody;
|
|
62
|
+
return async (request) => {
|
|
63
|
+
// ── 1. Parse JSON body ────────────────────────────────────────────────
|
|
64
|
+
let body;
|
|
65
|
+
try {
|
|
66
|
+
body = await request.json();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return new Response(JSON.stringify({ error: 'Failed to parse request body as JSON' }), { status: 400, headers: JSON_HEADERS });
|
|
70
|
+
}
|
|
71
|
+
// ── 2. Validate body ──────────────────────────────────────────────────
|
|
72
|
+
let validated;
|
|
73
|
+
try {
|
|
74
|
+
validated = validate(body);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
const detail = err instanceof Error ? err.message : 'Invalid request body';
|
|
78
|
+
return new Response(JSON.stringify({ error: detail }), { status: 400, headers: JSON_HEADERS });
|
|
79
|
+
}
|
|
80
|
+
// ── 3. Auth ───────────────────────────────────────────────────────────
|
|
81
|
+
let authContext;
|
|
82
|
+
try {
|
|
83
|
+
authContext = await config.auth(request);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
if (err instanceof errors_1.AdminAgentRouteUnauthorizedError) {
|
|
87
|
+
return new Response(JSON.stringify({ error: err.message }), { status: 401, headers: JSON_HEADERS });
|
|
88
|
+
}
|
|
89
|
+
log.error('[admin-agent-nextjs] Auth error', err instanceof Error ? err : new Error(String(err)));
|
|
90
|
+
return new Response(JSON.stringify({ error: 'Internal server error' }), { status: 500, headers: JSON_HEADERS });
|
|
91
|
+
}
|
|
92
|
+
// ── 4. Peek at first event to catch agent init errors pre-stream ──────
|
|
93
|
+
const iterable = config.agent.chat(validated.message, authContext, request.signal);
|
|
94
|
+
const iterator = iterable[Symbol.asyncIterator]();
|
|
95
|
+
let firstResult;
|
|
96
|
+
try {
|
|
97
|
+
firstResult = await iterator.next();
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
log.error('[admin-agent-nextjs] Agent init error', err instanceof Error ? err : new Error(String(err)));
|
|
101
|
+
return new Response(JSON.stringify({ error: 'Agent initialization failed' }), { status: 500, headers: JSON_HEADERS });
|
|
102
|
+
}
|
|
103
|
+
// ── 5. Stream events ──────────────────────────────────────────────────
|
|
104
|
+
const { transformEvent } = config;
|
|
105
|
+
const stream = new ReadableStream({
|
|
106
|
+
async start(controller) {
|
|
107
|
+
try {
|
|
108
|
+
let current = firstResult;
|
|
109
|
+
while (!current.done) {
|
|
110
|
+
const event = current.value;
|
|
111
|
+
const isTerminal = event.type === 'rate-limited' || event.type === 'feature-disabled';
|
|
112
|
+
const transformed = transformEvent !== undefined
|
|
113
|
+
? transformEvent(event)
|
|
114
|
+
: event;
|
|
115
|
+
if (transformed !== null) {
|
|
116
|
+
controller.enqueue(encodeEvent(transformed));
|
|
117
|
+
}
|
|
118
|
+
if (isTerminal) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
current = await iterator.next();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
log.error('[admin-agent-nextjs] Stream error', err instanceof Error ? err : new Error(String(err)));
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
controller.close();
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
return new Response(stream, {
|
|
133
|
+
status: 200,
|
|
134
|
+
headers: RESPONSE_HEADERS,
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../src/handler.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @bernierllc/admin-agent-nextjs
|
|
3
|
+
*
|
|
4
|
+
* Thin Next.js App Router adapter that wraps an AdminAgent into a streaming
|
|
5
|
+
* SSE route handler. Handles request parsing, auth extraction, event
|
|
6
|
+
* streaming, and error-to-HTTP mapping.
|
|
7
|
+
*
|
|
8
|
+
* Quick start:
|
|
9
|
+
* ```typescript
|
|
10
|
+
* // app/api/chat/admin/route.ts
|
|
11
|
+
* import { createAdminAgentRouteHandler } from '@bernierllc/admin-agent-nextjs';
|
|
12
|
+
*
|
|
13
|
+
* export const POST = createAdminAgentRouteHandler({
|
|
14
|
+
* agent: adminAgent,
|
|
15
|
+
* auth: async (req) => getAuthContextFromRequest(req),
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export { createAdminAgentRouteHandler } from './handler';
|
|
20
|
+
export type { AdminAgentRouteConfig } from './handler';
|
|
21
|
+
export { AdminAgentRouteError, AdminAgentRouteUnauthorizedError, AdminAgentRouteBodyError, } from './errors';
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAQA;;;;;;;;;;;;;;;;;GAiBG;AAGH,OAAO,EAAE,4BAA4B,EAAE,MAAM,WAAW,CAAC;AACzD,YAAY,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAGvD,OAAO,EACL,oBAAoB,EACpB,gCAAgC,EAChC,wBAAwB,GACzB,MAAM,UAAU,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*
|
|
3
|
+
Copyright (c) 2025 Bernier LLC
|
|
4
|
+
|
|
5
|
+
This file is licensed to the client under a limited-use license.
|
|
6
|
+
The client may use and modify this code *only within the scope of the project it was delivered for*.
|
|
7
|
+
Redistribution or use in other products or commercial offerings is not permitted without written consent from Bernier LLC.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AdminAgentRouteBodyError = exports.AdminAgentRouteUnauthorizedError = exports.AdminAgentRouteError = exports.createAdminAgentRouteHandler = void 0;
|
|
11
|
+
/**
|
|
12
|
+
* @bernierllc/admin-agent-nextjs
|
|
13
|
+
*
|
|
14
|
+
* Thin Next.js App Router adapter that wraps an AdminAgent into a streaming
|
|
15
|
+
* SSE route handler. Handles request parsing, auth extraction, event
|
|
16
|
+
* streaming, and error-to-HTTP mapping.
|
|
17
|
+
*
|
|
18
|
+
* Quick start:
|
|
19
|
+
* ```typescript
|
|
20
|
+
* // app/api/chat/admin/route.ts
|
|
21
|
+
* import { createAdminAgentRouteHandler } from '@bernierllc/admin-agent-nextjs';
|
|
22
|
+
*
|
|
23
|
+
* export const POST = createAdminAgentRouteHandler({
|
|
24
|
+
* agent: adminAgent,
|
|
25
|
+
* auth: async (req) => getAuthContextFromRequest(req),
|
|
26
|
+
* });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
30
|
+
var handler_1 = require("./handler");
|
|
31
|
+
Object.defineProperty(exports, "createAdminAgentRouteHandler", { enumerable: true, get: function () { return handler_1.createAdminAgentRouteHandler; } });
|
|
32
|
+
// ── Errors ────────────────────────────────────────────────────────────────────
|
|
33
|
+
var errors_1 = require("./errors");
|
|
34
|
+
Object.defineProperty(exports, "AdminAgentRouteError", { enumerable: true, get: function () { return errors_1.AdminAgentRouteError; } });
|
|
35
|
+
Object.defineProperty(exports, "AdminAgentRouteUnauthorizedError", { enumerable: true, get: function () { return errors_1.AdminAgentRouteUnauthorizedError; } });
|
|
36
|
+
Object.defineProperty(exports, "AdminAgentRouteBodyError", { enumerable: true, get: function () { return errors_1.AdminAgentRouteBodyError; } });
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;EAME;;;AAEF;;;;;;;;;;;;;;;;;GAiBG;AAEH,iFAAiF;AACjF,qCAAyD;AAAhD,uHAAA,4BAA4B,OAAA;AAGrC,iFAAiF;AACjF,mCAIkB;AAHhB,8GAAA,oBAAoB,OAAA;AACpB,0HAAA,gCAAgC,OAAA;AAChC,kHAAA,wBAAwB,OAAA"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,71 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bernierllc/admin-agent-nextjs",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Next.js App Router adapter for admin-agent-service: streaming SSE POST handler with auth, validation, and error mapping",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"browser": false,
|
|
5
8
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
"admin-agent",
|
|
10
|
+
"nextjs",
|
|
11
|
+
"app-router",
|
|
12
|
+
"streaming",
|
|
13
|
+
"sse",
|
|
14
|
+
"adapter",
|
|
15
|
+
"bernierllc"
|
|
16
|
+
],
|
|
17
|
+
"author": "Bernier LLC",
|
|
18
|
+
"license": "Bernier LLC",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@bernierllc/logger": "^1.7.0",
|
|
21
|
+
"@bernierllc/admin-agent-service": "0.1.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"next": ">=14.0.0 <16"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/jest": "^29.5.5",
|
|
28
|
+
"@types/node": "^20.6.0",
|
|
29
|
+
"jest": "^29.6.4",
|
|
30
|
+
"next": "^15.0.0",
|
|
31
|
+
"rimraf": "^5.0.1",
|
|
32
|
+
"ts-jest": "^29.1.1",
|
|
33
|
+
"typescript": "^5.2.2"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist/**/*",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "git+https://github.com/bernier-llc/tools.git"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18.0.0"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"registry": "https://registry.npmjs.org/"
|
|
50
|
+
},
|
|
51
|
+
"bernierllc": {
|
|
52
|
+
"runtime": "node",
|
|
53
|
+
"category": "service",
|
|
54
|
+
"integration": {
|
|
55
|
+
"neverhub": "not-applicable",
|
|
56
|
+
"neveradmin": "not-applicable",
|
|
57
|
+
"logger": "integrated"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "tsc",
|
|
62
|
+
"dev": "tsc --watch",
|
|
63
|
+
"test": "jest",
|
|
64
|
+
"test:watch": "jest --watch",
|
|
65
|
+
"test:run": "jest",
|
|
66
|
+
"test:coverage": "jest --coverage",
|
|
67
|
+
"lint": "eslint src/**/*.ts",
|
|
68
|
+
"clean": "rimraf dist",
|
|
69
|
+
"prebuild": "npm run clean"
|
|
70
|
+
}
|
|
71
|
+
}
|