@forestadmin/agent-bff 1.15.1 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -1
- package/dist/cli-core.d.ts +3 -0
- package/dist/cli-core.js +69 -10
- package/dist/cli-dispatch.d.ts +8 -2
- package/dist/cli-dispatch.js +90 -9
- package/dist/data/agent-query.d.ts +2 -0
- package/dist/data/agent-query.js +28 -17
- package/dist/data/data-routes-middleware.js +66 -26
- package/dist/data/pack-id.d.ts +1 -0
- package/dist/data/pack-id.js +4 -3
- package/dist/http/agent-error-mapper.js +15 -7
- package/dist/http/bff-http-error.d.ts +6 -1
- package/dist/http/bff-http-error.js +5 -4
- package/dist/http/bff-local-errors.d.ts +2 -0
- package/dist/http/bff-local-errors.js +12 -4
- package/dist/openapi/collect-unfolding.d.ts +23 -0
- package/dist/openapi/collect-unfolding.js +144 -0
- package/dist/openapi/component-pool.d.ts +18 -0
- package/dist/openapi/component-pool.js +28 -0
- package/dist/openapi/field-schemas.d.ts +9 -0
- package/dist/openapi/field-schemas.js +43 -0
- package/dist/openapi/names.d.ts +16 -0
- package/dist/openapi/names.js +28 -0
- package/dist/openapi/openapi-document.d.ts +2 -1
- package/dist/openapi/openapi-document.js +112 -66
- package/dist/openapi/openapi-routes.d.ts +4 -1
- package/dist/openapi/openapi-routes.js +46 -9
- package/dist/openapi/schemas.d.ts +14 -1
- package/dist/openapi/schemas.js +11 -10
- package/dist/openapi/unfolded-document.d.ts +28 -0
- package/dist/openapi/unfolded-document.js +52 -0
- package/dist/openapi/unfolded-paths.d.ts +20 -0
- package/dist/openapi/unfolded-paths.js +408 -0
- package/dist/openapi/unfolding.d.ts +66 -0
- package/dist/openapi/unfolding.js +17 -0
- package/dist/permissions/build-permission-hints.d.ts +40 -0
- package/dist/permissions/build-permission-hints.js +73 -0
- package/dist/permissions/can-role-perform.d.ts +12 -0
- package/dist/permissions/can-role-perform.js +18 -0
- package/dist/permissions/permissions-cache.d.ts +24 -0
- package/dist/permissions/permissions-cache.js +51 -0
- package/dist/permissions/permissions-client.d.ts +21 -0
- package/dist/permissions/permissions-client.js +27 -0
- package/dist/permissions/permissions-routes-middleware.d.ts +13 -0
- package/dist/permissions/permissions-routes-middleware.js +99 -0
- package/dist/read-model/agent-capabilities-fetcher.d.ts +8 -3
- package/dist/read-model/agent-capabilities-fetcher.js +15 -7
- package/dist/read-model/capabilities-cache.d.ts +11 -1
- package/dist/read-model/capabilities-cache.js +1 -1
- package/dist/read-model/read-model.d.ts +15 -0
- package/dist/read-model/read-model.js +39 -2
- package/dist/validation/capabilities-validator.d.ts +9 -0
- package/dist/validation/capabilities-validator.js +3 -1
- package/dist/validation/operator-normalizer.d.ts +6 -0
- package/dist/validation/operator-normalizer.js +11 -1
- package/dist/validation/validation-errors.js +7 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -25,6 +25,20 @@ forest-bff openapi --output # writes ./openapi.json
|
|
|
25
25
|
forest-bff openapi --output docs/api.json # writes that path
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
The document comes in two forms, and the command picks one from the environment:
|
|
29
|
+
|
|
30
|
+
- **Unfolded** when `FOREST_SERVER_URL`, `FOREST_ENV_SECRET`, `FOREST_AUTH_SECRET` and `AGENT_URL`
|
|
31
|
+
are all set: one path per exposed collection, per to-many relation and per action, each carrying
|
|
32
|
+
the collection's real field set. This is the form to generate a client from. The command reads the
|
|
33
|
+
Forest schema and asks the agent for each collection's capabilities, signing its own short-lived
|
|
34
|
+
agent token with `FOREST_AUTH_SECRET`. A deployment configured this way but whose schema cannot be
|
|
35
|
+
read exits 1 rather than emitting the generic document, which would look like a complete answer.
|
|
36
|
+
- **Generic** when that configuration is absent: the six runtime routes with `{collection}`,
|
|
37
|
+
`{relation}` and `{action}` as path parameters and no field enumerated. `info.description` says
|
|
38
|
+
which form the document is.
|
|
39
|
+
|
|
40
|
+
Either way the runtime routes stay generic — only the document unfolds.
|
|
41
|
+
|
|
28
42
|
`--output` takes the next argument as the destination unless it is empty or starts with
|
|
29
43
|
`-`; the default `openapi.json` is written only when `--output` is the last argument, and
|
|
30
44
|
a leftover token is rejected like any other extra. A missing parent directory is created,
|
|
@@ -58,7 +72,7 @@ yarn start:dev # node --env-file=.env dist/cli.js
|
|
|
58
72
|
| `HTTP_PORT` | no | Server port, integer 0–65535. Defaults to `3450`. `0` binds an OS-assigned ephemeral port. |
|
|
59
73
|
| `BFF_ALLOWED_ORIGINS`| no | Comma-separated CORS allow-list of exact origins (scheme + host + port). No wildcard. Empty ⇒ no cross-origin browser access. |
|
|
60
74
|
| `BFF_DEFAULT_TIMEZONE`| no | Fallback IANA timezone used when a request carries neither an `X-Forest-Timezone` header nor a body `timezone`. |
|
|
61
|
-
| `BFF_OPENAPI_ENABLED` | no | Serve `GET/HEAD /agent/openapi.json` (auth-gated) when `true`. Defaults to `true`. Set to `false` for customers who do not want the HTTP surface exposed: an authenticated `GET`/`HEAD` then gets `404 openapi_disabled`, other methods fall through to the agent routes exactly as they do when enabled, and `forest-bff openapi` keeps working either way. Accepted values: `true`/`false`. |
|
|
75
|
+
| `BFF_OPENAPI_ENABLED` | no | Serve `GET/HEAD /agent/openapi.json` (auth-gated) when `true`. Defaults to `true`. Set to `false` for customers who do not want the HTTP surface exposed: an authenticated `GET`/`HEAD` then gets `404 openapi_disabled`, other methods fall through to the agent routes exactly as they do when enabled, and `forest-bff openapi` keeps working either way. Accepted values: `true`/`false`. **The served document is unfolded and is not filtered per caller**: any authenticated caller, whatever their role, reads the name of every exposed collection, relation and field. Set this to `false` if that surface must not be reachable over HTTP. |
|
|
62
76
|
|
|
63
77
|
### Config validation
|
|
64
78
|
|
package/dist/cli-core.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import type { BFFConfig } from './config/env-config';
|
|
2
|
+
import type { UnfoldSource } from './openapi/unfolded-document';
|
|
1
3
|
import type { Logger } from './ports/logger-port';
|
|
2
4
|
import BFFHttpServer from './http/bff-http-server';
|
|
5
|
+
export declare function resolveUnfoldSource(config: BFFConfig, logger: Logger): UnfoldSource | undefined;
|
|
3
6
|
export default function runCli(env: NodeJS.ProcessEnv, logger?: Logger): Promise<BFFHttpServer>;
|
|
4
7
|
export declare function reportFatalError(err: unknown): void;
|
|
5
8
|
//# sourceMappingURL=cli-core.d.ts.map
|
package/dist/cli-core.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resolveUnfoldSource = resolveUnfoldSource;
|
|
6
7
|
exports.default = runCli;
|
|
7
8
|
exports.reportFatalError = reportFatalError;
|
|
8
9
|
const bodyparser_1 = require("@koa/bodyparser");
|
|
@@ -28,6 +29,9 @@ const oauth_routes_1 = __importDefault(require("./oauth/oauth-routes"));
|
|
|
28
29
|
const session_store_1 = __importDefault(require("./oauth/session-store"));
|
|
29
30
|
const token_cipher_1 = __importDefault(require("./oauth/token-cipher"));
|
|
30
31
|
const openapi_routes_1 = __importDefault(require("./openapi/openapi-routes"));
|
|
32
|
+
const permissions_cache_1 = __importDefault(require("./permissions/permissions-cache"));
|
|
33
|
+
const permissions_client_1 = __importDefault(require("./permissions/permissions-client"));
|
|
34
|
+
const permissions_routes_middleware_1 = __importDefault(require("./permissions/permissions-routes-middleware"));
|
|
31
35
|
const create_read_model_1 = __importDefault(require("./read-model/create-read-model"));
|
|
32
36
|
const timezone_middleware_1 = __importDefault(require("./timezone/timezone-middleware"));
|
|
33
37
|
const version_1 = __importDefault(require("./version"));
|
|
@@ -113,21 +117,72 @@ function buildApiKeyMiddleware(config, logger) {
|
|
|
113
117
|
});
|
|
114
118
|
return (0, api_key_middleware_1.default)({ authenticator, logger });
|
|
115
119
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
/**
|
|
121
|
+
* The read-model store the data routes, the action routes, the permissions endpoint and the OpenAPI
|
|
122
|
+
* unfolding all share — one cache, one schema fetch. Needs no agent: the permissions endpoint and the
|
|
123
|
+
* schema itself come from the SaaS.
|
|
124
|
+
*/
|
|
125
|
+
function resolveReadModelBundle(config, logger, metrics) {
|
|
119
126
|
const apiKeyConfig = resolveApiKeyConfig(config);
|
|
120
|
-
if (!apiKeyConfig
|
|
121
|
-
|
|
122
|
-
return [(0, agent_stub_1.default)()];
|
|
123
|
-
}
|
|
127
|
+
if (!apiKeyConfig)
|
|
128
|
+
return undefined;
|
|
124
129
|
const { store } = (0, create_read_model_1.default)({
|
|
125
130
|
forestServerUrl: apiKeyConfig.forestServerUrl,
|
|
126
131
|
envSecret: apiKeyConfig.forestEnvSecret,
|
|
127
132
|
logger,
|
|
133
|
+
metrics,
|
|
128
134
|
});
|
|
135
|
+
return { store, apiKeyConfig };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* When unfolding is possible, in ONE place: the document needs the AGENT_URL the store does not,
|
|
139
|
+
* because a collection's field set comes from the agent capabilities. The server passes the bundle it
|
|
140
|
+
* already built for the data routes; the CLI goes through `resolveUnfoldSource`. Silent on purpose —
|
|
141
|
+
* the two report a missing configuration differently.
|
|
142
|
+
*/
|
|
143
|
+
function toUnfoldSource(bundle, config, logger) {
|
|
144
|
+
if (!bundle || !config.agentUrl)
|
|
145
|
+
return undefined;
|
|
146
|
+
return {
|
|
147
|
+
store: bundle.store,
|
|
148
|
+
agentUrl: config.agentUrl,
|
|
149
|
+
timeoutMs: config.agentTimeoutMs,
|
|
150
|
+
logger,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Metrics are dropped rather than logged: without an explicit sink `createReadModel` builds a console
|
|
155
|
+
* one, which reports gauges at `Info`, and `createConsoleLogger` sends `Info` to `console.info` — the
|
|
156
|
+
* stdout the document is written to. The server keeps its metrics; the export has no sink for them
|
|
157
|
+
* anyway.
|
|
158
|
+
*/
|
|
159
|
+
const UNMEASURED = { increment: () => undefined, gauge: () => undefined };
|
|
160
|
+
function resolveUnfoldSource(config, logger) {
|
|
161
|
+
return toUnfoldSource(resolveReadModelBundle(config, logger, UNMEASURED), config, logger);
|
|
162
|
+
}
|
|
163
|
+
// The data middleware falls through to the action middleware on a non-data path.
|
|
164
|
+
function buildAgentRouteMiddlewares(bundle, config, logger) {
|
|
165
|
+
if (!bundle) {
|
|
166
|
+
logger('Warn', 'Data, action and permissions endpoints disabled: FOREST_SERVER_URL, FOREST_ENV_SECRET or FOREST_AUTH_SECRET is missing');
|
|
167
|
+
return [(0, agent_stub_1.default)()];
|
|
168
|
+
}
|
|
169
|
+
const { store, apiKeyConfig } = bundle;
|
|
129
170
|
const { agentUrl, agentTimeoutMs: timeoutMs } = config;
|
|
171
|
+
const permissionsMiddleware = (0, permissions_routes_middleware_1.default)({
|
|
172
|
+
store,
|
|
173
|
+
client: new permissions_client_1.default({
|
|
174
|
+
forestServerUrl: apiKeyConfig.forestServerUrl,
|
|
175
|
+
envSecret: apiKeyConfig.forestEnvSecret,
|
|
176
|
+
}),
|
|
177
|
+
cache: new permissions_cache_1.default(),
|
|
178
|
+
logger,
|
|
179
|
+
});
|
|
180
|
+
if (!agentUrl) {
|
|
181
|
+
logger('Warn', 'Data and action endpoints disabled: AGENT_URL is missing');
|
|
182
|
+
return [permissionsMiddleware, (0, agent_stub_1.default)()];
|
|
183
|
+
}
|
|
130
184
|
return [
|
|
185
|
+
permissionsMiddleware,
|
|
131
186
|
(0, data_routes_middleware_1.default)({ store, agentUrl, timeoutMs, logger }),
|
|
132
187
|
(0, action_routes_middleware_1.default)({ store, agentUrl, timeoutMs, logger }),
|
|
133
188
|
];
|
|
@@ -139,13 +194,17 @@ function buildAgentMiddlewares(config, logger) {
|
|
|
139
194
|
return [];
|
|
140
195
|
}
|
|
141
196
|
const apiKeyStep = buildApiKeyMiddleware(config, logger) ?? createApiKeyUnavailableGuard(logger);
|
|
197
|
+
// One store for the whole edge. The document only unfolds when the agent is reachable too: with no
|
|
198
|
+
// AGENT_URL every data path answers 501, so concrete paths would advertise a dead surface.
|
|
199
|
+
const bundle = resolveReadModelBundle(config, logger);
|
|
200
|
+
const source = toUnfoldSource(bundle, config, logger);
|
|
142
201
|
const chain = [
|
|
143
202
|
(0, auth_mode_middleware_1.default)({ authSecret: forestAuthSecret }),
|
|
144
203
|
apiKeyStep,
|
|
145
204
|
(0, per_key_origin_1.default)(),
|
|
146
|
-
(0, openapi_routes_1.default)({ version: version_1.default, enabled: config.openapiEnabled }),
|
|
205
|
+
(0, openapi_routes_1.default)({ version: version_1.default, enabled: config.openapiEnabled, source }),
|
|
147
206
|
(0, timezone_middleware_1.default)({ defaultTimezone }),
|
|
148
|
-
...buildAgentRouteMiddlewares(config, logger),
|
|
207
|
+
...buildAgentRouteMiddlewares(bundle, config, logger),
|
|
149
208
|
];
|
|
150
209
|
return chain.map(agentScoped);
|
|
151
210
|
}
|
|
@@ -180,4 +239,4 @@ function reportFatalError(err) {
|
|
|
180
239
|
process.stderr.write(`Error: ${(0, errors_1.extractErrorMessage)(err)}\n`);
|
|
181
240
|
process.exitCode = 1;
|
|
182
241
|
}
|
|
183
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
242
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWNvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2xpLWNvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUE4TkEsa0RBRUM7QUFzRUQseUJBa0NDO0FBRUQsNENBR0M7QUF0VUQsZ0RBQTZDO0FBRTdDLGlHQUE2RTtBQUM3RSwrRUFBNEQ7QUFDNUQsb0VBQTJEO0FBQzNELDRGQUF3RTtBQUN4RSw4RUFBb0Q7QUFDcEQsc0ZBQWtFO0FBQ2xFLDRFQUF5RDtBQUN6RCx1RkFBbUU7QUFDbkUsb0RBQWtEO0FBQ2xELDZFQUEwRDtBQUMxRCwyRUFBaUU7QUFDakUsMkZBQXVFO0FBQ3ZFLHFDQUErQztBQUMvQywwREFBcUQ7QUFDckQsNkVBQW1EO0FBQ25ELG1FQUEyQztBQUMzQywrRUFBNEQ7QUFDNUQsd0ZBQThEO0FBQzlELHdFQUFxRDtBQUNyRCwwRUFBK0Q7QUFDL0Qsd0VBQXFEO0FBQ3JELDhFQUEyRDtBQUMzRCx3RkFBK0Q7QUFDL0QsMEZBQWlFO0FBQ2pFLGdIQUE0RjtBQUM1Rix1RkFBNkQ7QUFDN0QseUZBQXNFO0FBQ3RFLHdEQUFnQztBQUVoQyxNQUFNLG1CQUFtQixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDO0FBRXpDLFNBQVMsV0FBVyxDQUFDLElBQVk7SUFDL0IsT0FBTyxJQUFJLEtBQUssUUFBUSxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUM7QUFDekQsQ0FBQztBQUVELFNBQVMsV0FBVyxDQUFDLFVBQXNCO0lBQ3pDLE9BQU8sS0FBSyxVQUFVLE1BQU0sQ0FBQyxHQUFHLEVBQUUsSUFBSTtRQUNwQyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzNCLE1BQU0sSUFBSSxFQUFFLENBQUM7WUFFYixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sVUFBVSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQztJ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
|
package/dist/cli-dispatch.d.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import type BFFHttpServer from './http/bff-http-server';
|
|
2
2
|
import type { Logger } from './ports/logger-port';
|
|
3
3
|
export declare const DEFAULT_OUTPUT_FILE = "openapi.json";
|
|
4
|
-
export declare const USAGE = "Usage: forest-bff [command]\n\nCommands:\n (none) Start the BFF server, configured from the environment.\n openapi Write the OpenAPI document to stdout. Needs no configuration.\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.";
|
|
4
|
+
export declare const USAGE = "Usage: forest-bff [command]\n\nCommands:\n (none) Start the BFF server, configured from the environment.\n openapi Write the OpenAPI document to stdout. Needs no configuration, but\n a deployment configured to reach its Forest schema and its agent\n (FOREST_SERVER_URL, FOREST_ENV_SECRET, FOREST_AUTH_SECRET,\n AGENT_URL) unfolds one path per collection, relation and action\n instead of the generic ones.\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.";
|
|
5
5
|
export declare const HINT = "Run 'forest-bff --help' for usage.";
|
|
6
6
|
export interface DispatchOutcome {
|
|
7
7
|
exitCode: number;
|
|
8
8
|
server?: BFFHttpServer;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Unfolds when the deployment is configured to be inspected, and emits the generic document when it
|
|
12
|
+
* is not configured at all — the command keeps working without configuration. A deployment that IS
|
|
13
|
+
* configured but whose schema cannot be read fails instead of quietly degrading: it asked for the
|
|
14
|
+
* unfolded document, and a generic one would look like a complete answer.
|
|
15
|
+
*/
|
|
16
|
+
export declare function renderOpenApi(env: NodeJS.ProcessEnv, logger: Logger): Promise<string>;
|
|
11
17
|
export default function dispatchCli(argv: string[], env: NodeJS.ProcessEnv, logger?: Logger): Promise<DispatchOutcome>;
|
|
12
18
|
//# sourceMappingURL=cli-dispatch.d.ts.map
|
package/dist/cli-dispatch.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -8,9 +41,13 @@ exports.renderOpenApi = renderOpenApi;
|
|
|
8
41
|
exports.default = dispatchCli;
|
|
9
42
|
const fs_1 = require("fs");
|
|
10
43
|
const path_1 = __importDefault(require("path"));
|
|
11
|
-
const
|
|
44
|
+
const console_logger_1 = __importDefault(require("./adapters/console-logger"));
|
|
45
|
+
const cli_core_1 = __importStar(require("./cli-core"));
|
|
46
|
+
const env_config_1 = require("./config/env-config");
|
|
12
47
|
const errors_1 = require("./errors");
|
|
13
48
|
const openapi_document_1 = require("./openapi/openapi-document");
|
|
49
|
+
const unfolded_document_1 = __importStar(require("./openapi/unfolded-document"));
|
|
50
|
+
const unfolding_1 = require("./openapi/unfolding");
|
|
14
51
|
const version_1 = __importDefault(require("./version"));
|
|
15
52
|
exports.DEFAULT_OUTPUT_FILE = 'openapi.json';
|
|
16
53
|
const OUTPUT_FLAG = '--output';
|
|
@@ -18,7 +55,11 @@ exports.USAGE = `Usage: forest-bff [command]
|
|
|
18
55
|
|
|
19
56
|
Commands:
|
|
20
57
|
(none) Start the BFF server, configured from the environment.
|
|
21
|
-
openapi Write the OpenAPI document to stdout. Needs no configuration
|
|
58
|
+
openapi Write the OpenAPI document to stdout. Needs no configuration, but
|
|
59
|
+
a deployment configured to reach its Forest schema and its agent
|
|
60
|
+
(FOREST_SERVER_URL, FOREST_ENV_SECRET, FOREST_AUTH_SECRET,
|
|
61
|
+
AGENT_URL) unfolds one path per collection, relation and action
|
|
62
|
+
instead of the generic ones.
|
|
22
63
|
--output [file] Write to a file instead of stdout, defaulting
|
|
23
64
|
to ${exports.DEFAULT_OUTPUT_FILE} in the current directory.
|
|
24
65
|
|
|
@@ -28,8 +69,47 @@ Options:
|
|
|
28
69
|
exports.HINT = "Run 'forest-bff --help' for usage.";
|
|
29
70
|
const HELP_FLAGS = new Set(['-h', '--help']);
|
|
30
71
|
const VERSION_FLAGS = new Set(['-v', '--version']);
|
|
31
|
-
|
|
32
|
-
|
|
72
|
+
const UNFOLD_VARS = [
|
|
73
|
+
'FOREST_SERVER_URL',
|
|
74
|
+
'FOREST_ENV_SECRET',
|
|
75
|
+
'FOREST_AUTH_SECRET',
|
|
76
|
+
'AGENT_URL',
|
|
77
|
+
];
|
|
78
|
+
const NOTHING_TO_UNFOLD = `${UNFOLD_VARS.join(', ')} must all be set to unfold it`;
|
|
79
|
+
function wantsUnfolding(env) {
|
|
80
|
+
return UNFOLD_VARS.every(name => (env[name] ?? '').trim() !== '');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Unfolds when the deployment is configured to be inspected, and emits the generic document when it
|
|
84
|
+
* is not configured at all — the command keeps working without configuration. A deployment that IS
|
|
85
|
+
* configured but whose schema cannot be read fails instead of quietly degrading: it asked for the
|
|
86
|
+
* unfolded document, and a generic one would look like a complete answer.
|
|
87
|
+
*/
|
|
88
|
+
async function renderOpenApi(env, logger) {
|
|
89
|
+
const authSecret = env.FOREST_AUTH_SECRET;
|
|
90
|
+
// `parseConfig` validates the WHOLE server configuration, including settings the export has nothing
|
|
91
|
+
// to do with (HTTP_PORT, the OAuth keys, the default timezone). A deployment that never asked for an
|
|
92
|
+
// unfolded document must not see its export die on one of those, so the config is parsed only once
|
|
93
|
+
// the four variables unfolding needs are all present — and from there a bad value is a real failure.
|
|
94
|
+
const unfoldable = authSecret && wantsUnfolding(env)
|
|
95
|
+
? { source: (0, cli_core_1.resolveUnfoldSource)((0, env_config_1.parseConfig)(env), logger), authSecret }
|
|
96
|
+
: undefined;
|
|
97
|
+
if (!unfoldable?.source) {
|
|
98
|
+
logger('Warn', `Emitting the generic OpenAPI document: ${NOTHING_TO_UNFOLD}`);
|
|
99
|
+
return `${(0, openapi_document_1.serializeOpenApi)((0, openapi_document_1.generateOpenApiDocument)(version_1.default))}\n`;
|
|
100
|
+
}
|
|
101
|
+
const { source } = unfoldable;
|
|
102
|
+
const readModel = await source.store.getReadModel();
|
|
103
|
+
const { document, unfolding } = await (0, unfolded_document_1.default)(source, readModel, () => (0, unfolded_document_1.issueOpenApiAgentToken)(unfoldable.authSecret), version_1.default);
|
|
104
|
+
// Not one collection came back with its field set, so the agent was unreachable throughout. The
|
|
105
|
+
// paths are real but every field schema is free-form, which is not the document this command
|
|
106
|
+
// promises — a CI job regenerating it needs something to branch on, and the degraded notes buried
|
|
107
|
+
// in the descriptions are not it. One odd collection stays a warning, not a failure.
|
|
108
|
+
if ((0, unfolding_1.isFullyDegraded)(unfolding)) {
|
|
109
|
+
throw new Error('No collection could be described: the agent answered no capabilities call, so every field ' +
|
|
110
|
+
'schema in the document would be free-form. Check AGENT_URL and the agent, then retry.');
|
|
111
|
+
}
|
|
112
|
+
return `${document}\n`;
|
|
33
113
|
}
|
|
34
114
|
function rejectCli(reason) {
|
|
35
115
|
process.stderr.write(`${reason}\n${exports.HINT}\n`);
|
|
@@ -46,12 +126,12 @@ function parseOutputOption(rest) {
|
|
|
46
126
|
extras: [...rest.slice(0, index), ...rest.slice(index + (takesValue ? 2 : 1))],
|
|
47
127
|
};
|
|
48
128
|
}
|
|
49
|
-
function writeOpenApiFile(file) {
|
|
129
|
+
function writeOpenApiFile(file, document) {
|
|
50
130
|
const asDirectory = file.endsWith('/') || file.endsWith(path_1.default.sep);
|
|
51
131
|
const destination = path_1.default.resolve(process.cwd(), asDirectory ? path_1.default.join(file, exports.DEFAULT_OUTPUT_FILE) : file);
|
|
52
132
|
try {
|
|
53
133
|
(0, fs_1.mkdirSync)(path_1.default.dirname(destination), { recursive: true });
|
|
54
|
-
(0, fs_1.writeFileSync)(destination,
|
|
134
|
+
(0, fs_1.writeFileSync)(destination, document);
|
|
55
135
|
}
|
|
56
136
|
catch (error) {
|
|
57
137
|
process.stderr.write(`Cannot write ${destination}: ${(0, errors_1.extractErrorMessage)(error)}\n`);
|
|
@@ -82,10 +162,11 @@ async function dispatchCli(argv, env, logger) {
|
|
|
82
162
|
if (extras.length > 0) {
|
|
83
163
|
return rejectCli(`openapi accepts only --output, got: ${extras.map(extra => JSON.stringify(extra)).join(' ')}`);
|
|
84
164
|
}
|
|
165
|
+
const document = await renderOpenApi(env, logger ?? (0, console_logger_1.default)());
|
|
85
166
|
if (file !== undefined) {
|
|
86
|
-
return writeOpenApiFile(file);
|
|
167
|
+
return writeOpenApiFile(file, document);
|
|
87
168
|
}
|
|
88
|
-
process.stdout.write(
|
|
169
|
+
process.stdout.write(document);
|
|
89
170
|
return { exitCode: 0 };
|
|
90
171
|
}
|
|
91
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
172
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWRpc3BhdGNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NsaS1kaXNwYXRjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFnRUEsc0NBdUNDO0FBZ0RELDhCQWdEQztBQXBNRCwyQkFBOEM7QUFDOUMsZ0RBQXdCO0FBRXhCLCtFQUE0RDtBQUM1RCx1REFBeUQ7QUFDekQsb0RBQWtEO0FBQ2xELHFDQUErQztBQUMvQyxpRUFBdUY7QUFDdkYsaUZBQTRGO0FBQzVGLG1EQUFzRDtBQUN0RCx3REFBZ0M7QUFFbkIsUUFBQSxtQkFBbUIsR0FBRyxjQUFjLENBQUM7QUFFbEQsTUFBTSxXQUFXLEdBQUcsVUFBVSxDQUFDO0FBRWxCLFFBQUEsS0FBSyxHQUFHOzs7Ozs7Ozs7O29DQVVlLDJCQUFtQjs7OztvREFJSCxDQUFDO0FBRXhDLFFBQUEsSUFBSSxHQUFHLG9DQUFvQyxDQUFDO0FBRXpELE1BQU0sVUFBVSxHQUFHLElBQUksR0FBRyxDQUFDLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7QUFDN0MsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsV0FBVyxDQUFDLENBQUMsQ0FBQztBQU9uRCxNQUFNLFdBQVcsR0FBRztJQUNsQixtQkFBbUI7SUFDbkIsbUJBQW1CO0lBQ25CLG9CQUFvQjtJQUNwQixXQUFXO0NBQ0gsQ0FBQztBQUVYLE1BQU0saUJBQWlCLEdBQUcsR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQywrQkFBK0IsQ0FBQztBQUVuRixTQUFTLGNBQWMsQ0FBQyxHQUFzQjtJQUM1QyxPQUFPLFdBQVcsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLENB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
|
package/dist/data/agent-query.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MAX_PARSED_FILTER_DEPTH = void 0;
|
|
3
4
|
exports.parseListRequest = parseListRequest;
|
|
4
5
|
exports.parseCountRequest = parseCountRequest;
|
|
5
6
|
exports.buildListAgentQuery = buildListAgentQuery;
|
|
@@ -10,9 +11,25 @@ exports.parseRelationListRequest = parseRelationListRequest;
|
|
|
10
11
|
exports.parseRelationCountRequest = parseRelationCountRequest;
|
|
11
12
|
exports.collectCountFieldPaths = collectCountFieldPaths;
|
|
12
13
|
const bff_local_errors_1 = require("../http/bff-local-errors");
|
|
14
|
+
const capabilities_validator_1 = require("../validation/capabilities-validator");
|
|
15
|
+
Object.defineProperty(exports, "MAX_PARSED_FILTER_DEPTH", { enumerable: true, get: function () { return capabilities_validator_1.MAX_FILTER_DEPTH; } });
|
|
16
|
+
const validation_errors_1 = require("../validation/validation-errors");
|
|
13
17
|
function isPlainObject(value) {
|
|
14
18
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
15
19
|
}
|
|
20
|
+
function assertNoNodeReadableAsBothLeafAndBranch(node, depth = 0) {
|
|
21
|
+
if (depth > capabilities_validator_1.MAX_FILTER_DEPTH)
|
|
22
|
+
throw (0, validation_errors_1.filterTooDeep)(capabilities_validator_1.MAX_FILTER_DEPTH);
|
|
23
|
+
if (typeof node !== 'object' || node === null)
|
|
24
|
+
return;
|
|
25
|
+
const readableAsBranch = (0, capabilities_validator_1.isBranch)(node);
|
|
26
|
+
if ((0, capabilities_validator_1.isLeaf)(node) && readableAsBranch) {
|
|
27
|
+
throw (0, bff_local_errors_1.invalidRequest)('A filter node cannot carry both "field" and "conditions"');
|
|
28
|
+
}
|
|
29
|
+
if (readableAsBranch) {
|
|
30
|
+
node.conditions.forEach(condition => assertNoNodeReadableAsBothLeafAndBranch(condition, depth + 1));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
16
33
|
// Validate the untyped request body before it reaches the query builders, so malformed shapes
|
|
17
34
|
// (e.g. `projection` or `sort` as a string) surface as 400 invalid_request rather than a 500 from
|
|
18
35
|
// an array method blowing up downstream.
|
|
@@ -35,8 +52,10 @@ function parseListRequest(body) {
|
|
|
35
52
|
if (!valid)
|
|
36
53
|
throw (0, bff_local_errors_1.invalidRequest)('sort must be an array of { field, direction? }');
|
|
37
54
|
}
|
|
38
|
-
if (filter !== undefined
|
|
39
|
-
|
|
55
|
+
if (filter !== undefined) {
|
|
56
|
+
if (!isPlainObject(filter))
|
|
57
|
+
throw (0, bff_local_errors_1.invalidRequest)('filter must be an object');
|
|
58
|
+
assertNoNodeReadableAsBothLeafAndBranch(filter);
|
|
40
59
|
}
|
|
41
60
|
if (page !== undefined) {
|
|
42
61
|
if (!isPlainObject(page)) {
|
|
@@ -54,26 +73,18 @@ function parseListRequest(body) {
|
|
|
54
73
|
function parseCountRequest(body) {
|
|
55
74
|
if (!isPlainObject(body))
|
|
56
75
|
throw (0, bff_local_errors_1.invalidRequest)('Request body must be an object');
|
|
57
|
-
if (body.filter !== undefined
|
|
58
|
-
|
|
76
|
+
if (body.filter !== undefined) {
|
|
77
|
+
if (!isPlainObject(body.filter))
|
|
78
|
+
throw (0, bff_local_errors_1.invalidRequest)('filter must be an object');
|
|
79
|
+
assertNoNodeReadableAsBothLeafAndBranch(body.filter);
|
|
59
80
|
}
|
|
60
81
|
return body;
|
|
61
82
|
}
|
|
62
|
-
function isBranch(node) {
|
|
63
|
-
return (typeof node === 'object' &&
|
|
64
|
-
node !== null &&
|
|
65
|
-
Array.isArray(node.conditions));
|
|
66
|
-
}
|
|
67
|
-
function isLeaf(node) {
|
|
68
|
-
return (typeof node === 'object' &&
|
|
69
|
-
node !== null &&
|
|
70
|
-
typeof node.field === 'string');
|
|
71
|
-
}
|
|
72
83
|
function collectFilterFields(filter, acc) {
|
|
73
|
-
if (isBranch(filter)) {
|
|
84
|
+
if ((0, capabilities_validator_1.isBranch)(filter)) {
|
|
74
85
|
filter.conditions.forEach(condition => collectFilterFields(condition, acc));
|
|
75
86
|
}
|
|
76
|
-
else if (isLeaf(filter)) {
|
|
87
|
+
else if ((0, capabilities_validator_1.isLeaf)(filter)) {
|
|
77
88
|
acc.push(filter.field);
|
|
78
89
|
}
|
|
79
90
|
}
|
|
@@ -141,4 +152,4 @@ function collectCountFieldPaths(body) {
|
|
|
141
152
|
collectFilterFields(body.filter, paths);
|
|
142
153
|
return paths;
|
|
143
154
|
}
|
|
144
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
155
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtcXVlcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGF0YS9hZ2VudC1xdWVyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUF5REEsNENBNkNDO0FBRUQsOENBU0M7QUEyQkQsa0RBYUM7QUFFRCxvREFNQztBQUVELHNEQU1DO0FBS0Qsc0NBWUM7QUFFRCw0REFJQztBQUVELDhEQUlDO0FBRUQsd0RBS0M7QUE3TUQsK0RBQTBEO0FBQzFELGlGQUEwRjtBQUc3RCx3R0FIcEIseUNBQWdCLE9BRzJCO0FBRnBELHVFQUFnRTtBQStCaEUsU0FBUyxhQUFhLENBQUMsS0FBYztJQUNuQyxPQUFPLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUM5RSxDQUFDO0FBRUQsU0FBUyx1Q0FBdUMsQ0FBQyxJQUFhLEVBQUUsS0FBSyxHQUFHLENBQUM7SUFDdkUsSUFBSSxLQUFLLEdBQUcseUNBQWdCO1FBQUUsTUFBTSxJQUFBLGlDQUFhLEVBQUMseUNBQWdCLENBQUMsQ0FBQztJQUNwRSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxJQUFJLEtBQUssSUFBSTtRQUFFLE9BQU87SUFFdEQsTUFBTSxnQkFBZ0IsR0FBRyxJQUFBLGlDQUFRLEVBQUMsSUFBSSxDQUFDLENBQUM7SUFFeEMsSUFBSSxJQUFBLCtCQUFNLEVBQUMsSUFBSSxDQUFDLElBQUksZ0JBQWdCLEVBQUUsQ0FBQztRQUNyQyxNQUFNLElBQUEsaUNBQWMsRUFBQywwREFBMEQsQ0FBQyxDQUFDO0lBQ25GLENBQUM7SUFFRCxJQUFJLGdCQUFnQixFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FDbEMsdUNBQXVDLENBQUMsU0FBUyxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FD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
|