@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.
package/README.md CHANGED
@@ -0,0 +1,73 @@
1
+ # @forestadmin/agent
2
+
3
+ The main entry point of the Forest Admin Node.js SDK: `createAgent(options)` returns an agent to
4
+ which you attach datasources, customizations, charts and plugins, then mount on your HTTP server.
5
+
6
+ See the [developer guide](https://docs.forestadmin.com/developer-guide-agents-nodejs) for the full
7
+ documentation.
8
+
9
+ ## Optional in-process components
10
+
11
+ Two components normally deployed on their own can run inside the agent instead. Both are optional
12
+ packages, loaded dynamically: an agent that does not use them never loads their code.
13
+
14
+ ### A BFF — `agent.addBff()`
15
+
16
+ ```bash
17
+ npm install @forestadmin/agent-bff
18
+ ```
19
+
20
+ ```ts
21
+ await createAgent(options)
22
+ .addDataSource(/* … */)
23
+ .addBff({ allowedOrigins: ['https://my-app.com'] })
24
+ .mountOnStandaloneServer(3351)
25
+ .start();
26
+ ```
27
+
28
+ Serves the REST BFF under `/bff` on whatever port the agent is mounted on, on every mount target —
29
+ `mountOnStandaloneServer` above, or the host's own listener with `mountOnExpress`, `mountOnKoa`,
30
+ `mountOnFastify`, `mountOnNestJs`. A `mountOn*` call is what opens a socket: `start()` only builds
31
+ the agent's router, so a chain without one serves nothing, BFF included.
32
+
33
+ The BFF reaches the agent in the same process, so there is no second port, no agent url to
34
+ configure, and no secrets to keep in sync — `authSecret`, `envSecret`, the Forest urls and the
35
+ logger are inherited.
36
+
37
+ Everything `addBff()` takes is a feature it switches on: `tokenEncryptionKey` enables OAuth (and
38
+ with it the AI relay), `allowedOrigins` enables browser access, `openapiEnabled` serves the docs
39
+ (off by default when embedded). `GET /bff/health` reports which of them are on, under `configured`.
40
+
41
+ **Mount the agent before any body parser of your own** — a parser that runs first consumes the
42
+ request stream, and every BFF `POST` then answers `500 stream.not.readable`.
43
+
44
+ A permissive `cors()` registered ahead of the mount costs you the preflight but not the allow-list:
45
+ the host answers `OPTIONS` with its own policy, and nothing downstream can take that back, so the
46
+ request that follows arrives here anyway — and is refused with `403 origin_not_allowed` unless its
47
+ `Origin` is one you listed. The browser sees the wrong preflight; the collection is still never read
48
+ for that origin.
49
+
50
+ Mounting under a sub-path of your own works: `app.use('/api', mounted)` serves the BFF at
51
+ `/api/bff`, and the prefix is derived per request, so the OpenAPI `servers` entry and the docs page
52
+ carry `/api/bff` too.
53
+
54
+ **`agentTimeoutMs` bounds the wait, not the work.** When a call to the agent exceeds it the BFF
55
+ answers with an error, but nothing is cancelled: the in-process request runs to completion. An
56
+ action cut at the timeout still applies its mutation, so a client that retries applies it twice.
57
+ Size the timeout above your slowest action, and make actions idempotent if you intend to retry them.
58
+
59
+ **`addBff()` cannot be combined with `mountAiMcpServer({ basePath: '/bff' })`** — the MCP server
60
+ would claim `/bff/oauth` and `/bff/mcp`. Whichever you call second throws on the spot, at the
61
+ builder call and not from `start()`.
62
+
63
+ See [`@forestadmin/agent-bff`](../agent-bff/README.md) for the routes, the auth modes and the
64
+ differences with the standalone deployment.
65
+
66
+ ### A workflow executor — `agent.addWorkflowExecutor()`
67
+
68
+ ```bash
69
+ npm install @forestadmin/workflow-executor
70
+ ```
71
+
72
+ Runs a workflow executor alongside the agent, which proxies `/_internal/executor/*` to it. See
73
+ [`@forestadmin/workflow-executor`](../workflow-executor/README.md).
package/dist/agent.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ForestAdminHttpDriverServices } from './services';
2
- import type { AgentOptions, AgentOptionsWithDefaults, WorkflowExecutorEmbedOptions } from './types';
2
+ import type { AgentOptions, AgentOptionsWithDefaults, BffEmbedOptions, WorkflowExecutorEmbedOptions } from './types';
3
3
  import type { CollectionCustomizer, DataSourceChartDefinition, DataSourceOptions, Plugin, TCollectionName, TSchema } from '@forestadmin/datasource-customizer';
