@forestadmin/agent 1.99.2 → 1.100.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.
@@ -0,0 +1,220 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const bff_routes_1 = require("./bff-routes");
37
+ /**
38
+ * Serialize the BFF's structured log context onto the message: the agent's logger only accepts an
39
+ * Error as its third argument, so the context would be dropped otherwise. Errors are unfolded by
40
+ * hand — their `message` and `stack` are not enumerable, so `JSON.stringify` alone turns the one
41
+ * value worth logging into `{}`. Never throws — logging must not break a request.
42
+ */
43
+ function formatLog(message, context) {
44
+ if (!context || Object.keys(context).length === 0)
45
+ return `[BFF] ${message}`;
46
+ try {
47
+ const serialized = JSON.stringify(context, (_key, value) => value instanceof Error
48
+ ? { name: value.name, message: value.message, stack: value.stack }
49
+ : value);
50
+ return `[BFF] ${message} ${serialized}`;
51
+ }
52
+ catch {
53
+ return `[BFF] ${message} [unserializable context]`;
54
+ }
55
+ }
56
+ /**
57
+ * Owns the lifecycle of a BFF embedded in the agent process: configuration, dynamic loading of the
58
+ * optional package, build, and the request handler the agent mounts at `/bff`. The agent only wires
59
+ * the callback and delegates start/stop.
60
+ */
61
+ class EmbeddedBff {
62
+ constructor(options, embedOptions) {
63
+ this.options = options;
64
+ this.embedOptions = embedOptions;
65
+ this.config = null;
66
+ this.bff = null;
67
+ this.stopped = false;
68
+ /**
69
+ * The callback the agent registers at `/bff`. Answers 503 rather than falling through while the
70
+ * BFF is not serving: a 404 from the host would read as "wrong url" instead of "not available".
71
+ * Boot and shutdown are told apart, because a probe should wait on the first and drain on the
72
+ * second.
73
+ */
74
+ this.handle = (req, res) => {
75
+ if (!this.bff) {
76
+ const type = this.stopped ? 'bff_stopped' : 'bff_not_started';
77
+ const message = this.stopped
78
+ ? 'The embedded BFF was stopped with the agent.'
79
+ : 'The embedded BFF is not started yet.';
80
+ res.statusCode = 503;
81
+ res.setHeader('Content-Type', 'application/json');
82
+ res.end(JSON.stringify({ error: { type, status: 503, message } }));
83
+ return;
84
+ }
85
+ // The BFF knows nothing of the prefix it is served under. `originalUrl` is claimed before the
86
+ // rewrite so a host logger reading it still reports the url the client asked for.
87
+ const bffReq = req;
88
+ bffReq.originalUrl ?? (bffReq.originalUrl = bffReq.url);
89
+ req.url = (0, bff_routes_1.stripBffPrefix)(req.url ?? bff_routes_1.BFF_PREFIX);
90
+ this.bff.callback(req, res);
91
+ };
92
+ }
93
+ /**
94
+ * Load the package and validate the options the caller handed to `addBff()`. Called before the
95
+ * agent mounts anything: everything checked here is caller input, and `parseConfig` throws on a
96
+ * mistyped `tokenEncryptionKey`, timezone, timeout or url. Failing here leaves nothing serving,
97
+ * where failing after mount() would leave the host with a live `/forest` and a bricked `/bff`.
98
+ */
99
+ async prepare() {
100
+ const { parseConfig, IN_PROCESS_AGENT_URL } = await this.importPackage();
101
+ const { embedOptions } = this;
102
+ this.config = parseConfig({
103
+ FOREST_AUTH_SECRET: this.options.authSecret,
104
+ FOREST_ENV_SECRET: this.options.envSecret,
105
+ FOREST_SERVER_URL: this.options.forestServerUrl,
106
+ FOREST_APP_URL: this.options.forestAppUrl,
107
+ // Names where the agent answers, never how it is reached: the dispatcher is the transport.
108
+ AGENT_URL: IN_PROCESS_AGENT_URL,
109
+ BFF_TOKEN_ENCRYPTION_KEY: embedOptions.tokenEncryptionKey,
110
+ BFF_ALLOWED_ORIGINS: embedOptions.allowedOrigins?.join(','),
111
+ BFF_DEFAULT_TIMEZONE: embedOptions.defaultTimezone,
112
+ BFF_AGENT_TIMEOUT_MS: embedOptions.agentTimeoutMs?.toString(),
113
+ BFF_AI_TIMEOUT_MS: embedOptions.aiTimeoutMs?.toString(),
114
+ // Off unless asked for: the document is not filtered per caller, so mounting a BFF must not
115
+ // publish the name of every exposed collection and field on an already-open port.
116
+ BFF_OPENAPI_ENABLED: String(embedOptions.openapiEnabled ?? false),
117
+ });
118
+ }
119
+ /**
120
+ * Build the BFF. Called from agent.start() after mount(), because the dispatcher only reaches the
121
+ * agent's own stack once that stack is mounted.
122
+ */
123
+ async start(dispatcher) {
124
+ if (!this.config)
125
+ await this.prepare();
126
+ // Cleared before the await, not after it: a start() following a stop() has to drop the previous
127
+ // shutdown's flag, while a stop() landing DURING the await must still be seen by the guard below.
128
+ this.stopped = false;
129
+ const { buildBff } = await this.importPackage();
130
+ const bff = await buildBff({
131
+ config: this.config,
132
+ dispatcher,
133
+ basePath: bff_routes_1.BFF_PREFIX,
134
+ // Counters are the schema cache's and the action-endpoint resolver's only channel — they take
135
+ // no logger — and every one of them reports a failure, so they go to the host's logs. Gauges
136
+ // do not: they are periodic cache sizes, and the default console sink reports them at Info,
137
+ // which would flood a host that only asked for a BFF.
138
+ metrics: {
139
+ // Tags carried through: `action_endpoint_error` and `action_endpoint_miss` name the
140
+ // rendering, collection and action that failed, which is the whole of what makes the line
141
+ // actionable — the metric name alone says only that something, somewhere, did not resolve.
142
+ increment: (name, tags) => this.options.logger('Warn', formatLog(`metric ${name}`, tags)),
143
+ gauge: () => undefined,
144
+ },
145
+ logger: (level, message, context) => this.options.logger(level, formatLog(message, context)),
146
+ });
147
+ // stop() may have landed while buildBff() was in flight. Assigning anyway would resurrect a
148
+ // stopped agent's /bff — dispatching into the stack it just tore down instead of answering 503.
149
+ if (this.stopped)
150
+ return;
151
+ this.bff = bff;
152
+ this.options.logger('Info', formatLog(`Embedded BFF mounted on ${bff_routes_1.BFF_PREFIX}`));
153
+ await this.warnIfExemptFromIpWhitelist();
154
+ }
155
+ /**
156
+ * The whitelist exempts a caller arriving over a loopback socket with no proxy hop, which is
157
+ * exactly what the in-process transport looks like — so every BFF request escapes it. That is the
158
+ * decision, not an oversight: propagating the caller's ip would make the embedded mode stricter
159
+ * than the standalone one, where the whitelist only ever sees the BFF's own host, and would refuse
160
+ * the browsers a third-party UI is made of. What it must not be is silent — an operator who turned
161
+ * the whitelist on to close a door has no other way to learn this door is not part of it.
162
+ *
163
+ * Reads the configuration itself rather than borrowing the one `IpWhitelist` already fetched: that
164
+ * route keeps it private, and reaching into it would put BFF concerns in an unrelated part of the
165
+ * agent. Costs one round-trip at boot. Never fails the boot: a warning is not worth refusing to
166
+ * serve over, and this is the same posture as the rest of the BFF's startup.
167
+ */
168
+ async warnIfExemptFromIpWhitelist() {
169
+ try {
170
+ const { isFeatureEnabled } = await this.options.forestAdminClient.getIpWhitelistConfiguration();
171
+ if (!isFeatureEnabled)
172
+ return;
173
+ this.options.logger('Warn', formatLog(`The IP whitelist is enabled for this environment, but requests served under ` +
174
+ `${bff_routes_1.BFF_PREFIX} are not subject to it: they reach the agent in-process, which the ` +
175
+ `whitelist exempts as a trusted loopback caller. A resolved API key or a valid OAuth ` +
176
+ `session is still required.`));
177
+ }
178
+ catch (error) {
179
+ this.options.logger('Debug', formatLog('Could not read the IP whitelist configuration', {
180
+ cause: error instanceof Error ? error.message : String(error),
181
+ }));
182
+ }
183
+ }
184
+ /** Drop what the BFF read from the SaaS. Called on a restart, which means the schema moved. */
185
+ invalidate() {
186
+ this.bff?.invalidate();
187
+ }
188
+ /**
189
+ * Stop answering. The host application keeps whatever middleware it registered, so without this
190
+ * a stopped agent would go on serving BFF data through a dispatcher pointing at a dead stack.
191
+ */
192
+ stop() {
193
+ this.bff = null;
194
+ this.stopped = true;
195
+ }
196
+ /**
197
+ * Dynamically load the optional @forestadmin/agent-bff package. Deferred so agents that embed no
198
+ * BFF never load its code at startup.
199
+ */
200
+ async importPackage() {
201
+ try {
202
+ return await Promise.resolve().then(() => __importStar(require('@forestadmin/agent-bff')));
203
+ }
204
+ catch (error) {
205
+ // The original reason is kept: the package resolves from the host's own node_modules, so this
206
+ // also fires on a broken transitive dependency, a SyntaxError from a partial install, or a
207
+ // throw during the package's own evaluation — none of which "install it" would fix.
208
+ const { message } = error;
209
+ const wrapped = new Error(`The embedded BFF requires the \`@forestadmin/agent-bff\` package, which failed to ` +
210
+ `load: ${message}. Install it with \`npm install @forestadmin/agent-bff\`.`);
211
+ // Assigned rather than passed to the constructor: the repo targets ES2020, whose lib types no
212
+ // options bag on Error. A plain assignment carries the cause on every runtime, and the reason
213
+ // is in the message regardless of what reads it.
214
+ wrapped.cause = error;
215
+ throw wrapped;
216
+ }
217
+ }
218
+ }
219
+ exports.default = EmbeddedBff;
220
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW1iZWRkZWQtYmZmLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2VtYmVkZGVkLWJmZi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUdBLDZDQUEwRDtBQUUxRDs7Ozs7R0FLRztBQUNILFNBQVMsU0FBUyxDQUFDLE9BQWUsRUFBRSxPQUFpQztJQUNuRSxJQUFJLENBQUMsT0FBTyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLFNBQVMsT0FBTyxFQUFFLENBQUM7SUFFN0UsSUFBSSxDQUFDO1FBQ0gsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FDekQsS0FBSyxZQUFZLEtBQUs7WUFDcEIsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssQ0FBQyxLQUFLLEVBQUU7WUFDbEUsQ0FBQyxDQUFDLEtBQUssQ0FDVixDQUFDO1FBRUYsT0FBTyxTQUFTLE9BQU8sSUFBSSxVQUFVLEVBQUUsQ0FBQztJQUMxQyxDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxTQUFTLE9BQU8sMkJBQTJCLENBQUM7SUFDckQsQ0FBQztBQUNILENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsTUFBcUIsV0FBVztJQUs5QixZQUNtQixPQUFpQyxFQUNqQyxZQUE2QjtRQUQ3QixZQUFPLEdBQVAsT0FBTyxDQUEwQjtRQUNqQyxpQkFBWSxHQUFaLFlBQVksQ0FBaUI7UUFOeEMsV0FBTSxHQUFxQixJQUFJLENBQUM7UUFDaEMsUUFBRyxHQUFlLElBQUksQ0FBQztRQUN2QixZQUFPLEdBQUcsS0FBSyxDQUFDO1FBa0l4Qjs7Ozs7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
@@ -1,4 +1,4 @@
1
- import type { HttpCallback, McpRouteMatcher } from './types';
1
+ import type { HttpCallback, RootHandler } from './types';
2
2
  import type { Logger } from '@forestadmin/datasource-toolkit';
