@forestadmin/gateway 0.0.0-stage → 1.0.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.
@@ -0,0 +1,9 @@
1
+ import type { BFFHttpServer, Logger } from '@forestadmin/agent-bff';
2
+ export declare const USAGE = "Usage: forest-gateway [command]\n\nCommands:\n (none) Start the Gateway, configured from the environment.\n FOREST_GATEWAY_SERVICES lists what it serves: mcp, api or mcp,api.\n openapi Write the API's OpenAPI document to stdout, its paths under\n FOREST_GATEWAY_BASE_PATH/api, its server FOREST_GATEWAY_API_PUBLIC_URL\n when set.\n --output [file] Write to a file instead of stdout, defaulting\n to openapi.json in the current directory.\n\nOptions:\n -h, --help Show this help and exit.\n -v, --version Show the package version and exit.";
3
+ export declare const HINT = "Run 'forest-gateway --help' for usage.";
4
+ export interface DispatchOutcome {
5
+ exitCode: number;
6
+ server?: BFFHttpServer;
7
+ }
8
+ export default function dispatchCli(argv: string[], env: NodeJS.ProcessEnv, logger?: Logger): Promise<DispatchOutcome>;
9
+ //# sourceMappingURL=cli-dispatch.d.ts.map
@@ -0,0 +1,67 @@
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.HINT = exports.USAGE = void 0;
7
+ exports.default = dispatchCli;
8
+ const agent_bff_1 = require("@forestadmin/agent-bff");
9
+ const gateway_env_1 = require("./gateway-env");
10
+ const run_gateway_1 = __importDefault(require("./run-gateway"));
11
+ const version_1 = __importDefault(require("./version"));
12
+ exports.USAGE = `Usage: forest-gateway [command]
13
+
14
+ Commands:
15
+ (none) Start the Gateway, configured from the environment.
16
+ FOREST_GATEWAY_SERVICES lists what it serves: mcp, api or mcp,api.
17
+ openapi Write the API's OpenAPI document to stdout, its paths under
18
+ FOREST_GATEWAY_BASE_PATH/api, its server FOREST_GATEWAY_API_PUBLIC_URL
19
+ when set.
20
+ --output [file] Write to a file instead of stdout, defaulting
21
+ to ${agent_bff_1.DEFAULT_OUTPUT_FILE} in the current directory.
22
+
23
+ Options:
24
+ -h, --help Show this help and exit.
25
+ -v, --version Show the package version and exit.`;
26
+ exports.HINT = "Run 'forest-gateway --help' for usage.";
27
+ const HELP_FLAGS = new Set(['-h', '--help']);
28
+ const VERSION_FLAGS = new Set(['-v', '--version']);
29
+ function rejectCli(reason) {
30
+ process.stderr.write(`${reason}\n${exports.HINT}\n`);
31
+ return { exitCode: 1 };
32
+ }
33
+ async function renderGatewayOpenApi(env, logger) {
34
+ const { basePath, api, warnings } = (0, gateway_env_1.parseOpenApiEnv)(env);
35
+ warnings.forEach(warning => logger('Warn', warning));
36
+ return (0, agent_bff_1.renderOpenApi)(api.env, logger, { basePath: (0, gateway_env_1.apiBasePath)(basePath), labels: api.labels });
37
+ }
38
+ async function dispatchCli(argv, env, logger) {
39
+ const [subcommand, ...rest] = argv;
40
+ if (subcommand === undefined) {
41
+ return { exitCode: 0, server: await (0, run_gateway_1.default)(env, logger) };
42
+ }
43
+ if (HELP_FLAGS.has(subcommand)) {
44
+ process.stdout.write(`${exports.USAGE}\n`);
45
+ return { exitCode: 0 };
46
+ }
47
+ if (VERSION_FLAGS.has(subcommand)) {
48
+ process.stdout.write(`${version_1.default}\n`);
49
+ return { exitCode: 0 };
50
+ }
51
+ if (subcommand !== 'openapi') {
52
+ return rejectCli(subcommand === agent_bff_1.OUTPUT_FLAG
53
+ ? `${agent_bff_1.OUTPUT_FLAG} only applies to the openapi command`
54
+ : `Unknown command: ${subcommand}`);
55
+ }
56
+ const { file, extras } = (0, agent_bff_1.parseOutputOption)(rest);
57
+ if (extras.length > 0) {
58
+ return rejectCli(`openapi accepts only --output, got: ${extras.map(extra => JSON.stringify(extra)).join(' ')}`);
59
+ }
60
+ const document = await renderGatewayOpenApi(env, logger ?? (0, agent_bff_1.createConsoleLogger)());
61
+ if (file !== undefined) {
62
+ return (0, agent_bff_1.writeOutputFile)(file, document);
63
+ }
64
+ process.stdout.write(document);
65
+ return { exitCode: 0 };
66
+ }
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWRpc3BhdGNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS1kaXNwYXRjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFzREEsOEJBZ0RDO0FBcEdELHNEQU9nQztBQUVoQywrQ0FBNkQ7QUFDN0QsZ0VBQXVDO0FBQ3ZDLHdEQUFnQztBQUVuQixRQUFBLEtBQUssR0FBRzs7Ozs7Ozs7O29DQVNlLCtCQUFtQjs7OztvREFJSCxDQUFDO0FBRXhDLFFBQUEsSUFBSSxHQUFHLHdDQUF3QyxDQUFDO0FBRTdELE1BQU0sVUFBVSxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDN0MsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQztBQU9uRCxTQUFTLFNBQVMsQ0FBQyxNQUFjO0lBQy9CLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUcsTUFBTSxLQUFLLFlBQUksSUFBSSxDQUFDLENBQUM7SUFFN0MsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsQ0FBQztBQUN6QixDQUFDO0FBRUQsS0FBSyxVQUFVLG9CQUFvQixDQUFDLEdBQXNCLEVBQUUsTUFBYztJQUN4RSxNQUFNLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsR0FBRyxJQUFBLDZCQUFlLEVBQUMsR0FBRyxDQUFDLENBQUM7SUFFekQsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUVyRCxPQUFPLElBQUEseUJBQWEsRUFBQyxHQUFHLENBQUMsR0FBRyxFQUFFLE1BQU0sRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFBLHlCQUFXLEVBQUMsUUFBUSxDQUFDLEVBQUUsTUFBTSxFQUFFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0FBQ2pHLENBQUM7QUFFYyxLQUFLLFVBQVUsV0FBVyxDQUN2QyxJQUFjLEVBQ2QsR0FBc0IsRUFDdEIsTUFBZTtJQUVmLE1BQU0sQ0FBQyxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUM7SUFFbkMsSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDN0IsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sSUFBQSxxQkFBVSxFQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsRUFBRSxDQUFDO0lBQ2hFLENBQUM7SUFFRCxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvQixPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLGFBQUssSUFBSSxDQUFDLENBQUM7UUFFbkMsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRUQsSUFBSSxhQUFhLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDbEMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxpQkFBTyxJQUFJLENBQUMsQ0FBQztRQUVyQyxPQUFPLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFRCxJQUFJLFVBQVUsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUM3QixPQUFPLFNBQVMsQ0FDZCxVQUFVLEtBQUssdUJBQVc7WUFDeEIsQ0FBQyxDQUFDLEdBQUcsdUJBQVcsc0NBQXNDO1lBQ3RELENBQUMsQ0FBQyxvQkFBb0IsVUFBVSxFQUFFLENBQ3JDLENBQUM7SUFDSixDQUFDO0lBRUQsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsR0FBRyxJQUFBLDZCQUFpQixFQUFDLElBQUksQ0FBQyxDQUFDO0lBRWpELElBQUksTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN0QixPQUFPLFNBQVMsQ0FDZCx1Q0FBdUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FDOUYsQ0FBQztJQUNKLENBQUM7SUFFRCxNQUFNLFFBQVEsR0FBRyxNQUFNLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxNQUFNLElBQUksSUFBQSwrQkFBbUIsR0FBRSxDQUFDLENBQUM7SUFFbEYsSUFBSSxJQUFJLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDdkIsT0FBTyxJQUFBLDJCQUFlLEVBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRCxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUUvQixPQUFPLEVBQUUsUUFBUSxFQUFFLENBQUMsRUFBRSxDQUFDO0FBQ3pCLENBQUMifQ==
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ /* istanbul ignore file */
8
+ const cli_dispatch_1 = __importDefault(require("./cli-dispatch"));
9
+ if (require.main === module) {
10
+ (0, cli_dispatch_1.default)(process.argv.slice(2), process.env)
11
+ .then(({ exitCode }) => {
12
+ if (exitCode !== 0)
13
+ process.exitCode = exitCode;
14
+ })
15
+ .catch(error => {
16
+ process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}\n`);
17
+ process.exitCode = 1;
18
+ });
19
+ }
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFDQSwwQkFBMEI7QUFDMUIsa0VBQXlDO0FBRXpDLElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxNQUFNLEVBQUUsQ0FBQztJQUM1QixJQUFBLHNCQUFXLEVBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQztTQUM1QyxJQUFJLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUU7UUFDckIsSUFBSSxRQUFRLEtBQUssQ0FBQztZQUFFLE9BQU8sQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQ2xELENBQUMsQ0FBQztTQUNELEtBQUssQ0FBQyxLQUFLLENBQUMsRUFBRTtRQUNiLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMzRixPQUFPLENBQUMsUUFBUSxHQUFHLENBQUMsQ0FBQztJQUN2QixDQUFDLENBQUMsQ0FBQztBQUNQLENBQUMifQ==
@@ -0,0 +1,15 @@
1
+ export interface Resolution {
2
+ key: string;
3
+ value?: string;
4
+ }
5
+ export interface ResolveOptions {
6
+ blankIsSet?: boolean;
7
+ }
8
+ export default class EnvAliases {
9
+ private readonly env;
10
+ readonly warnings: string[];
11
+ constructor(env: NodeJS.ProcessEnv);
12
+ resolve(name: string, aliases?: readonly string[], { blankIsSet }?: ResolveOptions): Resolution;
13
+ ignore(keys: readonly string[], reason: string): void;
14
+ }
15
+ //# sourceMappingURL=env-aliases.d.ts.map
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const agent_bff_1 = require("@forestadmin/agent-bff");
4
+ function isSet(value) {
5
+ return value !== undefined && value.trim() !== '';
6
+ }
7
+ function isNonEmpty(value) {
8
+ return value !== undefined && value !== '';
9
+ }
10
+ class EnvAliases {
11
+ constructor(env) {
12
+ this.env = env;
13
+ this.warnings = [];
14
+ }
15
+ resolve(name, aliases = [], { blankIsSet = false } = {}) {
16
+ const isUsed = blankIsSet ? isNonEmpty : isSet;
17
+ const usedAliases = aliases.filter(alias => isUsed(this.env[alias]));
18
+ if (isUsed(this.env[name])) {
19
+ usedAliases.forEach(alias => this.warnings.push(`${alias} is ignored: ${name} is set`));
20
+ return { key: name, value: this.env[name] };
21
+ }
22
+ if (new Set(usedAliases.map(alias => this.env[alias]?.trim())).size > 1) {
23
+ throw new agent_bff_1.ConfigurationError(`${usedAliases.join(' and ')} disagree: set ${name} to the value the Gateway should use.`);
24
+ }
25
+ usedAliases.forEach(alias => this.warnings.push(`${alias} is a legacy name: use ${name} instead`));
26
+ return usedAliases.length > 0
27
+ ? { key: usedAliases[0], value: this.env[usedAliases[0]] }
28
+ : { key: name };
29
+ }
30
+ ignore(keys, reason) {
31
+ keys
32
+ .filter(key => isSet(this.env[key]))
33
+ .forEach(key => this.warnings.push(`${key} is ignored: ${reason}`));
34
+ }
35
+ }
36
+ exports.default = EnvAliases;
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52LWFsaWFzZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZW52LWFsaWFzZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxzREFBNEQ7QUFXNUQsU0FBUyxLQUFLLENBQUMsS0FBeUI7SUFDdEMsT0FBTyxLQUFLLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDcEQsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLEtBQXlCO0lBQzNDLE9BQU8sS0FBSyxLQUFLLFNBQVMsSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO0FBQzdDLENBQUM7QUFFRCxNQUFxQixVQUFVO0lBRzdCLFlBQTZCLEdBQXNCO1FBQXRCLFFBQUcsR0FBSCxHQUFHLENBQW1CO1FBRjFDLGFBQVEsR0FBYSxFQUFFLENBQUM7SUFFcUIsQ0FBQztJQUV2RCxPQUFPLENBQ0wsSUFBWSxFQUNaLFVBQTZCLEVBQUUsRUFDL0IsRUFBRSxVQUFVLEdBQUcsS0FBSyxLQUFxQixFQUFFO1FBRTNDLE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7UUFDL0MsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVyRSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLEVBQUUsQ0FBQztZQUMzQixXQUFXLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLGdCQUFnQixJQUFJLFNBQVMsQ0FBQyxDQUFDLENBQUM7WUFFeEYsT0FBTyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUM5QyxDQUFDO1FBRUQsSUFBSSxJQUFJLEdBQUcsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3hFLE1BQU0sSUFBSSw4QkFBa0IsQ0FDMUIsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxrQkFBa0IsSUFBSSx1Q0FBdUMsQ0FDMUYsQ0FBQztRQUNKLENBQUM7UUFFRCxXQUFXLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQzFCLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsS0FBSywwQkFBMEIsSUFBSSxVQUFVLENBQUMsQ0FDckUsQ0FBQztRQUVGLE9BQU8sV0FBVyxDQUFDLE1BQU0sR0FBRyxDQUFDO1lBQzNCLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUU7WUFDMUQsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxDQUFDO0lBQ3BCLENBQUM7SUFFRCxNQUFNLENBQUMsSUFBdUIsRUFBRSxNQUFjO1FBQzVDLElBQUk7YUFDRCxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO2FBQ25DLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxnQkFBZ0IsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7Q0FDRjtBQXZDRCw2QkF1Q0MifQ==
@@ -0,0 +1,42 @@
1
+ import type { ConfigLabels } from '@forestadmin/agent-bff';
2
+ import type { McpEnv, McpEnvLabels } from '@forestadmin/mcp-server';
3
+ export type Service = 'mcp' | 'api';
4
+ export declare const SERVICES: readonly Service[];
5
+ export declare const SERVICES_VAR = "FOREST_GATEWAY_SERVICES";
6
+ export declare const BASE_PATH_VAR = "FOREST_GATEWAY_BASE_PATH";
7
+ export declare const PUBLIC_URL_VAR = "FOREST_GATEWAY_URL";
8
+ export declare const PORT_VAR = "PORT";
9
+ export declare const AGENT_URL_VAR = "FOREST_AGENT_URL";
10
+ export declare const API_PUBLIC_URL_VAR = "FOREST_GATEWAY_API_PUBLIC_URL";
11
+ export declare const ALLOWED_OAUTH_CLIENTS_VAR = "FOREST_GATEWAY_ALLOWED_OAUTH_CLIENTS";
12
+ export declare const DEFAULT_MCP_PORT = 3931;
13
+ export declare const DEFAULT_API_PORT = 3450;
14
+ export interface McpSettings {
15
+ env: McpEnv;
16
+ labels: Partial<McpEnvLabels>;
17
+ }
18
+ export interface ApiSettings {
19
+ env: NodeJS.ProcessEnv;
20
+ labels: ConfigLabels;
21
+ allowedOAuthClients?: string[];
22
+ }
23
+ export interface GatewayEnv {
24
+ services: Set<Service>;
25
+ basePath: string;
26
+ port: number;
27
+ publicUrl?: string;
28
+ mcp?: McpSettings;
29
+ api?: ApiSettings;
30
+ warnings: string[];
31
+ }
32
+ export interface OpenApiEnv {
33
+ basePath: string;
34
+ api: ApiSettings;
35
+ warnings: string[];
36
+ }
37
+ export declare function parseServices(raw: string | undefined): Set<Service>;
38
+ export declare function apiBasePath(basePath: string): string;
39
+ export declare function parseOpenApiEnv(env: NodeJS.ProcessEnv): OpenApiEnv;
40
+ export declare function resolveListenPort(env: NodeJS.ProcessEnv): number;
41
+ export default function parseGatewayEnv(env: NodeJS.ProcessEnv): GatewayEnv;
42
+ //# sourceMappingURL=gateway-env.d.ts.map
@@ -0,0 +1,181 @@
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.DEFAULT_API_PORT = exports.DEFAULT_MCP_PORT = exports.ALLOWED_OAUTH_CLIENTS_VAR = exports.API_PUBLIC_URL_VAR = exports.AGENT_URL_VAR = exports.PORT_VAR = exports.PUBLIC_URL_VAR = exports.BASE_PATH_VAR = exports.SERVICES_VAR = exports.SERVICES = void 0;
7
+ exports.parseServices = parseServices;
8
+ exports.apiBasePath = apiBasePath;
9
+ exports.parseOpenApiEnv = parseOpenApiEnv;
10
+ exports.resolveListenPort = resolveListenPort;
11
+ exports.default = parseGatewayEnv;
12
+ const agent_bff_1 = require("@forestadmin/agent-bff");
13
+ const forestadmin_client_1 = require("@forestadmin/forestadmin-client");
14
+ const mcp_server_1 = require("@forestadmin/mcp-server");
15
+ const env_aliases_1 = __importDefault(require("./env-aliases"));
16
+ exports.SERVICES = ['mcp', 'api'];
17
+ exports.SERVICES_VAR = 'FOREST_GATEWAY_SERVICES';
18
+ exports.BASE_PATH_VAR = 'FOREST_GATEWAY_BASE_PATH';
19
+ exports.PUBLIC_URL_VAR = 'FOREST_GATEWAY_URL';
20
+ exports.PORT_VAR = 'PORT';
21
+ exports.AGENT_URL_VAR = 'FOREST_AGENT_URL';
22
+ exports.API_PUBLIC_URL_VAR = 'FOREST_GATEWAY_API_PUBLIC_URL';
23
+ exports.ALLOWED_OAUTH_CLIENTS_VAR = 'FOREST_GATEWAY_ALLOWED_OAUTH_CLIENTS';
24
+ const API_VAR_PREFIX = 'FOREST_GATEWAY_API_';
25
+ const BFF_VAR_PREFIX = 'BFF_';
26
+ const BFF_LISTENER_ENV = {
27
+ port: 'HTTP_PORT',
28
+ publicUrl: 'BFF_PUBLIC_URL',
29
+ };
30
+ const PORT_ALIASES = [mcp_server_1.MCP_LISTENER_ENV.port, BFF_LISTENER_ENV.port];
31
+ const PUBLIC_URL_ALIASES = [mcp_server_1.MCP_LISTENER_ENV.publicUrl];
32
+ const AGENT_URL_ALIASES = ['AGENT_URL'];
33
+ const ALLOWED_OAUTH_CLIENTS_ALIASES = ['FOREST_MCP_ALLOWED_OAUTH_CLIENTS'];
34
+ const MCP_LABELS = {
35
+ accessTokenTtl: 'FOREST_MCP_ACCESS_TOKEN_TTL_SECONDS',
36
+ refreshTokenTtl: 'FOREST_MCP_REFRESH_TOKEN_TTL_SECONDS',
37
+ };
38
+ exports.DEFAULT_MCP_PORT = 3931;
39
+ exports.DEFAULT_API_PORT = 3450;
40
+ const MAX_PORT = 65535;
41
+ const DECIMAL_INTEGER = /^\d+$/;
42
+ const HTTP_PROTOCOLS = ['http:', 'https:'];
43
+ function isService(value) {
44
+ return exports.SERVICES.includes(value);
45
+ }
46
+ function parseServices(raw) {
47
+ const entries = (raw ?? '')
48
+ .split(',')
49
+ .map(entry => entry.trim())
50
+ .filter(entry => entry !== '');
51
+ if (entries.length === 0 || !entries.every(isService)) {
52
+ throw new agent_bff_1.ConfigurationError(`Invalid ${exports.SERVICES_VAR} "${raw ?? ''}": list the services to serve, ` +
53
+ `among ${exports.SERVICES.map(service => `"${service}"`).join(', ')} (e.g. "mcp,api").`);
54
+ }
55
+ return new Set(entries);
56
+ }
57
+ function apiBasePath(basePath) {
58
+ return `${basePath}/api`;
59
+ }
60
+ function parsePort({ key, value }, fallback) {
61
+ const trimmed = value?.trim();
62
+ if (!trimmed)
63
+ return fallback;
64
+ const port = DECIMAL_INTEGER.test(trimmed) ? Number(trimmed) : NaN;
65
+ if (Number.isNaN(port) || port > MAX_PORT) {
66
+ throw new agent_bff_1.ConfigurationError(`Invalid ${key} "${value}": expected an integer between 0 and ${MAX_PORT}.`);
67
+ }
68
+ return port;
69
+ }
70
+ function parseGatewayUrl({ key, value }) {
71
+ const trimmed = value?.trim();
72
+ if (!trimmed)
73
+ return undefined;
74
+ const parsed = URL.canParse(trimmed) ? new URL(trimmed) : undefined;
75
+ const isBareHttpOrigin = parsed && HTTP_PROTOCOLS.includes(parsed.protocol) && parsed.href === `${parsed.origin}/`;
76
+ if (!isBareHttpOrigin) {
77
+ throw new agent_bff_1.ConfigurationError(`Invalid ${key}: expected an http(s) origin with no path, query, fragment or ` +
78
+ 'credentials, e.g. https://gateway.example.com');
79
+ }
80
+ return parsed.origin;
81
+ }
82
+ function assertAgentUrl({ key, value }) {
83
+ if (value === undefined)
84
+ return;
85
+ const parsed = !/\s/.test(value) && URL.canParse(value) ? new URL(value) : undefined;
86
+ if (!parsed || !HTTP_PROTOCOLS.includes(parsed.protocol) || parsed.search || parsed.hash) {
87
+ throw new agent_bff_1.ConfigurationError(`Invalid ${key}: expected an absolute http(s) URL with no query string or fragment.`);
88
+ }
89
+ }
90
+ function parseAllowedOAuthClients({ key, value }) {
91
+ if (value === undefined)
92
+ return undefined;
93
+ return (0, forestadmin_client_1.normalizeDomainList)((0, forestadmin_client_1.parseDomainList)(value) ?? [], key);
94
+ }
95
+ function assertApiPublicUrl(value, key, basePath) {
96
+ const url = (0, agent_bff_1.parsePublicUrl)(value, key);
97
+ const suffix = apiBasePath(basePath);
98
+ if (url !== undefined && !new URL(url).pathname.endsWith(suffix)) {
99
+ throw new agent_bff_1.ConfigurationError(`Invalid configuration: ${key} must end with ${suffix}, where the Gateway serves the API.`);
100
+ }
101
+ }
102
+ function resolveApi(env, aliases, basePath, agentUrl) {
103
+ const apiEnv = {
104
+ ...env,
105
+ AGENT_URL: agentUrl.value,
106
+ [BFF_LISTENER_ENV.port]: undefined,
107
+ };
108
+ const labels = { AGENT_URL: agentUrl.key };
109
+ const bffKeys = agent_bff_1.CONFIG_KEYS.filter((key) => key.startsWith(BFF_VAR_PREFIX));
110
+ for (const bffKey of bffKeys) {
111
+ const { key, value } = aliases.resolve(`${API_VAR_PREFIX}${bffKey.slice(BFF_VAR_PREFIX.length)}`, [bffKey]);
112
+ apiEnv[bffKey] = value;
113
+ labels[bffKey] = key;
114
+ }
115
+ assertApiPublicUrl(apiEnv.BFF_PUBLIC_URL, labels.BFF_PUBLIC_URL ?? exports.API_PUBLIC_URL_VAR, basePath);
116
+ return { env: apiEnv, labels };
117
+ }
118
+ function resolveAgentUrl(aliases, withApi) {
119
+ if (!withApi) {
120
+ aliases.ignore(AGENT_URL_ALIASES, `the api service is off: use ${exports.AGENT_URL_VAR}`);
121
+ }
122
+ const agentUrl = aliases.resolve(exports.AGENT_URL_VAR, withApi ? AGENT_URL_ALIASES : []);
123
+ assertAgentUrl(agentUrl);
124
+ return agentUrl;
125
+ }
126
+ function parseOpenApiEnv(env) {
127
+ const basePath = (0, mcp_server_1.normalizeMountPath)(env[exports.BASE_PATH_VAR], exports.BASE_PATH_VAR);
128
+ const aliases = new env_aliases_1.default(env);
129
+ const api = resolveApi(env, aliases, basePath, resolveAgentUrl(aliases, true));
130
+ return { basePath, api, warnings: aliases.warnings };
131
+ }
132
+ function resolvePort(aliases, withMcp) {
133
+ return parsePort(aliases.resolve(exports.PORT_VAR, PORT_ALIASES), withMcp ? exports.DEFAULT_MCP_PORT : exports.DEFAULT_API_PORT);
134
+ }
135
+ function resolveListenPort(env) {
136
+ return resolvePort(new env_aliases_1.default(env), parseServices(env[exports.SERVICES_VAR]).has('mcp'));
137
+ }
138
+ function parseGatewayEnv(env) {
139
+ const services = parseServices(env[exports.SERVICES_VAR]);
140
+ const withMcp = services.has('mcp');
141
+ const withApi = services.has('api');
142
+ const basePath = (0, mcp_server_1.normalizeMountPath)(env[exports.BASE_PATH_VAR], exports.BASE_PATH_VAR);
143
+ const aliases = new env_aliases_1.default(env);
144
+ const port = resolvePort(aliases, withMcp);
145
+ if (!withMcp) {
146
+ aliases.ignore([exports.PUBLIC_URL_VAR, ...PUBLIC_URL_ALIASES], `the mcp service is off: the API reads ${exports.API_PUBLIC_URL_VAR}`);
147
+ }
148
+ const publicUrl = withMcp
149
+ ? parseGatewayUrl(aliases.resolve(exports.PUBLIC_URL_VAR, PUBLIC_URL_ALIASES))
150
+ : undefined;
151
+ const agentUrl = resolveAgentUrl(aliases, withApi);
152
+ const allowedOAuthClients = aliases.resolve(exports.ALLOWED_OAUTH_CLIENTS_VAR, ALLOWED_OAUTH_CLIENTS_ALIASES, { blankIsSet: true });
153
+ const allowedClientDomains = parseAllowedOAuthClients(allowedOAuthClients);
154
+ if (withMcp && port === 0 && !publicUrl) {
155
+ throw new agent_bff_1.ConfigurationError(`${exports.PORT_VAR}=0 binds a port chosen by the OS, which cannot be in the url advertised to MCP ` +
156
+ `clients. Set ${exports.PUBLIC_URL_VAR} to the public url they should use.`);
157
+ }
158
+ if (withMcp && !publicUrl) {
159
+ aliases.warnings.push(`${exports.PUBLIC_URL_VAR} is not set: MCP clients are told http://localhost:${port}`);
160
+ }
161
+ const mcp = withMcp
162
+ ? {
163
+ env: {
164
+ ...env,
165
+ FOREST_AGENT_URL: agentUrl.value,
166
+ FOREST_MCP_ALLOWED_OAUTH_CLIENTS: allowedOAuthClients.value,
167
+ [mcp_server_1.MCP_LISTENER_ENV.port]: undefined,
168
+ [mcp_server_1.MCP_LISTENER_ENV.publicUrl]: undefined,
169
+ },
170
+ labels: { ...MCP_LABELS, agentUrl: agentUrl.key },
171
+ }
172
+ : undefined;
173
+ const api = withApi
174
+ ? {
175
+ ...resolveApi(env, aliases, basePath, agentUrl),
176
+ allowedOAuthClients: allowedClientDomains,
177
+ }
178
+ : undefined;
179
+ return { services, basePath, port, publicUrl, mcp, api, warnings: aliases.warnings };
180
+ }
181
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2F0ZXdheS1lbnYuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZ2F0ZXdheS1lbnYudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBOEVBLHNDQWNDO0FBRUQsa0NBRUM7QUEwR0QsMENBTUM7QUFTRCw4Q0FFQztBQUVELGtDQTJEQztBQXBSRCxzREFBeUY7QUFDekYsd0VBQXVGO0FBQ3ZGLHdEQUErRTtBQUUvRSxnRUFBdUM7QUFJMUIsUUFBQSxRQUFRLEdBQXVCLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDO0FBRTlDLFFBQUEsWUFBWSxHQUFHLHlCQUF5QixDQUFDO0FBQ3pDLFFBQUEsYUFBYSxHQUFHLDBCQUEwQixDQUFDO0FBQzNDLFFBQUEsY0FBYyxHQUFHLG9CQUFvQixDQUFDO0FBQ3RDLFFBQUEsUUFBUSxHQUFHLE1BQU0sQ0FBQztBQUNsQixRQUFBLGFBQWEsR0FBRyxrQkFBa0IsQ0FBQztBQUNuQyxRQUFBLGtCQUFrQixHQUFHLCtCQUErQixDQUFDO0FBQ3JELFFBQUEseUJBQXlCLEdBQUcsc0NBQXNDLENBQUM7QUFFaEYsTUFBTSxjQUFjLEdBQUcscUJBQXFCLENBQUM7QUFDN0MsTUFBTSxjQUFjLEdBQUcsTUFBTSxDQUFDO0FBRTlCLE1BQU0sZ0JBQWdCLEdBQUc7SUFDdkIsSUFBSSxFQUFFLFdBQVc7SUFDakIsU0FBUyxFQUFFLGdCQUFnQjtDQUNpQixDQUFDO0FBRS9DLE1BQU0sWUFBWSxHQUFHLENBQUMsNkJBQWdCLENBQUMsSUFBSSxFQUFFLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO0FBQ3BFLE1BQU0sa0JBQWtCLEdBQUcsQ0FBQyw2QkFBZ0IsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN4RCxNQUFNLGlCQUFpQixHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7QUFDeEMsTUFBTSw2QkFBNkIsR0FBRyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7QUFFM0UsTUFBTSxVQUFVLEdBQTBCO0lBQ3hD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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export default function probeHealth(env: NodeJS.ProcessEnv, timeoutMs?: number): Promise<string | undefined>;
3
+ //# sourceMappingURL=healthcheck.d.ts.map
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.default = probeHealth;
8
+ const http_1 = __importDefault(require("http"));
9
+ const gateway_env_1 = require("./gateway-env");
10
+ const standalone_handler_1 = require("./standalone-handler");
11
+ const HTTP_OK = 200;
12
+ const PROBE_TIMEOUT_MS = 4000;
13
+ async function probeHealth(env, timeoutMs = PROBE_TIMEOUT_MS) {
14
+ let port;
15
+ try {
16
+ port = (0, gateway_env_1.resolveListenPort)(env);
17
+ }
18
+ catch (error) {
19
+ return error.message;
20
+ }
21
+ if (port === 0)
22
+ return 'PORT=0 binds a port chosen by the OS, which cannot be probed';
23
+ return new Promise(resolve => {
24
+ const request = http_1.default.get({ host: 'localhost', port, path: standalone_handler_1.HEALTH_PATH, timeout: timeoutMs }, response => {
25
+ response.resume();
26
+ resolve(response.statusCode === HTTP_OK
27
+ ? undefined
28
+ : `${standalone_handler_1.HEALTH_PATH} on port ${port} answered ${response.statusCode}`);
29
+ });
30
+ request.on('timeout', () => request.destroy(new Error(`timed out after ${timeoutMs}ms`)));
31
+ request.on('error', (error) => resolve(`${standalone_handler_1.HEALTH_PATH} on port ${port}: ${error.code ?? error.message}`));
32
+ });
33
+ }
34
+ /* istanbul ignore next */
35
+ if (require.main === module) {
36
+ probeHealth(process.env).then(failure => {
37
+ if (failure === undefined)
38
+ return;
39
+ process.stderr.write(`${failure}\n`);
40
+ process.exitCode = 1;
41
+ });
42
+ }
43
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVhbHRoY2hlY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaGVhbHRoY2hlY2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBU0EsOEJBZ0NDO0FBeENELGdEQUF3QjtBQUV4QiwrQ0FBa0Q7QUFDbEQsNkRBQW1EO0FBRW5ELE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQztBQUNwQixNQUFNLGdCQUFnQixHQUFHLElBQUksQ0FBQztBQUVmLEtBQUssVUFBVSxXQUFXLENBQ3ZDLEdBQXNCLEVBQ3RCLFNBQVMsR0FBRyxnQkFBZ0I7SUFFNUIsSUFBSSxJQUFZLENBQUM7SUFFakIsSUFBSSxDQUFDO1FBQ0gsSUFBSSxHQUFHLElBQUEsK0JBQWlCLEVBQUMsR0FBRyxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7UUFDZixPQUFRLEtBQWUsQ0FBQyxPQUFPLENBQUM7SUFDbEMsQ0FBQztJQUVELElBQUksSUFBSSxLQUFLLENBQUM7UUFBRSxPQUFPLDhEQUE4RCxDQUFDO0lBRXRGLE9BQU8sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7UUFDM0IsTUFBTSxPQUFPLEdBQUcsY0FBSSxDQUFDLEdBQUcsQ0FDdEIsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsZ0NBQVcsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEVBQ2xFLFFBQVEsQ0FBQyxFQUFFO1lBQ1QsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2xCLE9BQU8sQ0FDTCxRQUFRLENBQUMsVUFBVSxLQUFLLE9BQU87Z0JBQzdCLENBQUMsQ0FBQyxTQUFTO2dCQUNYLENBQUMsQ0FBQyxHQUFHLGdDQUFXLFlBQVksSUFBSSxhQUFhLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FDckUsQ0FBQztRQUNKLENBQUMsQ0FDRixDQUFDO1FBRUYsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsU0FBUyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUYsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUE0QixFQUFFLEVBQUUsQ0FDbkQsT0FBTyxDQUFDLEdBQUcsZ0NBQVcsWUFBWSxJQUFJLEtBQUssS0FBSyxDQUFDLElBQUksSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FDMUUsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELDBCQUEwQjtBQUMxQixJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssTUFBTSxFQUFFLENBQUM7SUFDNUIsV0FBVyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUU7UUFDdEMsSUFBSSxPQUFPLEtBQUssU0FBUztZQUFFLE9BQU87UUFFbEMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxPQUFPLElBQUksQ0FBQyxDQUFDO1FBQ3JDLE9BQU8sQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDO0lBQ3ZCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyJ9
@@ -0,0 +1,8 @@
1
+ export { default as runGateway, GATEWAY_NAME } from './run-gateway';
2
+ export { default as dispatchCli } from './cli-dispatch';
3
+ export { default as parseGatewayEnv, parseServices, DEFAULT_API_PORT, DEFAULT_MCP_PORT, } from './gateway-env';
4
+ export type { GatewayEnv, Service } from './gateway-env';
5
+ export { GATEWAY_VERSION_HEADER } from './standalone-handler';
6
+ export type { GatewayHealth } from './standalone-handler';
7
+ export { default as version } from './version';
8
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,21 @@
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.version = exports.GATEWAY_VERSION_HEADER = exports.DEFAULT_MCP_PORT = exports.DEFAULT_API_PORT = exports.parseServices = exports.parseGatewayEnv = exports.dispatchCli = exports.GATEWAY_NAME = exports.runGateway = void 0;
7
+ var run_gateway_1 = require("./run-gateway");
8
+ Object.defineProperty(exports, "runGateway", { enumerable: true, get: function () { return __importDefault(run_gateway_1).default; } });
9
+ Object.defineProperty(exports, "GATEWAY_NAME", { enumerable: true, get: function () { return run_gateway_1.GATEWAY_NAME; } });
10
+ var cli_dispatch_1 = require("./cli-dispatch");
11
+ Object.defineProperty(exports, "dispatchCli", { enumerable: true, get: function () { return __importDefault(cli_dispatch_1).default; } });
12
+ var gateway_env_1 = require("./gateway-env");
13
+ Object.defineProperty(exports, "parseGatewayEnv", { enumerable: true, get: function () { return __importDefault(gateway_env_1).default; } });
14
+ Object.defineProperty(exports, "parseServices", { enumerable: true, get: function () { return gateway_env_1.parseServices; } });
15
+ Object.defineProperty(exports, "DEFAULT_API_PORT", { enumerable: true, get: function () { return gateway_env_1.DEFAULT_API_PORT; } });
16
+ Object.defineProperty(exports, "DEFAULT_MCP_PORT", { enumerable: true, get: function () { return gateway_env_1.DEFAULT_MCP_PORT; } });
17
+ var standalone_handler_1 = require("./standalone-handler");
18
+ Object.defineProperty(exports, "GATEWAY_VERSION_HEADER", { enumerable: true, get: function () { return standalone_handler_1.GATEWAY_VERSION_HEADER; } });
19
+ var version_1 = require("./version");
20
+ Object.defineProperty(exports, "version", { enumerable: true, get: function () { return __importDefault(version_1).default; } });
21
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsNkNBQW9FO0FBQTNELDBIQUFBLE9BQU8sT0FBYztBQUFFLDJHQUFBLFlBQVksT0FBQTtBQUM1QywrQ0FBd0Q7QUFBL0MsNEhBQUEsT0FBTyxPQUFlO0FBQy9CLDZDQUt1QjtBQUpyQiwrSEFBQSxPQUFPLE9BQW1CO0FBQzFCLDRHQUFBLGFBQWEsT0FBQTtBQUNiLCtHQUFBLGdCQUFnQixPQUFBO0FBQ2hCLCtHQUFBLGdCQUFnQixPQUFBO0FBR2xCLDJEQUE4RDtBQUFyRCw0SEFBQSxzQkFBc0IsT0FBQTtBQUUvQixxQ0FBK0M7QUFBdEMsbUhBQUEsT0FBTyxPQUFXIn0=
@@ -0,0 +1,6 @@
1
+ import type { Logger } from '@forestadmin/agent-bff';
2
+ import { BFFHttpServer } from '@forestadmin/agent-bff';
3
+ export declare const GATEWAY_NAME = "Forest Gateway";
4
+ export declare const GATEWAY_API_NAME = "Gateway API";
5
+ export default function runGateway(env: NodeJS.ProcessEnv, logger?: Logger): Promise<BFFHttpServer>;
6
+ //# sourceMappingURL=run-gateway.d.ts.map