@gnomondigital/nebulas-kit-core 0.3.2 → 0.4.1

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 CHANGED
@@ -8,6 +8,16 @@ Framework-agnostic A2A chat client, Nebulas client, and server handlers.
8
8
  npm install @gnomondigital/nebulas-kit-core
9
9
  ```
10
10
 
11
+ ### Subpath exports
12
+
13
+ | Import path | Use |
14
+ |-------------|-----|
15
+ | `@gnomondigital/nebulas-kit-core` | Full API (Next.js, Express, proxy handlers). |
16
+ | `@gnomondigital/nebulas-kit-core/client` | Browser-only: `sendMessageStream`, Nebulas client, types. **Use from React/Vite** so `next/server` is never bundled. |
17
+ | `@gnomondigital/nebulas-kit-core/express` | Express router only; no Next.js. |
18
+
19
+ `@gnomondigital/nebulas-kit-react` imports from `/client` internally.
20
+
11
21
  ## Environment Variables
12
22
 
13
23
  | Variable | Required | Description |
@@ -19,10 +29,49 @@ npm install @gnomondigital/nebulas-kit-core
19
29
  | `AUTH0_CLIENT_ID` | For client_credentials, ROP | Auth0 client ID |
20
30
  | `AUTH0_CLIENT_SECRET` | For client_credentials, ROP | Auth0 client secret |
21
31
  | `AUTH0_A2A_AUDIENCE` | For Auth0 strategies | API audience |
32
+ | `AUTH0_ROP_USERNAME` | For env ROP (`createA2AProxyHandlerFromEnvROP`) | Service user username (server secret) |
33
+ | `AUTH0_ROP_PASSWORD` | For env ROP | Service user password (server secret) |
22
34
  | `NEBULAS_API_URL` | For Nebulas | Conversation API base URL |
23
35
  | `NEBULAS_API_KEY` | For Nebulas proxy | x-api-key fallback when no session token |
24
36
  | `NEBULAS_PROJECT_ID` | For Nebulas | Project ID |
25
37
 
38
+ ## A2A proxy auth modes (Next.js)
39
+
40
+ | Mode | When to use | Exports |
41
+ |------|-------------|---------|
42
+ | **Auth0 session** | User signs in with `@auth0/nextjs-auth0`; access token for `AUTH0_A2A_AUDIENCE` comes from the session. | `createA2AProxyHandler`, `createGetHeadersForAuth0`, `handleA2AAuthNextJsPOST` (body ROP, optional) |
43
+ | **Env ROP** | No browser Auth0; a fixed **service user** in env performs Resource Owner Password; token is cached per process. | `createA2AProxyHandlerFromEnvROP`, `createGetHeadersFromEnvROP`, `getCachedAccessTokenFromEnvROP` |
44
+
45
+ Env ROP example:
46
+
47
+ ```ts
48
+ // app/api/a2a/route.ts
49
+ import { createA2AProxyHandlerFromEnvROP } from "@gnomondigital/nebulas-kit-core";
50
+
51
+ export const POST = createA2AProxyHandlerFromEnvROP({
52
+ apiKey: process.env.A2A_API_KEY,
53
+ });
54
+ ```
55
+
56
+ ```ts
57
+ // app/api/a2a/config/route.ts
58
+ import type { NextRequest } from "next/server";
59
+ import {
60
+ handleA2AConfigNextJsGET,
61
+ createGetHeadersFromEnvROP,
62
+ } from "@gnomondigital/nebulas-kit-core";
63
+
64
+ const getHeaders = createGetHeadersFromEnvROP({
65
+ apiKey: process.env.A2A_API_KEY,
66
+ });
67
+
68
+ export async function GET(request: NextRequest) {
69
+ return handleA2AConfigNextJsGET(request, { getHeaders });
70
+ }
71
+ ```
72
+
73
+ See `apps/demo_rop` in the monorepo for a full app using env ROP.
74
+
26
75
  ## Usage
27
76
 
28
77
  ### Client: sendMessageStream
@@ -92,10 +141,26 @@ export const DELETE = handler;
92
141
 
93
142
  ```ts
94
143
  import express from "express";
95
- import { createA2AExpressRouter } from "@gnomondigital/nebulas-kit-core";
144
+ import { createA2AExpressRouter } from "@gnomondigital/nebulas-kit-core/express";
96
145
 
97
146
  const app = express();
98
147
  app.use(express.json());
99
148
  app.use("/api/a2a", createA2AExpressRouter(express));
100
149
  app.listen(3000);