4
4
  import type { DataSource, DataSourceFactory } from '@forestadmin/datasource-toolkit';
5
5
  import type { FileUploadsOptions, TokenTtlOptions, ToolName } from '@forestadmin/mcp-server';
@@ -32,7 +32,15 @@ export default class Agent<S extends TSchema = TSchema> extends FrameworkMounter
32
32
  private mcpFileUploads?;
33
33
  /** In-process workflow executor, created only when addWorkflowExecutor() is called. */
34
34
  private embeddedExecutor;
35
+ /** In-process BFF, created only when addBff() is called. */
36
+ private embeddedBff;
35
37
  private isRestarting;
38
+ /**
39
+ * Set as soon as start() begins, not once it finishes: mount() drains the `onFirstStart` hooks
40
+ * partway through, so a builder call landing mid-startup is already too late. Cleared again when
41
+ * startup fails, which leaves nothing mounted and makes the agent configurable once more.
42
+ */
43
+ private startupBegun;
36
44
  /**
37
45
  * Create a new Agent Builder.
38
46
  * If any options are missing, the default will be applied:
@@ -179,6 +187,35 @@ export default class Agent<S extends TSchema = TSchema> extends FrameworkMounter
179
187
  * .start();
180
188
  */
181
189
  addWorkflowExecutor(options?: WorkflowExecutorEmbedOptions): this;
190
+ /**
191
+ * Serve a BFF in-process, alongside the agent, at `/bff` — no second deployment, no second port.
192
+ * The agent builds it on start(), stops it on stop(), and hands it a dispatcher that reaches its
193
+ * own stack without a socket, so this works the same on every mount target.
194
+ *
195
+ * Requires the `@forestadmin/agent-bff` package to be installed:
196
+ * ```bash
197
+ * npm install @forestadmin/agent-bff
198
+ * ```
199
+ *
200
+ * The secrets, the Forest urls and the logger are inherited from the agent. Everything left is
201
+ * a feature the BFF switches on when configured: `tokenEncryptionKey` enables OAuth (and with it
202
+ * the AI relay), `allowedOrigins` enables browser access, `openapiEnabled` serves the docs.
203
+ *
204
+ * @param options embedded BFF options
205
+ * @returns the agent instance for chaining
206
+ * @throws Error if called more than once, or if the MCP server already claims `/bff`
207
+ *
208
+ * A `mountOn*` call is what opens a socket — start() only builds the router — so the BFF is only
209
+ * reachable on an agent that is mounted somewhere.
210
+ *
211
+ * @example
212
+ * await createAgent(options)
213
+ * .addDataSource(...)
214
+ * .addBff({ allowedOrigins: ['https://my-app.com'] })
215
+ * .mountOnStandaloneServer(3351)
216
+ * .start();
217
+ */
218
+ addBff(options?: BffEmbedOptions): this;
182
219
  protected getRoutes(dataSource: DataSource, services: ForestAdminHttpDriverServices): import("./routes/base-route").default[];