3
3
  import Router from '@koa/router';
4
4
  import InProcessDispatcher from './mcp-in-process-dispatcher';
@@ -11,16 +11,20 @@ export default class FrameworkMounter {
11
11
  protected readonly prefix: string;
12
12
  private readonly logger;
13
13
  private readonly fastifyAdapter;
14
- private readonly mcpMiddleware;
14
+ private readonly rootMiddleware;
15
15
  private readonly inProcessDispatcher;
16
16
  private inProcessHookRegistered;
17
17
  /** Compute the prefix that the main router should be mounted at in the client's application */
18
18
  private get completeMountPrefix();
19
19
  constructor(prefix: string, logger: Logger);
20
20
  /**
21
- * Set the MCP HTTP callback. Call this before mount() or remount().
21
+ * Register the MCP server at the root of the host application, or `null` to unregister it. The
22
+ * matcher comes with the callback: there is no default pattern set, so nothing can claim host
23
+ * urls by accident. Call this before mount() or remount().
22
24
  */
23
- protected setMcpCallback(callback: HttpCallback | null, routeMatcher?: McpRouteMatcher): void;
25
+ protected setMcpCallback(handler: RootHandler | null): void;
26
+ /** Serve an embedded BFF at `/bff`. Pass null to stop answering there. */
27
+ protected setBffCallback(callback: HttpCallback | null): void;
24
28
  /**
25
29
  * Dispatcher that runs agent-client requests against the agent's own `/forest` stack in-memory.
26
30
  * The handler is rebuilt on every (re)mount so a captured reference never goes stale.
@@ -7,9 +7,10 @@ const router_1 = __importDefault(require("@koa/router"));
7
7
  const http_1 = require("http");
8
8
  const koa_1 = __importDefault(require("koa"));
9
9
  const path_1 = __importDefault(require("path"));
10
+ const bff_routes_1 = require("./bff-routes");
10
11
  const fastify_adapter_1 = __importDefault(require("./fastify-adapter"));
11
12
  const mcp_in_process_dispatcher_1 = __importDefault(require("./mcp-in-process-dispatcher"));
12
- const mcp_middleware_1 = __importDefault(require("./mcp-middleware"));
13
+ const root_middleware_1 = __importDefault(require("./root-middleware"));
13
14
  class FrameworkMounter {
14
15
  /** Compute the prefix that the main router should be mounted at in the client's application */
15
16
  get completeMountPrefix() {
@@ -23,14 +24,20 @@ class FrameworkMounter {
23
24
  this.prefix = prefix;
24
25
  this.logger = logger;
25
26
  this.fastifyAdapter = new fastify_adapter_1.default(logger);
26
- this.mcpMiddleware = new mcp_middleware_1.default();
27
+ this.rootMiddleware = new root_middleware_1.default(logger);
27
28
  this.inProcessDispatcher = new mcp_in_process_dispatcher_1.default(logger);
28
29
  }
29
30
  /**
30
- * Set the MCP HTTP callback. Call this before mount() or remount().
31
+ * Register the MCP server at the root of the host application, or `null` to unregister it. The
32
+ * matcher comes with the callback: there is no default pattern set, so nothing can claim host
33
+ * urls by accident. Call this before mount() or remount().
31
34
  */
32
- setMcpCallback(callback, routeMatcher) {
33
- this.mcpMiddleware.setCallback(callback, routeMatcher);
35
+ setMcpCallback(handler) {
36
+ this.rootMiddleware.set('mcp', handler);
37
+ }
38
+ /** Serve an embedded BFF at `/bff`. Pass null to stop answering there. */
39
+ setBffCallback(callback) {
40
+ this.rootMiddleware.set('bff', callback && { callback, matches: bff_routes_1.isBffRoute });
34
41
  }
35
42
  /**
36
43
  * Dispatcher that runs agent-client requests against the agent's own `/forest` stack in-memory.
@@ -101,7 +108,7 @@ class FrameworkMounter {
101
108
  */
102
109
  mountOnExpress(express) {
103
110
  // MCP middleware - the callback handles its own path filtering and calls next() for non-MCP routes
104
- express.use(this.mcpMiddleware.getExpressMiddleware());
111
+ express.use(this.rootMiddleware.getExpressMiddleware());
105
112
  // Mount main forest routes at /{prefix}/forest
106
113
  express.use(this.completeMountPrefix, this.getConnectCallback(false));
107
114
  this.logger('Info', `Successfully mounted on Express.js`);
@@ -113,7 +120,7 @@ class FrameworkMounter {
113
120
  */
114
121
  mountOnFastify(fastify) {
115
122
  // MCP middleware at root - the callback handles its own path filtering
116
- this.fastifyAdapter.useCallback(fastify, this.mcpMiddleware.getExpressMiddleware(), '/');
123
+ this.fastifyAdapter.useCallback(fastify, this.rootMiddleware.getExpressMiddleware(), '/');
117
124
  // Mount main forest routes
118
125
  const callback = this.getConnectCallback(false);
119
126
  this.fastifyAdapter.useCallback(fastify, callback, this.completeMountPrefix);
@@ -138,7 +145,7 @@ class FrameworkMounter {
138
145
  parentRouter.use(driverRouter.routes());
139
146
  });
140
147
  // MCP middleware - intercepts MCP routes before they reach Koa's body parser
141
- koa.use(this.mcpMiddleware.getKoaMiddleware());
148
+ koa.use(this.rootMiddleware.getKoaMiddleware());
142
149
  koa.use(parentRouter.routes());
143
150
  this.logger('Info', `Successfully mounted on Koa`);
144
151
  return this;
@@ -152,13 +159,13 @@ class FrameworkMounter {
152
159
  const callback = this.getConnectCallback(false);
153
160
  if (adapter.constructor.name === 'ExpressAdapter') {
154
161
  // MCP middleware at root - the callback handles its own path filtering
155
- nestJs.use(this.mcpMiddleware.getExpressMiddleware());
162
+ nestJs.use(this.rootMiddleware.getExpressMiddleware());
156
163
  // Mount main forest routes
157
164
  nestJs.use(this.completeMountPrefix, callback);
158
165
  }
159
166
  else {
160
167
  // Fastify adapter - MCP middleware at root
161
- this.fastifyAdapter.useCallback(nestJs, this.mcpMiddleware.getExpressMiddleware(), '/');
168
+ this.fastifyAdapter.useCallback(nestJs, this.rootMiddleware.getExpressMiddleware(), '/');
162
169
  this.fastifyAdapter.useCallback(nestJs, callback, this.completeMountPrefix);
163
170
  }
164
171
  this.logger('Info', `Successfully mounted on NestJS`);
@@ -176,9 +183,9 @@ class FrameworkMounter {
176
183
  return (req, res) => {
177
184
  // For standalone server (nested), check MCP callback first
178
185
  // The MCP callback handles its own path filtering
179
- const mcpCallback = this.mcpMiddleware.getCallback();
180
- if (nested && mcpCallback) {
181
- mcpCallback(req, res, () => {
186
+ const rootCallback = this.rootMiddleware.getCallback();
187
+ if (nested && rootCallback) {
188
+ rootCallback(req, res, () => {
182
189
  // next() called means not an MCP route - forward to main handler
183
190
  if (handler) {
184
191
  handler(req, res);
@@ -201,4 +208,4 @@ class FrameworkMounter {
201
208
  }
202
209
  }
203
210
  exports.default = FrameworkMounter;
204
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWV3b3JrLW1vdW50ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZnJhbWV3b3JrLW1vdW50ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFLQSx5REFBaUM7QUFDakMsK0JBQW9DO0FBQ3BDLDhDQUFzQjtBQUN0QixnREFBd0I7QUFFeEIsd0VBQStDO0FBQy9DLDRGQUE4RDtBQUM5RCxzRUFBNkM7QUFFN0MsTUFBcUIsZ0JBQWdCO0lBZ0JuQywrRkFBK0Y7SUFDL0YsSUFBWSxtQkFBbUI7UUFDN0IsT0FBTyxjQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQsWUFBWSxNQUFjLEVBQUUsTUFBYztRQWpCekIsaUJBQVksR0FBNEIsRUFBRSxDQUFDO1FBQzNDLGdCQUFXLEdBQTBDLEVBQUUsQ0FBQztRQUV4RCxXQUFNLEdBQTRCLEVBQUUsQ0FBQztRQU85Qyw0QkFBdUIsR0FBRyxLQUFLLENBQUM7UUFRdEMsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLHlCQUFjLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDakQsSUFBSSxDQUFDLGFBQWEsR0FBRyxJQUFJLHdCQUFhLEVBQUUsQ0FBQztRQUN6QyxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxtQ0FBbUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM3RCxDQUFDO0lBRUQ7O09BRUc7SUFDTyxjQUFjLENBQUMsUUFBNkIsRUFBRSxZQUE4QjtRQUNwRixJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVEOzs7T0FHRztJQUNPLHNCQUFzQjtRQUM5QixJQUFJ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
211
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWV3b3JrLW1vdW50ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZnJhbWV3b3JrLW1vdW50ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFLQSx5REFBaUM7QUFDakMsK0JBQW9DO0FBQ3BDLDhDQUFzQjtBQUN0QixnREFBd0I7QUFFeEIsNkNBQTBDO0FBQzFDLHdFQUErQztBQUMvQyw0RkFBOEQ7QUFDOUQsd0VBQStDO0FBRS9DLE1BQXFCLGdCQUFnQjtJQWdCbkMsK0ZBQStGO0lBQy9GLElBQVksbUJBQW1CO1FBQzdCLE9BQU8sY0FBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVELFlBQVksTUFBYyxFQUFFLE1BQWM7UUFqQnpCLGlCQUFZLEdBQTRCLEVBQUUsQ0FBQztRQUMzQyxnQkFBVyxHQUEwQyxFQUFFLENBQUM7UUFFeEQsV0FBTSxHQUE0QixFQUFFLENBQUM7UUFPOUMsNEJBQXVCLEdBQUcsS0FBSyxDQUFDO1FBUXRDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSx5QkFBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSx5QkFBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLG1DQUFtQixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQzdELENBQUM7SUFFRDs7OztPQUlHO0lBQ08sY0FBYyxDQUFDLE9BQTJCO1FBQ2xELElBQUksQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMxQyxDQUFDO0lBRUQsMEVBQTBFO0lBQ2hFLGNB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
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { TSchema } from '@forestadmin/datasource-customizer';
3
3
  import Agent from './agent';
4
4
  export declare function createAgent<S extends TSchema = TSchema>(options: AgentOptions): Agent<S>;
5
5
  export { Agent };
6
- export { AgentOptions, WorkflowExecutorEmbedOptions } from './types';
6
+ export { AgentOptions, BffEmbedOptions, WorkflowExecutorEmbedOptions } from './types';
7
7
  export * from '@forestadmin/datasource-customizer';
8
8
  export { default as SchemaGenerator } from './utils/forest-schema/generator';
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,33 @@
1
+ import type { HttpCallback, RootHandler } from './types';
2
+ import type { Logger } from '@forestadmin/datasource-toolkit';
3
+ import type Koa from 'koa';
4
+ /**
5
+ * Handlers the agent serves at the root of the host application rather than under its own router
6
+ * prefix — the MCP server, the embedded BFF. Each one claims a set of paths through its matcher;
7
+ * anything else falls through to the host, untouched.
8
+ *
9
+ * Registered by name so a handler can be replaced or removed on a restart without the mount points
10
+ * having to know what is registered.
11
+ */
12
+ export default class RootMiddleware {
13
+ private readonly handlers;
14
+ private readonly logger;
15
+ constructor(logger: Logger);
16
+ set(name: string, handler: RootHandler | null): void;
17
+ private entryFor;
18
+ /**
19
+ * First registered matcher wins. Overlapping matchers cannot be caught at registration — the
20
+ * predicates are opaque — so the winner is named here instead: a request answered by the wrong
21
+ * handler is otherwise indistinguishable from one whose route was never registered.
22
+ */
23
+ private handlerFor;
24
+ /**
25
+ * Connect-style middleware. A handler that decides not to answer calls `next()`, which passes the
26
+ * request on to the host exactly as if nothing had been registered.
27
+ */
28
+ getExpressMiddleware(): HttpCallback;
29
+ getKoaMiddleware(): Koa.Middleware;
30
+ /** The combined callback, or null when nothing is registered and the host needs no detour. */
31
+ getCallback(): HttpCallback | null;
32
+ }
33
+ //# sourceMappingURL=root-middleware.d.ts.map
@@ -0,0 +1,70 @@
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
+ const express_to_koa_1 = __importDefault(require("./utils/express-to-koa"));
7
+ /**
8
+ * Handlers the agent serves at the root of the host application rather than under its own router
9
+ * prefix — the MCP server, the embedded BFF. Each one claims a set of paths through its matcher;
10
+ * anything else falls through to the host, untouched.
11
+ *
12
+ * Registered by name so a handler can be replaced or removed on a restart without the mount points
13
+ * having to know what is registered.
14
+ */
15
+ class RootMiddleware {
16
+ constructor(logger) {
17
+ this.handlers = new Map();
18
+ this.logger = logger;
19
+ }
20
+ set(name, handler) {
21
+ if (handler)
22
+ this.handlers.set(name, handler);
23
+ else
24
+ this.handlers.delete(name);
25
+ }
26
+ entryFor(url) {
27
+ for (const entry of this.handlers) {
28
+ if (entry[1].matches(url))
29
+ return entry;
30
+ }
31
+ return null;
32
+ }
33
+ /**
34
+ * First registered matcher wins. Overlapping matchers cannot be caught at registration — the
35
+ * predicates are opaque — so the winner is named here instead: a request answered by the wrong
36
+ * handler is otherwise indistinguishable from one whose route was never registered.
37
+ */
38
+ handlerFor(url) {
39
+ const entry = this.entryFor(url);
40
+ if (!entry)
41
+ return null;
42
+ this.logger('Debug', `Root middleware: '${entry[0]}' claims ${url}`);
43
+ return entry[1].callback;
44
+ }
45
+ /**
46
+ * Connect-style middleware. A handler that decides not to answer calls `next()`, which passes the
47
+ * request on to the host exactly as if nothing had been registered.
48
+ */
49
+ getExpressMiddleware() {
50
+ return (req, res, next) => {
51
+ const handler = this.handlerFor(req.url ?? '/');
52
+ if (handler) {
53
+ handler(req, res, next);
54
+ return;
55
+ }
56
+ next?.();
57
+ };
58
+ }
59
+ getKoaMiddleware() {
60
+ return (0, express_to_koa_1.default)(this.getExpressMiddleware(), url => this.entryFor(url) !== null);
61
+ }
62
+ /** The combined callback, or null when nothing is registered and the host needs no detour. */
63
+ getCallback() {
64
+ if (this.handlers.size === 0)
65
+ return null;
66
+ return this.getExpressMiddleware();
67
+ }
68
+ }
69
+ exports.default = RootMiddleware;
70
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9vdC1taWRkbGV3YXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Jvb3QtbWlkZGxld2FyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUlBLDRFQUFrRDtBQUVsRDs7Ozs7OztHQU9HO0FBQ0gsTUFBcUIsY0FBYztJQUlqQyxZQUFZLE1BQWM7UUFIVCxhQUFRLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7UUFJekQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7SUFDdkIsQ0FBQztJQUVELEdBQUcsQ0FBQyxJQUFZLEVBQUUsT0FBMkI7UUFDM0MsSUFBSSxPQUFPO1lBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDOztZQUN6QyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNsQyxDQUFDO0lBRU8sUUFBUSxDQUFDLEdBQVc7UUFDMUIsS0FBSyxNQUFNLEtBQUssSUFBSSxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDbEMsSUFBSSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztnQkFBRSxPQUFPLEtBQUssQ0FBQztRQUMxQyxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNLLFVBQVUsQ0FBQyxHQUFXO1FBQzVCLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFakMsSUFBSSxDQUFDLEtBQUs7WUFBRSxPQUFPLElBQUksQ0FBQztRQUV4QixJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxxQkFBcUIsS0FBSyxDQUFDLENBQUMsQ0FBQyxZQUFZLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFFckUsT0FBTyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxvQkFBb0I7UUFDbEIsT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUU7WUFDeEIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxDQUFDO1lBRWhELElBQUksT0FBTyxFQUFFLENBQUM7Z0JBQ1osT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7Z0JBRXhCLE9BQU87WUFDVCxDQUFDO1lBRUQsSUFBSSxFQUFFLEVBQUUsQ0FBQztRQUNYLENBQUMsQ0FBQztJQUNKLENBQUM7SUFFRCxnQkFBZ0I7UUFDZCxPQUFPLElBQUEsd0JBQVksRUFBQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7SUFDdkYsQ0FBQztJQUVELDhGQUE4RjtJQUM5RixXQUFXO1FBQ1QsSUFBSSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksS0FBSyxDQUFDO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFMUMsT0FBTyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztJQUNyQyxDQUFDO0NBQ0Y7QUFoRUQsaUNBZ0VDIn0=
package/dist/types.d.ts CHANGED
@@ -151,6 +151,47 @@ export type WorkflowExecutorEmbedOptions = Omit<WorkflowExecutorTuningOptions, '
151
151
  */
152
152
  encryptionKey?: string;
153
153
  };
154
+ /**
155
+ * Options of an embedded BFF. Everything the BFF shares with the agent — the secrets, the Forest
156
+ * urls, the logger — is inherited rather than repeated: a divergent `authSecret` would make the
157
+ * agent reject the very tokens the BFF mints, as an opaque 401.
158
+ */
159
+ export type BffEmbedOptions = {
160
+ /**
161
+ * Base64-encoded 32-byte AES-256 key encrypting stored refresh tokens. Gates the OAuth
162
+ * login/refresh flow (mode 1) and, with it, the AI relay.
163
+ *
164
+ * It is not an access control. The data routes accept a `bff_access` bearer whether or not this
165
+ * is set, because that token is verified against the agent's `authSecret` alone. Omitting it
166
+ * closes the login flow, not the session-bearer path — what protects that path is `authSecret`.
167
+ */
168
+ tokenEncryptionKey?: string;
169
+ /**
170
+ * Exact origins (scheme + host + port) allowed to call the BFF from a browser. No wildcard.
171
+ * Empty means no cross-origin browser access at all, which for a backend-for-frontend is
172
+ * almost always a mistake — the BFF warns about it at startup.
173
+ */
174
+ allowedOrigins?: string[];
175
+ /** Fallback IANA timezone for a request that carries none. */
176
+ defaultTimezone?: string;
177
+ /**
178
+ * How long a call to the agent may take. Defaults to 10s.
179
+ *
180
+ * It bounds how long the BFF waits, and cancels nothing: an action or a write cut off at the
181
+ * deadline keeps running inside the agent and still commits, so a client retrying on the timeout
182
+ * can double the mutation. Raise it rather than relying on a retry for operations that are not
183
+ * idempotent.
184
+ */
185
+ agentTimeoutMs?: number;
186
+ /** How long the AI relay waits for the Forest server. Defaults to 120s. */
187
+ aiTimeoutMs?: number;
188
+ /**
189
+ * Serve `/bff/docs` and `/bff/agent/openapi.json`. Defaults to `false` when embedded: the
190
+ * document is not filtered per caller, so any authenticated caller reads the name of every
191
+ * exposed collection, relation and field.
192
+ */
193
+ openapiEnabled?: boolean;
194
+ };
154
195
  export type AuditTrailRuntime = AuditTrailConfig & {
155
196
  store: AuditStore;
156
197
  close: () => Promise<void>;
@@ -159,7 +200,12 @@ export type AgentOptionsWithDefaults = Readonly<Required<Omit<AgentOptions, 'aud
159
200
  auditTrail: AuditTrailRuntime | null;
160
201
  }>;
161
202
  export type HttpCallback = (req: IncomingMessage, res: ServerResponse, next?: () => void) => void;
162
- export type McpRouteMatcher = (url: string) => boolean;
203
+ export type RouteMatcher = (url: string) => boolean;
204
+ /** A handler served at the root of the host application, with the urls it claims. */
205
+ export type RootHandler = {
206
+ callback: HttpCallback;
207
+ matches: RouteMatcher;
208
+ };
163
209
  export declare enum HttpCode {
164
210
  BadRequest = 400,
165
211
  Unauthorized = 401,
package/dist/types.js CHANGED
@@ -22,4 +22,4 @@ var RouteType;
22
22
  RouteType[RouteType["Authentication"] = 3] = "Authentication";
23
23
  RouteType[RouteType["PrivateRoute"] = 4] = "PrivateRoute";
24
24
  })(RouteType || (exports.RouteType = RouteType = {}));
25
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBc0tBLElBQVksUUFVWDtBQVZELFdBQVksUUFBUTtJQUNsQixxREFBZ0IsQ0FBQTtJQUNoQix5REFBa0IsQ0FBQTtJQUNsQixtREFBZSxDQUFBO0lBQ2YsaURBQWMsQ0FBQTtJQUNkLDJEQUFtQixDQUFBO0lBQ25CLCtEQUFxQixDQUFBO0lBQ3JCLHVFQUF5QixDQUFBO0lBQ3pCLG1EQUFlLENBQUE7SUFDZixxQ0FBUSxDQUFBO0FBQ1YsQ0FBQyxFQVZXLFFBQVEsd0JBQVIsUUFBUSxRQVVuQjtBQUVELElBQVksU0FPWDtBQVBELFdBQVksU0FBUztJQUNuQixpR0FBaUc7SUFDakcsMkRBQWlCLENBQUE7SUFDakIseURBQWdCLENBQUE7SUFDaEIsdURBQWUsQ0FBQTtJQUNmLDZEQUFrQixDQUFBO0lBQ2xCLHlEQUFnQixDQUFBO0FBQ2xCLENBQUMsRUFQVyxTQUFTLHlCQUFULFNBQVMsUUFPcEIifQ==
25
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBbU5BLElBQVksUUFVWDtBQVZELFdBQVksUUFBUTtJQUNsQixxREFBZ0IsQ0FBQTtJQUNoQix5REFBa0IsQ0FBQTtJQUNsQixtREFBZSxDQUFBO0lBQ2YsaURBQWMsQ0FBQTtJQUNkLDJEQUFtQixDQUFBO0lBQ25CLCtEQUFxQixDQUFBO0lBQ3JCLHVFQUF5QixDQUFBO0lBQ3pCLG1EQUFlLENBQUE7SUFDZixxQ0FBUSxDQUFBO0FBQ1YsQ0FBQyxFQVZXLFFBQVEsd0JBQVIsUUFBUSxRQVVuQjtBQUVELElBQVksU0FPWDtBQVBELFdBQVksU0FBUztJQUNuQixpR0FBaUc7SUFDakcsMkRBQWlCLENBQUE7SUFDakIseURBQWdCLENBQUE7SUFDaEIsdURBQWUsQ0FBQTtJQUNmLDZEQUFrQixDQUFBO0lBQ2xCLHlEQUFnQixDQUFBO0FBQ2xCLENBQUMsRUFQVyxTQUFTLHlCQUFULFNBQVMsUUFPcEIifQ==
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forestadmin/agent",
3
- "version": "1.99.2",
3
+ "version": "1.100.1",
4
4
  "main": "dist/index.js",
5
5
  "license": "GPL-3.0",
6
6
  "publishConfig": {
@@ -49,35 +49,42 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@fastify/express": "^1.1.0",
52
+ "@forestadmin/agent-bff": "1.29.0",
52
53
  "@forestadmin/datasource-sql": "1.17.14",
53
- "@forestadmin/workflow-executor": "1.28.0",
54
+ "@forestadmin/workflow-executor": "1.28.1",
54
55
  "@nestjs/common": "^11.1.24",
55
56
  "@nestjs/core": "^11.1.24",
56
57
  "@nestjs/platform-express": "^11.1.24",
57
58
  "@nestjs/platform-fastify": "^11.1.24",
58
59
  "@shopify/jest-koa-mocks": "^3.1.0",
59
- "sqlite3": "^5.1.7",
60
60
  "@types/json-api-serializer": "^2.6.3",
61
61
  "@types/jsonwebtoken": "^9.0.1",
62
62
  "@types/koa": "^2.13.5",
63
63
  "@types/koa__cors": "^3.3.0",
64
64
  "@types/superagent": "^8.1.9",
65
+ "@types/supertest": "^6.0.2",
65
66
  "express": "^4.18.2",
66
67
  "fastify": "^3.29.0",
67
68
  "fastify2": "npm:fastify@^2.15.3",
68
69
  "fastify4": "npm:fastify@^4.28.0",
69
70
  "openid-client": "^5.7.1",
70
71
  "reflect-metadata": "^0.1.13",
71
- "rxjs": "^7.8.0"
72
+ "rxjs": "^7.8.0",
73
+ "sqlite3": "^5.1.7",
74
+ "supertest": "^7.1.3"
72
75
  },
73
76
  "peerDependencies": {
74
77
  "@fastify/express": "^1.1.0 || ^2.0.0 || ^3.0.0 || ^4.0.0",
75
- "@forestadmin/workflow-executor": "1.28.0"
78
+ "@forestadmin/agent-bff": "1.29.0",
79
+ "@forestadmin/workflow-executor": "1.28.1"
76
80
  },
77
81
  "peerDependenciesMeta": {
78
82
  "@fastify/express": {
79
83
  "optional": true
80
84
  },
85
+ "@forestadmin/agent-bff": {
86
+ "optional": true
87
+ },
81
88
  "@forestadmin/workflow-executor": {
82
89
  "optional": true
83
90
  }