@forestadmin/agent-bff 1.7.0 → 1.8.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/dist/action/action-form-mapper.d.ts +18 -0
- package/dist/action/action-form-mapper.js +33 -0
- package/dist/action/action-routes-middleware.d.ts +12 -0
- package/dist/action/action-routes-middleware.js +97 -0
- package/dist/action/agent-action-client.d.ts +32 -0
- package/dist/action/agent-action-client.js +26 -0
- package/dist/cli-core.js +12 -5
- package/dist/data/data-routes-middleware.js +10 -45
- package/dist/http/agent-route-helpers.d.ts +9 -0
- package/dist/http/agent-route-helpers.js +51 -0
- package/package.json +3 -3
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ActionForm } from './agent-action-client';
|
|
2
|
+
import type { ForestServerActionFormLayoutElement } from '@forestadmin/forestadmin-client';
|
|
3
|
+
export interface ActionFormFieldResponse {
|
|
4
|
+
name: string;
|
|
5
|
+
type: string;
|
|
6
|
+
value: unknown;
|
|
7
|
+
isRequired: boolean;
|
|
8
|
+
enumValues?: string[] | null;
|
|
9
|
+
}
|
|
10
|
+
export interface ActionFormResponse {
|
|
11
|
+
fields: ActionFormFieldResponse[];
|
|
12
|
+
canExecute: boolean;
|
|
13
|
+
requiredFields: string[];
|
|
14
|
+
skippedFields: string[];
|
|
15
|
+
layout: ForestServerActionFormLayoutElement[];
|
|
16
|
+
}
|
|
17
|
+
export declare function mapActionForm(action: ActionForm, skippedFields: string[], layout: ForestServerActionFormLayoutElement[]): ActionFormResponse;
|
|
18
|
+
//# sourceMappingURL=action-form-mapper.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mapActionForm = mapActionForm;
|
|
4
|
+
const ENUM_TYPE = 'Enum';
|
|
5
|
+
// Mirrors the MCP getActionForm tool, adding `layout`. A required field is "missing a value" only
|
|
6
|
+
// when its resolved value is null/undefined; an explicit empty string or 0 counts as present.
|
|
7
|
+
function mapActionForm(action, skippedFields, layout) {
|
|
8
|
+
const fields = action.getFields();
|
|
9
|
+
const requiredFields = fields
|
|
10
|
+
.filter(field => field.isRequired())
|
|
11
|
+
.filter(field => field.getValue() === undefined || field.getValue() === null)
|
|
12
|
+
.map(field => field.getName());
|
|
13
|
+
return {
|
|
14
|
+
fields: fields.map(field => {
|
|
15
|
+
const base = {
|
|
16
|
+
name: field.getName(),
|
|
17
|
+
type: field.getType(),
|
|
18
|
+
value: field.getValue(),
|
|
19
|
+
isRequired: field.isRequired() ?? false,
|
|
20
|
+
};
|
|
21
|
+
// enumValues is emitted only for Enum fields, matching the MCP tool.
|
|
22
|
+
if (field.getType() === ENUM_TYPE) {
|
|
23
|
+
return { ...base, enumValues: action.getEnumField(field.getName()).getOptions() ?? null };
|
|
24
|
+
}
|
|
25
|
+
return base;
|
|
26
|
+
}),
|
|
27
|
+
canExecute: requiredFields.length === 0,
|
|
28
|
+
requiredFields,
|
|
29
|
+
skippedFields,
|
|
30
|
+
layout,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLWZvcm0tbWFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FjdGlvbi9hY3Rpb24tZm9ybS1tYXBwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUF1QkEsc0NBaUNDO0FBckRELE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQztBQWtCekIsa0dBQWtHO0FBQ2xHLDhGQUE4RjtBQUM5RixTQUFnQixhQUFhLENBQzNCLE1BQWtCLEVBQ2xCLGFBQXVCLEVBQ3ZCLE1BQTZDO0lBRTdDLE1BQU0sTUFBTSxHQUFHLE1BQU0sQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUVsQyxNQUFNLGNBQWMsR0FBRyxNQUFNO1NBQzFCLE1BQU0sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQztTQUNuQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsUUFBUSxFQUFFLEtBQUssU0FBUyxJQUFJLEtBQUssQ0FBQyxRQUFRLEVBQUUsS0FBSyxJQUFJLENBQUM7U0FDNUUsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFFakMsT0FBTztRQUNMLE1BQU0sRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ3pCLE1BQU0sSUFBSSxHQUE0QjtnQkFDcEMsSUFBSSxFQUFFLEtBQUssQ0FBQyxPQUFPLEVBQUU7Z0JBQ3JCLElBQUksRUFBRSxLQUFLLENBQUMsT0FBTyxFQUFFO2dCQUNyQixLQUFLLEVBQUUsS0FBSyxDQUFDLFFBQVEsRUFBRTtnQkFDdkIsVUFBVSxFQUFFLEtBQUssQ0FBQyxVQUFVLEVBQUUsSUFBSSxLQUFLO2FBQ3hDLENBQUM7WUFFRixxRUFBcUU7WUFDckUsSUFBSSxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssU0FBUyxFQUFFLENBQUM7Z0JBQ2xDLE9BQU8sRUFBRSxHQUFHLElBQUksRUFBRSxVQUFVLEVBQUUsTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxVQUFVLEVBQUUsSUFBSSxJQUFJLEVBQUUsQ0FBQztZQUM1RixDQUFDO1lBRUQsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDLENBQUM7UUFDRixVQUFVLEVBQUUsY0FBYyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQ3ZDLGNBQWM7UUFDZCxhQUFhO1FBQ2IsTUFBTTtLQUNQLENBQUM7QUFDSixDQUFDIn0=
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentActionClient, AgentActionClientOptions } from './agent-action-client';
|
|
2
|
+
import type { Logger } from '../ports/logger-port';
|
|
3
|
+
import type ReadModelStore from '../read-model/read-model-store';
|
|
4
|
+
import type { Middleware } from 'koa';
|
|
5
|
+
export interface ActionRoutesMiddlewareOptions {
|
|
6
|
+
store: ReadModelStore;
|
|
7
|
+
agentUrl: string;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
createClient?: (options: AgentActionClientOptions) => AgentActionClient;
|
|
10
|
+
}
|
|
11
|
+
export default function createActionRoutesMiddleware({ store, agentUrl, logger, createClient, }: ActionRoutesMiddlewareOptions): Middleware;
|
|
12
|
+
//# sourceMappingURL=action-routes-middleware.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.default = createActionRoutesMiddleware;
|
|
37
|
+
const action_form_mapper_1 = require("./action-form-mapper");
|
|
38
|
+
const agent_action_client_1 = __importStar(require("./agent-action-client"));
|
|
39
|
+
const agent_route_helpers_1 = require("../http/agent-route-helpers");
|
|
40
|
+
const bff_local_errors_1 = require("../http/bff-local-errors");
|
|
41
|
+
const ACTION_FORM_ROUTE = /^\/agent\/v1\/([^/]+)\/actions\/([^/]+)\/form$/;
|
|
42
|
+
// recordIds are opaque BFF ids; only presence and array-ness are checked. An empty array is allowed
|
|
43
|
+
// on purpose (global/bulk actions have no selected records); the spec AC only covers a missing
|
|
44
|
+
// recordIds, so `[]` is an explicit BFF choice, not a spec requirement.
|
|
45
|
+
// Ids are coerced to strings so a valid `0` (numeric primary key) survives agent-client's downstream
|
|
46
|
+
// `.filter(Boolean)`, which would otherwise drop it and load the form as if no record were selected.
|
|
47
|
+
function parseRecordIds(raw) {
|
|
48
|
+
if (!Array.isArray(raw)) {
|
|
49
|
+
throw (0, bff_local_errors_1.invalidRequest)('recordIds is required and must be an array');
|
|
50
|
+
}
|
|
51
|
+
return raw.map(id => String(id));
|
|
52
|
+
}
|
|
53
|
+
function parseValues(raw) {
|
|
54
|
+
if (raw === undefined)
|
|
55
|
+
return {};
|
|
56
|
+
if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
|
|
57
|
+
throw (0, bff_local_errors_1.invalidRequest)('values must be an object');
|
|
58
|
+
}
|
|
59
|
+
return raw;
|
|
60
|
+
}
|
|
61
|
+
function createActionRoutesMiddleware({ store, agentUrl, logger, createClient = agent_action_client_1.default, }) {
|
|
62
|
+
return async function actionRoutesMiddleware(ctx, next) {
|
|
63
|
+
const match = ACTION_FORM_ROUTE.exec(ctx.path);
|
|
64
|
+
if (!match || ctx.method !== 'POST') {
|
|
65
|
+
await next();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const collection = (0, agent_route_helpers_1.decodeSegment)(match[1], 'collection name');
|
|
69
|
+
const actionName = (0, agent_route_helpers_1.decodeSegment)(match[2], 'action name');
|
|
70
|
+
const token = (0, agent_route_helpers_1.requireAgentToken)(ctx);
|
|
71
|
+
const readModel = await (0, agent_route_helpers_1.resolveReadModel)(store);
|
|
72
|
+
// The read-model's action map IS the allow-list, so an absent action cannot be told from a
|
|
73
|
+
// known-but-disallowed one — every non-exposed action maps to 404 here; `action_not_allowed`
|
|
74
|
+
// (403) has no local trigger, mirroring `collection_not_allowed`/`relation_not_allowed`. The
|
|
75
|
+
// URL identity is resolved before the body, so a bad action 404s before its payload is read.
|
|
76
|
+
// TODO(PRD-673): distinguish disallowed from unknown when a separate exposure source exists.
|
|
77
|
+
if (!readModel.isActionAllowed(collection, actionName)) {
|
|
78
|
+
throw (0, bff_local_errors_1.unknownAction)(`Unknown action: ${collection}.${actionName}`);
|
|
79
|
+
}
|
|
80
|
+
const body = (ctx.request.body ?? {});
|
|
81
|
+
const recordIds = parseRecordIds(body.recordIds);
|
|
82
|
+
const values = parseValues(body.values);
|
|
83
|
+
const client = createClient({
|
|
84
|
+
agentUrl,
|
|
85
|
+
token,
|
|
86
|
+
actionEndpoints: readModel.getActionEndpoints(),
|
|
87
|
+
});
|
|
88
|
+
// Each agent-hitting call is wrapped on its own; getFields/extractRawLayout/mapping stay outside
|
|
89
|
+
// callAgent so a local BFF bug surfaces as a 500, not a mislabelled agent error. Fields and
|
|
90
|
+
// layout are read AFTER tryToSetFields because a change hook rebuilds them in place.
|
|
91
|
+
const action = await (0, agent_route_helpers_1.callAgent)(() => client.loadActionForm(collection, actionName, recordIds), logger);
|
|
92
|
+
const skippedFields = await (0, agent_route_helpers_1.callAgent)(() => action.tryToSetFields(values), logger);
|
|
93
|
+
ctx.status = 200;
|
|
94
|
+
ctx.body = (0, action_form_mapper_1.mapActionForm)(action, skippedFields, (0, agent_action_client_1.extractRawLayout)(action));
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLXJvdXRlcy1taWRkbGV3YXJlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FjdGlvbi9hY3Rpb24tcm91dGVzLW1pZGRsZXdhcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFvREEsK0NBbURDO0FBbEdELDZEQUFxRDtBQUNyRCw2RUFBeUY7QUFDekYscUVBS3FDO0FBQ3JDLCtEQUF5RTtBQUV6RSxNQUFNLGlCQUFpQixHQUFHLGdEQUFnRCxDQUFDO0FBTzNFLG9HQUFvRztBQUNwRywrRkFBK0Y7QUFDL0Ysd0VBQXdFO0FBQ3hFLHFHQUFxRztBQUNyRyxxR0FBcUc7QUFDckcsU0FBUyxjQUFjLENBQUMsR0FBWTtJQUNsQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sSUFBQSxpQ0FBYyxFQUFDLDRDQUE0QyxDQUFDLENBQUM7SUFDckUsQ0FBQztJQUVELE9BQU8sR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ25DLENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxHQUFZO0lBQy9CLElBQUksR0FBRyxLQUFLLFNBQVM7UUFBRSxPQUFPLEVBQUUsQ0FBQztJQUVqQyxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsSUFBSSxHQUFHLEtBQUssSUFBSSxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNsRSxNQUFNLElBQUEsaUNBQWMsRUFBQywwQkFBMEIsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFRCxPQUFPLEdBQThCLENBQUM7QUFDeEMsQ0FBQztBQVNELFNBQXdCLDRCQUE0QixDQUFDLEVBQ25ELEtBQUssRUFDTCxRQUFRLEVBQ1IsTUFBTSxFQUNOLFlBQVksR0FBRyw2QkFBOEIsR0FDZjtJQUM5QixPQUFPLEtBQUssVUFBVSxzQkFBc0IsQ0FBQyxHQUFHLEVBQUUsSUFBSTtRQUNwRCxNQUFNLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRS9DLElBQUksQ0FBQyxLQUFLLElBQUksR0FBRyxDQUFDLE1BQU0sS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksRUFBRSxDQUFDO1lBRWIsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLFVBQVUsR0FBRyxJQUFBLG1DQUFhLEVBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLGlCQUFpQixDQUFDLENBQUM7UUFDOUQsTUFBTSxVQUFVLEdBQUcsSUFBQSxtQ0FBYSxFQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxhQUFhLENBQUMsQ0FBQztRQUMxRCxNQUFNLEtBQUssR0FBRyxJQUFBLHVDQUFpQixFQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sU0FBUyxHQUFHLE1BQU0sSUFBQSxzQ0FBZ0IsRUFBQyxLQUFLLENBQUMsQ0FBQztRQUVoRCwyRkFBMkY7UUFDM0YsNkZBQTZGO1FBQzdGLDZGQUE2RjtRQUM3Riw2RkFBNkY7UUFDN0YsNkZBQTZGO1FBQzdGLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQ3ZELE1BQU0sSUFBQSxnQ0FBYSxFQUFDLG1CQUFtQixVQUFVLElBQUksVUFBVSxFQUFFLENBQUMsQ0FBQztRQUNyRSxDQUFDO1FBRUQsTUFBTSxJQUFJLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksSUFBSSxFQUFFLENBQTBCLENBQUM7UUFDL0QsTUFBTSxTQUFTLEdBQUcsY0FBYyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNqRCxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRXhDLE1BQU0sTUFBTSxHQUFHLFlBQVksQ0FBQztZQUMxQixRQUFRO1lBQ1IsS0FBSztZQUNMLGVBQWUsRUFBRSxTQUFTLENBQUMsa0JBQWtCLEVBQUU7U0FDaEQsQ0FBQyxDQUFDO1FBRUgsaUdBQWlHO1FBQ2pHLDRGQUE0RjtRQUM1RixxRkFBcUY7UUFDckYsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFBLCtCQUFTLEVBQzVCLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsVUFBVSxFQUFFLFVBQVUsRUFBRSxTQUFTLENBQUMsRUFDOUQsTUFBTSxDQUNQLENBQUM7UUFDRixNQUFNLGFBQWEsR0FBRyxNQUFNLElBQUEsK0JBQVMsRUFBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRW5GLEdBQUcsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDO1FBQ2pCLEdBQUcsQ0FBQyxJQUFJLEdBQUcsSUFBQSxrQ0FBYSxFQUFDLE1BQU0sRUFBRSxhQUFhLEVBQUUsSUFBQSxzQ0FBZ0IsRUFBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQzVFLENBQUMsQ0FBQztBQUNKLENBQUMifQ==
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ActionEndpointsByCollection } from '@forestadmin/agent-client';
|
|
2
|
+
import type { ForestServerActionFormLayoutElement } from '@forestadmin/forestadmin-client';
|
|
3
|
+
export interface ActionFormField {
|
|
4
|
+
getName(): string;
|
|
5
|
+
getType(): string;
|
|
6
|
+
getValue(): unknown;
|
|
7
|
+
isRequired(): boolean | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface ActionForm {
|
|
10
|
+
tryToSetFields(values: Record<string, unknown>): Promise<string[]>;
|
|
11
|
+
getFields(): ActionFormField[];
|
|
12
|
+
getEnumField(name: string): {
|
|
13
|
+
getOptions(): string[] | undefined;
|
|
14
|
+
};
|
|
15
|
+
getLayout(): unknown;
|
|
16
|
+
}
|
|
17
|
+
export interface AgentActionClient {
|
|
18
|
+
loadActionForm(collection: string, action: string, recordIds: string[]): Promise<ActionForm>;
|
|
19
|
+
}
|
|
20
|
+
export interface AgentActionClientOptions {
|
|
21
|
+
agentUrl: string;
|
|
22
|
+
token: string;
|
|
23
|
+
actionEndpoints: ActionEndpointsByCollection;
|
|
24
|
+
}
|
|
25
|
+
export declare function extractRawLayout(action: ActionForm): ForestServerActionFormLayoutElement[];
|
|
26
|
+
/**
|
|
27
|
+
* Thin action-form client bound to a request's agent token. Reuses agent-client's stateful form
|
|
28
|
+
* loading (`/hooks/load` + `/hooks/change`, Ruby 404 fallback, dependent-field re-evaluation) rather
|
|
29
|
+
* than reimplementing it. The endpoint map from the read-model is the action allow-list.
|
|
30
|
+
*/
|
|
31
|
+
export default function createAgentActionClient({ agentUrl, token, actionEndpoints, }: AgentActionClientOptions): AgentActionClient;
|
|
32
|
+
//# sourceMappingURL=agent-action-client.d.ts.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractRawLayout = extractRawLayout;
|
|
4
|
+
exports.default = createAgentActionClient;
|
|
5
|
+
const agent_client_1 = require("@forestadmin/agent-client");
|
|
6
|
+
// The raw layout must be read AFTER tryToSetFields: a change hook rebuilds fields+layout in place.
|
|
7
|
+
// agent-client's `Action.getLayout()` only returns an `ActionLayoutRoot` wrapper whose element array
|
|
8
|
+
// lives in a protected field. The rollback contract forbids agent-client changes, so we read it
|
|
9
|
+
// through a cast rather than adding a public accessor. `extract-raw-layout.test.ts` builds a real
|
|
10
|
+
// `ActionLayoutRoot` and asserts this unwraps it, so a rename of that field fails a test.
|
|
11
|
+
function extractRawLayout(action) {
|
|
12
|
+
const root = action.getLayout();
|
|
13
|
+
return root.layout ?? [];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Thin action-form client bound to a request's agent token. Reuses agent-client's stateful form
|
|
17
|
+
* loading (`/hooks/load` + `/hooks/change`, Ruby 404 fallback, dependent-field re-evaluation) rather
|
|
18
|
+
* than reimplementing it. The endpoint map from the read-model is the action allow-list.
|
|
19
|
+
*/
|
|
20
|
+
function createAgentActionClient({ agentUrl, token, actionEndpoints, }) {
|
|
21
|
+
const client = (0, agent_client_1.createRemoteAgentClient)({ url: agentUrl, token, actionEndpoints });
|
|
22
|
+
return {
|
|
23
|
+
loadActionForm: (collection, action, recordIds) => client.collection(collection).action(action, { recordIds }),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtYWN0aW9uLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hY3Rpb24vYWdlbnQtYWN0aW9uLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW9DQSw0Q0FJQztBQU9ELDBDQVdDO0FBdkRELDREQUFvRTtBQTRCcEUsbUdBQW1HO0FBQ25HLHFHQUFxRztBQUNyRyxnR0FBZ0c7QUFDaEcsa0dBQWtHO0FBQ2xHLDBGQUEwRjtBQUMxRixTQUFnQixnQkFBZ0IsQ0FBQyxNQUFrQjtJQUNqRCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsU0FBUyxFQUF3RCxDQUFDO0lBRXRGLE9BQU8sSUFBSSxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7QUFDM0IsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUF3Qix1QkFBdUIsQ0FBQyxFQUM5QyxRQUFRLEVBQ1IsS0FBSyxFQUNMLGVBQWUsR0FDVTtJQUN6QixNQUFNLE1BQU0sR0FBRyxJQUFBLHNDQUF1QixFQUFDLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FBQztJQUVsRixPQUFPO1FBQ0wsY0FBYyxFQUFFLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsRUFBRSxDQUNoRCxNQUFNLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsRUFBRSxTQUFTLEVBQUUsQ0FBQztLQUM5RCxDQUFDO0FBQ0osQ0FBQyJ9
|
package/dist/cli-core.js
CHANGED
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.default = runCli;
|
|
7
7
|
exports.reportFatalError = reportFatalError;
|
|
8
8
|
const bodyparser_1 = require("@koa/bodyparser");
|
|
9
|
+
const action_routes_middleware_1 = __importDefault(require("./action/action-routes-middleware"));
|
|
9
10
|
const console_logger_1 = __importDefault(require("./adapters/console-logger"));
|
|
10
11
|
const agent_stub_1 = __importDefault(require("./agent/agent-stub"));
|
|
11
12
|
const api_key_authenticator_1 = __importDefault(require("./api-key/api-key-authenticator"));
|
|
@@ -111,18 +112,24 @@ function buildApiKeyMiddleware(config, logger) {
|
|
|
111
112
|
});
|
|
112
113
|
return (0, api_key_middleware_1.default)({ authenticator, logger });
|
|
113
114
|
}
|
|
114
|
-
|
|
115
|
+
// Data and action routes share one read-model store (a single cache, a single schema fetch). The
|
|
116
|
+
// data middleware falls through to the action middleware on a non-data path.
|
|
117
|
+
function buildAgentRouteMiddlewares(config, logger) {
|
|
115
118
|
const apiKeyConfig = resolveApiKeyConfig(config);
|
|
116
119
|
if (!apiKeyConfig || !config.agentUrl) {
|
|
117
120
|
logger('Warn', 'Data endpoints disabled: AGENT_URL or read-model configuration is missing');
|
|
118
|
-
return (0, agent_stub_1.default)();
|
|
121
|
+
return [(0, agent_stub_1.default)()];
|
|
119
122
|
}
|
|
120
123
|
const { store } = (0, create_read_model_1.default)({
|
|
121
124
|
forestServerUrl: apiKeyConfig.forestServerUrl,
|
|
122
125
|
envSecret: apiKeyConfig.forestEnvSecret,
|
|
123
126
|
logger,
|
|
124
127
|
});
|
|
125
|
-
|
|
128
|
+
const { agentUrl } = config;
|
|
129
|
+
return [
|
|
130
|
+
(0, data_routes_middleware_1.default)({ store, agentUrl, logger }),
|
|
131
|
+
(0, action_routes_middleware_1.default)({ store, agentUrl, logger }),
|
|
132
|
+
];
|
|
126
133
|
}
|
|
127
134
|
function buildAgentMiddlewares(config, logger) {
|
|
128
135
|
const { forestAuthSecret, defaultTimezone } = config;
|
|
@@ -136,7 +143,7 @@ function buildAgentMiddlewares(config, logger) {
|
|
|
136
143
|
apiKeyStep,
|
|
137
144
|
(0, per_key_origin_1.default)(),
|
|
138
145
|
(0, timezone_middleware_1.default)({ defaultTimezone }),
|
|
139
|
-
|
|
146
|
+
...buildAgentRouteMiddlewares(config, logger),
|
|
140
147
|
];
|
|
141
148
|
return chain.map(agentScoped);
|
|
142
149
|
}
|
|
@@ -171,4 +178,4 @@ function reportFatalError(err) {
|
|
|
171
178
|
process.stderr.write(`Error: ${(0, errors_1.extractErrorMessage)(err)}\n`);
|
|
172
179
|
process.exitCode = 1;
|
|
173
180
|
}
|
|
174
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
181
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWNvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2xpLWNvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUEyTUEseUJBa0NDO0FBRUQsNENBR0M7QUE5T0QsZ0RBQTZDO0FBRTdDLGlHQUE2RTtBQUM3RSwrRUFBNEQ7QUFDNUQsb0VBQTJEO0FBQzNELDRGQUF3RTtBQUN4RSw4RUFBb0Q7QUFDcEQsc0ZBQWtFO0FBQ2xFLDRFQUF5RDtBQUN6RCx1RkFBbUU7QUFDbkUsb0RBQWtEO0FBQ2xELDZFQUEwRDtBQUMxRCwyRUFBaUU7QUFDakUsMkZBQXVFO0FBQ3ZFLHFDQUErQztBQUMvQywwREFBcUQ7QUFDckQsNkVBQW1EO0FBQ25ELCtFQUE0RDtBQUM1RCx3RkFBOEQ7QUFDOUQsd0VBQXFEO0FBQ3JELDBFQUErRDtBQUMvRCx3RUFBcUQ7QUFDckQsdUZBQTZEO0FBQzdELHlGQUFzRTtBQUN0RSx3REFBZ0M7QUFFaEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDO0FBQzFCLE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFFekMsU0FBUyxXQUFXLENBQUMsSUFBWTtJQUMvQixPQUFPLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsVUFBc0I7SUFDekMsT0FBTyxLQUFLLFVBQVUsTUFBTSxDQUFDLEdBQUcsRUFBRSxJQUFJO1FBQ3BDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUViLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzlCLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLDRCQUE0QixDQUFD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
|
|
@@ -7,10 +7,8 @@ exports.default = createDataRoutesMiddleware;
|
|
|
7
7
|
const agent_data_client_1 = __importDefault(require("./agent-data-client"));
|
|
8
8
|
const agent_query_1 = require("./agent-query");
|
|
9
9
|
const response_mappers_1 = require("./response-mappers");
|
|
10
|
-
const
|
|
11
|
-
const bff_http_error_1 = require("../http/bff-http-error");
|
|
10
|
+
const agent_route_helpers_1 = require("../http/agent-route-helpers");
|
|
12
11
|
const bff_local_errors_1 = require("../http/bff-local-errors");
|
|
13
|
-
const errors_1 = __importDefault(require("../read-model/errors"));
|
|
14
12
|
const relation_field_guard_1 = __importDefault(require("../validation/relation-field-guard"));
|
|
15
13
|
const DATA_ROUTE = /^\/agent\/v1\/([^/]+)\/(list|count)$/;
|
|
16
14
|
const RELATION_ROUTE = /^\/agent\/v1\/([^/]+)\/relations\/([^/]+)\/(list|count)$/;
|
|
@@ -23,45 +21,17 @@ function resolveForeignCollection(target) {
|
|
|
23
21
|
return null;
|
|
24
22
|
return target.target;
|
|
25
23
|
}
|
|
26
|
-
function decodeSegment(raw, label) {
|
|
27
|
-
try {
|
|
28
|
-
return decodeURIComponent(raw);
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
throw (0, bff_local_errors_1.invalidRequest)(`Malformed ${label} in path`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
async function resolveReadModel(store) {
|
|
35
|
-
try {
|
|
36
|
-
return await store.getReadModel();
|
|
37
|
-
}
|
|
38
|
-
catch (error) {
|
|
39
|
-
if (error instanceof errors_1.default)
|
|
40
|
-
throw (0, bff_local_errors_1.schemaUnavailable)();
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
// Only the agent call is wrapped: guard, query-building and mapping errors are BFF-origin and must
|
|
45
|
-
// keep their own type, not be recategorized as agent errors.
|
|
46
|
-
async function callAgent(fn, logger) {
|
|
47
|
-
try {
|
|
48
|
-
return await fn();
|
|
49
|
-
}
|
|
50
|
-
catch (error) {
|
|
51
|
-
throw (0, agent_error_mapper_1.mapAgentError)(error, { logger });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
24
|
async function handleList(ctx, body, deps) {
|
|
55
25
|
(0, relation_field_guard_1.default)((0, agent_query_1.collectListFieldPaths)(body));
|
|
56
26
|
const query = (0, agent_query_1.buildListAgentQuery)(deps.collection, deps.timezone, body);
|
|
57
|
-
const records = await callAgent(() => deps.client.list(deps.collection, query), deps.logger);
|
|
27
|
+
const records = await (0, agent_route_helpers_1.callAgent)(() => deps.client.list(deps.collection, query), deps.logger);
|
|
58
28
|
ctx.status = 200;
|
|
59
29
|
ctx.body = (0, response_mappers_1.mapListResponse)(deps.collection, records, deps.primaryKeys);
|
|
60
30
|
}
|
|
61
31
|
async function handleCount(ctx, body, deps) {
|
|
62
32
|
(0, relation_field_guard_1.default)((0, agent_query_1.collectCountFieldPaths)(body));
|
|
63
33
|
const query = (0, agent_query_1.buildCountAgentQuery)(deps.timezone, body);
|
|
64
|
-
const raw = await callAgent(() => deps.client.countRaw(deps.collection, query), deps.logger);
|
|
34
|
+
const raw = await (0, agent_route_helpers_1.callAgent)(() => deps.client.countRaw(deps.collection, query), deps.logger);
|
|
65
35
|
ctx.status = 200;
|
|
66
36
|
ctx.body = (0, response_mappers_1.mapCountResponse)(raw);
|
|
67
37
|
}
|
|
@@ -71,19 +41,19 @@ async function handleRelationList(ctx, body, deps) {
|
|
|
71
41
|
// browse is never checked. Plain foreign fields (no `:`) are unaffected.
|
|
72
42
|
(0, relation_field_guard_1.default)((0, agent_query_1.collectListFieldPaths)(body));
|
|
73
43
|
const query = (0, agent_query_1.buildListAgentQuery)(deps.foreignCollection, deps.timezone, body);
|
|
74
|
-
const records = await callAgent(() => deps.client.listRelation(deps.collection, body.parentId, deps.relation, query), deps.logger);
|
|
44
|
+
const records = await (0, agent_route_helpers_1.callAgent)(() => deps.client.listRelation(deps.collection, body.parentId, deps.relation, query), deps.logger);
|
|
75
45
|
ctx.status = 200;
|
|
76
46
|
ctx.body = (0, response_mappers_1.mapListResponse)(deps.foreignCollection, records, deps.primaryKeys);
|
|
77
47
|
}
|
|
78
48
|
async function handleRelationCount(ctx, body, deps) {
|
|
79
49
|
(0, relation_field_guard_1.default)((0, agent_query_1.collectCountFieldPaths)(body));
|
|
80
50
|
const query = (0, agent_query_1.buildCountAgentQuery)(deps.timezone, body);
|
|
81
|
-
const raw = await callAgent(() => deps.client.countRelationRaw(deps.collection, body.parentId, deps.relation, query), deps.logger);
|
|
51
|
+
const raw = await (0, agent_route_helpers_1.callAgent)(() => deps.client.countRelationRaw(deps.collection, body.parentId, deps.relation, query), deps.logger);
|
|
82
52
|
ctx.status = 200;
|
|
83
53
|
ctx.body = (0, response_mappers_1.mapCountResponse)(raw);
|
|
84
54
|
}
|
|
85
55
|
async function handleRelation(ctx, rawBody, match, { deps, readModel }) {
|
|
86
|
-
const relation = decodeSegment(match[2], 'relation name');
|
|
56
|
+
const relation = (0, agent_route_helpers_1.decodeSegment)(match[2], 'relation name');
|
|
87
57
|
const operation = match[3];
|
|
88
58
|
// The URL identity (does this listable relation exist?) is resolved before the body,
|
|
89
59
|
// so a bad path 404s before its payload is inspected.
|
|
@@ -119,14 +89,9 @@ function createDataRoutesMiddleware({ store, agentUrl, logger, createClient = ag
|
|
|
119
89
|
await next();
|
|
120
90
|
return;
|
|
121
91
|
}
|
|
122
|
-
const collection = decodeSegment(match[1], 'collection name');
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// TODO(PRD-637): mint an agent token from the OAuth principal so data routes work in OAuth mode.
|
|
126
|
-
const token = ctx.state.agentToken;
|
|
127
|
-
if (!token)
|
|
128
|
-
throw (0, bff_http_error_1.unauthorized)('No agent credentials for this request');
|
|
129
|
-
const readModel = await resolveReadModel(store);
|
|
92
|
+
const collection = (0, agent_route_helpers_1.decodeSegment)(match[1], 'collection name');
|
|
93
|
+
const token = (0, agent_route_helpers_1.requireAgentToken)(ctx);
|
|
94
|
+
const readModel = await (0, agent_route_helpers_1.resolveReadModel)(store);
|
|
130
95
|
if (!readModel.isCollectionAllowed(collection)) {
|
|
131
96
|
// TODO(PRD-671): the read-model exposes a single allow-list (the exposed collections), so it
|
|
132
97
|
// cannot tell an unknown collection from a known-but-disallowed one. Every absent name maps
|
|
@@ -156,4 +121,4 @@ function createDataRoutesMiddleware({ store, agentUrl, logger, createClient = ag
|
|
|
156
121
|
}
|
|
157
122
|
};
|
|
158
123
|
}
|
|
159
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
124
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1yb3V0ZXMtbWlkZGxld2FyZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhL2RhdGEtcm91dGVzLW1pZGRsZXdhcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUF3S0EsNkNBcURDO0FBaE5ELDRFQUErRDtBQUMvRCwrQ0FTdUI7QUFDdkIseURBQXVFO0FBQ3ZFLHFFQUtxQztBQUNyQywrREFBOEU7QUFDOUUsOEZBQTRFO0FBRTVFLE1BQU0sVUFBVSxHQUFHLHNDQUFzQyxDQUFDO0FBQzFELE1BQU0sY0FBYyxHQUFHLDBEQUEwRCxDQUFDO0FBRWxGLG9HQUFvRztBQUNwRyxxR0FBcUc7QUFDckcsU0FBUyx3QkFBd0IsQ0FBQyxNQUFrQztJQUNsRSxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxRQUFRLElBQUksTUFBTSxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDbEQsSUFBSSxNQUFNLENBQUMsSUFBSSxLQUFLLFNBQVMsSUFBSSxNQUFNLENBQUMsSUFBSSxLQUFLLGVBQWU7UUFBRSxPQUFPLElBQUksQ0FBQztJQUU5RSxPQUFPLE1BQU0sQ0FBQyxNQUFNLENBQUM7QUFDdkIsQ0FBQztBQWtCRCxLQUFLLFVBQVUsVUFBVSxDQUFDLEdBQVksRUFBRSxJQUFxQixFQUFFLElBQXFCO0lBQ2xGLElBQUEsOEJBQTBCLEVBQUMsSUFBQSxtQ0FBcUIsRUFBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBRXhELE1BQU0sS0FBSyxHQUFHLElBQUEsaUNBQW1CLEVBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3hFLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBQSwrQkFBUyxFQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLEVBQUUsSUFBSSxDQUFD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
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Logger } from '../ports/logger-port';
|
|
2
|
+
import type ReadModel from '../read-model/read-model';
|
|
3
|
+
import type ReadModelStore from '../read-model/read-model-store';
|
|
4
|
+
import type { Context } from 'koa';
|
|
5
|
+
export declare function decodeSegment(raw: string, label: string): string;
|
|
6
|
+
export declare function resolveReadModel(store: ReadModelStore): Promise<ReadModel>;
|
|
7
|
+
export declare function requireAgentToken(ctx: Context): string;
|
|
8
|
+
export declare function callAgent<T>(fn: () => Promise<T>, logger: Logger): Promise<T>;
|
|
9
|
+
//# sourceMappingURL=agent-route-helpers.d.ts.map
|
|
@@ -0,0 +1,51 @@
|
|
|
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.decodeSegment = decodeSegment;
|
|
7
|
+
exports.resolveReadModel = resolveReadModel;
|
|
8
|
+
exports.requireAgentToken = requireAgentToken;
|
|
9
|
+
exports.callAgent = callAgent;
|
|
10
|
+
const agent_error_mapper_1 = require("./agent-error-mapper");
|
|
11
|
+
const bff_http_error_1 = require("./bff-http-error");
|
|
12
|
+
const bff_local_errors_1 = require("./bff-local-errors");
|
|
13
|
+
const errors_1 = __importDefault(require("../read-model/errors"));
|
|
14
|
+
function decodeSegment(raw, label) {
|
|
15
|
+
try {
|
|
16
|
+
return decodeURIComponent(raw);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
throw (0, bff_local_errors_1.invalidRequest)(`Malformed ${label} in path`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async function resolveReadModel(store) {
|
|
23
|
+
try {
|
|
24
|
+
return await store.getReadModel();
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error instanceof errors_1.default)
|
|
28
|
+
throw (0, bff_local_errors_1.schemaUnavailable)();
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// The agent token is minted only on the API-key path; the OAuth path sets a principal but no agent
|
|
33
|
+
// token yet. Fail closed instead of calling the agent with `Bearer undefined`.
|
|
34
|
+
// TODO(PRD-637): mint an agent token from the OAuth principal so agent routes work in OAuth mode.
|
|
35
|
+
function requireAgentToken(ctx) {
|
|
36
|
+
const token = ctx.state.agentToken;
|
|
37
|
+
if (!token)
|
|
38
|
+
throw (0, bff_http_error_1.unauthorized)('No agent credentials for this request');
|
|
39
|
+
return token;
|
|
40
|
+
}
|
|
41
|
+
// Only the agent call is wrapped: guard, query-building and mapping errors are BFF-origin and must
|
|
42
|
+
// keep their own type, not be recategorized as agent errors.
|
|
43
|
+
async function callAgent(fn, logger) {
|
|
44
|
+
try {
|
|
45
|
+
return await fn();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
throw (0, agent_error_mapper_1.mapAgentError)(error, { logger });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtcm91dGUtaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9odHRwL2FnZW50LXJvdXRlLWhlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFVQSxzQ0FNQztBQUVELDRDQU9DO0FBS0QsOENBS0M7QUFJRCw4QkFNQztBQXhDRCw2REFBcUQ7QUFDckQscURBQWdEO0FBQ2hELHlEQUF1RTtBQUN2RSxrRUFBMEQ7QUFFMUQsU0FBZ0IsYUFBYSxDQUFDLEdBQVcsRUFBRSxLQUFhO0lBQ3RELElBQUksQ0FBQztRQUNILE9BQU8sa0JBQWtCLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE1BQU0sSUFBQSxpQ0FBYyxFQUFDLGFBQWEsS0FBSyxVQUFVLENBQUMsQ0FBQztJQUNyRCxDQUFDO0FBQ0gsQ0FBQztBQUVNLEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxLQUFxQjtJQUMxRCxJQUFJLENBQUM7UUFDSCxPQUFPLE1BQU0sS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3BDLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFDO1FBQ2YsSUFBSSxLQUFLLFlBQVksZ0JBQXNCO1lBQUUsTUFBTSxJQUFBLG9DQUFpQixHQUFFLENBQUM7UUFDdkUsTUFBTSxLQUFLLENBQUM7SUFDZCxDQUFDO0FBQ0gsQ0FBQztBQUVELG1HQUFtRztBQUNuRywrRUFBK0U7QUFDL0Usa0dBQWtHO0FBQ2xHLFNBQWdCLGlCQUFpQixDQUFDLEdBQVk7SUFDNUMsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxVQUFnQyxDQUFDO0lBQ3pELElBQUksQ0FBQyxLQUFLO1FBQUUsTUFBTSxJQUFBLDZCQUFZLEVBQUMsdUNBQXVDLENBQUMsQ0FBQztJQUV4RSxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxtR0FBbUc7QUFDbkcsNkRBQTZEO0FBQ3RELEtBQUssVUFBVSxTQUFTLENBQUksRUFBb0IsRUFBRSxNQUFjO0lBQ3JFLElBQUksQ0FBQztRQUNILE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQztJQUNwQixDQUFDO0lBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztRQUNmLE1BQU0sSUFBQSxrQ0FBYSxFQUFDLEtBQUssRUFBRSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDekMsQ0FBQztBQUNILENBQUMifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/agent-bff",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"forest-bff": "dist/cli.js"
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"test": "jest"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@forestadmin/agent-client": "1.10.
|
|
35
|
-
"@forestadmin/forestadmin-client": "1.40.
|
|
34
|
+
"@forestadmin/agent-client": "1.10.2",
|
|
35
|
+
"@forestadmin/forestadmin-client": "1.40.5",
|
|
36
36
|
"@koa/bodyparser": "^6.1.0",
|
|
37
37
|
"jsonwebtoken": "^9.0.3",
|
|
38
38
|
"koa": "^3.0.1",
|