@forestadmin/agent-bff 1.5.0 → 1.7.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.
Files changed (40) hide show
  1. package/dist/adapters/console-metrics.d.ts +4 -0
  2. package/dist/adapters/console-metrics.js +18 -0
  3. package/dist/adapters/safe-metrics.d.ts +8 -0
  4. package/dist/adapters/safe-metrics.js +29 -0
  5. package/dist/cli-core.js +17 -2
  6. package/dist/data/agent-data-client.d.ts +17 -0
  7. package/dist/data/agent-data-client.js +32 -0
  8. package/dist/data/agent-query.d.ts +36 -0
  9. package/dist/data/agent-query.js +144 -0
  10. package/dist/data/data-routes-middleware.d.ts +12 -0
  11. package/dist/data/data-routes-middleware.js +159 -0
  12. package/dist/data/pack-id.d.ts +9 -0
  13. package/dist/data/pack-id.js +37 -0
  14. package/dist/data/response-mappers.d.ts +20 -0
  15. package/dist/data/response-mappers.js +38 -0
  16. package/dist/http/agent-error-mapper.d.ts +18 -0
  17. package/dist/http/agent-error-mapper.js +114 -0
  18. package/dist/http/bff-local-errors.d.ts +12 -0
  19. package/dist/http/bff-local-errors.js +44 -0
  20. package/dist/ports/metrics-port.d.ts +6 -0
  21. package/dist/ports/metrics-port.js +3 -0
  22. package/dist/read-model/action-endpoint-resolver.d.ts +23 -0
  23. package/dist/read-model/action-endpoint-resolver.js +36 -0
  24. package/dist/read-model/agent-capabilities-fetcher.d.ts +11 -0
  25. package/dist/read-model/agent-capabilities-fetcher.js +13 -0
  26. package/dist/read-model/capabilities-cache.d.ts +27 -0
  27. package/dist/read-model/capabilities-cache.js +47 -0
  28. package/dist/read-model/create-read-model.d.ts +17 -0
  29. package/dist/read-model/create-read-model.js +24 -0
  30. package/dist/read-model/errors.d.ts +5 -0
  31. package/dist/read-model/errors.js +11 -0
  32. package/dist/read-model/forest-schema-client.d.ts +14 -0
  33. package/dist/read-model/forest-schema-client.js +13 -0
  34. package/dist/read-model/read-model-store.d.ts +20 -0
  35. package/dist/read-model/read-model-store.js +43 -0
  36. package/dist/read-model/read-model.d.ts +39 -0
  37. package/dist/read-model/read-model.js +105 -0
  38. package/dist/read-model/schema-cache.d.ts +35 -0
  39. package/dist/read-model/schema-cache.js +82 -0
  40. package/package.json +2 -1