101
150
  ```
151
+
152
+ Use **`@gnomondigital/nebulas-kit-core/express`** so the bundle does not load Next.js adapters (`next/server`).
153
+
154
+ **Env ROP** (service user in `AUTH0_ROP_USERNAME` / `AUTH0_ROP_PASSWORD`, same as Next.js `createA2AProxyHandlerFromEnvROP`):
155
+
156
+ ```ts
157
+ app.use(
158
+ "/api/a2a",
159
+ createA2AExpressRouter(express, {
160
+ useEnvRop: true,
161
+ envRopApiKey: process.env.A2A_API_KEY,
162
+ })
163
+ );
164
+ ```
165
+
166
+ See `apps/demo_express_rop` in the monorepo for a full Express + Vite example.
@@ -2,10 +2,9 @@
2
2
  * A2A JSON-RPC client for AI Chat.
3
3
  * Communicates with the A2A agent via proxy (configurable endpoint).
4
4
  */
5
+ import type { SendMessageStreamOptions } from "./types.js";
5
6
  /**
6
7
  * Send a message and stream the response via SSE.
7
8
  */
8
- export declare function sendMessageStream(message: string, onDelta: (chunk: string) => void, signal?: AbortSignal, files?: File[], stream?: boolean, sessionId?: string, options?: {
9
- endpoint?: string;
10
- }): Promise<string>;
9
+ export declare function sendMessageStream(message: string, onDelta: (chunk: string) => void, signal?: AbortSignal, files?: File[], stream?: boolean, sessionId?: string, options?: SendMessageStreamOptions): Promise<string>;
11
10
  //# sourceMappingURL=a2a-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"a2a-client.d.ts","sourceRoot":"","sources":["../src/a2a-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAChC,MAAM,CAAC,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,MAAM,UAAO,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC7B,GACA,OAAO,CAAC,MAAM,CAAC,CA4HjB"}
1
+ {"version":3,"file":"a2a-client.d.ts","sourceRoot":"","sources":["../src/a2a-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAY3D;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EAChC,MAAM,CAAC,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE,IAAI,EAAE,EACd,MAAM,UAAO,EACb,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,wBAAwB,GACjC,OAAO,CAAC,MAAM,CAAC,CAoIjB"}
@@ -32,7 +32,15 @@ export async function sendMessageStream(message, onDelta, signal, files, stream
32
32
  }
33
33
  const method = stream ? "message/stream" : "message/send";
34
34
  const messageId = crypto.randomUUID();
35
- const headers = { "Content-Type": "application/json" };
35
+ let extraHeaders = {};
36
+ if (options?.getHeaders) {
37
+ const h = options.getHeaders();
38
+ extraHeaders = h instanceof Promise ? await h : h;
39
+ }
40
+ const headers = {
41
+ ...extraHeaders,
42
+ "Content-Type": "application/json",
43
+ };
36
44
  const res = await fetch(endpoint, {
37
45
  method: "POST",
38
46
  headers,
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Browser / React entry: A2A client, Nebulas client, shared types.
3
+ * Does not load Next.js, Express adapters, or other server-only modules.
4
+ *
5
+ * Use from UI code: `import { sendMessageStream } from "@gnomondigital/nebulas-kit-core/client"`
6
+ */
7
+ export { sendMessageStream } from "./a2a-client.js";
8
+ export { createNebulasClient, nebulasClient, type NebulasConversation, type NebulasChatMessage, type CreateChatMessageParams, type NebulasClientOptions, } from "./nebulas-client.js";
9
+ export { transformUtcDatesToLocal } from "./utils/date-timezone.js";
10
+ export type { ChatMessage, ChatMessagePayload, SendMessageStreamOptions, } from "./types.js";
11
+ //# sourceMappingURL=client-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-api.d.ts","sourceRoot":"","sources":["../src/client-api.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Browser / React entry: A2A client, Nebulas client, shared types.
3
+ * Does not load Next.js, Express adapters, or other server-only modules.
4
+ *
5
+ * Use from UI code: `import { sendMessageStream } from "@gnomondigital/nebulas-kit-core/client"`
6
+ */
7
+ export { sendMessageStream } from "./a2a-client.js";
8
+ export { createNebulasClient, nebulasClient, } from "./nebulas-client.js";
9
+ export { transformUtcDatesToLocal } from "./utils/date-timezone.js";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Express-only entry: avoids pulling Next.js (next/server) from the main package barrel.
3
+ */
4
+ export { createA2AExpressRouter, type A2AExpressRouterOptions, } from "./server/express.js";
5
+ //# sourceMappingURL=express-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express-api.d.ts","sourceRoot":"","sources":["../src/express-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Express-only entry: avoids pulling Next.js (next/server) from the main package barrel.
3
+ */
4
+ export { createA2AExpressRouter, } from "./server/express.js";
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export { getAuthStrategy, getAuthHeaders, type AuthStrategy, } from "./server/au
11
11
  export { exchangePasswordForToken, type ROPAuthRequest, type ROPAuthResponse, } from "./server/auth-handler.js";
12
12
  export { createConfigResponse, type ConfigResponse, type AgentCard, type AgentCardCapabilities, } from "./server/config-handler.js";
13
13
  export { createA2AExpressRouter, type A2AExpressRouterOptions, } from "./server/express.js";
14
- export { handleA2ANextJsPOST, handleA2AAuthNextJsPOST, handleA2AConfigNextJsGET, createGetHeadersForAuth0, createA2AProxyHandler, createNebulasProxyHandler, type HandleA2AConfigOptions, type Auth0ClientInterface, type CreateA2AProxyHandlerOptions, type CreateNebulasProxyHandlerOptions, } from "./server/nextjs.js";
14
+ export { handleA2ANextJsPOST, handleA2AAuthNextJsPOST, handleA2AConfigNextJsGET, createGetHeadersForAuth0, createGetHeadersFromEnvROP, createA2AProxyHandler, createA2AProxyHandlerFromEnvROP, createNebulasProxyHandler, type HandleA2AConfigOptions, type Auth0ClientInterface, type CreateA2AProxyHandlerOptions, type CreateA2AProxyHandlerFromEnvROPOptions, type CreateGetHeadersFromEnvROPOptions, type CreateNebulasProxyHandlerOptions, } from "./server/nextjs.js";
15
+ export { getCachedAccessTokenFromEnvROP } from "./server/env-rop-token.js";
15
16
  export { handleNebulasProxy, isRefreshTokenInvalid, type NebulasProxyRequest, type NebulasProxyResponse, type NebulasProxyHandlerOptions, } from "./server/nebulas-proxy-handler.js";
16
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE5F,OAAO,EACL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACzB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,eAAe,EACf,cAAc,EACd,KAAK,YAAY,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,wBAAwB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,qBAAqB,GAC3B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,EACrB,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EACjC,KAAK,gCAAgC,GACtC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,GAChC,MAAM,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,mBAAmB,EACnB,aAAa,EACb,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE5F,OAAO,EACL,cAAc,EACd,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,GACzB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EACL,eAAe,EACf,cAAc,EACd,KAAK,YAAY,GAClB,MAAM,6BAA6B,CAAC;AAErC,OAAO,EACL,wBAAwB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,GACrB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACL,oBAAoB,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,qBAAqB,GAC3B,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,sBAAsB,EACtB,KAAK,uBAAuB,GAC7B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,wBAAwB,EACxB,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,+BAA+B,EAC/B,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,4BAA4B,EACjC,KAAK,sCAAsC,EAC3C,KAAK,iCAAiC,EACtC,KAAK,gCAAgC,GACtC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAE3E,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,GAChC,MAAM,mCAAmC,CAAC"}
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ export { getAuthStrategy, getAuthHeaders, } from "./server/auth-strategies.js";
10
10
  export { exchangePasswordForToken, } from "./server/auth-handler.js";
11
11
  export { createConfigResponse, } from "./server/config-handler.js";
12
12
  export { createA2AExpressRouter, } from "./server/express.js";
13
- // Usage: import express from "express"; app.use("/api/a2a", createA2AExpressRouter(express));
14
- export { handleA2ANextJsPOST, handleA2AAuthNextJsPOST, handleA2AConfigNextJsGET, createGetHeadersForAuth0, createA2AProxyHandler, createNebulasProxyHandler, } from "./server/nextjs.js";
13
+ // Express-only apps: import from "@gnomondigital/nebulas-kit-core/express" to avoid loading Next.js.
14
+ export { handleA2ANextJsPOST, handleA2AAuthNextJsPOST, handleA2AConfigNextJsGET, createGetHeadersForAuth0, createGetHeadersFromEnvROP, createA2AProxyHandler, createA2AProxyHandlerFromEnvROP, createNebulasProxyHandler, } from "./server/nextjs.js";
15
+ export { getCachedAccessTokenFromEnvROP } from "./server/env-rop-token.js";
15
16
  export { handleNebulasProxy, isRefreshTokenInvalid, } from "./server/nebulas-proxy-handler.js";
@@ -1 +1 @@
1
- {"version":3,"file":"auth-handler.d.ts","sourceRoot":"","sources":["../../src/server/auth-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CA8B1B"}
1
+ {"version":3,"file":"auth-handler.d.ts","sourceRoot":"","sources":["../../src/server/auth-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,eAAe,CAAC,CA+B1B"}
@@ -13,17 +13,18 @@ export async function exchangePasswordForToken(username, password) {
13
13
  if (!domain || !clientId || !clientSecret) {
14
14
  throw new Error("AUTH0_DOMAIN, AUTH0_CLIENT_ID, AUTH0_CLIENT_SECRET required for ROP");
15
15
  }
16
+ const body = new URLSearchParams({
17
+ grant_type: "password",
18
+ username,
19
+ password,
20
+ client_id: clientId,
21
+ client_secret: clientSecret,
22
+ ...(audience && { audience }),
23
+ });
16
24
  const res = await fetch(`https://${domain}/oauth/token`, {