183
220
  /**
184
221
  * Create an http handler which can respond to all queries which are expected from an agent.
package/dist/agent.js CHANGED
@@ -43,6 +43,8 @@ const router_1 = __importDefault(require("@koa/router"));
43
43
  const promises_1 = require("fs/promises");
44
44
  const json_stringify_pretty_compact_1 = __importDefault(require("json-stringify-pretty-compact"));
45
45
  const audit_trail_1 = require("./audit-trail");
46
+ const bff_routes_1 = require("./bff-routes");
47
+ const embedded_bff_1 = __importDefault(require("./embedded-bff"));
46
48
  const embedded_workflow_executor_1 = __importDefault(require("./embedded-workflow-executor"));
47
49
  const framework_mounter_1 = __importDefault(require("./framework-mounter"));
48
50
  const routes_1 = __importDefault(require("./routes"));
@@ -51,6 +53,12 @@ const customization_1 = __importDefault(require("./services/model-customizations
51
53
  const correlation_id_1 = require("./utils/correlation-id");
52
54
  const generator_1 = __importDefault(require("./utils/forest-schema/generator"));
53
55
  const options_validator_1 = __importDefault(require("./utils/options-validator"));
56
+ // Whichever is registered second raises it. `addBff()` registers at builder time and the MCP
57
+ // server only at start(), and the root middleware answers with the first handler whose matcher
58
+ // claims the url — so the BFF wins and the whole MCP surface would go silently dark.
59
+ const bffMcpCollision = (mcpBasePath) => `Cannot use addBff together with mountAiMcpServer({ basePath: '${mcpBasePath}' }): the MCP ` +
60
+ `server would claim ${bff_routes_1.BFF_PREFIX} paths the embedded BFF answers on (${bff_routes_1.BFF_PREFIX}/oauth, ` +
61
+ `${bff_routes_1.BFF_PREFIX}/mcp). Mount the MCP server elsewhere.`;
54
62
  /**
55
63
  * Allow to create a new Forest Admin agent from scratch.
56
64
  * Builds the application by composing and configuring all the collection decorators.
@@ -85,7 +93,15 @@ class Agent extends framework_mounter_1.default {
85
93
  this.mcpEnabled = false;
86
94
  /** In-process workflow executor, created only when addWorkflowExecutor() is called. */
87
95
  this.embeddedExecutor = null;
96
+ /** In-process BFF, created only when addBff() is called. */
97
+ this.embeddedBff = null;
88
98
  this.isRestarting = false;
99
+ /**
100
+ * Set as soon as start() begins, not once it finishes: mount() drains the `onFirstStart` hooks
101
+ * partway through, so a builder call landing mid-startup is already too late. Cleared again when
102
+ * startup fails, which leaves nothing mounted and makes the agent configurable once more.
103
+ */
104
+ this.startupBegun = false;
89
105
  this.options = allOptions;
