@terreno/api 0.15.1 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ ## 0.16.0
4
+
5
+ ### Added
6
+
7
+ - **modelRouter actions** — Declare `instanceActions` and `collectionActions` on `ModelRouterOptions` for named operations at `/resource/:id/action` and `/resource/action`. Handlers receive `{req, res, user, doc?, body, query}`; return values are wrapped in `{data: ...}`. OpenAPI operations are emitted automatically when `openApi` is configured.
8
+ - **`loadDocOr404`** — Shared document loader used by permission middleware and instance actions (soft-delete-aware 404 metadata preserved).
9
+
10
+ ### Changed
11
+
12
+ - Permission middleware doc loading now delegates to `loadDocOr404` (behavior-preserving).
13
+
14
+ ### Dependencies
15
+
16
+ - Added `@asteasolutions/zod-to-openapi` ^8.5.0 (direct dependency).
17
+ - Added **`zod` ^4.3.6 as a peer dependency** — backends that define action Zod schemas must install `zod`.
18
+
19
+ ### Migration
20
+
21
+ - Regenerate frontend SDKs after adding actions; `operationId` values follow `{tag}_{actionName}` (e.g. `todos_markComplete`).
@@ -0,0 +1,55 @@
1
+ import type express from "express";
2
+ import type { Request, Response } from "express";
3
+ import type { Model } from "mongoose";
4
+ import type { ZodSchema } from "zod";
5
+ import { type ModelRouterOptions } from "./api";
6
+ import { type User } from "./auth";
7
+ import { type PermissionMethod } from "./permissions";
8
+ export declare const ACTION_NAME_PATTERN: RegExp;
9
+ export interface ActionContext<TDoc, TBody, TQuery> {
10
+ req: Request;
11
+ res: Response;
12
+ user: User | undefined;
13
+ body: TBody;
14
+ query: TQuery;
15
+ doc: TDoc;
16
+ }
17
+ interface BaseActionConfig<TBody, TQuery, TResponse> {
18
+ method: "GET" | "POST";
19
+ permissions: PermissionMethod<unknown>[];
20
+ body?: ZodSchema<TBody>;
21
+ query?: ZodSchema<TQuery>;
22
+ response?: ZodSchema<TResponse>;
23
+ summary?: string;
24
+ description?: string;
25
+ tag?: string;
26
+ status?: number;
27
+ }
28
+ export interface InstanceActionConfig<TDoc, TBody, TQuery, TResponse> extends BaseActionConfig<TBody, TQuery, TResponse> {
29
+ handler: (ctx: ActionContext<TDoc, TBody, TQuery>) => TResponse | Promise<TResponse>;
30
+ }
31
+ export interface CollectionActionConfig<TBody, TQuery, TResponse> extends BaseActionConfig<TBody, TQuery, TResponse> {
32
+ handler: (ctx: Omit<ActionContext<never, TBody, TQuery>, "doc">) => TResponse | Promise<TResponse>;
33
+ }
34
+ export declare const defineInstanceAction: <TDoc, TBody = unknown, TQuery = unknown, TResponse = unknown>(config: InstanceActionConfig<TDoc, TBody, TQuery, TResponse>) => InstanceActionConfig<TDoc, TBody, TQuery, TResponse>;
35
+ export declare const defineCollectionAction: <TBody = unknown, TQuery = unknown, TResponse = unknown>(config: CollectionActionConfig<TBody, TQuery, TResponse>) => CollectionActionConfig<TBody, TQuery, TResponse>;
36
+ type ActionScope = "instance" | "collection";
37
+ export declare const runActionPermissions: <T>(action: BaseActionConfig<unknown, unknown, unknown>, scope: ActionScope, model: Model<T>, req: Request, doc?: T) => Promise<void>;
38
+ export declare const validateActionRequest: <TBody, TQuery>({ action, req, }: {
39
+ action: BaseActionConfig<TBody, TQuery, unknown>;
40
+ req: Request;
41
+ }) => {
42
+ body: TBody | undefined;
43
+ query: TQuery | undefined;
44
+ };
45
+ export declare const wrapActionResponse: (handlerResult: unknown, action: BaseActionConfig<unknown, unknown, unknown>, res: Response) => void;
46
+ export declare const createActionOpenApiMiddleware: <T>({ action, scope, actionName, model, options, }: {
47
+ action: BaseActionConfig<unknown, unknown, unknown>;
48
+ scope: ActionScope;
49
+ actionName: string;
50
+ model: Model<T>;
51
+ options: Partial<ModelRouterOptions<T>>;
52
+ }) => express.RequestHandler;
53
+ export declare const assertNoActionCollisions: <T>(model: Model<T>, options: Pick<ModelRouterOptions<T>, "instanceActions" | "collectionActions">) => void;
54
+ export declare const registerActionRoutes: <T>(router: express.Router, model: Model<T>, options: Partial<ModelRouterOptions<T>>) => void;
55
+ export {};
@@ -0,0 +1,472 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ var __values = (this && this.__values) || function(o) {
50
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
51
+ if (m) return m.call(o);
52
+ if (o && typeof o.length === "number") return {
53
+ next: function () {
54
+ if (o && i >= o.length) o = void 0;
55
+ return { value: o && o[i++], done: !o };
56
+ }
57
+ };
58
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
59
+ };
60
+ var __read = (this && this.__read) || function (o, n) {
61
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
62
+ if (!m) return o;
63
+ var i = m.call(o), r, ar = [], e;
64
+ try {
65
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
66
+ }
67
+ catch (error) { e = { error: error }; }
68
+ finally {
69
+ try {
70
+ if (r && !r.done && (m = i["return"])) m.call(i);
71
+ }
72
+ finally { if (e) throw e.error; }
73
+ }
74
+ return ar;
75
+ };
76
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
77
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
78
+ if (ar || !(i in from)) {
79
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
80
+ ar[i] = from[i];
81
+ }
82
+ }
83
+ return to.concat(ar || Array.prototype.slice.call(from));
84
+ };
85
+ Object.defineProperty(exports, "__esModule", { value: true });
86
+ exports.registerActionRoutes = exports.assertNoActionCollisions = exports.createActionOpenApiMiddleware = exports.wrapActionResponse = exports.validateActionRequest = exports.runActionPermissions = exports.defineCollectionAction = exports.defineInstanceAction = exports.ACTION_NAME_PATTERN = void 0;
87
+ var zod_to_openapi_1 = require("@asteasolutions/zod-to-openapi");
88
+ var api_1 = require("./api");
89
+ var auth_1 = require("./auth");
90
+ var docLoader_1 = require("./docLoader");
91
+ var errors_1 = require("./errors");
92
+ var openApi_1 = require("./openApi");
93
+ var permissions_1 = require("./permissions");
94
+ // At least two characters: leading letter plus one or more alphanumeric/_/- chars.
95
+ exports.ACTION_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]+$/;
96
+ var defineInstanceAction = function (config) {
97
+ return config;
98
+ };
99
+ exports.defineInstanceAction = defineInstanceAction;
100
+ var defineCollectionAction = function (config) {
101
+ return config;
102
+ };
103
+ exports.defineCollectionAction = defineCollectionAction;
104
+ var mapActionToCrudMethod = function (scope, httpMethod) {
105
+ if (scope === "instance") {
106
+ return httpMethod === "GET" ? "read" : "update";
107
+ }
108
+ return httpMethod === "GET" ? "list" : "create";
109
+ };
110
+ var runActionPermissions = function (action, scope, model, req, doc) { return __awaiter(void 0, void 0, void 0, function () {
111
+ var method, allowed;
112
+ var _a, _b;
113
+ return __generator(this, function (_c) {
114
+ switch (_c.label) {
115
+ case 0:
116
+ method = mapActionToCrudMethod(scope, action.method);
117
+ return [4 /*yield*/, (0, permissions_1.checkPermissions)(method, action.permissions, req.user, doc)];
118
+ case 1:
119
+ allowed = _c.sent();
120
+ if (allowed) {
121
+ return [2 /*return*/];
122
+ }
123
+ if (!doc) {
124
+ throw new errors_1.APIError({
125
+ status: 405,
126
+ title: "Access to ".concat(method.toUpperCase(), " on ").concat(model.modelName, " ") + "denied for ".concat((_a = req.user) === null || _a === void 0 ? void 0 : _a.id),
127
+ });
128
+ }
129
+ throw new errors_1.APIError({
130
+ status: 403,
131
+ title: "Access to ".concat(method.toUpperCase(), " on ").concat(model.modelName, ":").concat(req.params.id, " ") +
132
+ "denied for ".concat((_b = req.user) === null || _b === void 0 ? void 0 : _b.id),
133
+ });
134
+ }
135
+ });
136
+ }); };
137
+ exports.runActionPermissions = runActionPermissions;
138
+ var flattenZodFieldErrors = function (fieldErrors) {
139
+ var e_1, _a;
140
+ var fields = {};
141
+ try {
142
+ for (var _b = __values(Object.entries(fieldErrors)), _c = _b.next(); !_c.done; _c = _b.next()) {
143
+ var _d = __read(_c.value, 2), key = _d[0], msgs = _d[1];
144
+ if (msgs && msgs.length > 0) {
145
+ fields[key] = msgs[0];
146
+ }
147
+ }
148
+ }
149
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
150
+ finally {
151
+ try {
152
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
153
+ }
154
+ finally { if (e_1) throw e_1.error; }
155
+ }
156
+ return fields;
157
+ };
158
+ var validateActionRequest = function (_a) {
159
+ var action = _a.action, req = _a.req;
160
+ var body;
161
+ if (action.body) {
162
+ var parsedBody = action.body.safeParse(req.body);
163
+ if (!parsedBody.success) {
164
+ throw new errors_1.APIError({
165
+ fields: flattenZodFieldErrors(parsedBody.error.flatten().fieldErrors),
166
+ status: 400,
167
+ title: "Validation failed",
168
+ });
169
+ }
170
+ body = parsedBody.data;
171
+ }
172
+ else {
173
+ body = req.body;
174
+ }
175
+ var query;
176
+ if (action.query) {
177
+ var parsedQuery = action.query.safeParse(req.query);
178
+ if (!parsedQuery.success) {
179
+ throw new errors_1.APIError({
180
+ fields: flattenZodFieldErrors(parsedQuery.error.flatten().fieldErrors),
181
+ status: 400,
182
+ title: "Validation failed",
183
+ });
184
+ }
185
+ query = parsedQuery.data;
186
+ }
187
+ else {
188
+ query = req.query;
189
+ }
190
+ return { body: body, query: query };
191
+ };
192
+ exports.validateActionRequest = validateActionRequest;
193
+ var wrapActionResponse = function (handlerResult, action, res) {
194
+ var _a;
195
+ if (res.headersSent) {
196
+ return;
197
+ }
198
+ res.status((_a = action.status) !== null && _a !== void 0 ? _a : 200).json({ data: handlerResult !== null && handlerResult !== void 0 ? handlerResult : null });
199
+ };
200
+ exports.wrapActionResponse = wrapActionResponse;
201
+ var inlineOpenApiSchemaCounter = 0;
202
+ var zodToJsonSchema = function (zodSchema) {
203
+ var _a;
204
+ var registry = new zod_to_openapi_1.OpenAPIRegistry();
205
+ var refId = "ActionInlineSchema".concat(inlineOpenApiSchemaCounter++);
206
+ registry.register(refId, zodSchema);
207
+ var generator = new zod_to_openapi_1.OpenApiGeneratorV3(registry.definitions);
208
+ var components = generator.generateComponents().components;
209
+ var schema = (_a = components === null || components === void 0 ? void 0 : components.schemas) === null || _a === void 0 ? void 0 : _a[refId];
210
+ if (schema && typeof schema === "object") {
211
+ return schema;
212
+ }
213
+ return { type: "object" };
214
+ };
215
+ var queryParametersFromSchema = function (querySchema) {
216
+ var _a;
217
+ var jsonSchema = zodToJsonSchema(querySchema);
218
+ var properties = jsonSchema.properties;
219
+ if (!properties) {
220
+ return [];
221
+ }
222
+ var requiredFields = (_a = jsonSchema.required) !== null && _a !== void 0 ? _a : [];
223
+ return Object.entries(properties).map(function (_a) {
224
+ var _b = __read(_a, 2), name = _b[0], schema = _b[1];
225
+ return ({
226
+ in: "query",
227
+ name: name,
228
+ required: requiredFields.includes(name),
229
+ schema: schema,
230
+ });
231
+ });
232
+ };
233
+ var createActionOpenApiMiddleware = function (_a) {
234
+ var _b;
235
+ var _c, _d, _e, _f;
236
+ var action = _a.action, scope = _a.scope, actionName = _a.actionName, model = _a.model, options = _a.options;
237
+ if (!((_c = options.openApi) === null || _c === void 0 ? void 0 : _c.path)) {
238
+ return function (_req, _res, next) { return next(); };
239
+ }
240
+ var tag = (_d = action.tag) !== null && _d !== void 0 ? _d : model.collection.collectionName;
241
+ var statusCode = String((_e = action.status) !== null && _e !== void 0 ? _e : 200);
242
+ var parameters = [];
243
+ if (scope === "instance") {
244
+ parameters.push({
245
+ in: "path",
246
+ name: "id",
247
+ required: true,
248
+ schema: { type: "string" },
249
+ });
250
+ }
251
+ if (action.query) {
252
+ parameters.push.apply(parameters, __spreadArray([], __read(queryParametersFromSchema(action.query)), false));
253
+ }
254
+ var operation = {
255
+ description: action.description,
256
+ operationId: "".concat(tag, "_").concat(actionName),
257
+ parameters: parameters,
258
+ responses: __assign((_b = {}, _b[statusCode] = {
259
+ content: {
260
+ "application/json": {
261
+ schema: action.response
262
+ ? {
263
+ properties: {
264
+ data: zodToJsonSchema(action.response),
265
+ },
266
+ required: ["data"],
267
+ type: "object",
268
+ }
269
+ : {
270
+ properties: {
271
+ data: { type: "object" },
272
+ },
273
+ type: "object",
274
+ },
275
+ },
276
+ },
277
+ description: "Successful response",
278
+ }, _b), openApi_1.defaultOpenApiErrorResponses),
279
+ summary: (_f = action.summary) !== null && _f !== void 0 ? _f : "".concat(actionName, " ").concat(scope, " action"),
280
+ tags: [tag],
281
+ };
282
+ if (action.body) {
283
+ operation.requestBody = {
284
+ content: {
285
+ "application/json": {
286
+ schema: zodToJsonSchema(action.body),
287
+ },
288
+ },
289
+ required: true,
290
+ };
291
+ }
292
+ return options.openApi.path(operation);
293
+ };
294
+ exports.createActionOpenApiMiddleware = createActionOpenApiMiddleware;
295
+ var getArrayFieldNames = function (model) {
296
+ return Object.values(model.schema.paths)
297
+ .filter(function (config) { return config.instance === "Array"; })
298
+ .map(function (config) { return config.path; });
299
+ };
300
+ // Registration-time validation throws plain Error so misconfiguration fails at app boot.
301
+ var validateActionConfig = function (scope, name, config) {
302
+ if (!name) {
303
+ throw new Error("Action name cannot be empty");
304
+ }
305
+ if (!exports.ACTION_NAME_PATTERN.test(name)) {
306
+ throw new Error("Invalid action name \"".concat(name, "\". Action names must match ").concat(exports.ACTION_NAME_PATTERN.toString()));
307
+ }
308
+ if (config.permissions === undefined) {
309
+ throw new Error("Action \"".concat(name, "\" (").concat(scope, ") is missing required \"permissions\". ") +
310
+ "Provide at least one permission function, or [] to disable the action.");
311
+ }
312
+ if (config.method !== "GET" && config.method !== "POST") {
313
+ throw new Error("Action \"".concat(name, "\" (").concat(scope, ") only supports GET and POST methods"));
314
+ }
315
+ };
316
+ var assertNoActionCollisions = function (model, options) {
317
+ var arrayFields = new Set(getArrayFieldNames(model));
318
+ var validateMap = function (actions, scope) {
319
+ var e_2, _a;
320
+ if (!actions) {
321
+ return;
322
+ }
323
+ try {
324
+ for (var _b = __values(Object.entries(actions)), _c = _b.next(); !_c.done; _c = _b.next()) {
325
+ var _d = __read(_c.value, 2), name_1 = _d[0], config = _d[1];
326
+ validateActionConfig(scope, name_1, config);
327
+ if (scope === "instance" && arrayFields.has(name_1)) {
328
+ throw new Error("instanceAction '".concat(name_1, "' collides with array field operations on /:id/").concat(name_1));
329
+ }
330
+ }
331
+ }
332
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
333
+ finally {
334
+ try {
335
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
336
+ }
337
+ finally { if (e_2) throw e_2.error; }
338
+ }
339
+ };
340
+ validateMap(options.instanceActions, "instance");
341
+ validateMap(options.collectionActions, "collection");
342
+ };
343
+ exports.assertNoActionCollisions = assertNoActionCollisions;
344
+ var buildActionMiddleware = function (model, options, registered) {
345
+ var action = registered.config;
346
+ var scope = registered.scope;
347
+ var actionName = registered.name;
348
+ var preDocPermissions = function (req, _res, next) { return __awaiter(void 0, void 0, void 0, function () {
349
+ var error_1;
350
+ return __generator(this, function (_a) {
351
+ switch (_a.label) {
352
+ case 0:
353
+ _a.trys.push([0, 2, , 3]);
354
+ return [4 /*yield*/, (0, exports.runActionPermissions)(action, scope, model, req)];
355
+ case 1:
356
+ _a.sent();
357
+ return [2 /*return*/, next()];
358
+ case 2:
359
+ error_1 = _a.sent();
360
+ return [2 /*return*/, next(error_1)];
361
+ case 3: return [2 /*return*/];
362
+ }
363
+ });
364
+ }); };
365
+ var loadDocAndPostPermissions = scope === "instance"
366
+ ? function (req, _res, next) { return __awaiter(void 0, void 0, void 0, function () {
367
+ var doc, error_2;
368
+ return __generator(this, function (_a) {
369
+ switch (_a.label) {
370
+ case 0:
371
+ _a.trys.push([0, 3, , 4]);
372
+ return [4 /*yield*/, (0, docLoader_1.loadDocOr404)(model, req.params.id, options.populatePaths)];
373
+ case 1:
374
+ doc = _a.sent();
375
+ req.obj = doc;
376
+ return [4 /*yield*/, (0, exports.runActionPermissions)(action, scope, model, req, doc)];
377
+ case 2:
378
+ _a.sent();
379
+ return [2 /*return*/, next()];
380
+ case 3:
381
+ error_2 = _a.sent();
382
+ return [2 /*return*/, next(error_2)];
383
+ case 4: return [2 /*return*/];
384
+ }
385
+ });
386
+ }); }
387
+ : null;
388
+ var validateAndRun = (0, api_1.asyncHandler)(function (req, res) { return __awaiter(void 0, void 0, void 0, function () {
389
+ var _a, body, query, doc, ctx, result, _b;
390
+ return __generator(this, function (_c) {
391
+ switch (_c.label) {
392
+ case 0:
393
+ _a = (0, exports.validateActionRequest)({ action: action, req: req }), body = _a.body, query = _a.query;
394
+ doc = scope === "instance" ? req.obj : undefined;
395
+ ctx = {
396
+ body: body,
397
+ doc: doc,
398
+ query: query,
399
+ req: req,
400
+ res: res,
401
+ user: req.user,
402
+ };
403
+ if (!(scope === "instance")) return [3 /*break*/, 2];
404
+ return [4 /*yield*/, action.handler(ctx)];
405
+ case 1:
406
+ _b = _c.sent();
407
+ return [3 /*break*/, 4];
408
+ case 2: return [4 /*yield*/, action.handler(ctx)];
409
+ case 3:
410
+ _b = _c.sent();
411
+ _c.label = 4;
412
+ case 4:
413
+ result = _b;
414
+ (0, exports.wrapActionResponse)(result, action, res);
415
+ return [2 /*return*/];
416
+ }
417
+ });
418
+ }); });
419
+ var chain = [
420
+ (0, auth_1.authenticateMiddleware)(options.allowAnonymous),
421
+ (0, exports.createActionOpenApiMiddleware)({ action: action, actionName: actionName, model: model, options: options, scope: scope }),
422
+ preDocPermissions,
423
+ ];
424
+ if (loadDocAndPostPermissions) {
425
+ chain.push(loadDocAndPostPermissions);
426
+ }
427
+ chain.push(validateAndRun);
428
+ return chain;
429
+ };
430
+ var registerActionRoutes = function (router, model, options) {
431
+ var e_3, _a;
432
+ var _b, _c;
433
+ var instanceActions = (_b = options.instanceActions) !== null && _b !== void 0 ? _b : {};
434
+ var collectionActions = (_c = options.collectionActions) !== null && _c !== void 0 ? _c : {};
435
+ var registeredActions = __spreadArray(__spreadArray([], __read(Object.entries(instanceActions).map(function (_a) {
436
+ var _b = __read(_a, 2), name = _b[0], config = _b[1];
437
+ return ({
438
+ config: config,
439
+ name: name,
440
+ scope: "instance",
441
+ });
442
+ })), false), __read(Object.entries(collectionActions).map(function (_a) {
443
+ var _b = __read(_a, 2), name = _b[0], config = _b[1];
444
+ return ({
445
+ config: config,
446
+ name: name,
447
+ scope: "collection",
448
+ });
449
+ })), false);
450
+ try {
451
+ for (var registeredActions_1 = __values(registeredActions), registeredActions_1_1 = registeredActions_1.next(); !registeredActions_1_1.done; registeredActions_1_1 = registeredActions_1.next()) {
452
+ var registered = registeredActions_1_1.value;
453
+ var config = registered.config, name_2 = registered.name, scope = registered.scope;
454
+ var middleware = buildActionMiddleware(model, options, registered);
455
+ var routePath = scope === "instance" ? "/:id/".concat(name_2) : "/".concat(name_2);
456
+ if (config.method === "GET") {
457
+ router.get(routePath, middleware);
458
+ }
459
+ else {
460
+ router.post(routePath, middleware);
461
+ }
462
+ }
463
+ }
464
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
465
+ finally {
466
+ try {
467
+ if (registeredActions_1_1 && !registeredActions_1_1.done && (_a = registeredActions_1.return)) _a.call(registeredActions_1);
468
+ }
469
+ finally { if (e_3) throw e_3.error; }
470
+ }
471
+ };
472
+ exports.registerActionRoutes = registerActionRoutes;
@@ -0,0 +1 @@
1
+ export {};