17
25
  method: "POST",
18
26
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
19
- body: new URLSearchParams({
20
- grant_type: "password",
21
- username,
22
- password,
23
- client_id: clientId,
24
- client_secret: clientSecret,
25
- ...(audience && { audience }),
26
- }),
27
+ body: body.toString(),
27
28
  });
28
29
  if (!res.ok) {
29
30
  const body = await res.json().catch(() => ({}));
@@ -1 +1 @@
1
- {"version":3,"file":"config-handler.d.ts","sourceRoot":"","sources":["../../src/server/config-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAyBD,wBAAsB,oBAAoB,CACxC,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,cAAc,CAAC,CAmBzB"}
1
+ {"version":3,"file":"config-handler.d.ts","sourceRoot":"","sources":["../../src/server/config-handler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,kGAAkG;IAClG,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAyBD,wBAAsB,oBAAoB,CACxC,OAAO,CAAC,EAAE,2BAA2B,GACpC,OAAO,CAAC,cAAc,CAAC,CAmBzB"}
@@ -3,7 +3,8 @@
3
3
  * Fetches agent card from A2A_URL/.well-known/agent-card.json when A2A_URL is set.
4
4
  * Framework-agnostic; returns JSON response body.
5
5
  */
6
- const A2A_URL = process.env.A2A_URL || process.env.NEXT_PUBLIC_A2A_URL || "";
6
+ import { nodeEnv } from "./node-env.js";
7
+ const A2A_URL = nodeEnv("A2A_URL") || nodeEnv("NEXT_PUBLIC_A2A_URL") || "";
7
8
  async function fetchAgentCard(headers) {
8
9
  const base = A2A_URL.replace(/\/$/, "");
9
10
  if (!base)
@@ -28,7 +29,7 @@ async function fetchAgentCard(headers) {
28
29
  }
29
30
  }
30
31
  export async function createConfigResponse(options) {
31
- const nebulasProjectId = process.env.NEBULAS_PROJECT_ID ?? null;
32
+ const nebulasProjectId = nodeEnv("NEBULAS_PROJECT_ID") ?? null;
32
33
  const includeAgentCard = options?.includeAgentCard !== false;
33
34
  if (!includeAgentCard) {
34
35
  return {
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Cached Auth0 Resource Owner Password token using credentials from environment.
3
+ * Single service user (AUTH0_ROP_USERNAME / AUTH0_ROP_PASSWORD); shared across requests per process.
4
+ */
5
+ /**
6
+ * Returns a valid access token, refreshing from Auth0 when near expiry.
7
+ * Concurrent callers share a single in-flight refresh.
8
+ */
9
+ export declare function getCachedAccessTokenFromEnvROP(): Promise<string>;
10
+ //# sourceMappingURL=env-rop-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-rop-token.d.ts","sourceRoot":"","sources":["../../src/server/env-rop-token.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA8BH;;;GAGG;AACH,wBAAsB,8BAA8B,IAAI,OAAO,CAAC,MAAM,CAAC,CAiBtE"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Cached Auth0 Resource Owner Password token using credentials from environment.
3
+ * Single service user (AUTH0_ROP_USERNAME / AUTH0_ROP_PASSWORD); shared across requests per process.
4
+ */
5
+ import { exchangePasswordForToken } from "./auth-handler.js";
6
+ const EXPIRY_SKEW_MS = 60000;
7
+ let cache = null;
8
+ let refreshPromise = null;
9
+ async function fetchAndCacheToken() {
10
+ const username = process.env.AUTH0_ROP_USERNAME;
11
+ const password = process.env.AUTH0_ROP_PASSWORD;
12
+ if (!username || !password) {
13
+ throw new Error("AUTH0_ROP_USERNAME and AUTH0_ROP_PASSWORD are required for env ROP token");
14
+ }
15
+ const data = await exchangePasswordForToken(username, password);
16
+ const expiresInSec = data.expires_in ?? 3600;
17
+ const expiresAtMs = Date.now() + expiresInSec * 1000;
18
+ cache = { token: data.access_token, expiresAtMs };
19
+ return data.access_token;
20
+ }
21
+ /**
22
+ * Returns a valid access token, refreshing from Auth0 when near expiry.
23
+ * Concurrent callers share a single in-flight refresh.
24
+ */
25
+ export async function getCachedAccessTokenFromEnvROP() {
26
+ if (refreshPromise) {
27
+ return refreshPromise;
28
+ }
29
+ if (cache &&
30
+ Date.now() < cache.expiresAtMs - EXPIRY_SKEW_MS) {
31
+ return cache.token;
32
+ }
33
+ refreshPromise = fetchAndCacheToken().finally(() => {
34
+ refreshPromise = null;
35
+ });
36
+ return refreshPromise;
37
+ }
@@ -28,6 +28,13 @@ import { type ProxyHandlerOptions } from "./proxy-handler.js";
28
28
  export interface A2AExpressRouterOptions extends ProxyHandlerOptions {
29
29
  /** When provided, uses these headers when fetching agent card (same auth as A2A proxy). */
30
30
  configGetHeaders?: (req: Request) => Promise<Record<string, string>>;
31
+ /**
32
+ * When true, uses AUTH0_ROP_USERNAME / AUTH0_ROP_PASSWORD for the A2A proxy and agent card
33
+ * (server-side env ROP), matching Next.js `createA2AProxyHandlerFromEnvROP`.
34
+ */
35
+ useEnvRop?: boolean;
36
+ /** Optional x-api-key when useEnvRop is true (e.g. process.env.A2A_API_KEY). */
37
+ envRopApiKey?: string;
31
38
  }
32
39
  /**
33
40
  * Create Express router for A2A proxy, auth (ROP), and config.
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/server/express.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,eAAe,CAAC;IAC5D,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/B;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;IAC3G,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,KAAK,IAAI,CAAC;CAC3F;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,aAAa,CAAC;CAC7B;AAED,KAAK,OAAO,GAAG,cAAc,CAAC;AAE9B,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAI9E,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACtE;AAeD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,uBAAuB,iBAwElC"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/server/express.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,UAAU,eAAe;IACvB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,eAAe,CAAC;IAC1C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,eAAe,CAAC;IAC5D,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/B,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,IAAI,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CAC/B;AAED,UAAU,aAAa;IACrB,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC;IAC3G,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE,eAAe,KAAK,IAAI,KAAK,IAAI,CAAC;CAC3F;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,aAAa,CAAC;CAC7B;AAED,KAAK,OAAO,GAAG,cAAc,CAAC;AAE9B,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9E,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE,2FAA2F;IAC3F,gBAAgB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAoCD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE,uBAAuB,iBAiHlC"}
@@ -5,6 +5,23 @@
5
5
  import { handleA2AProxy } from "./proxy-handler.js";
6
6
  import { exchangePasswordForToken } from "./auth-handler.js";
7
7
  import { createConfigResponse } from "./config-handler.js";
8
+ import { getCachedAccessTokenFromEnvROP } from "./env-rop-token.js";
9
+ async function buildEnvRopHeaders(apiKey) {
10
+ const headers = {};
11
+ if (apiKey) {
12
+ headers["x-api-key"] = apiKey;
13
+ }
14
+ const token = await getCachedAccessTokenFromEnvROP();
15
+ headers["Authorization"] = `Bearer ${token}`;
16
+ return headers;
17
+ }
18
+ function expressRouterProxyOptions(options) {
19
+ if (!options) {
20
+ return {};
21
+ }
22
+ const { configGetHeaders: _c, useEnvRop: _u, envRopApiKey: _a, ...rest } = options;
23
+ return rest;
24
+ }
8
25
  function getHeadersFromRequest(req) {
9
26
  const headers = {};
10
27
  const h = req.headers;
@@ -37,7 +54,28 @@ export function createA2AExpressRouter(express, options) {
37
54
  headers: getHeadersFromRequest(req),
38
55
  body: body || undefined,
39
56
  };
40
- const result = await handleA2AProxy(proxyReq, options);
57
+ let proxyOptions;
58
+ if (options?.useEnvRop) {
59
+ try {
60
+ const authHeaders = await buildEnvRopHeaders(options.envRopApiKey);
61
+ proxyOptions = {
62
+ ...expressRouterProxyOptions(options),
63
+ headers: authHeaders,
64
+ };
65
+ }
66
+ catch (err) {
67
+ console.error("[Env ROP] Failed to get access token:", err);
68
+ res.status(401).json({
69
+ error: "Unauthorized",
70
+ hint: "Check AUTH0_ROP_USERNAME, AUTH0_ROP_PASSWORD, AUTH0_DOMAIN, client credentials, and Auth0 ROP configuration.",
71
+ });
72
+ return;
73
+ }
74
+ }
75
+ else {
76
+ proxyOptions = expressRouterProxyOptions(options);
77
+ }
78
+ const result = await handleA2AProxy(proxyReq, proxyOptions);
41
79
  res.status(result.status);
42
80
  for (const [k, v] of Object.entries(result.headers)) {
43
81
  res.setHeader(k, v);
@@ -84,13 +122,34 @@ export function createA2AExpressRouter(express, options) {
84
122
  }
85
123
  });
86
124
  router.get("/config", async (req, res) => {
87
- const includeAgentCard = req.query?.includeAgentCard !== "false";
88
- let headers;
89
- if (options?.configGetHeaders && includeAgentCard) {
90
- headers = await options.configGetHeaders(req);
125
+ try {
126
+ const includeAgentCard = req.query?.includeAgentCard !== "false";
127
+ let headers;
128
+ if (includeAgentCard) {
129
+ if (options?.useEnvRop) {
130
+ try {
131
+ headers = await buildEnvRopHeaders(options.envRopApiKey);
132
+ }
133
+ catch (err) {
134
+ console.error("[Env ROP] Failed to get access token:", err);
135
+ res.status(401).json({
136
+ error: "Unauthorized",
137
+ hint: "Check AUTH0_ROP_USERNAME, AUTH0_ROP_PASSWORD, AUTH0_DOMAIN, client credentials, and Auth0 ROP configuration.",
138
+ });
139
+ return;
140
+ }
141
+ }
142
+ else if (options?.configGetHeaders) {
143
+ headers = await options.configGetHeaders(req);
144
+ }
145
+ }
146
+ const config = await createConfigResponse({ includeAgentCard, headers });
147
+ res.json(config);
148
+ }
149
+ catch (err) {
150
+ console.error("[A2A Express] Config error:", err);
151
+ res.status(500).json({ error: "Internal server error" });
91
152
  }
92
- const config = await createConfigResponse({ includeAgentCard, headers });
93
- res.json(config);
94
153
  });
95
154
  return router;
96
155
  }
@@ -1 +1 @@
1
- {"version":3,"file":"nebulas-proxy-handler.d.ts","sourceRoot":"","sources":["../../src/server/nebulas-proxy-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,WAAW,CAAC;CAC1D;AAED,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3E;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAS3D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,oBAAoB,CAAC,CAwH/B"}
1
+ {"version":3,"file":"nebulas-proxy-handler.d.ts","sourceRoot":"","sources":["../../src/server/nebulas-proxy-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,GAAG,WAAW,CAAC;CAC1D;AAED,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,mBAAmB,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC3E;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAS3D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,mBAAmB,EACxB,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,oBAAoB,CAAC,CAwH/B"}
@@ -2,10 +2,11 @@
2
2
  * Framework-agnostic Nebulas API proxy handler.
3
3
  * Proxies requests to the Nebulas API (conversations, chat_messages).
4
4
  */
5
- const NEBULAS_API_URL = process.env.NEBULAS_API_URL || "http://localhost:8020";
6
- const A2A_AUDIENCE = process.env.AUTH0_A2A_AUDIENCE;
7
- const A2A_API_KEY = process.env.A2A_API_KEY;
8
- const NEBULAS_API_KEY = process.env.NEBULAS_API_KEY;
5
+ import { nodeEnv } from "./node-env.js";
6
+ const NEBULAS_API_URL = nodeEnv("NEBULAS_API_URL") || "http://localhost:8020";
7
+ const A2A_AUDIENCE = nodeEnv("AUTH0_A2A_AUDIENCE");
8
+ const A2A_API_KEY = nodeEnv("A2A_API_KEY");
9
+ const NEBULAS_API_KEY = nodeEnv("NEBULAS_API_KEY");
9
10
  /**
10
11
  * Check if an error indicates invalid refresh token (for session re-auth).
11
12
  */
@@ -72,6 +72,24 @@ export interface CreateA2AProxyHandlerOptions {
72
72
  * export const POST = handler;
73
73
  */
74
74
  export declare function createA2AProxyHandler(options: CreateA2AProxyHandlerOptions): (request: NextRequest) => Promise<Response>;
75
+ export interface CreateGetHeadersFromEnvROPOptions {
76
+ apiKey?: string;
77
+ }
78
+ /**
79
+ * Builds Authorization from a cached env-based ROP token (AUTH0_ROP_USERNAME / AUTH0_ROP_PASSWORD).
80
+ * Optional request parameter reserved for future use (e.g. per-request context).
81
+ */
82
+ export declare function createGetHeadersFromEnvROP(options?: CreateGetHeadersFromEnvROPOptions): (request?: NextRequest) => Promise<Record<string, string>>;
83
+ export interface CreateA2AProxyHandlerFromEnvROPOptions {
84
+ apiKey?: string;
85
+ }
86
+ /**
87
+ * Next.js POST handler for the A2A proxy using env ROP (service user), not Auth0 session.
88
+ *
89
+ * Use in app/api/a2a/route.ts:
90
+ * export const POST = createA2AProxyHandlerFromEnvROP({ apiKey: process.env.A2A_API_KEY });
91
+ */
92
+ export declare function createA2AProxyHandlerFromEnvROP(options?: CreateA2AProxyHandlerFromEnvROPOptions): (request: NextRequest) => Promise<Response>;
75
93
  /**
76
94
  * Options for the Nebulas API proxy handler.
77
95
  */
@@ -1 +1 @@
1
- {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../src/server/nextjs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAiB9E;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,mBAAmB,qBA6B9B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,WAAW,qBAyBjE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACxE;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,sBAAsB,qBAcjC;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC7D,cAAc,CACZ,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,CACF,OAAO,EAAE,WAAW,EACpB,YAAY,CAAC,EAAE,YAAY,KACxB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoDnC;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,IAO3C,SAAS,WAAW,uBAuDnD;AAED;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gCAAgC,IAE/E,SAAS,WAAW,EACpB,KAAK;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CAAE,oCAkH/C"}
1
+ {"version":3,"file":"nextjs.d.ts","sourceRoot":"","sources":["../../src/server/nextjs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAkB,KAAK,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAkB9E;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,mBAAmB,qBA6B9B;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE,WAAW,qBAyBjE;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACxE;AAED;;;GAGG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,sBAAsB,qBAqBjC;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC7D,cAAc,CACZ,GAAG,EAAE,OAAO,EACZ,GAAG,EAAE,OAAO,EACZ,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GACzB,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE;IAChD,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,CACF,OAAO,EAAE,WAAW,EACpB,YAAY,CAAC,EAAE,YAAY,KACxB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAoDnC;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,IAO3C,SAAS,WAAW,uBAuDnD;AAED,MAAM,WAAW,iCAAiC;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,CAAC,EAAE,iCAAiC,GAC1C,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAsB5D;AAED,MAAM,WAAW,sCAAsC;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,CAAC,EAAE,sCAAsC,IAIlB,SAAS,WAAW,uBAiDnD;AAED;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,gCAAgC,IAE/E,SAAS,WAAW,EACpB,KAAK;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAA;CAAE,oCAiH/C"}
@@ -6,6 +6,7 @@ import { NextResponse } from "next/server";
6
6
  import { handleA2AProxy } from "./proxy-handler.js";
7
7
  import { handleNebulasProxy, isRefreshTokenInvalid, } from "./nebulas-proxy-handler.js";
8
8
  import { exchangePasswordForToken } from "./auth-handler.js";
9
+ import { getCachedAccessTokenFromEnvROP } from "./env-rop-token.js";
9
10
  import { createConfigResponse } from "./config-handler.js";
10
11
  function headersFromRequest(req) {
11
12
  const headers = {};
@@ -76,7 +77,15 @@ export async function handleA2AConfigNextJsGET(request, options) {
76
77
  const includeAgentCard = request.nextUrl.searchParams.get("includeAgentCard") !== "false";
77
78
  let headers;
78
79
  if (options?.getHeaders && includeAgentCard) {
79
- headers = await options.getHeaders(request);
80
+ try {
81
+ headers = await options.getHeaders(request);
82
+ }
83
+ catch (e) {
84
+ if (e instanceof NextResponse) {
85
+ return e;
86
+ }
87
+ throw e;
88
+ }
80
89
  }
81
90
  const config = await createConfigResponse({ includeAgentCard, headers });
82
91
  return new Response(JSON.stringify(config), {
@@ -199,6 +208,82 @@ export function createA2AProxyHandler(options) {
199
208
  return new Response(null, { status: result.status, headers: responseHeaders });
200
209
  };
201
210
  }
211
+ /**
212
+ * Builds Authorization from a cached env-based ROP token (AUTH0_ROP_USERNAME / AUTH0_ROP_PASSWORD).
213
+ * Optional request parameter reserved for future use (e.g. per-request context).
214
+ */
215
+ export function createGetHeadersFromEnvROP(options) {
216
+ return async (_request) => {
217
+ const headers = {};
218
+ if (options?.apiKey) {
219
+ headers["x-api-key"] = options.apiKey;
220
+ }
221
+ try {
222
+ const token = await getCachedAccessTokenFromEnvROP();
223
+ headers["Authorization"] = `Bearer ${token}`;
224
+ }
225
+ catch (err) {
226
+ console.error("[Env ROP] Failed to get access token:", err);
227
+ throw new NextResponse(JSON.stringify({
228
+ error: "Unauthorized",
229
+ hint: "Check AUTH0_ROP_USERNAME, AUTH0_ROP_PASSWORD, AUTH0_DOMAIN, client credentials, and Auth0 ROP configuration.",
230
+ }), { status: 401, headers: { "Content-Type": "application/json" } });
231
+ }
232
+ return headers;
233
+ };
234
+ }
235
+ /**
236
+ * Next.js POST handler for the A2A proxy using env ROP (service user), not Auth0 session.
237
+ *
238
+ * Use in app/api/a2a/route.ts:
239
+ * export const POST = createA2AProxyHandlerFromEnvROP({ apiKey: process.env.A2A_API_KEY });
240
+ */
241
+ export function createA2AProxyHandlerFromEnvROP(options) {
242
+ const getHeaders = createGetHeadersFromEnvROP(options);
243
+ return async function handler(request) {
244
+ let authHeaders;
245
+ try {
246
+ authHeaders = await getHeaders(request);
247
+ }
248
+ catch (err) {
249
+ if (err instanceof NextResponse) {
250
+ return err;
251
+ }
252
+ throw err;
253
+ }
254
+ let body;
255
+ try {
256
+ const text = await request.text();
257
+ body = text.length > 0 ? text : undefined;
258
+ }
259
+ catch {
260
+ return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
261
+ }
262
+ const proxyReq = {
263
+ method: request.method,
264
+ headers: headersFromRequest(request),
265
+ body,
266
+ };
267
+ const result = await handleA2AProxy(proxyReq, { headers: authHeaders });
268
+ const responseHeaders = new Headers();
269
+ for (const [k, v] of Object.entries(result.headers)) {
270
+ responseHeaders.set(k, v);
271
+ }
272
+ if (typeof result.body === "string") {
273
+ return new Response(result.body, {
274
+ status: result.status,
275
+ headers: responseHeaders,
276
+ });
277
+ }
278
+ if (result.body instanceof ReadableStream) {
279
+ return new Response(result.body, {
280
+ status: result.status,
281
+ headers: responseHeaders,
282
+ });
283
+ }
284
+ return new Response(null, { status: result.status, headers: responseHeaders });
285
+ };
286
+ }
202
287
  /**
203
288
  * Creates a Next.js App Router handler for the Nebulas API proxy (catch-all [...path]).
204
289
  * Proxies requests to NEBULAS_API_URL with Auth0 session token or API key.
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Read `process.env` only when `process` exists (Node). Prevents ReferenceError if server
3
+ * modules are accidentally included in a browser bundle (e.g. incomplete tree-shaking).
4
+ */
5
+ export declare function nodeEnv(name: string): string | undefined;
6
+ //# sourceMappingURL=node-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-env.d.ts","sourceRoot":"","sources":["../../src/server/node-env.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAKxD"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Read `process.env` only when `process` exists (Node). Prevents ReferenceError if server
3
+ * modules are accidentally included in a browser bundle (e.g. incomplete tree-shaking).
4
+ */
5
+ export function nodeEnv(name) {
6
+ if (typeof process === "undefined")
7
+ return undefined;
8
+ const env = process.env;
9
+ if (!env)
10
+ return undefined;
11
+ return env[name];
12
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"proxy-handler.d.ts","sourceRoot":"","sources":["../../src/server/proxy-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrE;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,YAAY,EACjB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,aAAa,CAAC,CAkFxB"}
1
+ {"version":3,"file":"proxy-handler.d.ts","sourceRoot":"","sources":["../../src/server/proxy-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAYH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrE;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,YAAY,EACjB,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,aAAa,CAAC,CAkFxB"}
@@ -3,7 +3,8 @@
3
3
  * Accepts a minimal request/response interface.
4
4
  */
5
5
  import { getAuthStrategy, getAuthHeaders, } from "./auth-strategies.js";
6
- const A2A_URL = process.env.A2A_URL || process.env.NEXT_PUBLIC_A2A_URL || "http://localhost:9999";
6
+ import { nodeEnv } from "./node-env.js";
7
+ const A2A_URL = nodeEnv("A2A_URL") || nodeEnv("NEXT_PUBLIC_A2A_URL") || "http://localhost:9999";
7
8
  /**
8
9
  * Handle A2A proxy request. Returns response to send.
9
10
  */
@@ -26,7 +27,7 @@ export async function handleA2AProxy(req, options = {}) {
26
27
  else if (strategy === "session" && options.getSessionToken) {
27
28
  bearerToken = await options.getSessionToken(req);
28
29
  }
29
- if (strategy === "session" && !bearerToken && !process.env.A2A_API_KEY) {
30
+ if (strategy === "session" && !bearerToken && !nodeEnv("A2A_API_KEY")) {
30
31
  return {
31
32
  status: 401,
32
33
  headers: { "Content-Type": "application/json" },
package/dist/types.d.ts CHANGED
@@ -14,14 +14,13 @@ export interface ChatMessagePayload {
14
14
  role: "user" | "assistant";
15
15
  content: string;
16
16
  }
17
+ /** Options for {@link import("./a2a-client.js").sendMessageStream}. */
17
18
  export interface SendMessageStreamOptions {
18
- endpoint: string;
19
- message: string;
20
- onDelta: (chunk: string) => void;
21
- signal?: AbortSignal;
22
- files?: File[];
23
- stream?: boolean;
24
- sessionId?: string;
25
- getHeaders?: () => Promise<Record<string, string>>;
19
+ endpoint?: string;
20
+ /**
21
+ * Extra headers merged before Content-Type (e.g. Authorization Bearer for ROP).
22
+ * Sync or async; Content-Type is always set to application/json after merge.
23
+ */
24
+ getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
26
25
  }
27
26
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACpD"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uEAAuE;AACvE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC7E"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@gnomondigital/nebulas-kit-core",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
+ "sideEffects": false,
5
6
  "main": "./dist/index.js",
6
7
  "module": "./dist/index.js",
7
8
  "types": "./dist/index.d.ts",
@@ -9,6 +10,14 @@
9
10
  ".": {
10
11
  "import": "./dist/index.js",
11
12
  "types": "./dist/index.d.ts"
13
+ },
14
+ "./express": {
15
+ "import": "./dist/express-api.js",
16
+ "types": "./dist/express-api.d.ts"
17
+ },
18
+ "./client": {
19
+ "import": "./dist/client-api.js",
20
+ "types": "./dist/client-api.d.ts"
12
21
  }
13
22
  },
14
23
  "files": [