@@ -0,0 +1,4 @@
1
+ import type { Logger } from '../ports/logger-port';
2
+ import type { Metrics } from '../ports/metrics-port';
3
+ export default function createConsoleMetrics(logger?: Logger): Metrics;
4
+ //# sourceMappingURL=console-metrics.d.ts.map
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = createConsoleMetrics;
7
+ const console_logger_1 = __importDefault(require("./console-logger"));
8
+ function createConsoleMetrics(logger = (0, console_logger_1.default)()) {
9
+ return {
10
+ increment(name, tags) {
11
+ logger('Info', 'metric.increment', { metric: name, ...(tags ?? {}) });
12
+ },
13
+ gauge(name, value, tags) {
14
+ logger('Info', 'metric.gauge', { metric: name, value, ...(tags ?? {}) });
15
+ },
16
+ };
17
+ }
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc29sZS1tZXRyaWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXJzL2NvbnNvbGUtbWV0cmljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUtBLHVDQVNDO0FBWEQsc0VBQW1EO0FBRW5ELFNBQXdCLG9CQUFvQixDQUFDLFNBQWlCLElBQUEsd0JBQW1CLEdBQUU7SUFDakYsT0FBTztRQUNMLFNBQVMsQ0FBQyxJQUFZLEVBQUUsSUFBaUI7WUFDdkMsTUFBTSxDQUFDLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUNELEtBQUssQ0FBQyxJQUFZLEVBQUUsS0FBYSxFQUFFLElBQWlCO1lBQ2xELE1BQU0sQ0FBQyxNQUFNLEVBQUUsY0FBYyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUUsR0FBRyxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDM0UsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDIn0=
@@ -0,0 +1,8 @@
1
+ import type { Metrics } from '../ports/metrics-port';
2
+ /**
3
+ * Wraps a Metrics port so emitting a metric can never throw into business logic. Metrics is a
4
+ * user-supplied implementation; a backend that throws must not break a request (e.g. a throwing
5
+ * gauge on the schema cache-hit path would otherwise degrade every read).
6
+ */
7
+ export default function safeMetrics(metrics: Metrics): Metrics;
8
+ //# sourceMappingURL=safe-metrics.d.ts.map
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = safeMetrics;
4
+ /**
5
+ * Wraps a Metrics port so emitting a metric can never throw into business logic. Metrics is a
6
+ * user-supplied implementation; a backend that throws must not break a request (e.g. a throwing
7
+ * gauge on the schema cache-hit path would otherwise degrade every read).
8
+ */
9
+ function safeMetrics(metrics) {
10
+ return {
11
+ increment(name, tags) {
12
+ try {
13
+ metrics.increment(name, tags);
14
+ }
15
+ catch {
16
+ // Swallow: a metrics-backend failure must never break business logic.
17
+ }
18
+ },
19
+ gauge(name, value, tags) {
20
+ try {
21
+ metrics.gauge(name, value, tags);
22
+ }
23
+ catch {
24
+ // Swallow: a metrics-backend failure must never break business logic.
25
+ }
26
+ },
27
+ };
28
+ }
29
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FmZS1tZXRyaWNzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FkYXB0ZXJzL3NhZmUtbWV0cmljcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQU9BLDhCQWlCQztBQXRCRDs7OztHQUlHO0FBQ0gsU0FBd0IsV0FBVyxDQUFDLE9BQWdCO0lBQ2xELE9BQU87UUFDTCxTQUFTLENBQUMsSUFBWSxFQUFFLElBQWlCO1lBQ3ZDLElBQUksQ0FBQztnQkFDSCxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNoQyxDQUFDO1lBQUMsTUFBTSxDQUFDO2dCQUNQLHNFQUFzRTtZQUN4RSxDQUFDO1FBQ0gsQ0FBQztRQUNELEtBQUssQ0FBQyxJQUFZLEVBQUUsS0FBYSxFQUFFLElBQWlCO1lBQ2xELElBQUksQ0FBQztnQkFDSCxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDbkMsQ0FBQztZQUFDLE1BQU0sQ0FBQztnQkFDUCxzRUFBc0U7WUFDeEUsQ0FBQztRQUNILENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQyJ9
package/dist/cli-core.js CHANGED
@@ -16,6 +16,7 @@ const auth_mode_middleware_1 = __importDefault(require("./auth/auth-mode-middlew
16
16
  const env_config_1 = require("./config/env-config");
17
17
  const cors_middleware_1 = __importDefault(require("./cors/cors-middleware"));
18
18
  const per_key_origin_1 = __importDefault(require("./cors/per-key-origin"));
19
+ const data_routes_middleware_1 = __importDefault(require("./data/data-routes-middleware"));
19
20
  const errors_1 = require("./errors");
20
21
  const bff_http_error_1 = require("./http/bff-http-error");
21
22
  const bff_http_server_1 = __importDefault(require("./http/bff-http-server"));
@@ -24,6 +25,7 @@ const forest_server_client_1 = __importDefault(require("./oauth/forest-server-cl
24
25
  const oauth_routes_1 = __importDefault(require("./oauth/oauth-routes"));
25
26
  const session_store_1 = __importDefault(require("./oauth/session-store"));
26
27
  const token_cipher_1 = __importDefault(require("./oauth/token-cipher"));
28
+ const create_read_model_1 = __importDefault(require("./read-model/create-read-model"));
27
29
  const timezone_middleware_1 = __importDefault(require("./timezone/timezone-middleware"));
28
30
  const version_1 = __importDefault(require("./version"));
29
31
  const BODY_LIMIT = '16kb';
@@ -109,6 +111,19 @@ function buildApiKeyMiddleware(config, logger) {
109
111
  });
110
112
  return (0, api_key_middleware_1.default)({ authenticator, logger });
111
113
  }
114
+ function buildDataRoutesMiddleware(config, logger) {
115
+ const apiKeyConfig = resolveApiKeyConfig(config);
116
+ if (!apiKeyConfig || !config.agentUrl) {
117
+ logger('Warn', 'Data endpoints disabled: AGENT_URL or read-model configuration is missing');
118
+ return (0, agent_stub_1.default)();
119
+ }
120
+ const { store } = (0, create_read_model_1.default)({
121
+ forestServerUrl: apiKeyConfig.forestServerUrl,
122
+ envSecret: apiKeyConfig.forestEnvSecret,
123
+ logger,
124
+ });
125
+ return (0, data_routes_middleware_1.default)({ store, agentUrl: config.agentUrl, logger });
126
+ }
112
127
  function buildAgentMiddlewares(config, logger) {
113
128
  const { forestAuthSecret, defaultTimezone } = config;
114
129
  if (!forestAuthSecret) {
@@ -121,7 +136,7 @@ function buildAgentMiddlewares(config, logger) {
121
136
  apiKeyStep,
122
137
  (0, per_key_origin_1.default)(),
123
138
  (0, timezone_middleware_1.default)({ defaultTimezone }),
124
- (0, agent_stub_1.default)(),
139
+ buildDataRoutesMiddleware(config, logger),
125
140
  ];
126
141
  return chain.map(agentScoped);
127
142
  }
@@ -156,4 +171,4 @@ function reportFatalError(err) {
156
171
  process.stderr.write(`Error: ${(0, errors_1.extractErrorMessage)(err)}\n`);
157
172
  process.exitCode = 1;
158
173
  }
159
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWNvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2xpLWNvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFnTEEseUJBa0NDO0FBRUQsNENBR0M7QUFuTkQsZ0RBQTZDO0FBRTdDLCtFQUE0RDtBQUM1RCxvRUFBMkQ7QUFDM0QsNEZBQXdFO0FBQ3hFLDhFQUFvRDtBQUNwRCxzRkFBa0U7QUFDbEUsNEVBQXlEO0FBQ3pELHVGQUFtRTtBQUNuRSxvREFBa0Q7QUFDbEQsNkVBQTBEO0FBQzFELDJFQUFpRTtBQUNqRSxxQ0FBK0M7QUFDL0MsMERBQXFEO0FBQ3JELDZFQUFtRDtBQUNuRCwrRUFBNEQ7QUFDNUQsd0ZBQThEO0FBQzlELHdFQUFxRDtBQUNyRCwwRUFBK0Q7QUFDL0Qsd0VBQXFEO0FBQ3JELHlGQUFzRTtBQUN0RSx3REFBZ0M7QUFFaEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDO0FBQzFCLE1BQU0sbUJBQW1CLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUM7QUFFekMsU0FBUyxXQUFXLENBQUMsSUFBWTtJQUMvQixPQUFPLElBQUksS0FBSyxRQUFRLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsVUFBc0I7SUFDekMsT0FBTyxLQUFLLFVBQVUsTUFBTSxDQUFDLEdBQUcsRUFBRSxJQUFJO1FBQ3BDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDM0IsTUFBTSxJQUFJLEVBQUUsQ0FBQztZQUViLE9BQU87UUFDVCxDQUFDO1FBRUQsTUFBTSxVQUFVLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQzlCLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLDRCQUE0QixDQUFDLE1BQWM7SUFDbEQsT0FBTyxLQUFLLFVBQVUsc0JBQXNCLENBQUMs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
174
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWNvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY2xpLWNvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFvTUEseUJBa0NDO0FBRUQsNENBR0M7QUF2T0QsZ0RBQTZDO0FBRTdDLCtFQUE0RDtBQUM1RCxvRUFBMkQ7QUFDM0QsNEZBQXdFO0FBQ3hFLDhFQUFvRDtBQUNwRCxzRkFBa0U7QUFDbEUsNEVBQXlEO0FBQ3pELHVGQUFtRTtBQUNuRSxvREFBa0Q7QUFDbEQsNkVBQTBEO0FBQzFELDJFQUFpRTtBQUNqRSwyRkFBdUU7QUFDdkUscUNBQStDO0FBQy9DLDBEQUFxRDtBQUNyRCw2RUFBbUQ7QUFDbkQsK0VBQTREO0FBQzVELHdGQUE4RDtBQUM5RCx3RUFBcUQ7QUFDckQsMEVBQStEO0FBQy9ELHdFQUFxRDtBQUNyRCx1RkFBNkQ7QUFDN0QseUZBQXNFO0FBQ3RFLHdEQUFnQztBQUVoQyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUM7QUFDMUIsTUFBTSxtQkFBbUIsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsQ0FBQztBQUV6QyxTQUFTLFdBQVcsQ0FBQyxJQUFZO0lBQy9CLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0FBQ3pELENBQUM7QUFFRCxTQUFTLFdBQVcsQ0FBQyxVQUFzQjtJQUN6QyxPQUFPLEtBQUssVUFBVSxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUk7UUFDcEMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksRUFBRSxDQUFDO1lBRWIsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLFVBQVUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDOUIsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVELFNBQVMsNEJBQTRCLENBQUMsTUFBYztJQUNsRCxP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
@@ -0,0 +1,17 @@
1
+ export interface AgentDataClientOptions {
2
+ agentUrl: string;
3
+ token: string;
4
+ }
5
+ export interface AgentDataClient {
6
+ list(collection: string, query: Record<string, unknown>): Promise<Record<string, unknown>[]>;
7
+ countRaw(collection: string, query: Record<string, unknown>): Promise<unknown>;
8
+ listRelation(collection: string, parentId: string, relation: string, query: Record<string, unknown>): Promise<Record<string, unknown>[]>;
9
+ countRelationRaw(collection: string, parentId: string, relation: string, query: Record<string, unknown>): Promise<unknown>;
10
+ }
11
+ /**
12
+ * Thin data client bound to a request's agent token. Uses the raw `HttpRequester` (not `Collection`)
13
+ * so the BFF controls the query params — notably the resolved `timezone` — and can read the count
14
+ * endpoint's raw payload, which `collection.count()` coerces through `Number()` and loses.
15
+ */
16
+ export default function createAgentDataClient({ agentUrl, token, }: AgentDataClientOptions): AgentDataClient;
17
+ //# sourceMappingURL=agent-data-client.d.ts.map
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = createAgentDataClient;
4
+ const agent_client_1 = require("@forestadmin/agent-client");
5
+ /**
6
+ * Thin data client bound to a request's agent token. Uses the raw `HttpRequester` (not `Collection`)
7
+ * so the BFF controls the query params — notably the resolved `timezone` — and can read the count
8
+ * endpoint's raw payload, which `collection.count()` coerces through `Number()` and loses.
9
+ */
10
+ function createAgentDataClient({ agentUrl, token, }) {
11
+ const requester = new agent_client_1.HttpRequester(token, { url: agentUrl });
12
+ // Segments are passed raw: HttpRequester.buildUrl already runs the whole path through
13
+ // escapeUrlSlug/encodeURI, so pre-encoding here would double-encode (`|` -> `%257C`).
14
+ const relationPath = (collection, parentId, relation) => `/forest/${collection}/${parentId}/relationships/${relation}`;
15
+ return {
16
+ list: (collection, query) => requester.query({ method: 'get', path: `/forest/${collection}`, query }),
17
+ countRaw: (collection, query) => requester.query({
18
+ method: 'get',
19
+ path: `/forest/${collection}/count`,
20
+ query,
21
+ skipDeserialization: true,
22
+ }),
23
+ listRelation: (collection, parentId, relation, query) => requester.query({ method: 'get', path: relationPath(collection, parentId, relation), query }),
24
+ countRelationRaw: (collection, parentId, relation, query) => requester.query({
25
+ method: 'get',
26
+ path: `${relationPath(collection, parentId, relation)}/count`,
27
+ query,
28
+ skipDeserialization: true,
29
+ }),
30
+ };
31
+ }
32
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtZGF0YS1jbGllbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGF0YS9hZ2VudC1kYXRhLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQTZCQSx3Q0ErQkM7QUE1REQsNERBQTBEO0FBd0IxRDs7OztHQUlHO0FBQ0gsU0FBd0IscUJBQXFCLENBQUMsRUFDNUMsUUFBUSxFQUNSLEtBQUssR0FDa0I7SUFDdkIsTUFBTSxTQUFTLEdBQUcsSUFBSSw0QkFBYSxDQUFDLEtBQUssRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBRTlELHNGQUFzRjtJQUN0RixzRkFBc0Y7SUFDdEYsTUFBTSxZQUFZLEdBQUcsQ0FBQyxVQUFrQixFQUFFLFFBQWdCLEVBQUUsUUFBZ0IsRUFBRSxFQUFFLENBQzlFLFdBQVcsVUFBVSxJQUFJLFFBQVEsa0JBQWtCLFFBQVEsRUFBRSxDQUFDO0lBRWhFLE9BQU87UUFDTCxJQUFJLEVBQUUsQ0FBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FDMUIsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFdBQVcsVUFBVSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUM7UUFDMUUsUUFBUSxFQUFFLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxFQUFFLENBQzlCLFNBQVMsQ0FBQyxLQUFLLENBQUM7WUFDZCxNQUFNLEVBQUUsS0FBSztZQUNiLElBQUksRUFBRSxXQUFXLFVBQVUsUUFBUTtZQUNuQyxLQUFLO1lBQ0wsbUJBQW1CLEVBQUUsSUFBSTtTQUMxQixDQUFDO1FBQ0osWUFBWSxFQUFFLENBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FDdEQsU0FBUyxDQUFDLEtBQUssQ0FBQyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFlBQVksQ0FBQyxVQUFVLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDO1FBQy9GLGdCQUFnQixFQUFFLENBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEVBQUUsQ0FDMUQsU0FBUyxDQUFDLEtBQUssQ0FBQztZQUNkLE1BQU0sRUFBRSxLQUFLO1lBQ2IsSUFBSSxFQUFFLEdBQUcsWUFBWSxDQUFDLFVBQVUsRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7WUFDN0QsS0FBSztZQUNMLG1CQUFtQixFQUFFLElBQUk7U0FDMUIsQ0FBQztLQUNMLENBQUM7QUFDSixDQUFDIn0=
@@ -0,0 +1,36 @@
1
+ export interface BffSortClause {
2
+ field: string;
3
+ direction?: 'asc' | 'desc';
4
+ }
5
+ export interface BffPage {
6
+ limit: number;
7
+ offset: number;
8
+ }
9
+ export interface ListRequestBody {
10
+ filter?: unknown;
11
+ projection?: string[];
12
+ sort?: BffSortClause[];
13
+ page?: BffPage;
14
+ }
15
+ export interface CountRequestBody {
16
+ filter?: unknown;
17
+ }
18
+ export type RelationListRequestBody = ListRequestBody & {
19
+ parentId: string;
20
+ };
21
+ export type RelationCountRequestBody = CountRequestBody & {
22
+ parentId: string;
23
+ };
24
+ export type AgentQuery = Record<string, unknown> & {
25
+ timezone: string;
26
+ };
27
+ export declare function parseListRequest(body: unknown): ListRequestBody;
28
+ export declare function parseCountRequest(body: unknown): CountRequestBody;
29
+ export declare function buildListAgentQuery(collection: string, timezone: string, body: ListRequestBody): AgentQuery;
30
+ export declare function buildCountAgentQuery(timezone: string, body: CountRequestBody): AgentQuery;
31
+ export declare function collectListFieldPaths(body: ListRequestBody): string[];
32
+ export declare function parseParentId(parentId: unknown): string;
33
+ export declare function parseRelationListRequest(body: unknown): RelationListRequestBody;
34
+ export declare function parseRelationCountRequest(body: unknown): RelationCountRequestBody;
35
+ export declare function collectCountFieldPaths(body: CountRequestBody): string[];
36
+ //# sourceMappingURL=agent-query.d.ts.map
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseListRequest = parseListRequest;
4
+ exports.parseCountRequest = parseCountRequest;
5
+ exports.buildListAgentQuery = buildListAgentQuery;
6
+ exports.buildCountAgentQuery = buildCountAgentQuery;
7
+ exports.collectListFieldPaths = collectListFieldPaths;
8
+ exports.parseParentId = parseParentId;
9
+ exports.parseRelationListRequest = parseRelationListRequest;
10
+ exports.parseRelationCountRequest = parseRelationCountRequest;
11
+ exports.collectCountFieldPaths = collectCountFieldPaths;
12
+ const bff_local_errors_1 = require("../http/bff-local-errors");
13
+ function isPlainObject(value) {
14
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
15
+ }
16
+ // Validate the untyped request body before it reaches the query builders, so malformed shapes
17
+ // (e.g. `projection` or `sort` as a string) surface as 400 invalid_request rather than a 500 from
18
+ // an array method blowing up downstream.
19
+ function parseListRequest(body) {
20
+ if (!isPlainObject(body))
21
+ throw (0, bff_local_errors_1.invalidRequest)('Request body must be an object');
22
+ const { filter, projection, sort, page } = body;
23
+ if (projection !== undefined) {
24
+ if (!Array.isArray(projection) || projection.some(field => typeof field !== 'string')) {
25
+ throw (0, bff_local_errors_1.invalidRequest)('projection must be an array of field names');
26
+ }
27
+ }
28
+ if (sort !== undefined) {
29
+ const valid = Array.isArray(sort) &&
30
+ sort.every(clause => isPlainObject(clause) &&
31
+ typeof clause.field === 'string' &&
32
+ (clause.direction === undefined ||
33
+ clause.direction === 'asc' ||
34
+ clause.direction === 'desc'));
35
+ if (!valid)
36
+ throw (0, bff_local_errors_1.invalidRequest)('sort must be an array of { field, direction? }');
37
+ }
38
+ if (filter !== undefined && !isPlainObject(filter)) {
39
+ throw (0, bff_local_errors_1.invalidRequest)('filter must be an object');
40
+ }
41
+ if (page !== undefined) {
42
+ if (!isPlainObject(page)) {
43
+ throw (0, bff_local_errors_1.invalidRequest)('page must be an object with limit and offset');
44
+ }
45
+ if (!Number.isInteger(page.limit) || page.limit <= 0) {
46
+ throw (0, bff_local_errors_1.invalidRequest)('page.limit must be a positive integer');
47
+ }
48
+ if (!Number.isInteger(page.offset) || page.offset < 0) {
49
+ throw (0, bff_local_errors_1.invalidRequest)('page.offset must be a non-negative integer');
50
+ }
51
+ }
52
+ return body;
53
+ }
54
+ function parseCountRequest(body) {
55
+ if (!isPlainObject(body))
56
+ throw (0, bff_local_errors_1.invalidRequest)('Request body must be an object');
57
+ if (body.filter !== undefined && !isPlainObject(body.filter)) {
58
+ throw (0, bff_local_errors_1.invalidRequest)('filter must be an object');
59
+ }
60
+ return body;
61
+ }
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
+ function collectFilterFields(filter, acc) {
73
+ if (isBranch(filter)) {
74
+ filter.conditions.forEach(condition => collectFilterFields(condition, acc));
75
+ }
76
+ else if (isLeaf(filter)) {
77
+ acc.push(filter.field);
78
+ }
79
+ }
80
+ function serializeSort(sort) {
81
+ return sort.map(({ field, direction }) => (direction === 'desc' ? `-${field}` : field)).join(',');
82
+ }
83
+ // `parseListRequest` guarantees `limit` > 0 and `offset` >= 0 are integers; this only enforces the
84
+ // page-model rule. The agent paginates by page number/size, so an arbitrary offset that is not a
85
+ // whole multiple of the limit cannot be expressed — reject it rather than return a shifted window.
86
+ function serializePage(page) {
87
+ const { limit, offset } = page;
88
+ if (offset % limit !== 0) {
89
+ throw (0, bff_local_errors_1.invalidRequest)(`page.offset (${offset}) must be a multiple of page.limit (${limit})`);
90
+ }
91
+ return { 'page[size]': limit, 'page[number]': offset / limit + 1 };
92
+ }
93
+ function buildListAgentQuery(collection, timezone, body) {
94
+ const query = { timezone };
95
+ if (body.filter !== undefined)
96
+ query.filters = JSON.stringify(body.filter);
97
+ if (body.projection?.length)
98
+ query[`fields[${collection}]`] = body.projection.join(',');
99
+ if (body.sort?.length)
100
+ query.sort = serializeSort(body.sort);
101
+ if (body.page)
102
+ Object.assign(query, serializePage(body.page));
103
+ return query;
104
+ }
105
+ function buildCountAgentQuery(timezone, body) {
106
+ const query = { timezone };
107
+ if (body.filter !== undefined)
108
+ query.filters = JSON.stringify(body.filter);
109
+ return query;
110
+ }
111
+ function collectListFieldPaths(body) {
112
+ const paths = [...(body.projection ?? [])];
113
+ collectFilterFields(body.filter, paths);
114
+ (body.sort ?? []).forEach(({ field }) => paths.push(field));
115
+ return paths;
116
+ }
117
+ // The parent record id is opaque: a packed/composite id must survive unchanged, so its content is
118
+ // never inspected — only presence and primitive type. A finite number (single numeric pk) is
119
+ // coerced to string; anything else is a BFF-local 400 with no agent call.
120
+ function parseParentId(parentId) {
121
+ if (typeof parentId === 'string') {
122
+ if (parentId.trim() === '')
123
+ throw (0, bff_local_errors_1.invalidRequest)('parentId must not be empty');
124
+ return parentId;
125
+ }
126
+ if (typeof parentId === 'number' && Number.isFinite(parentId)) {
127
+ return String(parentId);
128
+ }
129
+ throw (0, bff_local_errors_1.invalidRequest)('parentId is required and must be a non-empty string or a number');
130
+ }
131
+ function parseRelationListRequest(body) {
132
+ const parentId = parseParentId(body?.parentId);
133
+ return { ...parseListRequest(body), parentId };
134
+ }
135
+ function parseRelationCountRequest(body) {
136
+ const parentId = parseParentId(body?.parentId);
137
+ return { ...parseCountRequest(body), parentId };
138
+ }
139
+ function collectCountFieldPaths(body) {
140
+ const paths = [];
141
+ collectFilterFields(body.filter, paths);
142
+ return paths;
143
+ }
144
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtcXVlcnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZGF0YS9hZ2VudC1xdWVyeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQW9DQSw0Q0E0Q0M7QUFFRCw4Q0FRQztBQW1ERCxrREFhQztBQUVELG9EQU1DO0FBRUQsc0RBTUM7QUFLRCxzQ0FZQztBQUVELDREQUlDO0FBRUQsOERBSUM7QUFFRCx3REFLQztBQTlNRCwrREFBMEQ7QUE2QjFELFNBQVMsYUFBYSxDQUFDLEtBQWM7SUFDbkMsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDOUUsQ0FBQztBQUVELDhGQUE4RjtBQUM5RixrR0FBa0c7QUFDbEcseUNBQXlDO0FBQ3pDLFNBQWdCLGdCQUFnQixDQUFDLElBQWE7SUFDNUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUM7UUFBRSxNQUFNLElBQUEsaUNBQWMsRUFBQyxnQ0FBZ0MsQ0FBQyxDQUFDO0lBRWpGLE1BQU0sRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsR0FBRyxJQUFJLENBQUM7SUFFaEQsSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sS0FBSyxLQUFLLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDdEYsTUFBTSxJQUFBLGlDQUFjLEVBQUMsNENBQTRDLENBQUMsQ0FBQztRQUNyRSxDQUFDO0lBQ0gsQ0FBQztJQUVELElBQUksSUFBSSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3ZCLE1BQU0sS0FBSyxHQUNULEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFD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
@@ -0,0 +1,12 @@
1
+ import type { AgentDataClient, AgentDataClientOptions } from './agent-data-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 DataRoutesMiddlewareOptions {
6
+ store: ReadModelStore;
7
+ agentUrl: string;
8
+ logger: Logger;
9
+ createClient?: (options: AgentDataClientOptions) => AgentDataClient;
10
+ }
11
+ export default function createDataRoutesMiddleware({ store, agentUrl, logger, createClient, }: DataRoutesMiddlewareOptions): Middleware;
12
+ //# sourceMappingURL=data-routes-middleware.d.ts.map
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.default = createDataRoutesMiddleware;
7
+ const agent_data_client_1 = __importDefault(require("./agent-data-client"));
8
+ const agent_query_1 = require("./agent-query");
9
+ const response_mappers_1 = require("./response-mappers");
10
+ const agent_error_mapper_1 = require("../http/agent-error-mapper");
11
+ const bff_http_error_1 = require("../http/bff-http-error");
12
+ const bff_local_errors_1 = require("../http/bff-local-errors");
13
+ const errors_1 = __importDefault(require("../read-model/errors"));
14
+ const relation_field_guard_1 = __importDefault(require("../validation/relation-field-guard"));
15
+ const DATA_ROUTE = /^\/agent\/v1\/([^/]+)\/(list|count)$/;
16
+ const RELATION_ROUTE = /^\/agent\/v1\/([^/]+)\/relations\/([^/]+)\/(list|count)$/;
17
+ // Only to-many relations expose list/count on the agent; to-one relations get update-relation only.
18
+ // A polymorphic relation carrying multiple targets is always the to-one (PolymorphicManyToOne) side.
19
+ function resolveForeignCollection(target) {
20
+ if (!target || !('target' in target))
21
+ return null;
22
+ if (target.type !== 'HasMany' && target.type !== 'BelongsToMany')
23
+ return null;
24
+ return target.target;
25
+ }
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
+ async function handleList(ctx, body, deps) {
55
+ (0, relation_field_guard_1.default)((0, agent_query_1.collectListFieldPaths)(body));
56
+ 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);
58
+ ctx.status = 200;
59
+ ctx.body = (0, response_mappers_1.mapListResponse)(deps.collection, records, deps.primaryKeys);
60
+ }
61
+ async function handleCount(ctx, body, deps) {
62
+ (0, relation_field_guard_1.default)((0, agent_query_1.collectCountFieldPaths)(body));
63
+ const query = (0, agent_query_1.buildCountAgentQuery)(deps.timezone, body);
64
+ const raw = await callAgent(() => deps.client.countRaw(deps.collection, query), deps.logger);
65
+ ctx.status = 200;
66
+ ctx.body = (0, response_mappers_1.mapCountResponse)(raw);
67
+ }
68
+ async function handleRelationList(ctx, body, deps) {
69
+ // The nested-relation guard IS wired here: the agent's list-related asserts browse only on the
70
+ // immediate foreign collection, so a nested `:`-path would traverse to a third collection whose
71
+ // browse is never checked. Plain foreign fields (no `:`) are unaffected.
72
+ (0, relation_field_guard_1.default)((0, agent_query_1.collectListFieldPaths)(body));
73
+ 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);
75
+ ctx.status = 200;
76
+ ctx.body = (0, response_mappers_1.mapListResponse)(deps.foreignCollection, records, deps.primaryKeys);
77
+ }
78
+ async function handleRelationCount(ctx, body, deps) {
79
+ (0, relation_field_guard_1.default)((0, agent_query_1.collectCountFieldPaths)(body));
80
+ 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);
82
+ ctx.status = 200;
83
+ ctx.body = (0, response_mappers_1.mapCountResponse)(raw);
84
+ }
85
+ async function handleRelation(ctx, rawBody, match, { deps, readModel }) {
86
+ const relation = decodeSegment(match[2], 'relation name');
87
+ const operation = match[3];
88
+ // The URL identity (does this listable relation exist?) is resolved before the body,
89
+ // so a bad path 404s before its payload is inspected.
90
+ const foreignCollection = resolveForeignCollection(readModel.getRelationTarget(deps.collection, relation));
91
+ // TODO(PRD-672): the read-model's relation map is the allow-list, so an absent/to-one/polymorphic
92
+ // relation cannot be told from a disallowed one — every non-listable relation maps to 404 here;
93
+ // `relation_not_allowed` (403) has no local trigger, mirroring `collection_not_allowed`.
94
+ if (!foreignCollection) {
95
+ throw (0, bff_local_errors_1.unknownRelation)(`Unknown relation: ${deps.collection}.${relation}`);
96
+ }
97
+ // The agent's count-related authorizes only the parent, so an unguarded foreign collection would
98
+ // leak a hidden collection's rows/count. Guard it here, mirroring the parent allow-list check.
99
+ if (!readModel.isCollectionAllowed(foreignCollection)) {
100
+ throw (0, bff_local_errors_1.unknownCollection)();
101
+ }
102
+ const relationDeps = { ...deps, relation, foreignCollection };
103
+ if (operation === 'list') {
104
+ await handleRelationList(ctx, (0, agent_query_1.parseRelationListRequest)(rawBody), {
105
+ ...relationDeps,
106
+ primaryKeys: readModel.getPrimaryKeys(foreignCollection),
107
+ });
108
+ }
109
+ else {
110
+ await handleRelationCount(ctx, (0, agent_query_1.parseRelationCountRequest)(rawBody), relationDeps);
111
+ }
112
+ }
113
+ function createDataRoutesMiddleware({ store, agentUrl, logger, createClient = agent_data_client_1.default, }) {
114
+ return async function dataRoutesMiddleware(ctx, next) {
115
+ const dataMatch = DATA_ROUTE.exec(ctx.path);
116
+ const relationMatch = dataMatch ? null : RELATION_ROUTE.exec(ctx.path);
117
+ const match = dataMatch ?? relationMatch;
118
+ if (!match || ctx.method !== 'POST') {
119
+ await next();
120
+ return;
121
+ }
122
+ const collection = decodeSegment(match[1], 'collection name');
123
+ // The agent token is minted only on the API-key path; the OAuth path sets a principal but no
124
+ // agent token yet. Fail closed instead of calling the agent with `Bearer undefined`.
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);
130
+ if (!readModel.isCollectionAllowed(collection)) {
131
+ // TODO(PRD-671): the read-model exposes a single allow-list (the exposed collections), so it
132
+ // cannot tell an unknown collection from a known-but-disallowed one. Every absent name maps
133
+ // to 404 here; `collection_not_allowed` (403) has no local trigger until a distinct exposure
134
+ // source exists. Escalated on the ticket — revisit when Anthony answers.
135
+ throw (0, bff_local_errors_1.unknownCollection)(`Unknown collection: ${collection}`);
136
+ }
137
+ const deps = {
138
+ collection,
139
+ client: createClient({ agentUrl, token }),
140
+ timezone: ctx.state.timezone,
141
+ logger,
142
+ };
143
+ const rawBody = ctx.request.body ?? {};
144
+ if (relationMatch) {
145
+ await handleRelation(ctx, rawBody, relationMatch, { deps, readModel });
146
+ return;
147
+ }
148
+ const operation = match[2];
149
+ if (operation === 'list') {
150
+ const body = (0, agent_query_1.parseListRequest)(rawBody);
151
+ await handleList(ctx, body, { ...deps, primaryKeys: readModel.getPrimaryKeys(collection) });
152
+ }
153
+ else {
154
+ const body = (0, agent_query_1.parseCountRequest)(rawBody);
155
+ await handleCount(ctx, body, deps);
156
+ }
157
+ };
158
+ }
159
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1yb3V0ZXMtbWlkZGxld2FyZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhL2RhdGEtcm91dGVzLW1pZGRsZXdhcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFxTUEsNkNBMkRDO0FBblBELDRFQUErRDtBQUMvRCwrQ0FTdUI7QUFDdkIseURBQXVFO0FBQ3ZFLG1FQUEyRDtBQUMzRCwyREFBc0Q7QUFDdEQsK0RBS2tDO0FBQ2xDLGtFQUEwRDtBQUMxRCw4RkFBNEU7QUFFNUUsTUFBTSxVQUFVLEdBQUcsc0NBQXNDLENBQUM7QUFDMUQsTUFBTSxjQUFjLEdBQUcsMERBQTBELENBQUM7QUFFbEYsb0dBQW9HO0FBQ3BHLHFHQUFxRztBQUNyRyxTQUFTLHdCQUF3QixDQUFDLE1BQWtDO0lBQ2xFLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUNsRCxJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssU0FBUyxJQUFJLE1BQU0sQ0FBQyxJQUFJLEtBQUssZUFBZTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBRTlFLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQztBQUN2QixDQUFDO0FBa0JELFNBQVMsYUFBYSxDQUFDLEdBQVcsRUFBRSxLQUFhO0lBQy9DLElBQUksQ0FBQztRQUNILE9BQU8sa0JBQWtCLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLE1BQU0sSUFBQSxpQ0FBYyxFQUFDLGFBQWEsS0FBSyxVQUFVLENBQUMsQ0FBQztJQUNyRCxDQUFDO0FBQ0gsQ0FBQztBQUVELEtBQUssVUFBVSxnQkFBZ0IsQ0FBQyxLQUFxQjtJQUNuRCxJQUFJLENBQUM7UUFDSCxPQUFPLE1BQU0sS0FBSyxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3BDLENBQUM7SUFBQyxPQUFPLEtBQUssRUFBRSxDQUFD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
@@ -0,0 +1,9 @@
1
+ import type { PrimaryKeyField } from '../read-model/read-model';
2
+ /**
3
+ * Rebuild the structured primary key of a record from its opaque packed id, mirroring the agent's
4
+ * `IdUtils.packId`/`unpackId` (`|`-joined values, `Number` columns cast back to numbers). Returns a
5
+ * `{ pkField: value }` map for `__forest.primaryKey`. Throws a mapping error rather than emitting a
6
+ * malformed key when the schema lacks key metadata or the packed id shape does not match it.
7
+ */
8
+ export default function unpackPrimaryKey(packedId: string, primaryKeys: PrimaryKeyField[]): Record<string, string | number>;
9
+ //# sourceMappingURL=pack-id.d.ts.map
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = unpackPrimaryKey;
4
+ const bff_local_errors_1 = require("../http/bff-local-errors");
5
+ const PACKED_ID_SEPARATOR = '|';
6
+ // The only column type unpacked to a number, mirroring the agent's `IdUtils.unpackId`.
7
+ const NUMBER_COLUMN_TYPE = 'Number';
8
+ /**
9
+ * Rebuild the structured primary key of a record from its opaque packed id, mirroring the agent's
10
+ * `IdUtils.packId`/`unpackId` (`|`-joined values, `Number` columns cast back to numbers). Returns a
11
+ * `{ pkField: value }` map for `__forest.primaryKey`. Throws a mapping error rather than emitting a
12
+ * malformed key when the schema lacks key metadata or the packed id shape does not match it.
13
+ */
14
+ function unpackPrimaryKey(packedId, primaryKeys) {
15
+ if (primaryKeys.length === 0) {
16
+ throw (0, bff_local_errors_1.mappingError)('Cannot build primary key: the collection exposes no key metadata');
17
+ }
18
+ const values = packedId.split(PACKED_ID_SEPARATOR);
19
+ if (values.length !== primaryKeys.length) {
20
+ throw (0, bff_local_errors_1.mappingError)(`Cannot build primary key: expected ${primaryKeys.length} values, found ${values.length}`);
21
+ }
22
+ const result = {};
23
+ primaryKeys.forEach(({ name, type }, index) => {
24
+ const value = values[index];
25
+ if (type !== NUMBER_COLUMN_TYPE) {
26
+ result[name] = value;
27
+ return;
28
+ }
29
+ const numeric = Number(value);
30
+ if (Number.isNaN(numeric)) {
31
+ throw (0, bff_local_errors_1.mappingError)(`Cannot build primary key: invalid numeric value "${value}" for "${name}"`);
32
+ }
33
+ result[name] = numeric;
34
+ });
35
+ return result;
36
+ }
37
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFjay1pZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYXRhL3BhY2staWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFlQSxtQ0F1Q0M7QUFwREQsK0RBQXdEO0FBRXhELE1BQU0sbUJBQW1CLEdBQUcsR0FBRyxDQUFDO0FBRWhDLHVGQUF1RjtBQUN2RixNQUFNLGtCQUFrQixHQUFHLFFBQVEsQ0FBQztBQUVwQzs7Ozs7R0FLRztBQUNILFNBQXdCLGdCQUFnQixDQUN0QyxRQUFnQixFQUNoQixXQUE4QjtJQUU5QixJQUFJLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDN0IsTUFBTSxJQUFBLCtCQUFZLEVBQUMsa0VBQWtFLENBQUMsQ0FBQztJQUN6RixDQUFDO0lBRUQsTUFBTSxNQUFNLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0lBRW5ELElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDekMsTUFBTSxJQUFBLCtCQUFZLEVBQ2hCLHNDQUFzQyxXQUFXLENBQUMsTUFBTSxrQkFBa0IsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUMxRixDQUFDO0lBQ0osQ0FBQztJQUVELE1BQU0sTUFBTSxHQUFvQyxFQUFFLENBQUM7SUFFbkQsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFO1FBQzVDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUU1QixJQUFJLElBQUksS0FBSyxrQkFBa0IsRUFBRSxDQUFDO1lBQ2hDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUM7WUFFckIsT0FBTztRQUNULENBQUM7UUFFRCxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFOUIsSUFBSSxNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDMUIsTUFBTSxJQUFBLCtCQUFZLEVBQ2hCLG9EQUFvRCxLQUFLLFVBQVUsSUFBSSxHQUFHLENBQzNFLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE9BQU8sQ0FBQztJQUN6QixDQUFDLENBQUMsQ0FBQztJQUVILE9BQU8sTUFBTSxDQUFDO0FBQ2hCLENBQUMifQ==