@forestadmin/agent-bff 1.30.0 → 1.30.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-routes-middleware.js +8 -1
- package/dist/context/build-context.d.ts +1 -0
- package/dist/context/build-context.js +18 -4
- package/dist/data/agent-query.js +23 -3
- package/dist/data/data-routes-middleware.js +7 -2
- package/dist/data/pack-id.d.ts +6 -1
- package/dist/data/pack-id.js +96 -3
- package/dist/data/response-mappers.js +2 -2
- package/dist/http/agent-error-mapper.js +42 -27
- package/dist/openapi/collect-unfolding.js +23 -9
- package/dist/openapi/schemas.d.ts +1 -0
- package/dist/openapi/schemas.js +22 -3
- package/dist/openapi/unfolded-document.js +7 -2
- package/dist/openapi/unfolded-paths.js +96 -16
- package/dist/openapi/unfolding.d.ts +12 -0
- package/dist/openapi/unfolding.js +1 -1
- package/dist/read-model/agent-capabilities-fetcher.d.ts +6 -1
- package/dist/read-model/agent-capabilities-fetcher.js +88 -6
- package/dist/read-model/capabilities-cache.d.ts +1 -0
- package/dist/read-model/capabilities-cache.js +1 -1
- package/dist/read-model/forest-schema-client.d.ts +3 -3
- package/dist/read-model/forest-schema-client.js +2 -2
- package/dist/read-model/read-model-store.d.ts +2 -1
- package/dist/read-model/read-model-store.js +3 -3
- package/dist/read-model/read-model.d.ts +34 -0
- package/dist/read-model/read-model.js +79 -4
- package/dist/read-model/schema-cache.d.ts +17 -1
- package/dist/read-model/schema-cache.js +19 -6
- package/dist/read-model/synthesize-capabilities.d.ts +35 -0
- package/dist/read-model/synthesize-capabilities.js +133 -0
- package/dist/validation/capabilities-validator.d.ts +6 -4
- package/dist/validation/capabilities-validator.js +12 -1
- package/dist/validation/operator-normalizer.d.ts +0 -6
- package/dist/validation/operator-normalizer.js +6 -14
- package/dist/validation/validation-errors.d.ts +1 -0
- package/dist/validation/validation-errors.js +7 -1
- package/package.json +3 -3
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LEGACY_LIANAS = exports.LEGACY_LIANA_OPERATORS = void 0;
|
|
4
|
+
exports.default = synthesizeCapabilities;
|
|
5
|
+
const agent_client_1 = require("@forestadmin/agent-client");
|
|
6
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
|
+
const field_type_1 = require("./field-type");
|
|
8
|
+
/**
|
|
9
|
+
* The operators every supported legacy liana honours, measured against
|
|
10
|
+
* `forest-express-sequelize 9.6.10` and `forest_liana 9.21.0`: the scalar cases of their filter
|
|
11
|
+
* switch plus the date family their separate date parser handles. Names are the legacy snake_case
|
|
12
|
+
* wire format, which is also what a real capabilities response carries.
|
|
13
|
+
*
|
|
14
|
+
* This list exists because a legacy liana publishes a single `isFilterable` boolean per field, never
|
|
15
|
+
* an operator list. Advertising the column type's whole operator set instead would admit operators
|
|
16
|
+
* the liana rejects on its own, which the BFF maps to `422 unprocessable_entity` rather than the
|
|
17
|
+
* `400 invalid_filter_operator` a caller can act on.
|
|
18
|
+
*
|
|
19
|
+
* It is the intersection of the two, not the union: `includes_all` sits in the column type table for
|
|
20
|
+
* every array-capable type, and on a scalar column `forest-express-sequelize` answers it with a 500
|
|
21
|
+
* carrying SQL while `forest_liana` rejects it outright. `i_contains` goes the other way — Rails
|
|
22
|
+
* honours it, Express does not — so it stays out too.
|
|
23
|
+
*/
|
|
24
|
+
exports.LEGACY_LIANA_OPERATORS = new Set([
|
|
25
|
+
'after',
|
|
26
|
+
'after_x_hours_ago',
|
|
27
|
+
'before',
|
|
28
|
+
'before_x_hours_ago',
|
|
29
|
+
'blank',
|
|
30
|
+
'contains',
|
|
31
|
+
'ends_with',
|
|
32
|
+
'equal',
|
|
33
|
+
'future',
|
|
34
|
+
'greater_than',
|
|
35
|
+
'in',
|
|
36
|
+
'less_than',
|
|
37
|
+
'not_contains',
|
|
38
|
+
'not_equal',
|
|
39
|
+
'past',
|
|
40
|
+
'present',
|
|
41
|
+
'previous_month',
|
|
42
|
+
'previous_month_to_date',
|
|
43
|
+
'previous_quarter',
|
|
44
|
+
'previous_quarter_to_date',
|
|
45
|
+
'previous_week',
|
|
46
|
+
'previous_week_to_date',
|
|
47
|
+
'previous_x_days',
|
|
48
|
+
'previous_x_days_to_date',
|
|
49
|
+
'previous_year',
|
|
50
|
+
'previous_year_to_date',
|
|
51
|
+
'starts_with',
|
|
52
|
+
'today',
|
|
53
|
+
'yesterday',
|
|
54
|
+
]);
|
|
55
|
+
/**
|
|
56
|
+
* The lianas that never served `/forest/_internal/capabilities`, as the Forest server itself
|
|
57
|
+
* enumerates them. The set is closed in practice — no new one is published — while the v2 agent
|
|
58
|
+
* family grows, so listing the legacy names keeps an unlisted agent on the failing path rather than
|
|
59
|
+
* silently downgrading it to the operator set above.
|
|
60
|
+
*/
|
|
61
|
+
exports.LEGACY_LIANAS = new Set([
|
|
62
|
+
'forest-express-sequelize',
|
|
63
|
+
'forest-express-mongoose',
|
|
64
|
+
'forest-rails',
|
|
65
|
+
]);
|
|
66
|
+
const MANY_TO_ONE = 'ManyToOne';
|
|
67
|
+
/**
|
|
68
|
+
* A `Map` and not the exported object: the type name is read from the apimap, and the table is a
|
|
69
|
+
* frozen object literal, so a field typed `constructor` would resolve to the Object constructor —
|
|
70
|
+
* truthy, and fatal on the `.map` below. A `Map` answers `undefined` for anything not a real key.
|
|
71
|
+
*/
|
|
72
|
+
const OPERATORS_BY_COLUMN_TYPE = new Map(Object.entries(datasource_toolkit_1.allowedOperatorsForColumnType));
|
|
73
|
+
/**
|
|
74
|
+
* An array column has no name here on purpose. Unwrapping `['Number']` to `Number` would publish the
|
|
75
|
+
* scalar operator table on it -- `greater_than` on a Postgres array raises in the liana, which the
|
|
76
|
+
* BFF answers as 503 agent_unavailable. The v2 agent publishes no operator for such a column either
|
|
77
|
+
* (`allowedOperatorsForColumnType` is keyed by primitive names only), so the two generations agree.
|
|
78
|
+
*/
|
|
79
|
+
function primitiveNameOf(type) {
|
|
80
|
+
const normalized = (0, field_type_1.normalizeFieldType)(type);
|
|
81
|
+
return typeof normalized === 'string' ? normalized : undefined;
|
|
82
|
+
}
|
|
83
|
+
function operatorsFor(field, collection, logger) {
|
|
84
|
+
if (field.isFilterable === false)
|
|
85
|
+
return [];
|
|
86
|
+
const primitive = primitiveNameOf(field.type);
|
|
87
|
+
const allowed = primitive === undefined ? undefined : OPERATORS_BY_COLUMN_TYPE.get(primitive);
|
|
88
|
+
if (!allowed) {
|
|
89
|
+
logger('Warn', 'No operator table for a synthesized column type; field reads as not filterable', {
|
|
90
|
+
collection,
|
|
91
|
+
field: field.field,
|
|
92
|
+
type: JSON.stringify(field.type),
|
|
93
|
+
});
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
return allowed.map(agent_client_1.toWireOperator).filter(operator => exports.LEGACY_LIANA_OPERATORS.has(operator));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The one, none or zero capability entries a single apimap field becomes: a scalar carries its
|
|
100
|
+
* operators, a to-one relation is present without any (so a direct filter on it is
|
|
101
|
+
* `field_not_filterable`), and every other relation is dropped (so a filter on it is
|
|
102
|
+
* `unknown_field`).
|
|
103
|
+
*/
|
|
104
|
+
function toCapabilityFields(field, collection, logger) {
|
|
105
|
+
if (field.relationship) {
|
|
106
|
+
if (field.relationship !== 'BelongsTo')
|
|
107
|
+
return [];
|
|
108
|
+
// A relation carries no operators, but it is still sortable through its target, so a sort the
|
|
109
|
+
// liana denies has to be published as denied here too -- otherwise the BFF accepts the sort
|
|
110
|
+
// and forwards it instead of answering field_not_sortable.
|
|
111
|
+
const relation = { name: field.field, type: MANY_TO_ONE };
|
|
112
|
+
return [field.isSortable === false ? { ...relation, sortable: false } : relation];
|
|
113
|
+
}
|
|
114
|
+
const entry = {
|
|
115
|
+
name: field.field,
|
|
116
|
+
type: field.type,
|
|
117
|
+
operators: operatorsFor(field, collection, logger),
|
|
118
|
+
};
|
|
119
|
+
return [field.isSortable === false ? { ...entry, sortable: false } : entry];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Build the capabilities a v1 liana would have answered, from the apimap it already pushed.
|
|
123
|
+
*
|
|
124
|
+
* The field classes mirror what the v2 agent's capabilities route emits, so the validator produces
|
|
125
|
+
* the same error for the same input on both generations.
|
|
126
|
+
*/
|
|
127
|
+
function synthesizeCapabilities(collection, logger) {
|
|
128
|
+
const declared = (collection.fields ?? []).filter((field) => typeof field === 'object' && field !== null && typeof field.field === 'string');
|
|
129
|
+
return {
|
|
130
|
+
fields: declared.flatMap(field => toCapabilityFields(field, collection.name, logger)),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3ludGhlc2l6ZS1jYXBhYmlsaXRpZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVhZC1tb2RlbC9zeW50aGVzaXplLWNhcGFiaWxpdGllcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUEwSkEseUNBWUM7QUFoS0QsNERBQTJEO0FBQzNELHdFQUFnRjtBQUVoRiw2Q0FBa0Q7QUFFbEQ7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ1UsUUFBQSxzQkFBc0IsR0FBd0IsSUFBSSxHQUFHLENBQUM7SUFDakUsT0FBTztJQUNQLG1CQUFtQjtJQUNuQixRQUFRO0lBQ1Isb0JBQW9CO0lBQ3BCLE9BQU87SUFDUCxVQUFVO0lBQ1YsV0FBVztJQUNYLE9BQU87SUFDUCxRQUFRO0lBQ1IsY0FBYztJQUNkLElBQUk7SUFDSixXQUFXO0lBQ1gsY0FBYztJQUNkLFdBQVc7SUFDWCxNQUFNO0lBQ04sU0FBUztJQUNULGdCQUFnQjtJQUNoQix3QkFBd0I7SUFDeEIsa0JBQWtCO0lBQ2xCLDBCQUEwQjtJQUMxQixlQUFlO0lBQ2YsdUJBQXVCO0lBQ3ZCLGlCQUFpQjtJQUNqQix5QkFBeUI7SUFDekIsZUFBZTtJQUNmLHVCQUF1QjtJQUN2QixhQUFhO0lBQ2IsT0FBTztJQUNQLFdBQVc7Q0FDWixDQUFDLENBQUM7QUFFSDs7Ozs7R0FLRztBQUNVLFFBQUEsYUFBYSxHQUF3QixJQUFJLEdBQUcsQ0FBQztJQUN4RCwwQkFBMEI7SUFDMUIseUJBQXlCO0lBQ3pCLGNBQWM7Q0FDZixDQUFDLENBQUM7QUFFSCxNQUFNLFdBQVcsR0FBRyxXQUFXLENBQUM7QUFFaEM7Ozs7R0FJRztBQUNILE1BQU0sd0JBQXdCLEdBQUcsSUFBSSxHQUFHLENBQ3RDLE1BQU0sQ0FBQyxPQUFPLENBQUMsa0RBQTZCLENBQUMsQ0FDOUMsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsU0FBUyxlQUFlLENBQUMsSUFBZTtJQUN0QyxNQUFNLFVBQVUsR0FBRyxJQUFBLCtCQUFr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
|
|
@@ -5,13 +5,16 @@ export interface ValidateParams {
|
|
|
5
5
|
sortFields?: string[];
|
|
6
6
|
projectionFields?: string[];
|
|
7
7
|
}
|
|
8
|
-
interface FilterLeaf {
|
|
8
|
+
export interface FilterLeaf {
|
|
9
9
|
field: string;
|
|
10
10
|
operator?: string;
|
|
11
|
+
value?: unknown;
|
|
11
12
|
}
|
|
12
|
-
export
|
|
13
|
+
export interface FilterBranch {
|
|
14
|
+
aggregator?: string;
|
|
13
15
|
conditions: unknown[];
|
|
14
|
-
}
|
|
16
|
+
}
|
|
17
|
+
export declare function isBranch(node: unknown): node is FilterBranch;
|
|
15
18
|
export declare function isLeaf(node: unknown): node is FilterLeaf;
|
|
16
19
|
export declare const MAX_FILTER_DEPTH = 100;
|
|
17
20
|
/**
|
|
@@ -27,5 +30,4 @@ export declare function hasCapabilityConstrainedInput(params: ValidateParams): b
|
|
|
27
30
|
*/
|
|
28
31
|
export declare function validateAgainstCapabilities(params: ValidateParams, capabilities: CapabilitiesResult): BffHttpError[];
|
|
29
32
|
export declare function assertValidAgainstCapabilities(params: ValidateParams, capabilities: CapabilitiesResult): void;
|
|
30
|
-
export {};
|
|
31
33
|
//# sourceMappingURL=capabilities-validator.d.ts.map
|
|
@@ -69,6 +69,16 @@ function validateFilter(filter, index) {
|
|
|
69
69
|
function validateExistence(fields, index) {
|
|
70
70
|
return fields.filter(field => !index.has(field)).map(validation_errors_1.unknownField);
|
|
71
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* Only the v1 synthesis states sortability, from the apimap's `isSortable`; a real capabilities
|
|
74
|
+
* response says nothing about it, so an absent flag means "not stated" and skips the check. Without
|
|
75
|
+
* this, a sort on a legacy computed field reaches the liana and raises a database error naming the
|
|
76
|
+
* missing column.
|
|
77
|
+
*/
|
|
78
|
+
function validateSortable(fields, capabilities) {
|
|
79
|
+
const notSortable = new Set(capabilities.fields.filter(field => field.sortable === false).map(field => field.name));
|
|
80
|
+
return fields.filter(field => notSortable.has(field)).map(validation_errors_1.fieldNotSortable);
|
|
81
|
+
}
|
|
72
82
|
function dedupe(errors) {
|
|
73
83
|
const seen = new Set();
|
|
74
84
|
const result = [];
|
|
@@ -101,6 +111,7 @@ function validateAgainstCapabilities(params, capabilities) {
|
|
|
101
111
|
return dedupe([
|
|
102
112
|
...validateFilter(params.filter, index),
|
|
103
113
|
...validateExistence(params.sortFields ?? [], index),
|
|
114
|
+
...validateSortable(params.sortFields ?? [], capabilities),
|
|
104
115
|
...validateExistence(params.projectionFields ?? [], index),
|
|
105
116
|
]);
|
|
106
117
|
}
|
|
@@ -109,4 +120,4 @@ function assertValidAgainstCapabilities(params, capabilities) {
|
|
|
109
120
|
if (first)
|
|
110
121
|
throw first;
|
|
111
122
|
}
|
|
112
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
123
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FwYWJpbGl0aWVzLXZhbGlkYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92YWxpZGF0aW9uL2NhcGFiaWxpdGllcy12YWxpZGF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBOEJBLDRCQU1DO0FBRUQsd0JBTUM7QUFtR0Qsc0VBTUM7QUFRRCxrRUFZQztBQUVELHdFQU9DO0FBL0tELCtEQUEwRDtBQUMxRCwyREFNNkI7QUFDN0IsK0RBQXdEO0FBbUJ4RCxTQUFnQixRQUFRLENBQUMsSUFBYTtJQUNwQyxPQUFPLENBQ0wsT0FBTyxJQUFJLEtBQUssUUFBUTtRQUN4QixJQUFJLEtBQUssSUFBSTtRQUNiLEtBQUssQ0FBQyxPQUFPLENBQUUsSUFBaUMsQ0FBQyxVQUFVLENBQUMsQ0FDN0QsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixNQUFNLENBQUMsSUFBYTtJQUNsQyxPQUFPLENBQ0wsT0FBTyxJQUFJLEtBQUssUUFBUTtRQUN4QixJQUFJLEtBQUssSUFBSTtRQUNiLE9BQVEsSUFBNEIsQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUN4RCxDQUFDO0FBQ0osQ0FBQztBQUVZLFFBQUEsZ0JBQWdCLEdBQUcsR0FBRyxDQUFDO0FBRXBDLFNBQVMsYUFBYSxDQUFDLElBQWEsRUFBRSxHQUFpQixFQUFFLEtBQUssR0FBRyxDQUFDO0lBQ2hFLElBQUksS0FBSyxHQUFHLHdCQUFnQjtRQUFFLE1BQU0sSUFBQSxpQ0FBYSxFQUFDLHdCQUFnQixDQUFDLENBQUM7SUFFcEUsSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztRQUNuQixJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxTQUFTLEVBQUUsR0FBRyxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pGLENBQUM7U0FBTSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFB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
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import type { Operator } from '@forestadmin/datasource-toolkit';
|
|
2
|
-
/**
|
|
3
|
-
* Mirrors the agent's capabilities serialization (`packages/agent/src/routes/capabilities.ts`),
|
|
4
|
-
* which converts each PascalCase operator to snake_case before returning it. Kept identical so the
|
|
5
|
-
* inverse map below round-trips every operator the agent can emit.
|
|
6
|
-
*/
|
|
7
|
-
export declare function toSnakeCaseOperator(operator: string): string;
|
|
8
2
|
/**
|
|
9
3
|
* Maps an agent snake_case capabilities operator to the canonical PascalCase operator from
|
|
10
4
|
* datasource-toolkit `allOperators`. Returns undefined when no canonical operator matches, which
|
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toSnakeCaseOperator = toSnakeCaseOperator;
|
|
4
3
|
exports.normalizeOperator = normalizeOperator;
|
|
5
4
|
exports.toCanonicalOperatorSet = toCanonicalOperatorSet;
|
|
5
|
+
const agent_client_1 = require("@forestadmin/agent-client");
|
|
6
6
|
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
*/
|
|
12
|
-
function toSnakeCaseOperator(operator) {
|
|
13
|
-
return operator
|
|
14
|
-
.split(/\.?(?=[A-Z])/)
|
|
15
|
-
.join('_')
|
|
16
|
-
.toLowerCase();
|
|
17
|
-
}
|
|
18
|
-
const SNAKE_TO_PASCAL = new Map(datasource_toolkit_1.allOperators.map(operator => [toSnakeCaseOperator(operator), operator]));
|
|
7
|
+
// `toWireOperator` is the one PascalCase -> snake_case mapping in the monorepo, and it is the same
|
|
8
|
+
// spelling the agent's capabilities route emits, so the inverse map round-trips every operator the
|
|
9
|
+
// agent can announce.
|
|
10
|
+
const SNAKE_TO_PASCAL = new Map(datasource_toolkit_1.allOperators.map(operator => [(0, agent_client_1.toWireOperator)(operator), operator]));
|
|
19
11
|
/**
|
|
20
12
|
* Maps an agent snake_case capabilities operator to the canonical PascalCase operator from
|
|
21
13
|
* datasource-toolkit `allOperators`. Returns undefined when no canonical operator matches, which
|
|
@@ -33,4 +25,4 @@ const CANONICAL_ORDER = new Map(datasource_toolkit_1.allOperators.map((operator,
|
|
|
33
25
|
function toCanonicalOperatorSet(operators) {
|
|
34
26
|
return [...new Set(operators)].sort((left, right) => CANONICAL_ORDER.get(left) - CANONICAL_ORDER.get(right));
|
|
35
27
|
}
|
|
36
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlcmF0b3Itbm9ybWFsaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy92YWxpZGF0aW9uL29wZXJhdG9yLW5vcm1hbGl6ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFpQkEsOENBRUM7QUFXRCx3REFJQztBQWhDRCw0REFBMkQ7QUFDM0Qsd0VBQStEO0FBRS9ELG1HQUFtRztBQUNuRyxtR0FBbUc7QUFDbkcsc0JBQXNCO0FBQ3RCLE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxDQUM3QixpQ0FBWSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBQSw2QkFBYyxFQUFDLFFBQVEsQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQ25FLENBQUM7QUFFRjs7OztHQUlHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsaUJBQXlCO0lBQ3pELE9BQU8sZUFBZSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0FBQ2hELENBQUM7QUFFRCxNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FDN0IsaUNBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUN6RCxDQUFDO0FBRUY7Ozs7R0FJRztBQUNILFNBQWdCLHNCQUFzQixDQUFDLFNBQXFCO0lBQzFELE9BQU8sQ0FBQyxHQUFHLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUNqQyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUFFLGVBQWUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFZLEdBQUksZUFBZSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQVksQ0FDaEcsQ0FBQztBQUNKLENBQUMifQ==
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BffHttpError } from '../http/bff-http-error';
|
|
2
2
|
export declare function unknownField(field: string): BffHttpError;
|
|
3
3
|
export declare function fieldNotFilterable(field: string): BffHttpError;
|
|
4
|
+
export declare function fieldNotSortable(field: string): BffHttpError;
|
|
4
5
|
export declare function filterTooDeep(maxDepth: number): BffHttpError;
|
|
5
6
|
export declare function invalidFilterOperator(field: string, validOperators: string[]): BffHttpError;
|
|
6
7
|
export declare function missingRequiredActionFields(fields: string[]): BffHttpError;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.unknownField = unknownField;
|
|
4
4
|
exports.fieldNotFilterable = fieldNotFilterable;
|
|
5
|
+
exports.fieldNotSortable = fieldNotSortable;
|
|
5
6
|
exports.filterTooDeep = filterTooDeep;
|
|
6
7
|
exports.invalidFilterOperator = invalidFilterOperator;
|
|
7
8
|
exports.missingRequiredActionFields = missingRequiredActionFields;
|
|
@@ -17,6 +18,11 @@ function fieldNotFilterable(field) {
|
|
|
17
18
|
details: { field },
|
|
18
19
|
});
|
|
19
20
|
}
|
|
21
|
+
function fieldNotSortable(field) {
|
|
22
|
+
return new bff_http_error_1.BffHttpError(422, 'field_not_sortable', `Field is not sortable: ${field}`, {
|
|
23
|
+
details: { field },
|
|
24
|
+
});
|
|
25
|
+
}
|
|
20
26
|
function filterTooDeep(maxDepth) {
|
|
21
27
|
return new bff_http_error_1.BffHttpError(400, 'filter_too_deep', `Filter nesting exceeds the maximum depth of ${maxDepth}`, { details: { maxDepth } });
|
|
22
28
|
}
|
|
@@ -34,4 +40,4 @@ function invalidActionValue(violations) {
|
|
|
34
40
|
details: { fields: violations },
|
|
35
41
|
});
|
|
36
42
|
}
|
|
37
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
43
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGlvbi1lcnJvcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdmFsaWRhdGlvbi92YWxpZGF0aW9uLWVycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUVBLG9DQUlDO0FBRUQsZ0RBSUM7QUFFRCw0Q0FJQztBQUVELHNDQU9DO0FBRUQsc0RBT0M7QUFFRCxrRUFPQztBQU9ELGdEQVFDO0FBNURELDJEQUFzRDtBQUV0RCxTQUFnQixZQUFZLENBQUMsS0FBYTtJQUN4QyxPQUFPLElBQUksNkJBQVksQ0FBQyxHQUFHLEVBQUUsZUFBZSxFQUFFLGtCQUFrQixLQUFLLEVBQUUsRUFBRTtRQUN2RSxPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUU7S0FDbkIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQWdCLGtCQUFrQixDQUFDLEtBQWE7SUFDOUMsT0FBTyxJQUFJLDZCQUFZLENBQUMsR0FBRyxFQUFFLHNCQUFzQixFQUFFLDRCQUE0QixLQUFLLEVBQUUsRUFBRTtRQUN4RixPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUU7S0FDbkIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQWdCLGdCQUFnQixDQUFDLEtBQWE7SUFDNUMsT0FBTyxJQUFJLDZCQUFZLENBQUMsR0FBRyxFQUFFLG9CQUFvQixFQUFFLDBCQUEwQixLQUFLLEVBQUUsRUFBRTtRQUNwRixPQUFPLEVBQUUsRUFBRSxLQUFLLEVBQUU7S0FDbkIsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxRQUFnQjtJQUM1QyxPQUFPLElBQUksNkJBQVksQ0FDckIsR0FBRyxFQUNILGlCQUFpQixFQUNqQiwrQ0FBK0MsUUFBUSxFQUFFLEVBQ3pELEVBQUUsT0FBTyxFQUFFLEVBQUUsUUFBUSxFQUFFLEVBQUUsQ0FDMUIsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFnQixxQkFBcUIsQ0FBQyxLQUFhLEVBQUUsY0FBd0I7SUFDM0UsT0FBTyxJQUFJLDZCQUFZLENBQ3JCLEdBQUcsRUFDSCx5QkFBeUIsRUFDekIsbUNBQW1DLEtBQUssRUFBRSxFQUMxQyxFQUFFLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxjQUFjLEVBQUUsRUFBRSxDQUN2QyxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQWdCLDJCQUEyQixDQUFDLE1BQWdCO0lBQzFELE9BQU8sSUFBSSw2QkFBWSxDQUNyQixHQUFHLEVBQ0gseUJBQXlCLEVBQ3pCLHVDQUF1QyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLEVBQzFELEVBQUUsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FDeEIsQ0FBQztBQUNKLENBQUM7QUFPRCxTQUFnQixrQkFBa0IsQ0FBQyxVQUFrQztJQUNuRSxNQUFNLE9BQU8sR0FBRyxVQUFVO1NBQ3ZCLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLEtBQUssY0FBYyxTQUFTLENBQUMsUUFBUSxHQUFHLENBQUM7U0FDdkUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWQsT0FBTyxJQUFJLDZCQUFZLENBQUMsR0FBRyxFQUFFLHNCQUFzQixFQUFFLGdDQUFnQyxPQUFPLEVBQUUsRUFBRTtRQUM5RixPQUFPLEVBQUUsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFO0tBQ2hDLENBQUMsQ0FBQztBQUNMLENBQUMifQ==
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/agent-bff",
|
|
3
|
-
"version": "1.30.
|
|
3
|
+
"version": "1.30.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"bin": {
|
|
6
6
|
"forest-bff": "dist/cli.js"
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@asteasolutions/zod-to-openapi": "8.5.0",
|
|
36
|
-
"@forestadmin/agent-client": "1.15.
|
|
36
|
+
"@forestadmin/agent-client": "1.15.3",
|
|
37
37
|
"@forestadmin/datasource-toolkit": "1.55.1",
|
|
38
|
-
"@forestadmin/forestadmin-client": "1.43.
|
|
38
|
+
"@forestadmin/forestadmin-client": "1.43.4",
|
|
39
39
|
"@koa/bodyparser": "^6.1.0",
|
|
40
40
|
"inflected": "^1.1.6",
|
|
41
41
|
"jsonwebtoken": "^9.0.3",
|