90
106
  this.customizer = new datasource_customizer_1.DataSourceCustomizer({
91
107
  ignoreMissingSchemaElementErrors: options.ignoreMissingSchemaElementErrors || false,
@@ -98,18 +114,31 @@ class Agent extends framework_mounter_1.default {
98
114
  */
99
115
  async start() {
100
116
  let mounted = false;
117
+ this.startupBegun = true;
101
118
  try {
102
- const { router, mcpHttpCallback, mcpIsMcpRoute } = await this.buildRouterAndSendSchema();
119
+ // First, before anything is mounted or subscribed: everything it validates is what the caller
120
+ // handed to addBff(), so a mistyped key must fail on that line rather than leave the host
121
+ // serving /forest with a permanently bricked /bff.
122
+ await this.embeddedBff?.prepare();
123
+ const { router, mcp } = await this.buildRouterAndSendSchema();
103
124
  await this.options.forestAdminClient.subscribeToServerEvents();
104
125
  this.options.forestAdminClient.onRefreshCustomizations(this.restart.bind(this));
105
- this.setMcpCallback(mcpHttpCallback ?? null, mcpIsMcpRoute);
126
+ this.setMcpCallback(mcp ?? null);
106
127
  await this.mount(router);
107
128
  mounted = true;
108
129
  // Boot after mount(): the embedded executor reaches the agent over HTTP, and the
109
130
  // standalone server's host/port (used to derive that URL) are only known once mounted.
110
131
  await this.embeddedExecutor?.start(this.standaloneServerHost, this.standaloneServerPort);
132
+ // Same reason, without the socket: the dispatcher injects into the stack mount() just built.
133
+ await this.embeddedBff?.start(this.getInProcessDispatcher());
111
134
  }
112
135
  catch (error) {
136
+ // Only when nothing was mounted. Past mount() the host framework is already serving this
137
+ // agent, so it is not configurable again: clearing the flag would let a later addBff() past
138
+ // its guard and register a BFF whose start() nothing calls — /bff would answer 503 for the
139
+ // rest of the process, and restart() only invalidates, it never starts it.
140
+ if (!mounted)
141
+ this.startupBegun = false;
113
142
  const { message } = error;
114
143
  this.options.logger('Error', `Forest Admin agent startup failure: ${message}`);
115
144
  // buildRouterAndSendSchema() may already have opened the audit-trail connection even
@@ -133,7 +162,10 @@ class Agent extends framework_mounter_1.default {
133
162
  * Stop the agent.
134
163
  */
135
164
  async stop() {
136
- // Drain the embedded executor first, while the agent it depends on is still serving.
165
+ // Stop answering before the stack it dispatches into goes away: the host application keeps
166
+ // whatever middleware it registered, so a stopped agent would otherwise still serve BFF data.
167
+ this.embeddedBff?.stop();
168
+ // Drain the embedded executor next, while the agent it depends on is still serving.
137
169
  await this.embeddedExecutor?.stop();
138
170
  // Close anything related to ForestAdmin client
139
171
  this.options.forestAdminClient.close();
@@ -163,9 +195,11 @@ class Agent extends framework_mounter_1.default {
163
195
  this.isRestarting = true;
164
196
  try {
165
197
  // We force sending schema when restarting
166
- const { router, mcpHttpCallback, mcpIsMcpRoute } = await this.buildRouterAndSendSchema();
167
- this.setMcpCallback(mcpHttpCallback ?? null, mcpIsMcpRoute);
198
+ const { router, mcp } = await this.buildRouterAndSendSchema();
199
+ this.setMcpCallback(mcp ?? null);
168
200
  await this.remount(router);
201
+ // A restart means the customizations changed, so the schema the BFF read is stale.
202
+ this.embeddedBff?.invalidate();
169
203
  }
170
204
  finally {
171
205
  this.isRestarting = false;
@@ -277,6 +311,9 @@ class Agent extends framework_mounter_1.default {
277
311
  * agent.mountAiMcpServer({ fileUploads: false });
278
312
  */
279
313
  mountAiMcpServer(options) {
314
+ if (this.embeddedBff && (0, bff_routes_1.collidesWithBff)(options?.basePath)) {
315
+ throw new Error(bffMcpCollision(options?.basePath));
316
+ }
280
317
  this.mcpEnabled = true;
281
318
  this.mcpEnabledTools = options?.enabledTools;
282
319
  this.mcpBasePath = options?.basePath;
@@ -320,6 +357,58 @@ class Agent extends framework_mounter_1.default {
320
357
  this.embeddedExecutor = executor;
321
358
  return this;
322
359
  }
360
+ /**
361
+ * Serve a BFF in-process, alongside the agent, at `/bff` — no second deployment, no second port.
362
+ * The agent builds it on start(), stops it on stop(), and hands it a dispatcher that reaches its
363
+ * own stack without a socket, so this works the same on every mount target.
364
+ *
365
+ * Requires the `@forestadmin/agent-bff` package to be installed:
366
+ * ```bash
367
+ * npm install @forestadmin/agent-bff
368
+ * ```
369
+ *
370
+ * The secrets, the Forest urls and the logger are inherited from the agent. Everything left is
371
+ * a feature the BFF switches on when configured: `tokenEncryptionKey` enables OAuth (and with it
372
+ * the AI relay), `allowedOrigins` enables browser access, `openapiEnabled` serves the docs.
373
+ *
374
+ * @param options embedded BFF options
375
+ * @returns the agent instance for chaining
376
+ * @throws Error if called more than once, or if the MCP server already claims `/bff`
377
+ *
378
+ * A `mountOn*` call is what opens a socket — start() only builds the router — so the BFF is only
379
+ * reachable on an agent that is mounted somewhere.
380
+ *
381
+ * @example
382
+ * await createAgent(options)
383
+ * .addDataSource(...)
384
+ * .addBff({ allowedOrigins: ['https://my-app.com'] })
385
+ * .mountOnStandaloneServer(3351)
386
+ * .start();
387
+ */
388
+ addBff(options = {}) {
389
+ if (this.embeddedBff) {
390
+ throw new Error('addBff can only be called once.');
391
+ }
392
+ // Refused rather than accepted and left dark: once startup has begun the dispatcher hook has no
393
+ // mount left to attach to and nothing calls the BFF's own start(), so `/bff` would answer 503
394
+ // for the rest of the process while every other route works. A throw on the line the developer
395
+ // wrote instead. Refused from the first line of start(), not from its last: `start()` is async,
396
+ // so a call made while it is still in flight is just as late.
397
+ if (this.startupBegun) {
398
+ throw new Error('addBff must be called before start(): the agent is already starting.');
399
+ }
400
+ if ((0, bff_routes_1.collidesWithBff)(this.mcpBasePath)) {
401
+ throw new Error(bffMcpCollision(this.mcpBasePath));
402
+ }
403
+ const bff = new embedded_bff_1.default(this.options, options);
404
+ this.embeddedBff = bff;
405
+ // Registered now rather than at start(): getInProcessDispatcher() pushes its hook the first
406
+ // time it is called, and mount() only runs the hooks registered before it — asked for later,
407
+ // the dispatcher would have no handler until the first restart.
408
+ this.getInProcessDispatcher();
409
+ this.setBffCallback(bff.handle);
410
+ return this;
411
+ }
323
412
  getRoutes(dataSource, services) {
324
413
  return (0, routes_1.default)(dataSource, this.options, services);
325
414
  }
@@ -333,11 +422,9 @@ class Agent extends framework_mounter_1.default {
333
422
  const routes = this.getRoutes(dataSource, services);
334
423
  await Promise.all(routes.map(route => route.bootstrap()));
335
424
  // Initialize MCP server if enabled via mountAiMcpServer()
336
- let mcpHttpCallback;
337
- let mcpIsMcpRoute;
425
+ let mcp;
338
426
  if (this.mcpEnabled) {
339
- ({ httpCallback: mcpHttpCallback, isMcpRoute: mcpIsMcpRoute } =
340
- await this.initializeMcpServer());
427
+ mcp = await this.initializeMcpServer();
341
428
  }
342
429
  // Build main router
343
430
  const router = new router_1.default();
@@ -355,7 +442,7 @@ class Agent extends framework_mounter_1.default {
355
442
  }));
356
443
  router.use(correlation_id_1.correlationIdMiddleware);
357
444
  routes.forEach(route => route.setupRoutes(router));
358
- return { router, mcpHttpCallback, mcpIsMcpRoute };
445
+ return { router, mcp };
359
446
  }
360
447
  /**
361
448
  * Initialize the MCP server.
@@ -382,11 +469,11 @@ class Agent extends framework_mounter_1.default {
382
469
  fileUploads: this.mcpFileUploads,
383
470
  agentDispatcher: this.getInProcessDispatcher(),
384
471
  });
385
- const httpCallback = await mcpServer.getHttpCallback();
386
- const isMcpRoute = makeIsMcpRoute(this.mcpBasePath);
472
+ const callback = await mcpServer.getHttpCallback();
473
+ const matches = makeIsMcpRoute(this.mcpBasePath);
387
474
  mcpLogger('Info', 'Server initialized successfully');
388
475
  mcpLogger('Info', 'Tool calls dispatch in-process and skip any middleware mounted in front of the agent');
389
- return { httpCallback, isMcpRoute };
476
+ return { callback, matches };
390
477
  }
391
478
  catch (error) {
392
479
  const { message } = error;
@@ -507,4 +594,4 @@ class Agent extends framework_mounter_1.default {
507
594
  }
508
595
  }
509
596
  exports.default = Agent;
510
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWdlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFxQkEsOEVBQTBFO0FBQzFFLGlFQUF5QztBQUN6QyxxREFBNkI7QUFDN0IseURBQWlDO0FBQ2pDLDBDQUFrRDtBQUNsRCxrR0FBc0Q7QUFFdEQsK0NBQXVEO0FBQ3ZELDhGQUFvRTtBQUNwRSw0RUFBbUQ7QUFDbkQsc0RBQWtDO0FBQ2xDLDBEQUFzQztBQUN0QyxrR0FBaUY7QUFDakYsMkRBQXdGO0FBQ3hGLGdGQUE4RDtBQUM5RCxrRkFBeUQ7QUFFekQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBcUIsS0FBbUMsU0FBUSwyQkFBZ0I7SUFvQjlFOzs7Ozs7Ozs7Ozs7Ozs7T0FlRztJQUNILFlBQVksT0FBcUI7UUFDL0IsTUFBTSxVQUFVLEdBQUcsMkJBQWdCLENBQUMsUUFBUSxDQUFDLDJCQUFnQixDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3JGLEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQS9COUMsMkNBQTJDO1FBQ25DLGVBQVUsR0FBRyxLQUFLLENBQUM7UUFPM0IsdUZBQXVGO1FBQy9FLHFCQUFnQixHQUFvQyxJQUFJLENBQUM7UUFFekQsaUJBQVksR0FBRyxLQUFLLENBQUM7UUFzQjNCLElBQUksQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDO1FBQzFCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSw0Q0FBb0IsQ0FBSTtZQUM1QyxnQ0FBZ0MsRUFBRSxPQUFPLENBQUMsZ0NBQWdDLElBQUksS0FBSztTQUNwRixDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsb0JBQW9CLEdBQUcsSUFBSSx1QkFBb0IsQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNqRSxJQUFJLENBQUMsZUFBZSxH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
597
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYWdlbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFxQkEsOEVBQTBFO0FBQzFFLGlFQUF5QztBQUN6QyxxREFBNkI7QUFDN0IseURBQWlDO0FBQ2pDLDBDQUFrRDtBQUNsRCxrR0FBc0Q7QUFFdEQsK0NBQXVEO0FBQ3ZELDZDQUEyRDtBQUMzRCxrRUFBeUM7QUFDekMsOEZBQW9FO0FBQ3BFLDRFQUFtRDtBQUNuRCxzREFBa0M7QUFDbEMsMERBQXNDO0FBQ3RDLGtHQUFpRjtBQUNqRiwyREFBd0Y7QUFDeEYsZ0ZBQThEO0FBQzlELGtGQUF5RDtBQUV6RCw2RkFBNkY7QUFDN0YsK0ZBQStGO0FBQy9GLHFGQUFxRjtBQUNyRixNQUFNLGVBQWUsR0FBRyxDQUFDLFdBQW1CLEVBQUUsRUFBRSxDQUM5QyxpRUFBaUUsV0FBVyxnQkFBZ0I7SUFDNUYsc0JBQXNCLHVCQUFVLHVDQUF1Qyx1QkFBVSxVQUFVO0lBQzNGLEdBQUcsdUJBQVUsd0NBQXdDLENBQUM7QUFFeEQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBcUIsS0FBbUMsU0FBUSwyQkFBZ0I7SUE4QjlFOzs7Ozs7Ozs7Ozs7Ozs7T0FlRztJQUNILFlBQVksT0FBcUI7UUFDL0IsTUFBTSxVQUFVLEdBQUcsMkJBQWdCLENBQUMsUUFBUSxDQUFDLDJCQUFnQixDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3JGLEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQXpDOUMsMkNBQTJDO1FBQ25DLGVBQVUsR0FBRyxLQUFLLENBQUM7UUFPM0IsdUZBQXVGO1FBQy9FLHFCQUFnQixHQUFvQyxJQUFJLENBQUM7UUFFakUsNERBQTREO1FBQ3BELGdCQUFXLEdBQXVCLElBQUksQ0FBQztRQUV2QyxpQkFB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
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Where an embedded BFF answers, at the root of the host application. Fixed: the BFF serves its own
3
+ * `/oauth/*` and `/docs`, which would otherwise collide with the MCP server's root paths and with
4
+ * whatever the host already serves.
5
+ */
6
+ export declare const BFF_PREFIX = "/bff";
7
+ /**
8
+ * Matches on the pathname and on a segment boundary, so `/bff?x=1` is claimed and `/bffalo` is not.
9
+ */
10
+ export declare function isBffRoute(url: string): boolean;
11
+ /**
12
+ * The url the BFF itself expects: it knows nothing of the prefix the host serves it under, and its
13
+ * routes are absolute (`/agent/v1/…`, `/health`). Never yields an empty string — Koa would read that
14
+ * as a malformed request rather than as the root.
15
+ */
16
+ export declare function stripBffPrefix(url: string): string;
17
+ /**
18
+ * Whether an MCP mount path would land inside `/bff`. The MCP server normalizes its `basePath`
19
+ * (trim, leading slash, collapsed and stripped trailing slashes) before deriving
20
+ * `<basePath>/oauth/` and `<basePath>/mcp`, so comparing the raw option to `/bff` would let `bff`,
21
+ * `/bff/` and `/bff/ai` through — each of which claims paths the BFF answers on. The normalization
22
+ * is mirrored rather than imported: mcp-server keeps it internal.
23
+ */
24
+ export declare function collidesWithBff(mcpBasePath?: string): boolean;
25
+ //# sourceMappingURL=bff-routes.d.ts.map
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BFF_PREFIX = void 0;
4
+ exports.isBffRoute = isBffRoute;
5
+ exports.stripBffPrefix = stripBffPrefix;
6
+ exports.collidesWithBff = collidesWithBff;
7
+ /**
8
+ * Where an embedded BFF answers, at the root of the host application. Fixed: the BFF serves its own
9
+ * `/oauth/*` and `/docs`, which would otherwise collide with the MCP server's root paths and with
10
+ * whatever the host already serves.
11
+ */
12
+ exports.BFF_PREFIX = '/bff';
13
+ /**
14
+ * Matches on the pathname and on a segment boundary, so `/bff?x=1` is claimed and `/bffalo` is not.
15
+ */
16
+ function isBffRoute(url) {
17
+ const [pathname] = url.split(/[?#]/, 1);
18
+ return pathname === exports.BFF_PREFIX || pathname.startsWith(`${exports.BFF_PREFIX}/`);
19
+ }
20
+ /**
21
+ * The url the BFF itself expects: it knows nothing of the prefix the host serves it under, and its
22
+ * routes are absolute (`/agent/v1/…`, `/health`). Never yields an empty string — Koa would read that
23
+ * as a malformed request rather than as the root.
24
+ */
25
+ function stripBffPrefix(url) {
26
+ const remainder = url.slice(exports.BFF_PREFIX.length);
27
+ if (remainder === '')
28
+ return '/';
29
+ return remainder.startsWith('/') ? remainder : `/${remainder}`;
30
+ }
31
+ /**
32
+ * Whether an MCP mount path would land inside `/bff`. The MCP server normalizes its `basePath`
33
+ * (trim, leading slash, collapsed and stripped trailing slashes) before deriving
34
+ * `<basePath>/oauth/` and `<basePath>/mcp`, so comparing the raw option to `/bff` would let `bff`,
35
+ * `/bff/` and `/bff/ai` through — each of which claims paths the BFF answers on. The normalization
36
+ * is mirrored rather than imported: mcp-server keeps it internal.
37
+ */
38
+ function collidesWithBff(mcpBasePath) {
39
+ if (!mcpBasePath)
40
+ return false;
41
+ const trimmed = mcpBasePath.trim();
42
+ if (trimmed === '' || trimmed === '/')
43
+ return false;
44
+ const normalized = (trimmed.startsWith('/') ? trimmed : `/${trimmed}`)
45
+ .replace(/\/+/g, '/')
46
+ .replace(/\/+$/, '');
47
+ return isBffRoute(`${normalized}/mcp`);
48
+ }
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmZmLXJvdXRlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9iZmYtcm91dGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQVVBLGdDQUlDO0FBT0Qsd0NBTUM7QUFTRCwwQ0FZQztBQWhERDs7OztHQUlHO0FBQ1UsUUFBQSxVQUFVLEdBQUcsTUFBTSxDQUFDO0FBRWpDOztHQUVHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLEdBQVc7SUFDcEMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRXhDLE9BQU8sUUFBUSxLQUFLLGtCQUFVLElBQUksUUFBUSxDQUFDLFVBQVUsQ0FBQyxHQUFHLGtCQUFVLEdBQUcsQ0FBQyxDQUFDO0FBQzFFLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsY0FBYyxDQUFDLEdBQVc7SUFDeEMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxrQkFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBRS9DLElBQUksU0FBUyxLQUFLLEVBQUU7UUFBRSxPQUFPLEdBQUcsQ0FBQztJQUVqQyxPQUFPLFNBQVMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxTQUFTLEVBQUUsQ0FBQztBQUNqRSxDQUFDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsZUFBZSxDQUFDLFdBQW9CO0lBQ2xELElBQUksQ0FBQyxXQUFXO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFFL0IsTUFBTSxPQUFPLEdBQUcsV0FBVyxDQUFDLElBQUksRUFBRSxDQUFDO0lBRW5DLElBQUksT0FBTyxLQUFLLEVBQUUsSUFBSSxPQUFPLEtBQUssR0FBRztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBRXBELE1BQU0sVUFBVSxHQUFHLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLE9BQU8sRUFBRSxDQUFDO1NBQ25FLE9BQU8sQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDO1NBQ3BCLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFdkIsT0FBTyxVQUFVLENBQUMsR0FBRyxVQUFVLE1BQU0sQ0FBQyxDQUFDO0FBQ3pDLENBQUMifQ==
@@ -0,0 +1,61 @@
1
+ import type { AgentOptionsWithDefaults, BffEmbedOptions, HttpCallback } from './types';
2
+ import type { AgentDispatcher } from '@forestadmin/agent-bff';
3
+ /**
4
+ * Owns the lifecycle of a BFF embedded in the agent process: configuration, dynamic loading of the
5
+ * optional package, build, and the request handler the agent mounts at `/bff`. The agent only wires
6
+ * the callback and delegates start/stop.
7
+ */
8
+ export default class EmbeddedBff {
9
+ private readonly options;
10
+ private readonly embedOptions;
11
+ private config;
12
+ private bff;
13
+ private stopped;
14
+ constructor(options: AgentOptionsWithDefaults, embedOptions: BffEmbedOptions);
15
+ /**
16
+ * Load the package and validate the options the caller handed to `addBff()`. Called before the
17
+ * agent mounts anything: everything checked here is caller input, and `parseConfig` throws on a
18
+ * mistyped `tokenEncryptionKey`, timezone, timeout or url. Failing here leaves nothing serving,
19
+ * where failing after mount() would leave the host with a live `/forest` and a bricked `/bff`.
20
+ */
21
+ prepare(): Promise<void>;
22
+ /**
23
+ * Build the BFF. Called from agent.start() after mount(), because the dispatcher only reaches the
24
+ * agent's own stack once that stack is mounted.
25
+ */
26
+ start(dispatcher: AgentDispatcher): Promise<void>;
27
+ /**
28
+ * The whitelist exempts a caller arriving over a loopback socket with no proxy hop, which is
29
+ * exactly what the in-process transport looks like — so every BFF request escapes it. That is the
30
+ * decision, not an oversight: propagating the caller's ip would make the embedded mode stricter
31
+ * than the standalone one, where the whitelist only ever sees the BFF's own host, and would refuse
32
+ * the browsers a third-party UI is made of. What it must not be is silent — an operator who turned
33
+ * the whitelist on to close a door has no other way to learn this door is not part of it.
34
+ *
35
+ * Reads the configuration itself rather than borrowing the one `IpWhitelist` already fetched: that
36
+ * route keeps it private, and reaching into it would put BFF concerns in an unrelated part of the
37
+ * agent. Costs one round-trip at boot. Never fails the boot: a warning is not worth refusing to
38
+ * serve over, and this is the same posture as the rest of the BFF's startup.
39
+ */
40
+ private warnIfExemptFromIpWhitelist;
41
+ /** Drop what the BFF read from the SaaS. Called on a restart, which means the schema moved. */
42
+ invalidate(): void;
43
+ /**
44
+ * Stop answering. The host application keeps whatever middleware it registered, so without this
45
+ * a stopped agent would go on serving BFF data through a dispatcher pointing at a dead stack.
46
+ */
47
+ stop(): void;
48
+ /**
49
+ * The callback the agent registers at `/bff`. Answers 503 rather than falling through while the
50
+ * BFF is not serving: a 404 from the host would read as "wrong url" instead of "not available".
51
+ * Boot and shutdown are told apart, because a probe should wait on the first and drain on the
52
+ * second.
53
+ */
54
+ readonly handle: HttpCallback;
55
+ /**
56
+ * Dynamically load the optional @forestadmin/agent-bff package. Deferred so agents that embed no
57
+ * BFF never load its code at startup.
58
+ */
59
+ private importPackage;
60
+ }
61
+ //# sourceMappingURL=embedded-bff.d.ts.map