@forestadmin/agent-bff 1.25.4 → 1.26.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/dist/action/action-routes-middleware.d.ts +3 -3
- package/dist/action/action-routes-middleware.js +3 -4
- package/dist/action/agent-action-client.d.ts +3 -3
- package/dist/action/agent-action-client.js +4 -8
- package/dist/agent/agent-transport.d.ts +19 -0
- package/dist/agent/agent-transport.js +14 -0
- package/dist/agent/in-process-transport.d.ts +33 -0
- package/dist/agent/in-process-transport.js +77 -0
- package/dist/ai/ai-routes-middleware.d.ts +3 -2
- package/dist/ai/ai-routes-middleware.js +22 -2
- package/dist/build-bff.d.ts +32 -0
- package/dist/build-bff.js +372 -0
- package/dist/cli-core.d.ts +0 -12
- package/dist/cli-core.js +4 -339
- package/dist/cli-dispatch.js +5 -4
- package/dist/config/missing-config-warning.d.ts +9 -0
- package/dist/config/missing-config-warning.js +17 -0
- package/dist/context/context-routes-middleware.d.ts +6 -2
- package/dist/context/context-routes-middleware.js +3 -2
- package/dist/data/agent-data-client.d.ts +3 -3
- package/dist/data/agent-data-client.js +3 -7
- package/dist/data/data-routes-middleware.d.ts +3 -3
- package/dist/data/data-routes-middleware.js +5 -10
- package/dist/http/bff-http-server.d.ts +22 -5
- package/dist/http/bff-http-server.js +24 -27
- package/dist/http/bff-local-errors.d.ts +2 -0
- package/dist/http/bff-local-errors.js +9 -1
- package/dist/http/health-route.d.ts +9 -0
- package/dist/http/health-route.js +17 -0
- package/dist/http/version-header-middleware.d.ts +4 -0
- package/dist/http/version-header-middleware.js +12 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -2
- package/dist/oauth/environment-fetch-error.d.ts +15 -0
- package/dist/oauth/environment-fetch-error.js +34 -0
- package/dist/oauth/environment-id.d.ts +25 -0
- package/dist/oauth/environment-id.js +72 -0
- package/dist/oauth/forest-server-client.d.ts +2 -1
- package/dist/oauth/forest-server-client.js +17 -8
- package/dist/oauth/oauth-routes.d.ts +2 -1
- package/dist/oauth/oauth-routes.js +19 -2
- package/dist/openapi/unfolded-document.d.ts +2 -2
- package/dist/openapi/unfolded-document.js +2 -6
- package/dist/read-model/agent-capabilities-fetcher.d.ts +3 -3
- package/dist/read-model/agent-capabilities-fetcher.js +4 -8
- package/package.json +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { AgentActionClient, AgentActionClientOptions } from './agent-action-client';
|
|
2
|
+
import type { AgentTransport } from '../agent/agent-transport';
|
|
2
3
|
import type { Logger } from '../ports/logger-port';
|
|
3
4
|
import type ReadModelStore from '../read-model/read-model-store';
|
|
4
5
|
import type { Middleware } from 'koa';
|
|
5
6
|
export interface ActionRoutesMiddlewareOptions {
|
|
6
7
|
store: ReadModelStore;
|
|
7
|
-
|
|
8
|
-
timeoutMs?: number;
|
|
8
|
+
transport: AgentTransport;
|
|
9
9
|
logger: Logger;
|
|
10
10
|
createClient?: (options: AgentActionClientOptions) => AgentActionClient;
|
|
11
11
|
}
|
|
12
|
-
export default function createActionRoutesMiddleware({ store,
|
|
12
|
+
export default function createActionRoutesMiddleware({ store, transport, logger, createClient, }: ActionRoutesMiddlewareOptions): Middleware;
|
|
13
13
|
//# sourceMappingURL=action-routes-middleware.d.ts.map
|
|
@@ -141,7 +141,7 @@ async function handleExecute({ ctx, action, values, logger, }) {
|
|
|
141
141
|
ctx.status = status;
|
|
142
142
|
ctx.body = body;
|
|
143
143
|
}
|
|
144
|
-
function createActionRoutesMiddleware({ store,
|
|
144
|
+
function createActionRoutesMiddleware({ store, transport, logger, createClient = agent_action_client_1.default, }) {
|
|
145
145
|
return async function actionRoutesMiddleware(ctx, next) {
|
|
146
146
|
const match = ACTION_ROUTE.exec(ctx.path);
|
|
147
147
|
if (!match || ctx.method !== 'POST') {
|
|
@@ -166,10 +166,9 @@ function createActionRoutesMiddleware({ store, agentUrl, timeoutMs, logger, crea
|
|
|
166
166
|
const recordIds = parseRecordIds(body.recordIds);
|
|
167
167
|
const values = parseValues(body.values);
|
|
168
168
|
const client = createClient({
|
|
169
|
-
|
|
169
|
+
transport,
|
|
170
170
|
token,
|
|
171
171
|
actionEndpoints: readModel.getActionEndpoints(),
|
|
172
|
-
timeoutMs,
|
|
173
172
|
});
|
|
174
173
|
const action = await (0, agent_route_helpers_1.callAgent)(() => client.loadAction({
|
|
175
174
|
collection,
|
|
@@ -186,4 +185,4 @@ function createActionRoutesMiddleware({ store, agentUrl, timeoutMs, logger, crea
|
|
|
186
185
|
}
|
|
187
186
|
};
|
|
188
187
|
}
|
|
189
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
188
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXJvdXRlcy1taWRkbGV3YXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FjdGlvbi9hY3Rpb24tcm91dGVzLW1pZGRsZXdhcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFtTEEsK0NBNERDO0FBcE9ELDREQUttQztBQUVuQyxtRUFBaUU7QUFDakUsNkRBQXFEO0FBQ3JELHdGQUFxRTtBQUNyRSw2RUFBeUY7QUFDekYsa0ZBQXdEO0FBQ3hELG1FQUEyRDtBQUMzRCxxRUFLcUM7QUFDckMsK0RBS2tDO0FBRWxDLE1BQU0sWUFBWSxHQUFHLDBEQUEwRCxDQUFDO0FBT2hGLG9HQUFvRztBQUNwRywrRkFBK0Y7QUFDL0Ysd0VBQXdFO0FBQ3hFLHFHQUFxRztBQUNyRyxxR0FBcUc7QUFDckcsU0FBUyxjQUFjLENBQUMsR0FBWTtJQUNsQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sSUFBQSxpQ0FBYyxFQUFDLDRDQUE0QyxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ25DLENBQUM7QUFFRCxNQUFNLGdCQUFnQixHQUFHLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztBQUU3RCxnR0FBZ0c7QUFDaEcsMEVBQTBFO0FBQzFFLFNBQVMsbUJBQW1CLENBQUMsSUFBNkI7SUFDeEQsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRTdFLElB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
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentTransport } from '../agent/agent-transport';
|
|
1
2
|
import type { ActionEndpointsByCollection } from '@forestadmin/agent-client';
|
|
2
3
|
import type { ForestServerActionFormLayoutElement } from '@forestadmin/forestadmin-client';
|
|
3
4
|
export interface ActionFormField {
|
|
@@ -30,10 +31,9 @@ export interface AgentActionClient {
|
|
|
30
31
|
loadAction(params: LoadActionParams): Promise<Action>;
|
|
31
32
|
}
|
|
32
33
|
export interface AgentActionClientOptions {
|
|
33
|
-
|
|
34
|
+
transport: AgentTransport;
|
|
34
35
|
token: string;
|
|
35
36
|
actionEndpoints: ActionEndpointsByCollection;
|
|
36
|
-
timeoutMs?: number;
|
|
37
37
|
}
|
|
38
38
|
export declare function extractRawLayout(action: ActionForm): ForestServerActionFormLayoutElement[];
|
|
39
39
|
/**
|
|
@@ -41,5 +41,5 @@ export declare function extractRawLayout(action: ActionForm): ForestServerAction
|
|
|
41
41
|
* loading (`/hooks/load` + `/hooks/change`, Ruby 404 fallback, dependent-field re-evaluation) rather
|
|
42
42
|
* than reimplementing it. The endpoint map from the read-model is the action allow-list.
|
|
43
43
|
*/
|
|
44
|
-
export default function createAgentActionClient({
|
|
44
|
+
export default function createAgentActionClient({ transport, token, actionEndpoints, }: AgentActionClientOptions): AgentActionClient;
|
|
45
45
|
//# sourceMappingURL=agent-action-client.d.ts.map
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.extractRawLayout = extractRawLayout;
|
|
7
4
|
exports.default = createAgentActionClient;
|
|
8
5
|
const agent_client_1 = require("@forestadmin/agent-client");
|
|
9
|
-
const create_agent_http_requester_1 = __importDefault(require("../agent/create-agent-http-requester"));
|
|
10
6
|
// The raw layout must be read AFTER tryToSetFields: a change hook rebuilds fields+layout in place.
|
|
11
7
|
// agent-client's `Action.getLayout()` only returns an `ActionLayoutRoot` wrapper whose element array
|
|
12
8
|
// lives in a protected field. The rollback contract forbade agent-client changes, so we read it
|
|
@@ -21,15 +17,15 @@ function extractRawLayout(action) {
|
|
|
21
17
|
* loading (`/hooks/load` + `/hooks/change`, Ruby 404 fallback, dependent-field re-evaluation) rather
|
|
22
18
|
* than reimplementing it. The endpoint map from the read-model is the action allow-list.
|
|
23
19
|
*/
|
|
24
|
-
function createAgentActionClient({
|
|
20
|
+
function createAgentActionClient({ transport, token, actionEndpoints, }) {
|
|
25
21
|
const client = (0, agent_client_1.createRemoteAgentClient)({
|
|
26
|
-
url:
|
|
22
|
+
url: transport.url,
|
|
27
23
|
token,
|
|
28
24
|
actionEndpoints,
|
|
29
|
-
httpRequester:
|
|
25
|
+
httpRequester: transport.createRequester(token),
|
|
30
26
|
});
|
|
31
27
|
return {
|
|
32
28
|
loadAction: ({ collection, actionName, recordIds, timezone }) => client.collection(collection).action(actionName, { recordIds, timezone }),
|
|
33
29
|
};
|
|
34
30
|
}
|
|
35
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtYWN0aW9uLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hY3Rpb24vYWdlbnQtYWN0aW9uLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQXFEQSw0Q0FJQztBQU9ELDBDQWdCQztBQTVFRCw0REFBb0U7QUE0Q3BFLG1HQUFtRztBQUNuRyxxR0FBcUc7QUFDckcsZ0dBQWdHO0FBQ2hHLGtHQUFrRztBQUNsRywwRkFBMEY7QUFDMUYsU0FBZ0IsZ0JBQWdCLENBQUMsTUFBa0I7SUFDakQsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLFNBQVMsRUFBd0QsQ0FBQztJQUV0RixPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7QUFDdkQsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUF3Qix1QkFBdUIsQ0FBQyxFQUM5QyxTQUFTLEVBQ1QsS0FBSyxFQUNMLGVBQWUsR0FDVTtJQUN6QixNQUFNLE1BQU0sR0FBRyxJQUFBLHNDQUF1QixFQUFDO1FBQ3JDLEdBQUcsRUFBRSxTQUFTLENBQUMsR0FBRztRQUNsQixLQUFLO1FBQ0wsZUFBZTtRQUNmLGFBQWEsRUFBRSxTQUFTLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQztLQUNoRCxDQUFDLENBQUM7SUFFSCxPQUFPO1FBQ0wsVUFBVSxFQUFFLENBQUMsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLENBQzlELE1BQU0sQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsQ0FBQztLQUM1RSxDQUFDO0FBQ0osQ0FBQyJ9
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HttpRequester } from '@forestadmin/agent-client';
|
|
2
|
+
/**
|
|
3
|
+
* How the BFF reaches the agent. Everything that talks to the agent takes one of these instead of a
|
|
4
|
+
* URL, so the same routes serve a remote agent over HTTP and an agent embedded in the same process.
|
|
5
|
+
*/
|
|
6
|
+
export interface AgentTransport {
|
|
7
|
+
/**
|
|
8
|
+
* Base url `createRemoteAgentClient` still requires. Over HTTP it is the agent; in-process it is a
|
|
9
|
+
* sentinel that never reaches the network, since the requester answers before any socket is opened.
|
|
10
|
+
*/
|
|
11
|
+
url: string;
|
|
12
|
+
createRequester(token: string): HttpRequester;
|
|
13
|
+
}
|
|
14
|
+
export interface HttpTransportOptions {
|
|
15
|
+
agentUrl: string;
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function createHttpTransport({ agentUrl, timeoutMs }: HttpTransportOptions): AgentTransport;
|
|
19
|
+
//# sourceMappingURL=agent-transport.d.ts.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createHttpTransport = createHttpTransport;
|
|
7
|
+
const create_agent_http_requester_1 = __importDefault(require("./create-agent-http-requester"));
|
|
8
|
+
function createHttpTransport({ agentUrl, timeoutMs }) {
|
|
9
|
+
return {
|
|
10
|
+
url: agentUrl,
|
|
11
|
+
createRequester: token => (0, create_agent_http_requester_1.default)(token, agentUrl, timeoutMs),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtdHJhbnNwb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FnZW50L2FnZW50LXRyYW5zcG9ydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQXNCQSxrREFLQztBQXpCRCxnR0FBcUU7QUFvQnJFLFNBQWdCLG1CQUFtQixDQUFDLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBd0I7SUFDL0UsT0FBTztRQUNMLEdBQUcsRUFBRSxRQUFRO1FBQ2IsZUFBZSxFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBQSxxQ0FBd0IsRUFBQyxLQUFLLEVBQUUsUUFBUSxFQUFFLFNBQVMsQ0FBQztLQUMvRSxDQUFDO0FBQ0osQ0FBQyJ9
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentTransport } from './agent-transport';
|
|
2
|
+
export interface AgentDispatchRequest {
|
|
3
|
+
method: 'get' | 'post' | 'put' | 'delete';
|
|
4
|
+
path: string;
|
|
5
|
+
headers: Record<string, string>;
|
|
6
|
+
query?: Record<string, unknown>;
|
|
7
|
+
payload?: Record<string, unknown>;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface AgentDispatchResponse {
|
|
11
|
+
status: number;
|
|
12
|
+
body: unknown;
|
|
13
|
+
text?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Dispatches a request into an agent living in the same process, without a socket. Declared
|
|
17
|
+
* structurally so neither package has to depend on the other for six primitive fields.
|
|
18
|
+
*/
|
|
19
|
+
export interface AgentDispatcher {
|
|
20
|
+
/**
|
|
21
|
+
* Bounding the call is the implementor's duty: there is no socket to abort, so nothing here can
|
|
22
|
+
* cut a hung agent handler loose. When `timeoutMs` is absent the deployment configured none —
|
|
23
|
+
* apply the 10s ceiling `HttpRequester.query` always has rather than waiting forever. A dispatch
|
|
24
|
+
* that fails, times out included, must reject.
|
|
25
|
+
*/
|
|
26
|
+
request(request: AgentDispatchRequest): Promise<AgentDispatchResponse>;
|
|
27
|
+
}
|
|
28
|
+
export interface InProcessTransportOptions {
|
|
29
|
+
dispatcher: AgentDispatcher;
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
export default function createInProcessTransport({ dispatcher, timeoutMs, }: InProcessTransportOptions): AgentTransport;
|
|
33
|
+
//# sourceMappingURL=in-process-transport.d.ts.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.default = createInProcessTransport;
|
|
4
|
+
const agent_client_1 = require("@forestadmin/agent-client");
|
|
5
|
+
const bff_local_errors_1 = require("../http/bff-local-errors");
|
|
6
|
+
/** A sentinel that never reaches the network: `query` answers before any socket is opened. */
|
|
7
|
+
const IN_PROCESS_URL = 'http://in-process.agent';
|
|
8
|
+
/**
|
|
9
|
+
* Reaches the agent through the dispatcher instead of the network, reusing `HttpRequester`'s parse
|
|
10
|
+
* helpers so results and error shape stay identical to the HTTP path.
|
|
11
|
+
*/
|
|
12
|
+
class InProcessRequester extends agent_client_1.HttpRequester {
|
|
13
|
+
constructor(bearerToken, dispatcher, defaultTimeoutMs) {
|
|
14
|
+
super(bearerToken, { url: IN_PROCESS_URL });
|
|
15
|
+
this.bearerToken = bearerToken;
|
|
16
|
+
this.dispatcher = dispatcher;
|
|
17
|
+
this.defaultTimeoutMs = defaultTimeoutMs;
|
|
18
|
+
}
|
|
19
|
+
// No socket to stream from, and nothing in the BFF streams today. A typed 501 rather than a raw
|
|
20
|
+
// Error, so the day a route does reach here the client is told what is missing instead of being
|
|
21
|
+
// sent looking for a network the request never crossed.
|
|
22
|
+
async stream() {
|
|
23
|
+
throw (0, bff_local_errors_1.streamingUnsupported)('Streaming is not supported over the in-process transport');
|
|
24
|
+
}
|
|
25
|
+
async query({ method, path, body, query, maxTimeAllowed, contentType, skipDeserialization, }) {
|
|
26
|
+
const target = InProcessRequester.toDispatchTarget(path);
|
|
27
|
+
const { status, body: responseBody, text, } = await this.dispatch({
|
|
28
|
+
method,
|
|
29
|
+
path: target.path,
|
|
30
|
+
headers: {
|
|
31
|
+
Authorization: `Bearer ${this.bearerToken}`,
|
|
32
|
+
'Content-Type': contentType ?? 'application/json',
|
|
33
|
+
Accept: contentType ?? 'application/json',
|
|
34
|
+
},
|
|
35
|
+
query: { timezone: 'Europe/Paris', ...target.query, ...query },
|
|
36
|
+
payload: body,
|
|
37
|
+
timeoutMs: maxTimeAllowed ?? this.defaultTimeoutMs,
|
|
38
|
+
});
|
|
39
|
+
if (status >= 400)
|
|
40
|
+
throw this.buildError(status, responseBody, text);
|
|
41
|
+
return this.deserialize(responseBody, text, skipDeserialization);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A rejection here is the agent throwing or the dispatch itself failing — never a network hop,
|
|
45
|
+
* since there is none. Rethrown with the shape an agent 5xx has, so `mapAgentError` logs the real
|
|
46
|
+
* cause and answers `agent_unavailable` instead of sending whoever debugs it to look for a socket.
|
|
47
|
+
*/
|
|
48
|
+
async dispatch(request) {
|
|
49
|
+
try {
|
|
50
|
+
return await this.dispatcher.request(request);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
const detail = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
54
|
+
throw this.buildError(500, { errors: [{ detail }] });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Callers hand over raw segments — a record id, a collection name — because `buildUrl` escapes the
|
|
59
|
+
* whole path on the HTTP side, so the escaping has to happen here too. Escaping alone is not
|
|
60
|
+
* enough: `escapeUrlSlug` prefixes `+?*` with a backslash, which the WHATWG parser `buildUrl`
|
|
61
|
+
* feeds reads as a path separator, and that parse also resolves `..` and splits a trailing query
|
|
62
|
+
* off. Running it here is what keeps a given id addressing the same record over both transports —
|
|
63
|
+
* both remain wrong for those three characters, which is PRD-1124's to fix on both at once.
|
|
64
|
+
*/
|
|
65
|
+
static toDispatchTarget(path) {
|
|
66
|
+
const normalized = path.startsWith('/') ? path : `/${path}`;
|
|
67
|
+
const url = new URL(`${IN_PROCESS_URL}${agent_client_1.HttpRequester.escapeUrlSlug(normalized)}`);
|
|
68
|
+
return { path: url.pathname, query: Object.fromEntries(url.searchParams) };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function createInProcessTransport({ dispatcher, timeoutMs, }) {
|
|
72
|
+
return {
|
|
73
|
+
url: IN_PROCESS_URL,
|
|
74
|
+
createRequester: token => new InProcessRequester(token, dispatcher, timeoutMs),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW4tcHJvY2Vzcy10cmFuc3BvcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnQvaW4tcHJvY2Vzcy10cmFuc3BvcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUEwSUEsMkNBUUM7QUFoSkQsNERBQTBEO0FBRTFELCtEQUFnRTtBQUVoRSw4RkFBOEY7QUFDOUYsTUFBTSxjQUFjLEdBQUcseUJBQXlCLENBQUM7QUErQmpEOzs7R0FHRztBQUNILE1BQU0sa0JBQW1CLFNBQVEsNEJBQWE7SUFDNUMsWUFDbUIsV0FBbUIsRUFDbkIsVUFBMkIsRUFDM0IsZ0JBQXlCO1FBRTFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsRUFBRSxHQUFHLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQztRQUozQixnQkFBVyxHQUFYLFdBQVcsQ0FBUTtRQUNuQixlQUFVLEdBQVYsVUFBVSxDQUFpQjtRQUMzQixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQVM7SUFHNUMsQ0FBQztJQUVELGdHQUFnRztJQUNoRyxnR0FBZ0c7SUFDaEcsd0RBQXdEO0lBQy9DLEtBQUssQ0FBQyxNQUFNO1FBQ25CLE1BQU0sSUFBQSx1Q0FBb0IsRUFBQywwREFBMEQsQ0FBQyxDQUFDO0lBQ3pGLENBQUM7SUFFUSxLQUFLLENBQUMsS0FBSyxDQUFpQixFQUNuQyxNQUFNLEVBQ04sSUFBSSxFQUNKLElBQUksRUFDSixLQUFLLEVBQ0wsY0FBYyxFQUNkLFdBQVcsRUFDWCxtQkFBbUIsR0FTcEI7UUFDQyxNQUFNLE1BQU0sR0FBRyxrQkFBa0IsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUV6RCxNQUFNLEVBQ0osTUFBTSxFQUNOLElBQUksRUFBRSxZQUFZLEVBQ2xCLElBQUksR0FDTCxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQztZQUN0QixNQUFNO1lBQ04sSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJO1lBQ2pCLE9BQU8sRUFBRTtnQkFDUCxhQUFhLEVBQUUsVUFBVSxJQUFJLENBQUMsV0FBVyxFQUFFO2dCQUMzQyxjQUFjLEVBQUUsV0FBVyxJQUFJLGtCQUFrQjtnQkFDakQsTUFBTSxFQUFFLFdBQVcsSUFBSSxrQkFBa0I7YUFDMUM7WUFDRCxLQUFLLEVBQUUsRUFBRSxRQUFRLEVBQUUsY0FBYyxFQUFFLEdBQUcsTUFBTSxDQUFDLEtBQUssRUFBRSxHQUFHLEtBQUssRUFBRTtZQUM5RCxPQUFPLEVBQUUsSUFBSTtZQUNiLFNBQVMsRUFBRSxjQUFjLElBQUksSUFBSSxDQUFDLGdCQUFnQjtTQUNuRCxDQUFDLENBQUM7UUFFSCxJQUFJLE1BQU0sSUFBSSxHQUFHO1lBQUUsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxZQUFZLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFckUsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFPLFlBQVksRUFBRSxJQUFJLEVBQUUsbUJBQW1CLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBNkI7UUFDbEQsSUFBSSxDQUFDO1lBQ0gsT0FBTyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2hELENBQUM7UUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQ2YsTUFBTSxNQUFNLEdBQUcsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLEtBQUssSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7WUFFckYsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsRUFBRSxFQUFFLE1BQU0sRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdkQsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ssTUFBTSxDQUFDLGdCQUFnQixDQUFDLElBQVk7UUFJMUMsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQzVELE1BQU0sR0FBRyxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsY0FBYyxHQUFHLDRCQUFhLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVuRixPQUFPLEVBQUUsSUFBSSxFQUFFLEdBQUcsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7SUFDN0UsQ0FBQztDQUNGO0FBT0QsU0FBd0Isd0JBQXdCLENBQUMsRUFDL0MsVUFBVSxFQUNWLFNBQVMsR0FDaUI7SUFDMUIsT0FBTztRQUNMLEdBQUcsRUFBRSxjQUFjO1FBQ25CLGVBQWUsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksa0JBQWtCLENBQUMsS0FBSyxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQUM7S0FDL0UsQ0FBQztBQUNKLENBQUMifQ==
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type AiProxyClient from './ai-proxy-client';
|
|
2
|
+
import type { EnvironmentIdResolver } from '../oauth/environment-id';
|
|
2
3
|
import type ForestServerClient from '../oauth/forest-server-client';
|
|
3
4
|
import type { SessionStore } from '../oauth/session-store';
|
|
4
5
|
import type { Logger } from '../ports/logger-port';
|
|
@@ -8,8 +9,8 @@ export interface AiRoutesMiddlewareOptions {
|
|
|
8
9
|
client: AiProxyClient;
|
|
9
10
|
sessionStore: SessionStore;
|
|
10
11
|
serverClient: ForestServerClient;
|
|
11
|
-
|
|
12
|
+
resolveEnvironmentId?: EnvironmentIdResolver;
|
|
12
13
|
logger: Logger;
|
|
13
14
|
}
|
|
14
|
-
export default function createAiRoutesMiddleware({ client, sessionStore, serverClient,
|
|
15
|
+
export default function createAiRoutesMiddleware({ client, sessionStore, serverClient, resolveEnvironmentId, logger, }: AiRoutesMiddlewareOptions): Middleware;
|
|
15
16
|
//# sourceMappingURL=ai-routes-middleware.d.ts.map
|
|
@@ -9,6 +9,7 @@ const ai_proxy_client_1 = require("./ai-proxy-client");
|
|
|
9
9
|
const auth_mode_1 = require("../auth/auth-mode");
|
|
10
10
|
const bff_http_error_1 = require("../http/bff-http-error");
|
|
11
11
|
const bff_local_errors_1 = require("../http/bff-local-errors");
|
|
12
|
+
const environment_fetch_error_1 = require("../oauth/environment-fetch-error");
|
|
12
13
|
const oauth_error_1 = require("../oauth/oauth-error");
|
|
13
14
|
const session_lifecycle_1 = __importDefault(require("../oauth/session-lifecycle"));
|
|
14
15
|
exports.AI_QUERY_ROUTE = '/agent/v1/ai/query';
|
|
@@ -34,6 +35,24 @@ function describeFailure(error, depthLeft = MAX_CAUSE_DEPTH) {
|
|
|
34
35
|
const tail = walkable ? ` (cause: ${describeFailure(cause, depthLeft - 1)})` : '';
|
|
35
36
|
return `${error.name}: ${clamp(error.message)}${tail}`;
|
|
36
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Resolved outside the `try` that maps AI proxy failures: a Forest server refusing the environment
|
|
40
|
+
* read is not the AI proxy being unreachable, and telling the operator otherwise sends them
|
|
41
|
+
* debugging a component that was never contacted.
|
|
42
|
+
*/
|
|
43
|
+
async function resolveEnvironmentIdOrRefuse(resolveEnvironmentId, logger) {
|
|
44
|
+
if (!resolveEnvironmentId)
|
|
45
|
+
return undefined;
|
|
46
|
+
try {
|
|
47
|
+
return await resolveEnvironmentId();
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
logger((0, environment_fetch_error_1.environmentFailureLevel)(error), 'AI query refused: the Forest environment id could not be resolved', { cause: describeFailure(error) });
|
|
51
|
+
if (error instanceof Error && error.name === 'TimeoutError')
|
|
52
|
+
throw (0, bff_local_errors_1.upstreamTimeout)();
|
|
53
|
+
throw (0, bff_local_errors_1.environmentUnresolved)();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
37
56
|
async function resolveSessionAccessToken(principal, store, serverClient, logger) {
|
|
38
57
|
try {
|
|
39
58
|
return await (0, session_lifecycle_1.default)({ sid: principal.sid, store, serverClient });
|
|
@@ -64,7 +83,7 @@ function relayJsonBodyOrGenericError(ctx, response, logger) {
|
|
|
64
83
|
ctx.type = JSON_CONTENT_TYPE;
|
|
65
84
|
ctx.body = JSON.stringify(response.body);
|
|
66
85
|
}
|
|
67
|
-
function createAiRoutesMiddleware({ client, sessionStore, serverClient,
|
|
86
|
+
function createAiRoutesMiddleware({ client, sessionStore, serverClient, resolveEnvironmentId, logger, }) {
|
|
68
87
|
return async function aiRoutesMiddleware(ctx, next) {
|
|
69
88
|
if (ctx.path !== exports.AI_QUERY_ROUTE || ctx.method !== 'POST') {
|
|
70
89
|
await next();
|
|
@@ -73,6 +92,7 @@ function createAiRoutesMiddleware({ client, sessionStore, serverClient, environm
|
|
|
73
92
|
const principal = requireSessionPrincipal(ctx);
|
|
74
93
|
const renderingId = (0, auth_mode_1.requireRenderingId)(principal);
|
|
75
94
|
const saasAccessToken = await resolveSessionAccessToken(principal, sessionStore, serverClient, logger);
|
|
95
|
+
const environmentId = await resolveEnvironmentIdOrRefuse(resolveEnvironmentId, logger);
|
|
76
96
|
let response;
|
|
77
97
|
try {
|
|
78
98
|
response = await client.query({
|
|
@@ -93,4 +113,4 @@ function createAiRoutesMiddleware({ client, sessionStore, serverClient, environm
|
|
|
93
113
|
relayJsonBodyOrGenericError(ctx, response, logger);
|
|
94
114
|
};
|
|
95
115
|
}
|
|
96
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
116
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktcm91dGVzLW1pZGRsZXdhcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWkvYWktcm91dGVzLW1pZGRsZXdhcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBbUlBLDJDQStDQztBQXpLRCx1REFBd0Q7QUFDeEQsaURBQXVEO0FBQ3ZELDJEQUFzRDtBQUN0RCwrREFNa0M7QUFDbEMsOEVBQTJFO0FBQzNFLHNEQUF5RDtBQUN6RCxtRkFBaUU7QUFFcEQsUUFBQSxjQUFjLEdBQUcsb0JBQW9CLENBQUM7QUFFbkQsTUFBTSxpQkFBaUIsR0FBRyxrQkFBa0IsQ0FBQztBQUM3QyxNQUFNLGVBQWUsR0FBRyxDQUFDLENBQUM7QUFDMUIsTUFBTSxpQkFBaUIsR0FBRyxHQUFHLENBQUM7QUFVOUIsU0FBUyx1QkFBdUIsQ0FBQyxHQUFZO0lBQzNDLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLEtBQUssU0FBUztRQUFFLE1BQU0sSUFBQSxnQ0FBYSxHQUFFLENBQUM7SUFFNUQsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUE4QyxDQUFDO0lBQzNFLElBQUksQ0FBQyxTQUFTO1FBQUUsTUFBTSxJQUFBLDZCQUFZLEVBQUMsNkJBQTZCLENBQUMsQ0FBQztJQUVsRSxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsU0FBUyxLQUFLLENBQUMsT0FBZTtJQUM1QixPQUFPLE9BQU8sQ0FBQyxNQUFNLEdBQUcsaUJBQWlCLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsaUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7QUFDbEcsQ0FBQztBQUVELFNBQVMsZUFBZSxDQUFDLEtBQWMsRUFBRSxTQUFTLEdBQUcsZUFBZTtJQUNsRSxJQUFJLENBQUMsQ0FBQyxLQUFLLFlBQVksS0FBSyxDQUFDO1FBQUUsT0FBTyxLQUFLLENB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
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { BFFConfig } from './config/env-config';
|
|
2
|
+
import type { UnfoldSource } from './openapi/unfolded-document';
|
|
3
|
+
import type { Logger } from './ports/logger-port';
|
|
4
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
5
|
+
/** What a host must hand to `http.createServer`, or mount, to serve the BFF. */
|
|
6
|
+
export type BffCallback = (req: IncomingMessage, res: ServerResponse) => void | Promise<void>;
|
|
7
|
+
export interface BuildBffOptions {
|
|
8
|
+
config: BFFConfig;
|
|
9
|
+
logger?: Logger;
|
|
10
|
+
}
|
|
11
|
+
export interface Bff {
|
|
12
|
+
callback: BffCallback;
|
|
13
|
+
}
|
|
14
|
+
interface ResolvedOAuthConfig {
|
|
15
|
+
forestServerUrl: string;
|
|
16
|
+
forestEnvSecret: string;
|
|
17
|
+
forestAppUrl: string;
|
|
18
|
+
forestAuthSecret: string;
|
|
19
|
+
tokenEncryptionKey: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function resolveOAuthConfig(config: BFFConfig): ResolvedOAuthConfig | undefined;
|
|
22
|
+
export declare function resolveUnfoldSource(config: BFFConfig, logger: Logger): UnfoldSource | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Assemble the whole BFF — `/health`, the version header, and every middleware in the one order both
|
|
25
|
+
* deployment modes must share — and hand back the request handler. `runCli` puts it behind a
|
|
26
|
+
* listener; an embedding host mounts it at the root of its own server. The handler is terminal — it
|
|
27
|
+
* answers 404 itself instead of yielding to a host `next()` — and every path it serves is absolute,
|
|
28
|
+
* so a prefix mount would move `/health` and `/agent/...` off the paths the frontend calls.
|
|
29
|
+
*/
|
|
30
|
+
export default function buildBff({ config, logger, }: BuildBffOptions): Promise<Bff>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=build-bff.d.ts.map
|