@web-ts-toolkit/access-router 0.4.0 → 0.5.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/index.mjs CHANGED
@@ -1,16 +1,16 @@
1
1
  // src/index.ts
2
- import { isPlainObject as isPlainObject11, isString as isString12, isUndefined as isUndefined4 } from "@web-ts-toolkit/utils";
2
+ import { isPlainObject as isPlainObject14, isString as isString12, isUndefined as isUndefined4 } from "@web-ts-toolkit/utils";
3
3
 
4
4
  // src/middleware.ts
5
5
  import JsonRouter2 from "@web-ts-toolkit/express-json-router";
6
- import { isArray as isArray9, isFunction as isFunction6, isPlainObject as isPlainObject8, isString as isString7 } from "@web-ts-toolkit/utils";
6
+ import { isArray as isArray10, isFunction as isFunction6, isPlainObject as isPlainObject11, isString as isString7 } from "@web-ts-toolkit/utils";
7
7
 
8
8
  // src/core.ts
9
9
  import {
10
10
  castArray as castArray5,
11
11
  compact as compact3,
12
- forEach as forEach6,
13
- isArray as isArray8,
12
+ forEach as forEach7,
13
+ isArray as isArray9,
14
14
  isBoolean as isBoolean5,
15
15
  isFunction as isFunction5,
16
16
  isString as isString6,
@@ -25,11 +25,11 @@ import {
25
25
  addLeadingSlash,
26
26
  forEach as forEach2,
27
27
  get as get3,
28
- isArray as isArray3,
28
+ isArray as isArray4,
29
29
  isBoolean,
30
30
  isFunction,
31
31
  isNil as isNil2,
32
- isPlainObject as isPlainObject5,
32
+ isPlainObject as isPlainObject7,
33
33
  isString as isString4,
34
34
  keys
35
35
  } from "@web-ts-toolkit/utils";
@@ -51,20 +51,11 @@ var findElementById = (collection, id) => {
51
51
  };
52
52
 
53
53
  // src/helpers/document.ts
54
- import { get, isArray, isPlainObject as isPlainObject3, isPromise, isString as isString2, pick, set } from "@web-ts-toolkit/utils";
55
-
56
- // src/lib.ts
57
- import { Document, Schema } from "mongoose";
58
- import { isPlainObject } from "@web-ts-toolkit/utils";
59
- var isSchema = (val) => val instanceof Schema;
60
- var isObjectIdType = (val) => val === "ObjectId" || val === Schema.Types.ObjectId;
61
- var isReference = (val) => isPlainObject(val) && !!val.ref && isObjectIdType(val.type);
62
- var isDocument = function isDocument2(doc) {
63
- return doc instanceof Document;
64
- };
54
+ import { Document } from "mongoose";
55
+ import { get, isPlainObject as isPlainObject2, pick, set } from "@web-ts-toolkit/utils";
65
56
 
66
57
  // src/helpers/query.ts
67
- import { flattenDeep, isNaN, isNil, isPlainObject as isPlainObject2, isString, reduce } from "@web-ts-toolkit/utils";
58
+ import { flattenDeep, isNaN, isNil, isPlainObject, isString, reduce } from "@web-ts-toolkit/utils";
68
59
  function genPagination({
69
60
  skip,
70
61
  limit,
@@ -92,7 +83,7 @@ function parseSortString(sortString) {
92
83
  }
93
84
  function normalizeSelect(select) {
94
85
  if (Array.isArray(select)) return flattenDeep(select.map(normalizeSelect));
95
- if (isPlainObject2(select)) {
86
+ if (isPlainObject(select)) {
96
87
  return reduce(
97
88
  select,
98
89
  (ret, val, key) => {
@@ -108,17 +99,21 @@ function normalizeSelect(select) {
108
99
  }
109
100
 
110
101
  // src/helpers/document.ts
111
- function getDocValue(doc, path, defalutValue) {
102
+ import { isArray, isPromise, isString as isString2 } from "@web-ts-toolkit/utils";
103
+ function isDocument(doc) {
104
+ return doc instanceof Document;
105
+ }
106
+ function getDocValue(doc, path, defaultValue) {
112
107
  if (isDocument(doc)) {
113
- return get(doc._doc, path, defalutValue);
114
- } else if (isPlainObject3(doc)) {
115
- return get(doc, path, defalutValue);
108
+ return get(doc._doc, path, defaultValue);
109
+ } else if (isPlainObject2(doc)) {
110
+ return get(doc, path, defaultValue);
116
111
  }
117
112
  }
118
113
  function setDocValue(doc, path, value) {
119
114
  if (isDocument(doc)) {
120
115
  set(doc._doc, path, value);
121
- } else if (isPlainObject3(doc)) {
116
+ } else if (isPlainObject2(doc)) {
122
117
  set(doc, path, value);
123
118
  }
124
119
  }
@@ -207,16 +202,19 @@ function handleResultError(result) {
207
202
  }
208
203
 
209
204
  // src/helpers/index.ts
210
- import {
211
- forEach,
212
- isArray as isArray2,
213
- isEmpty,
214
- isObject,
215
- isPlainObject as isPlainObject4,
216
- isString as isString3,
217
- mapValuesAsync,
218
- noop
219
- } from "@web-ts-toolkit/utils";
205
+ import { forEach, isArray as isArray2, isEmpty, isObject, isPlainObject as isPlainObject4, isString as isString3, mapValuesAsync } from "@web-ts-toolkit/utils";
206
+
207
+ // src/lib.ts
208
+ import { Document as Document2, Schema } from "mongoose";
209
+ import { isPlainObject as isPlainObject3 } from "@web-ts-toolkit/utils";
210
+ var isSchema = (val) => val instanceof Schema;
211
+ var isObjectIdType = (val) => val === "ObjectId" || val === Schema.Types.ObjectId;
212
+ var isReference = (val) => isPlainObject3(val) && !!val.ref && isObjectIdType(val.type);
213
+ var isDocument2 = function isDocument3(doc) {
214
+ return doc instanceof Document2;
215
+ };
216
+
217
+ // src/helpers/index.ts
220
218
  function recurseObject(obj) {
221
219
  if (isSchema(obj)) {
222
220
  return buildRefs(obj.tree);
@@ -266,7 +264,7 @@ function buildSubPaths(schema) {
266
264
  }
267
265
  async function iterateQuery(query, handler) {
268
266
  if (!isPlainObject4(query)) return query;
269
- if (!handler) return noop;
267
+ if (!handler) return query;
270
268
  const queryObject = query;
271
269
  return mapValuesAsync(queryObject, async (val, key) => {
272
270
  if (isPlainObject4(val)) {
@@ -295,6 +293,252 @@ var createValidator = (fn) => {
295
293
  return { stringHandler, arrayHandler };
296
294
  };
297
295
 
296
+ // src/openapi/build-spec.ts
297
+ import { isArray as isArray3, isPlainObject as isPlainObject6 } from "@web-ts-toolkit/utils";
298
+
299
+ // src/openapi/responses.ts
300
+ var json = (schema) => ({
301
+ content: {
302
+ "application/json": {
303
+ schema
304
+ }
305
+ }
306
+ });
307
+ var problemJson = {
308
+ content: {
309
+ "application/problem+json": {
310
+ schema: {
311
+ type: "object",
312
+ properties: {
313
+ type: { type: "string" },
314
+ title: { type: "string" },
315
+ status: { type: "number" },
316
+ detail: { type: "string" },
317
+ errors: { type: "array", items: {} }
318
+ },
319
+ additionalProperties: true
320
+ }
321
+ }
322
+ }
323
+ };
324
+ var genericDataSchema = { type: "object", additionalProperties: true };
325
+ var genericListSchema = { type: "array", items: genericDataSchema };
326
+ var openApiResponses = {
327
+ single(description = "Success") {
328
+ return {
329
+ 200: { description, ...json(genericDataSchema) },
330
+ 400: { description: "Bad Request", ...problemJson },
331
+ 401: { description: "Unauthorized", ...problemJson },
332
+ 404: { description: "Not Found", ...problemJson }
333
+ };
334
+ },
335
+ list(description = "Success") {
336
+ return {
337
+ 200: { description, ...json(genericListSchema) },
338
+ 400: { description: "Bad Request", ...problemJson },
339
+ 401: { description: "Unauthorized", ...problemJson }
340
+ };
341
+ },
342
+ create(description = "Created") {
343
+ return {
344
+ 201: { description, ...json(genericDataSchema) },
345
+ 400: { description: "Bad Request", ...problemJson },
346
+ 401: { description: "Unauthorized", ...problemJson }
347
+ };
348
+ },
349
+ delete(description = "Deleted") {
350
+ return {
351
+ 200: { description, ...json(genericDataSchema) },
352
+ 400: { description: "Bad Request", ...problemJson },
353
+ 401: { description: "Unauthorized", ...problemJson },
354
+ 404: { description: "Not Found", ...problemJson }
355
+ };
356
+ },
357
+ batch(description = "Success") {
358
+ return {
359
+ 200: { description, ...json(genericListSchema) },
360
+ 400: { description: "Bad Request", ...problemJson },
361
+ 401: { description: "Unauthorized", ...problemJson }
362
+ };
363
+ }
364
+ };
365
+
366
+ // src/openapi/schemas.ts
367
+ import { z } from "zod";
368
+ import { isPlainObject as isPlainObject5 } from "@web-ts-toolkit/utils";
369
+ var fallbackObjectSchema = { type: "object", additionalProperties: true };
370
+ function patchOpenApiObjectSchema(source, properties) {
371
+ return {
372
+ kind: "objectProperties",
373
+ source,
374
+ properties
375
+ };
376
+ }
377
+ function defineOpenApiSchemaResolver(resolve) {
378
+ return {
379
+ kind: "schemaResolver",
380
+ resolve
381
+ };
382
+ }
383
+ function getNestedOpenApiSchemaDataSource(source) {
384
+ return isPlainObject5(source) && "data" in source ? source.data : void 0;
385
+ }
386
+ function unwrapNestedOpenApiSchemaSource(source, fallback) {
387
+ if (isPlainObject5(source) && ("default" in source || "data" in source)) {
388
+ return source.default ?? fallback;
389
+ }
390
+ return source ?? fallback;
391
+ }
392
+ function isOpenApiSchemaPatch(source) {
393
+ return isPlainObject5(source) && source.kind === "objectProperties";
394
+ }
395
+ function isOpenApiSchemaResolver(source) {
396
+ return isPlainObject5(source) && source.kind === "schemaResolver" && typeof source.resolve === "function";
397
+ }
398
+ function isJsonSchemaLike(source) {
399
+ return isPlainObject5(source) && ("type" in source || "properties" in source || "$ref" in source || "anyOf" in source);
400
+ }
401
+ function hasOpenApiSchema(source) {
402
+ return isPlainObject5(source) && isJsonSchemaLike(source.openapi);
403
+ }
404
+ function toOpenApiSchema(source) {
405
+ if (!source) return void 0;
406
+ const resolvedSource = isOpenApiSchemaResolver(source) ? source.resolve() : source;
407
+ if (!resolvedSource) return void 0;
408
+ if (isOpenApiSchemaPatch(resolvedSource)) {
409
+ const schema = toOpenApiSchema(resolvedSource.source) ?? { ...fallbackObjectSchema };
410
+ const properties = isPlainObject5(schema.properties) ? { ...schema.properties } : {};
411
+ for (const [key, value] of Object.entries(resolvedSource.properties)) {
412
+ properties[key] = toOpenApiSchema(value) ?? fallbackObjectSchema;
413
+ }
414
+ return {
415
+ ...schema,
416
+ type: schema.type ?? "object",
417
+ properties
418
+ };
419
+ }
420
+ if (hasOpenApiSchema(resolvedSource)) {
421
+ return resolvedSource.openapi;
422
+ }
423
+ if (isJsonSchemaLike(resolvedSource)) {
424
+ return resolvedSource;
425
+ }
426
+ try {
427
+ return z.toJSONSchema(resolvedSource);
428
+ } catch {
429
+ return fallbackObjectSchema;
430
+ }
431
+ }
432
+
433
+ // src/openapi/build-spec.ts
434
+ var openApiMediaType = "application/json";
435
+ var normalizePath = (path) => {
436
+ if (!path) return "/";
437
+ return path.startsWith("/") ? path : `/${path}`;
438
+ };
439
+ var toOpenApiPath = (path) => normalizePath(path).replace(/:([A-Za-z0-9_]+)/g, "{$1}");
440
+ var schemaToQueryParameters = (schema) => {
441
+ const jsonSchema = toOpenApiSchema(schema);
442
+ if (!jsonSchema || jsonSchema.type !== "object") return [];
443
+ const properties = isPlainObject6(jsonSchema.properties) ? jsonSchema.properties : {};
444
+ const required = new Set(
445
+ isArray3(jsonSchema.required) ? jsonSchema.required.filter((item) => typeof item === "string") : []
446
+ );
447
+ return Object.entries(properties).map(([name, value]) => ({
448
+ name,
449
+ in: "query",
450
+ required: required.has(name),
451
+ schema: value
452
+ }));
453
+ };
454
+ var schemaToPathParameters = (path, pathParams) => {
455
+ const names = [...toOpenApiPath(path).matchAll(/\{([^}]+)\}/g)].map((item) => item[1]);
456
+ return names.map((name) => ({
457
+ name,
458
+ in: "path",
459
+ required: true,
460
+ schema: (pathParams && name in pathParams ? toOpenApiSchema(pathParams[name]) : void 0) ?? { type: "string" }
461
+ }));
462
+ };
463
+ var getDefaultResponses = (route) => {
464
+ if (route.operationId === "root.query") return openApiResponses.batch();
465
+ if (route.method === "delete") return openApiResponses.delete();
466
+ if (route.operationId?.toLowerCase().includes("create")) return openApiResponses.create();
467
+ if (route.operationId?.toLowerCase().includes("list")) return openApiResponses.list();
468
+ if (route.operationId?.toLowerCase().includes("distinct")) return openApiResponses.list();
469
+ return openApiResponses.single();
470
+ };
471
+ var buildOperation = (route) => {
472
+ const queryParameters = schemaToQueryParameters(route.query);
473
+ const pathParameters = schemaToPathParameters(route.path, route.pathParams);
474
+ const bodySchema = toOpenApiSchema(route.body);
475
+ const responses = route.responses ?? getDefaultResponses(route);
476
+ const operation = {
477
+ operationId: route.operationId,
478
+ summary: route.summary,
479
+ description: route.description,
480
+ tags: route.tags,
481
+ deprecated: route.deprecated,
482
+ responses
483
+ };
484
+ const parameters = [...pathParameters, ...queryParameters];
485
+ if (parameters.length) {
486
+ operation.parameters = parameters;
487
+ }
488
+ if (bodySchema) {
489
+ operation.requestBody = {
490
+ required: true,
491
+ content: {
492
+ [openApiMediaType]: {
493
+ schema: bodySchema
494
+ }
495
+ }
496
+ };
497
+ }
498
+ if (route.acl) {
499
+ operation["x-access-router-acl"] = route.acl;
500
+ }
501
+ return operation;
502
+ };
503
+ function buildOpenApiSpec(routes, options) {
504
+ const paths = {};
505
+ const { servers, ...info } = options;
506
+ for (const route of routes) {
507
+ const path = toOpenApiPath(route.path);
508
+ if (!paths[path]) {
509
+ paths[path] = {};
510
+ }
511
+ paths[path][route.method] = buildOperation(route);
512
+ }
513
+ return {
514
+ openapi: "3.1.0",
515
+ info,
516
+ servers,
517
+ paths
518
+ };
519
+ }
520
+
521
+ // src/openapi/registry.ts
522
+ var OpenApiRegistry = class {
523
+ constructor() {
524
+ this.routes = [];
525
+ }
526
+ register(route) {
527
+ const existingIndex = this.routes.findIndex((item) => item.method === route.method && item.path === route.path);
528
+ if (existingIndex === -1) {
529
+ this.routes.push(route);
530
+ return;
531
+ }
532
+ this.routes[existingIndex] = route;
533
+ }
534
+ getRoutes() {
535
+ return [...this.routes];
536
+ }
537
+ getSpec(info) {
538
+ return buildOpenApiSpec(this.routes, info);
539
+ }
540
+ };
541
+
298
542
  // src/logger-default.ts
299
543
  import util from "util";
300
544
  import { createLogger, format, transports } from "winston";
@@ -401,9 +645,9 @@ var hasModelPermission = (value, modelPermissionPrefix) => {
401
645
  if (isString4(value)) {
402
646
  return value.trim().split(" ").some((item) => item.startsWith(modelPermissionPrefix));
403
647
  }
404
- if (isArray3(value)) {
648
+ if (isArray4(value)) {
405
649
  return value.some((item) => {
406
- if (isString4(item) || isArray3(item)) {
650
+ if (isString4(item) || isArray4(item)) {
407
651
  return hasModelPermission(item, modelPermissionPrefix);
408
652
  }
409
653
  return true;
@@ -417,13 +661,13 @@ var classifyPermissionSchema = (permissionSchema, modelPermissionPrefix) => {
417
661
  const modelPermissionKeys = {};
418
662
  forEach2(schemaKeys, (schemaKey) => {
419
663
  const schemaRule = permissionSchema[schemaKey];
420
- const ruleEntries = isPlainObject5(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
664
+ const ruleEntries = isPlainObject7(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
421
665
  for (let x = 0; x < ruleEntries.length; x++) {
422
666
  const [accessKey, value] = ruleEntries[x];
423
- if (!isArray3(globalPermissionKeys[accessKey])) {
667
+ if (!isArray4(globalPermissionKeys[accessKey])) {
424
668
  globalPermissionKeys[accessKey] = [];
425
669
  }
426
- if (!isArray3(modelPermissionKeys[accessKey])) {
670
+ if (!isArray4(modelPermissionKeys[accessKey])) {
427
671
  modelPermissionKeys[accessKey] = [];
428
672
  }
429
673
  if (isBoolean(value)) {
@@ -467,6 +711,16 @@ var AccessRuntime = class {
467
711
  this.modelRefs = {};
468
712
  this.modelSubs = {};
469
713
  this.modelAtts = {};
714
+ this.openApiRegistry = new OpenApiRegistry();
715
+ }
716
+ registerOpenApiRoute(route) {
717
+ this.openApiRegistry.register(route);
718
+ }
719
+ getOpenApiRoutes() {
720
+ return this.openApiRegistry.getRoutes();
721
+ }
722
+ getOpenApiSpec(info) {
723
+ return this.openApiRegistry.getSpec(info);
470
724
  }
471
725
  setGlobalOptions(options) {
472
726
  this.globalOptions.assign(options);
@@ -738,19 +992,19 @@ import {
738
992
  forEach as forEach3,
739
993
  get as get4,
740
994
  intersectionBy,
741
- isArray as isArray4,
742
- isPlainObject as isPlainObject6,
995
+ isArray as isArray5,
996
+ isPlainObject as isPlainObject8,
743
997
  uniq
744
998
  } from "@web-ts-toolkit/utils";
745
999
  function validateClientFilter(filter2) {
746
1000
  const errors = [];
747
1001
  const blockedOperators = /* @__PURE__ */ new Set(["$where", "$expr", "$function", "$accumulator"]);
748
1002
  const visit = (value, path) => {
749
- if (isArray4(value)) {
1003
+ if (isArray5(value)) {
750
1004
  value.forEach((item, index) => visit(item, `${path}[${index}]`));
751
1005
  return;
752
1006
  }
753
- if (!isPlainObject6(value)) return;
1007
+ if (!isPlainObject8(value)) return;
754
1008
  Object.entries(value).forEach(([key, child]) => {
755
1009
  const nextPath = path ? `${path}.${key}` : key;
756
1010
  if (blockedOperators.has(key)) {
@@ -866,7 +1120,7 @@ var Base = class {
866
1120
  if (!include) return docs;
867
1121
  const includes = compact(castArray(include));
868
1122
  if (includes.length === 0) return docs;
869
- const isSingle = !isArray4(docs);
1123
+ const isSingle = !isArray5(docs);
870
1124
  if (isSingle) docs = [docs];
871
1125
  for (let x = 0; x < includes.length; x++) {
872
1126
  const include2 = includes[x];
@@ -951,14 +1205,16 @@ var Base = class {
951
1205
  if (!result.success) return null;
952
1206
  let ret = result.data;
953
1207
  if (sqOptions.path) {
954
- ret = isArray4(ret) ? flatten(ret.map((v) => get4(v, sqOptions.path))) : get4(ret, sqOptions.path);
1208
+ ret = isArray5(ret) ? flatten(ret.map((v) => get4(v, sqOptions.path))) : get4(ret, sqOptions.path);
955
1209
  }
956
1210
  if (sqOptions.compact) {
957
1211
  ret = compact(castArray(ret));
958
1212
  }
959
1213
  return ret;
960
1214
  }
961
- async handleDate(val, key) {
1215
+ handleDate(val, key) {
1216
+ if (val instanceof Date) return val;
1217
+ if (typeof val === "string" || typeof val === "number") return new Date(val);
962
1218
  return /* @__PURE__ */ new Date();
963
1219
  }
964
1220
  };
@@ -966,7 +1222,7 @@ var Base = class {
966
1222
  // src/services/service.ts
967
1223
  import {
968
1224
  castArray as castArray2,
969
- isArray as isArray5,
1225
+ isArray as isArray6,
970
1226
  isBoolean as isBoolean3,
971
1227
  isFunction as isFunction3,
972
1228
  omit,
@@ -977,6 +1233,21 @@ import diff from "deep-diff";
977
1233
 
978
1234
  // src/model.ts
979
1235
  import mongoose3 from "mongoose";
1236
+
1237
+ // src/logger.ts
1238
+ var passthrough = (level) => (...args) => {
1239
+ const globalLogger = getGlobalOption("logger");
1240
+ const target = globalLogger?.[level] ?? defaultLogger[level];
1241
+ return target.apply(globalLogger ?? defaultLogger, args);
1242
+ };
1243
+ var logger = {
1244
+ debug: passthrough("debug"),
1245
+ info: passthrough("info"),
1246
+ warn: passthrough("warn"),
1247
+ error: passthrough("error")
1248
+ };
1249
+
1250
+ // src/model.ts
980
1251
  var Model = class {
981
1252
  constructor(modelName) {
982
1253
  this.modelName = modelName;
@@ -1006,12 +1277,15 @@ var Model = class {
1006
1277
  if (lean) builder.lean();
1007
1278
  return builder;
1008
1279
  }
1009
- // See https://github.com/Automattic/mongoose/blob/65b2d12a8f85f86136cfaf32947f338ba0c5f451/lib/query.js#L3011
1010
- validateSort(sort, logError = console.error) {
1280
+ validateSort(sort, logError = logger.error) {
1011
1281
  const validSortOrders = [1, -1, "asc", "ascending", "desc", "descending"];
1282
+ const fieldPathPattern = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/;
1283
+ const isValidFieldPath = (field) => fieldPathPattern.test(field);
1012
1284
  if (sort === null || sort === void 0) return true;
1013
1285
  if (typeof sort === "string") {
1014
- if (!/^[a-zA-Z0-9\s-]+/.test(sort)) {
1286
+ const fields = sort.trim().split(/\s+/).filter(Boolean);
1287
+ const isValid = fields.every((field) => isValidFieldPath(field.startsWith("-") ? field.slice(1) : field));
1288
+ if (!isValid) {
1015
1289
  logError("Invalid sort string:", sort);
1016
1290
  return false;
1017
1291
  }
@@ -1024,8 +1298,8 @@ var Model = class {
1024
1298
  return false;
1025
1299
  }
1026
1300
  const [key, order] = pair;
1027
- if (typeof key !== "string") {
1028
- logError("Invalid sort array key: must be string", key);
1301
+ if (typeof key !== "string" || !isValidFieldPath(key)) {
1302
+ logError("Invalid sort array key: must be a field path string", key);
1029
1303
  return false;
1030
1304
  }
1031
1305
  if (!validSortOrders.includes(order)) {
@@ -1037,7 +1311,11 @@ var Model = class {
1037
1311
  return isValid;
1038
1312
  }
1039
1313
  if (typeof sort === "object" && !(sort instanceof Map)) {
1040
- const isValid = Object.values(sort).every((order) => {
1314
+ const isValid = Object.entries(sort).every(([key, order]) => {
1315
+ if (!isValidFieldPath(key)) {
1316
+ logError("Invalid sort object key: must be a field path string", key);
1317
+ return false;
1318
+ }
1041
1319
  if (!validSortOrders.includes(order)) {
1042
1320
  logError('Invalid sort object value: must be 1, -1, "asc", or "desc"', order);
1043
1321
  return false;
@@ -1047,7 +1325,11 @@ var Model = class {
1047
1325
  return isValid;
1048
1326
  }
1049
1327
  if (sort instanceof Map) {
1050
- const isValid = Array.from(sort.values()).every((order) => {
1328
+ const isValid = Array.from(sort.entries()).every(([key, order]) => {
1329
+ if (!isValidFieldPath(key)) {
1330
+ logError("Invalid sort Map key: must be a field path string", key);
1331
+ return false;
1332
+ }
1051
1333
  if (!validSortOrders.includes(order)) {
1052
1334
  logError('Invalid sort Map value: must be 1, -1, "asc", or "desc"', order);
1053
1335
  return false;
@@ -1070,9 +1352,6 @@ var Model = class {
1070
1352
  if (lean) builder.lean();
1071
1353
  return builder;
1072
1354
  }
1073
- findOneAndDelete(filter2) {
1074
- return this.model.findOneAndDelete(filter2);
1075
- }
1076
1355
  exists(filter2) {
1077
1356
  if (!filter2) return null;
1078
1357
  return this.findOne(filter2).select("_id").lean();
@@ -1081,10 +1360,6 @@ var Model = class {
1081
1360
  countDocuments(filter2 = {}) {
1082
1361
  return this.model.countDocuments(filter2);
1083
1362
  }
1084
- // see https://mongoosejs.com/docs/api.html#model_Model.estimatedDocumentCount
1085
- estimatedDocumentCount() {
1086
- return this.model.estimatedDocumentCount();
1087
- }
1088
1363
  // see https://mongoosejs.com/docs/api.html#model_Model.distinct
1089
1364
  distinct(field, conditions = {}) {
1090
1365
  return this.model.distinct(field, conditions);
@@ -1092,19 +1367,6 @@ var Model = class {
1092
1367
  };
1093
1368
  var model_default = Model;
1094
1369
 
1095
- // src/logger.ts
1096
- var passthrough = (level) => (...args) => {
1097
- const globalLogger = getGlobalOption("logger");
1098
- const target = globalLogger?.[level] ?? defaultLogger[level];
1099
- return target.apply(globalLogger ?? defaultLogger, args);
1100
- };
1101
- var logger = {
1102
- debug: passthrough("debug"),
1103
- info: passthrough("info"),
1104
- warn: passthrough("warn"),
1105
- error: passthrough("error")
1106
- };
1107
-
1108
1370
  // src/services/model-subdocument-service.ts
1109
1371
  import { forEach as forEach4, get as get5, pick as pick3 } from "@web-ts-toolkit/utils";
1110
1372
  async function listSub(service, id, sub, options) {
@@ -1328,7 +1590,7 @@ function resolveExistsOptions(service, options = {}) {
1328
1590
 
1329
1591
  // src/services/service.ts
1330
1592
  var assertModelDocument = (value, modelName, hookName) => {
1331
- if (isDocument(value)) {
1593
+ if (isDocument2(value)) {
1332
1594
  return value;
1333
1595
  }
1334
1596
  throw new Error(`${hookName} hook for model=${modelName} must return a Mongoose document instance`);
@@ -1422,7 +1684,7 @@ var Service = class extends Base {
1422
1684
  genPagination({ skip, limit, page, pageSize }, this.options.listHardLimit)
1423
1685
  ]);
1424
1686
  const finalSelect = normalizeSelect(_select);
1425
- const filteredPopulate = isArray5(finalSelect) && isArray5(_populate) ? _populate.filter((p) => finalSelect.includes(p.path.split(".")[0])) : _populate;
1687
+ const filteredPopulate = isArray6(finalSelect) && isArray6(_populate) ? _populate.filter((p) => finalSelect.includes(p.path.split(".")[0])) : _populate;
1426
1688
  const { includes, includeLocalFields, includePaths } = this.processInclude(include);
1427
1689
  const query = {
1428
1690
  filter: _filter,
@@ -1505,7 +1767,7 @@ var Service = class extends Base {
1505
1767
  validationError = { success: false, code: "bad_request" /* BadRequest */ };
1506
1768
  return;
1507
1769
  }
1508
- } else if (isArray5(validated)) {
1770
+ } else if (isArray6(validated)) {
1509
1771
  if (validated.length > 0) {
1510
1772
  validationError = { success: false, code: "bad_request" /* BadRequest */, errors: validated };
1511
1773
  return;
@@ -1595,7 +1857,7 @@ var Service = class extends Base {
1595
1857
  const validated = await this.validate(allowedData, "update", context);
1596
1858
  if (isBoolean3(validated)) {
1597
1859
  if (!validated) return { success: false, code: "bad_request" /* BadRequest */ };
1598
- } else if (isArray5(validated)) {
1860
+ } else if (isArray6(validated)) {
1599
1861
  if (validated.length > 0) return { success: false, code: "bad_request" /* BadRequest */, errors: validated };
1600
1862
  }
1601
1863
  const prepared = await this.prepare(allowedData, "update", context);
@@ -2199,29 +2461,29 @@ var DataService = class {
2199
2461
  };
2200
2462
 
2201
2463
  // src/processors.ts
2202
- import { castArray as castArray3, cloneDeep, forEach as forEach5, get as get6, isArray as isArray6, map as map3, set as set5 } from "@web-ts-toolkit/utils";
2464
+ import { castArray as castArray3, cloneDeep, forEach as forEach6, get as get7, isArray as isArray7, map as map2, set as set5 } from "@web-ts-toolkit/utils";
2203
2465
  var copyAndDepopulate = (docObject, operations, options = { mutable: true, idField: "_id" }) => {
2204
- const obj = get6(options, "mutable", true) ? docObject : cloneDeep(docObject);
2205
- const idField = get6(options, "idField", "_id");
2206
- forEach5(castArray3(operations), (op) => {
2466
+ const obj = get7(options, "mutable", true) ? docObject : cloneDeep(docObject);
2467
+ const idField = get7(options, "idField", "_id");
2468
+ forEach6(castArray3(operations), (op) => {
2207
2469
  if (!op.src || !op.dest) return;
2208
2470
  let targets = [obj];
2209
2471
  const segs = op.src.split(".");
2210
- forEach5(segs, (seg, ind) => {
2472
+ forEach6(segs, (seg, ind) => {
2211
2473
  if (segs.length === ind + 1) {
2212
- forEach5(targets, (target) => {
2474
+ forEach6(targets, (target) => {
2213
2475
  const targetObject = target;
2214
- set5(targetObject, op.dest, get6(targetObject, seg));
2476
+ set5(targetObject, op.dest, get7(targetObject, seg));
2215
2477
  set5(
2216
2478
  targetObject,
2217
2479
  seg,
2218
- isArray6(targetObject[seg]) ? map3(targetObject[seg], idField) : get6(targetObject, `${seg}.${idField}`)
2480
+ isArray7(targetObject[seg]) ? map2(targetObject[seg], idField) : get7(targetObject, `${seg}.${idField}`)
2219
2481
  );
2220
2482
  });
2221
2483
  } else {
2222
2484
  targets = targets.reduce((ret, target) => {
2223
2485
  const targetObject = target;
2224
- if (isArray6(targetObject[seg])) ret.push(...targetObject[seg]);
2486
+ if (isArray7(targetObject[seg])) ret.push(...targetObject[seg]);
2225
2487
  else ret.push(targetObject[seg]);
2226
2488
  return ret;
2227
2489
  }, []);
@@ -2272,12 +2534,12 @@ var Cache = class {
2272
2534
  import {
2273
2535
  castArray as castArray4,
2274
2536
  arrayToRecord,
2275
- isArray as isArray7,
2537
+ isArray as isArray8,
2276
2538
  isBoolean as isBoolean4,
2277
2539
  isEmpty as isEmpty2,
2278
2540
  isEqual,
2279
2541
  isFunction as isFunction4,
2280
- isPlainObject as isPlainObject7,
2542
+ isPlainObject as isPlainObject10,
2281
2543
  isString as isString5
2282
2544
  } from "@web-ts-toolkit/utils";
2283
2545
 
@@ -2317,10 +2579,10 @@ var permission_default = Permission;
2317
2579
 
2318
2580
  // src/core-shared.ts
2319
2581
  function isAndFilter(filter2) {
2320
- return !!filter2 && isPlainObject7(filter2) && Object.keys(filter2).length === 1 && isArray7(filter2.$and);
2582
+ return !!filter2 && isPlainObject10(filter2) && Object.keys(filter2).length === 1 && isArray8(filter2.$and);
2321
2583
  }
2322
2584
  function isMergeableClause(filter2) {
2323
- return !!filter2 && isPlainObject7(filter2) && Object.keys(filter2).every((key) => !key.startsWith("$"));
2585
+ return !!filter2 && isPlainObject10(filter2) && Object.keys(filter2).every((key) => !key.startsWith("$"));
2324
2586
  }
2325
2587
  function optimizeAndFilter(clausesInput) {
2326
2588
  const clauses = [];
@@ -2365,7 +2627,7 @@ function optimizeAndFilter(clausesInput) {
2365
2627
  }
2366
2628
  function normalizeFilter(filter2) {
2367
2629
  if (filter2 === false) return false;
2368
- if (!filter2 || !isPlainObject7(filter2) || isEmpty2(filter2)) return null;
2630
+ if (!filter2 || !isPlainObject10(filter2) || isEmpty2(filter2)) return null;
2369
2631
  if (!isAndFilter(filter2)) {
2370
2632
  return filter2;
2371
2633
  }
@@ -2417,8 +2679,8 @@ async function setRequestPermissions(req) {
2417
2679
  const globalPermissions = getGlobalOption("globalPermissions");
2418
2680
  if (!isFunction4(globalPermissions)) return;
2419
2681
  const permissions = await globalPermissions.call(req, req);
2420
- if (isPlainObject7(permissions)) req[requestPermissionField] = permissions;
2421
- else if (isArray7(permissions)) req[requestPermissionField] = arrayToRecord(permissions);
2682
+ if (isPlainObject10(permissions)) req[requestPermissionField] = permissions;
2683
+ else if (isArray8(permissions)) req[requestPermissionField] = arrayToRecord(permissions);
2422
2684
  else if (isString5(permissions)) req[requestPermissionField] = { [permissions]: true };
2423
2685
  }
2424
2686
  async function evaluateRouteGuard(req, permissions, routeGuard) {
@@ -2430,7 +2692,7 @@ async function evaluateRouteGuard(req, permissions, routeGuard) {
2430
2692
  if (isString5(routeGuard)) {
2431
2693
  return stringHandler(routeGuard);
2432
2694
  }
2433
- if (isArray7(routeGuard)) {
2695
+ if (isArray8(routeGuard)) {
2434
2696
  return arrayHandler(routeGuard);
2435
2697
  }
2436
2698
  if (isFunction4(routeGuard)) {
@@ -2468,7 +2730,7 @@ async function collectSchemaFields({
2468
2730
  if (value) fields.push(key);
2469
2731
  } else if (isString5(value)) {
2470
2732
  if (stringHandler(value)) fields.push(key);
2471
- } else if (isArray7(value)) {
2733
+ } else if (isArray8(value)) {
2472
2734
  if (arrayHandler(value)) fields.push(key);
2473
2735
  } else if (isFunction4(value)) {
2474
2736
  if (await value.call(req, ...functionArgs)) fields.push(key);
@@ -2757,7 +3019,7 @@ var Core = class {
2757
3019
  if (isFunction5(validate)) {
2758
3020
  const permissions = this.getGlobalPermissions();
2759
3021
  return validate.call(this.req, allowedData, permissions, context);
2760
- } else if (isBoolean5(validate) || isArray8(validate)) {
3022
+ } else if (isBoolean5(validate) || isArray9(validate)) {
2761
3023
  return validate;
2762
3024
  } else {
2763
3025
  return true;
@@ -2888,7 +3150,7 @@ var Core = class {
2888
3150
  runTasks(modelName, docObject, task) {
2889
3151
  const tasks = compact3(castArray5(task));
2890
3152
  if (tasks.length === 0) return docObject;
2891
- forEach6(tasks, (task2) => {
3153
+ forEach7(tasks, (task2) => {
2892
3154
  const { type, args, options } = task2;
2893
3155
  switch (type) {
2894
3156
  case "COPY_AND_DEPOPULATE":
@@ -2971,19 +3233,19 @@ function guard(condition) {
2971
3233
  const permissions = req[PERMISSIONS];
2972
3234
  let cond = condition;
2973
3235
  let phas = (key) => permissions.has(key);
2974
- if (isPlainObject8(condition)) {
3236
+ if (isPlainObject11(condition)) {
2975
3237
  const { modelName, id, condition: _cond } = condition;
2976
3238
  const svc = req.macl.getPublicService(modelName);
2977
3239
  const select = getModelOption(modelName, `alwaysSelectFields.read`, void 0);
2978
3240
  let _id = isString7(id) ? id : null;
2979
- if (isPlainObject8(id)) {
3241
+ if (isPlainObject11(id)) {
2980
3242
  const { type = "param", key } = id;
2981
3243
  if (type === "param") {
2982
3244
  const paramValue = req.params[key];
2983
- _id = isArray9(paramValue) ? paramValue[0] ?? null : paramValue ?? null;
3245
+ _id = isArray10(paramValue) ? paramValue[0] ?? null : paramValue ?? null;
2984
3246
  } else if (type === "query") {
2985
3247
  const _qval = req.query[key];
2986
- if (isArray9(_qval)) _id = _qval.length > 0 ? _qval[0] : null;
3248
+ if (isArray10(_qval)) _id = _qval.length > 0 ? _qval[0] : null;
2987
3249
  else _id = _qval;
2988
3250
  } else {
2989
3251
  _id = null;
@@ -3003,7 +3265,7 @@ function guard(condition) {
3003
3265
  const { stringHandler, arrayHandler } = createValidator(phas);
3004
3266
  if (isString7(cond)) {
3005
3267
  if (stringHandler(cond)) return next();
3006
- } else if (isArray9(cond)) {
3268
+ } else if (isArray10(cond)) {
3007
3269
  if (arrayHandler(cond)) return next();
3008
3270
  } else if (isFunction6(cond)) {
3009
3271
  const result = await cond.call(req, permissions);
@@ -3014,11 +3276,11 @@ function guard(condition) {
3014
3276
  }
3015
3277
 
3016
3278
  // src/routers/index.ts
3017
- import express from "express";
3279
+ import express2 from "express";
3018
3280
 
3019
3281
  // src/routers/model-router.ts
3020
3282
  import JsonRouter5 from "@web-ts-toolkit/express-json-router";
3021
- import { forEach as forEach7, isPlainObject as isPlainObject9, isString as isString9, isUndefined as isUndefined2, normalizeUrlPath, padEnd } from "@web-ts-toolkit/utils";
3283
+ import { forEach as forEach8, isPlainObject as isPlainObject12, isString as isString9, isUndefined as isUndefined2, normalizeUrlPath as normalizeUrlPath2, padEnd } from "@web-ts-toolkit/utils";
3022
3284
 
3023
3285
  // src/routers/router-mutation.ts
3024
3286
  var MODEL_BUILD_TIME_OPTION_KEYS = /* @__PURE__ */ new Set([
@@ -3110,88 +3372,88 @@ function formatModelUpsertResponse(result) {
3110
3372
  import JsonRouter4 from "@web-ts-toolkit/express-json-router";
3111
3373
 
3112
3374
  // src/validation/common.ts
3113
- import { z } from "zod";
3114
- var stringOrStringArray = z.union([z.string(), z.array(z.string())]);
3115
- var queryBooleanString = z.enum(["true", "false"]);
3116
- var positiveIntegerString = z.string().regex(/^\d+$/, "Expected a non-negative integer");
3117
- var nonNegativeIntegerSchema = z.number().int().min(0);
3118
- var unknownRecord = z.record(z.string(), z.unknown());
3119
- var projectionObjectSchema = z.record(z.string(), z.union([z.literal(1), z.literal(-1)]));
3120
- var projectionSchema = z.union([z.string(), z.array(z.string()), projectionObjectSchema]);
3121
- var sortOrderSchema = z.union([
3122
- z.literal(-1),
3123
- z.literal(1),
3124
- z.literal("asc"),
3125
- z.literal("ascending"),
3126
- z.literal("desc"),
3127
- z.literal("descending")
3375
+ import { z as z2 } from "zod";
3376
+ var stringOrStringArray = z2.union([z2.string(), z2.array(z2.string())]);
3377
+ var queryBooleanString = z2.enum(["true", "false"]);
3378
+ var positiveIntegerString = z2.string().regex(/^\d+$/, "Expected a non-negative integer");
3379
+ var nonNegativeIntegerSchema = z2.number().int().min(0);
3380
+ var unknownRecord = z2.record(z2.string(), z2.unknown());
3381
+ var projectionObjectSchema = z2.record(z2.string(), z2.union([z2.literal(1), z2.literal(-1)]));
3382
+ var projectionSchema = z2.union([z2.string(), z2.array(z2.string()), projectionObjectSchema]);
3383
+ var sortOrderSchema = z2.union([
3384
+ z2.literal(-1),
3385
+ z2.literal(1),
3386
+ z2.literal("asc"),
3387
+ z2.literal("ascending"),
3388
+ z2.literal("desc"),
3389
+ z2.literal("descending")
3128
3390
  ]);
3129
- var sortSchema = z.union([
3130
- z.string(),
3131
- z.record(z.string(), sortOrderSchema),
3132
- z.array(z.tuple([z.string(), sortOrderSchema])),
3133
- z.null()
3391
+ var sortSchema = z2.union([
3392
+ z2.string(),
3393
+ z2.record(z2.string(), sortOrderSchema),
3394
+ z2.array(z2.tuple([z2.string(), sortOrderSchema])),
3395
+ z2.null()
3134
3396
  ]);
3135
- var populateSchema = z.union([
3136
- z.string(),
3137
- z.array(
3138
- z.union([
3139
- z.string(),
3140
- z.object({
3141
- path: z.string().min(1),
3397
+ var populateSchema = z2.union([
3398
+ z2.string(),
3399
+ z2.array(
3400
+ z2.union([
3401
+ z2.string(),
3402
+ z2.object({
3403
+ path: z2.string().min(1),
3142
3404
  select: projectionSchema.optional(),
3143
- match: z.unknown().optional(),
3144
- access: z.enum(["list", "read"]).optional()
3405
+ match: z2.unknown().optional(),
3406
+ access: z2.enum(["list", "read"]).optional()
3145
3407
  }).passthrough()
3146
3408
  ])
3147
3409
  ),
3148
- z.object({
3149
- path: z.string().min(1),
3410
+ z2.object({
3411
+ path: z2.string().min(1),
3150
3412
  select: projectionSchema.optional(),
3151
- match: z.unknown().optional(),
3152
- access: z.enum(["list", "read"]).optional()
3413
+ match: z2.unknown().optional(),
3414
+ access: z2.enum(["list", "read"]).optional()
3153
3415
  }).passthrough()
3154
3416
  ]);
3155
- var subPopulateSchema = z.union([
3156
- z.string(),
3157
- z.array(
3158
- z.union([
3159
- z.string(),
3160
- z.object({
3161
- path: z.string().min(1),
3417
+ var subPopulateSchema = z2.union([
3418
+ z2.string(),
3419
+ z2.array(
3420
+ z2.union([
3421
+ z2.string(),
3422
+ z2.object({
3423
+ path: z2.string().min(1),
3162
3424
  select: projectionSchema.optional()
3163
3425
  }).passthrough()
3164
3426
  ])
3165
3427
  ),
3166
- z.object({
3167
- path: z.string().min(1),
3428
+ z2.object({
3429
+ path: z2.string().min(1),
3168
3430
  select: projectionSchema.optional()
3169
3431
  }).passthrough()
3170
3432
  ]);
3171
- var includeItemSchema = z.object({
3172
- model: z.string().min(1),
3173
- op: z.enum(["list", "read", "count"]),
3174
- path: z.string().min(1),
3175
- filter: z.record(z.string(), z.unknown()).optional(),
3176
- localField: z.string().min(1),
3177
- foreignField: z.string().min(1),
3178
- args: z.unknown().optional(),
3179
- options: z.unknown().optional()
3433
+ var includeItemSchema = z2.object({
3434
+ model: z2.string().min(1),
3435
+ op: z2.enum(["list", "read", "count"]),
3436
+ path: z2.string().min(1),
3437
+ filter: z2.record(z2.string(), z2.unknown()).optional(),
3438
+ localField: z2.string().min(1),
3439
+ foreignField: z2.string().min(1),
3440
+ args: z2.unknown().optional(),
3441
+ options: z2.unknown().optional()
3180
3442
  }).passthrough();
3181
- var includeSchema = z.union([includeItemSchema, z.array(includeItemSchema)]);
3182
- var fieldsSchema = z.array(z.string().min(1));
3183
- var taskSchema = z.object({
3184
- type: z.string().min(1),
3185
- args: z.unknown(),
3443
+ var includeSchema = z2.union([includeItemSchema, z2.array(includeItemSchema)]);
3444
+ var fieldsSchema = z2.array(z2.string().min(1));
3445
+ var taskSchema = z2.object({
3446
+ type: z2.string().min(1),
3447
+ args: z2.unknown(),
3186
3448
  options: unknownRecord.optional()
3187
3449
  });
3188
- var tasksSchema = z.union([taskSchema, z.array(taskSchema)]);
3189
- var objectOrArraySchema = z.union([z.record(z.string(), z.unknown()), z.array(z.unknown())]);
3450
+ var tasksSchema = z2.union([taskSchema, z2.array(taskSchema)]);
3451
+ var objectOrArraySchema = z2.union([z2.record(z2.string(), z2.unknown()), z2.array(z2.unknown())]);
3190
3452
  function rejectKeys(body, ctx, keys2) {
3191
3453
  for (const key of keys2) {
3192
3454
  if (key in body) {
3193
3455
  ctx.addIssue({
3194
- code: z.ZodIssueCode.custom,
3456
+ code: z2.ZodIssueCode.custom,
3195
3457
  message: `Unsupported field: ${key}`,
3196
3458
  path: [key]
3197
3459
  });
@@ -3280,8 +3542,11 @@ function toRequestSchemaValidator(schema) {
3280
3542
  if (isRequestSchemaValidator(schema)) return schema;
3281
3543
  return schema.validate;
3282
3544
  }
3283
- function defineRequestSchema(validator) {
3284
- return validator;
3545
+ function defineRequestSchema(validator, options = {}) {
3546
+ return {
3547
+ validate: validator,
3548
+ openapi: options.openapi
3549
+ };
3285
3550
  }
3286
3551
  function fromZod(schema) {
3287
3552
  return (value) => {
@@ -3561,8 +3826,8 @@ function buildPointer(path) {
3561
3826
  }
3562
3827
 
3563
3828
  // src/validation/model-router.ts
3564
- import { z as z2 } from "zod";
3565
- var listQuerySchema = z2.object({
3829
+ import { z as z3 } from "zod";
3830
+ var listQuerySchema = z3.object({
3566
3831
  skip: positiveIntegerString.optional(),
3567
3832
  limit: positiveIntegerString.optional(),
3568
3833
  page: positiveIntegerString.optional(),
@@ -3572,122 +3837,122 @@ var listQuerySchema = z2.object({
3572
3837
  include_count: queryBooleanString.optional(),
3573
3838
  include_extra_headers: queryBooleanString.optional()
3574
3839
  }).passthrough();
3575
- var createQuerySchema = z2.object({
3840
+ var createQuerySchema = z3.object({
3576
3841
  include_permissions: queryBooleanString.optional()
3577
3842
  }).passthrough();
3578
- var readQuerySchema = z2.object({
3843
+ var readQuerySchema = z3.object({
3579
3844
  include_permissions: queryBooleanString.optional(),
3580
3845
  try_list: queryBooleanString.optional()
3581
3846
  }).passthrough();
3582
- var updateQuerySchema = z2.object({
3847
+ var updateQuerySchema = z3.object({
3583
3848
  returning_all: queryBooleanString.optional(),
3584
3849
  include_permissions: queryBooleanString.optional()
3585
3850
  }).passthrough();
3586
- var upsertQuerySchema = z2.object({
3851
+ var upsertQuerySchema = z3.object({
3587
3852
  returning_all: queryBooleanString.optional(),
3588
3853
  include_permissions: queryBooleanString.optional()
3589
3854
  }).passthrough();
3590
- var listBodySchema = z2.object({
3855
+ var listBodySchema = z3.object({
3591
3856
  filter: objectOrArraySchema.optional(),
3592
3857
  select: projectionSchema.optional(),
3593
3858
  sort: sortSchema.optional(),
3594
3859
  populate: populateSchema.optional(),
3595
3860
  include: includeSchema.optional(),
3596
3861
  tasks: tasksSchema.optional(),
3597
- skip: z2.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3598
- limit: z2.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3599
- page: z2.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3600
- pageSize: z2.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3601
- options: z2.object({
3602
- skim: z2.boolean().optional(),
3603
- includePermissions: z2.boolean().optional(),
3604
- includeCount: z2.boolean().optional(),
3605
- includeExtraHeaders: z2.boolean().optional(),
3606
- populateAccess: z2.unknown().optional()
3862
+ skip: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3863
+ limit: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3864
+ page: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3865
+ pageSize: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3866
+ options: z3.object({
3867
+ skim: z3.boolean().optional(),
3868
+ includePermissions: z3.boolean().optional(),
3869
+ includeCount: z3.boolean().optional(),
3870
+ includeExtraHeaders: z3.boolean().optional(),
3871
+ populateAccess: z3.unknown().optional()
3607
3872
  }).passthrough().optional()
3608
3873
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]));
3609
- var countBodySchema = z2.object({
3874
+ var countBodySchema = z3.object({
3610
3875
  filter: objectOrArraySchema.optional(),
3611
- options: z2.object({
3612
- access: z2.unknown().optional()
3876
+ options: z3.object({
3877
+ access: z3.unknown().optional()
3613
3878
  }).passthrough().optional()
3614
3879
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query", "access"]));
3615
- var readFilterBodySchema = z2.object({
3880
+ var readFilterBodySchema = z3.object({
3616
3881
  filter: objectOrArraySchema.optional(),
3617
3882
  select: projectionSchema.optional(),
3618
3883
  sort: sortSchema.optional(),
3619
3884
  populate: populateSchema.optional(),
3620
3885
  include: includeSchema.optional(),
3621
3886
  tasks: tasksSchema.optional(),
3622
- options: z2.object({
3623
- skim: z2.boolean().optional(),
3624
- includePermissions: z2.boolean().optional(),
3625
- tryList: z2.boolean().optional(),
3626
- populateAccess: z2.unknown().optional()
3887
+ options: z3.object({
3888
+ skim: z3.boolean().optional(),
3889
+ includePermissions: z3.boolean().optional(),
3890
+ tryList: z3.boolean().optional(),
3891
+ populateAccess: z3.unknown().optional()
3627
3892
  }).passthrough().optional()
3628
3893
  }).passthrough();
3629
- var readByIdBodySchema = z2.object({
3894
+ var readByIdBodySchema = z3.object({
3630
3895
  select: projectionSchema.optional(),
3631
3896
  populate: populateSchema.optional(),
3632
3897
  include: includeSchema.optional(),
3633
3898
  tasks: tasksSchema.optional(),
3634
- options: z2.object({
3635
- skim: z2.boolean().optional(),
3636
- includePermissions: z2.boolean().optional(),
3637
- tryList: z2.boolean().optional(),
3638
- populateAccess: z2.unknown().optional()
3899
+ options: z3.object({
3900
+ skim: z3.boolean().optional(),
3901
+ includePermissions: z3.boolean().optional(),
3902
+ tryList: z3.boolean().optional(),
3903
+ populateAccess: z3.unknown().optional()
3639
3904
  }).passthrough().optional()
3640
3905
  }).passthrough();
3641
- var advancedCreateBodySchema = z2.object({
3642
- data: z2.unknown(),
3906
+ var advancedCreateBodySchema = z3.object({
3907
+ data: z3.unknown(),
3643
3908
  select: projectionSchema.optional(),
3644
3909
  populate: populateSchema.optional(),
3645
3910
  tasks: tasksSchema.optional(),
3646
- options: z2.object({
3647
- includePermissions: z2.boolean().optional(),
3648
- populateAccess: z2.unknown().optional()
3911
+ options: z3.object({
3912
+ includePermissions: z3.boolean().optional(),
3913
+ populateAccess: z3.unknown().optional()
3649
3914
  }).passthrough().optional()
3650
3915
  }).passthrough();
3651
- var createBodySchema = z2.union([
3652
- z2.record(z2.string(), z2.unknown()),
3653
- z2.array(z2.record(z2.string(), z2.unknown()))
3916
+ var createBodySchema = z3.union([
3917
+ z3.record(z3.string(), z3.unknown()),
3918
+ z3.array(z3.record(z3.string(), z3.unknown()))
3654
3919
  ]);
3655
- var updateBodySchema = z2.record(z2.string(), z2.unknown());
3656
- var advancedUpdateBodySchema = z2.object({
3657
- data: z2.unknown(),
3920
+ var updateBodySchema = z3.record(z3.string(), z3.unknown());
3921
+ var advancedUpdateBodySchema = z3.object({
3922
+ data: z3.unknown(),
3658
3923
  select: projectionSchema.optional(),
3659
3924
  populate: populateSchema.optional(),
3660
3925
  tasks: tasksSchema.optional(),
3661
- options: z2.object({
3662
- returningAll: z2.boolean().optional(),
3663
- includePermissions: z2.boolean().optional(),
3664
- populateAccess: z2.unknown().optional()
3926
+ options: z3.object({
3927
+ returningAll: z3.boolean().optional(),
3928
+ includePermissions: z3.boolean().optional(),
3929
+ populateAccess: z3.unknown().optional()
3665
3930
  }).passthrough().optional()
3666
3931
  }).passthrough();
3667
- var upsertBodySchema = z2.record(z2.string(), z2.unknown());
3668
- var advancedUpsertBodySchema = z2.object({
3669
- data: z2.record(z2.string(), z2.unknown()),
3932
+ var upsertBodySchema = z3.record(z3.string(), z3.unknown());
3933
+ var advancedUpsertBodySchema = z3.object({
3934
+ data: z3.record(z3.string(), z3.unknown()),
3670
3935
  select: projectionSchema.optional(),
3671
3936
  populate: populateSchema.optional(),
3672
3937
  tasks: tasksSchema.optional(),
3673
- options: z2.object({
3674
- returningAll: z2.boolean().optional(),
3675
- includePermissions: z2.boolean().optional(),
3676
- populateAccess: z2.unknown().optional()
3938
+ options: z3.object({
3939
+ returningAll: z3.boolean().optional(),
3940
+ includePermissions: z3.boolean().optional(),
3941
+ populateAccess: z3.unknown().optional()
3677
3942
  }).passthrough().optional()
3678
3943
  }).passthrough();
3679
- var distinctBodySchema = z2.object({
3944
+ var distinctBodySchema = z3.object({
3680
3945
  filter: objectOrArraySchema.optional()
3681
3946
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]));
3682
- var subListBodySchema = z2.object({
3683
- filter: z2.record(z2.string(), z2.unknown()).optional(),
3947
+ var subListBodySchema = z3.object({
3948
+ filter: z3.record(z3.string(), z3.unknown()).optional(),
3684
3949
  select: fieldsSchema.optional()
3685
3950
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["fields"]));
3686
- var subMutationBodySchema = z2.union([
3687
- z2.record(z2.string(), z2.unknown()),
3688
- z2.array(z2.record(z2.string(), z2.unknown()))
3951
+ var subMutationBodySchema = z3.union([
3952
+ z3.record(z3.string(), z3.unknown()),
3953
+ z3.array(z3.record(z3.string(), z3.unknown()))
3689
3954
  ]);
3690
- var subReadBodySchema = z2.object({
3955
+ var subReadBodySchema = z3.object({
3691
3956
  select: fieldsSchema.optional(),
3692
3957
  populate: subPopulateSchema.optional()
3693
3958
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["fields"]));
@@ -3700,54 +3965,54 @@ var requestSchemas = {
3700
3965
  };
3701
3966
 
3702
3967
  // src/validation/data-router.ts
3703
- import { z as z3 } from "zod";
3704
- var dataListBodySchema = z3.object({
3968
+ import { z as z4 } from "zod";
3969
+ var dataListBodySchema = z4.object({
3705
3970
  filter: objectOrArraySchema.optional(),
3706
3971
  select: projectionSchema.optional(),
3707
- sort: z3.string().optional(),
3708
- skip: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3709
- limit: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3710
- page: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3711
- pageSize: z3.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3712
- options: z3.object({
3713
- includeCount: z3.boolean().optional(),
3714
- includeExtraHeaders: z3.boolean().optional()
3972
+ sort: z4.string().optional(),
3973
+ skip: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3974
+ limit: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3975
+ page: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3976
+ pageSize: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3977
+ options: z4.object({
3978
+ includeCount: z4.boolean().optional(),
3979
+ includeExtraHeaders: z4.boolean().optional()
3715
3980
  }).passthrough().optional()
3716
3981
  }).passthrough();
3717
- var dataReadFilterBodySchema = z3.object({
3982
+ var dataReadFilterBodySchema = z4.object({
3718
3983
  filter: objectOrArraySchema.optional(),
3719
3984
  select: projectionSchema.optional()
3720
3985
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["options"]));
3721
- var dataReadByIdBodySchema = z3.object({
3986
+ var dataReadByIdBodySchema = z4.object({
3722
3987
  select: projectionSchema.optional()
3723
3988
  }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["options"]));
3724
3989
 
3725
3990
  // src/validation/root-router.ts
3726
- import { z as z4 } from "zod";
3991
+ import { z as z5 } from "zod";
3727
3992
  var rootEntryBaseSchema = {
3728
- target: z4.enum(["model", "data"]),
3729
- name: z4.string().min(1),
3730
- order: z4.number().int().optional()
3993
+ target: z5.enum(["model", "data"]),
3994
+ name: z5.string().min(1),
3995
+ order: z5.number().int().optional()
3731
3996
  };
3732
- var rootModelListArgsSchema = z4.object({
3997
+ var rootModelListArgsSchema = z5.object({
3733
3998
  select: projectionSchema.optional(),
3734
3999
  populate: populateSchema.optional(),
3735
4000
  include: includeSchema.optional(),
3736
4001
  sort: sortSchema.optional(),
3737
- skip: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3738
- limit: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3739
- page: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3740
- pageSize: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4002
+ skip: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4003
+ limit: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4004
+ page: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4005
+ pageSize: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3741
4006
  tasks: tasksSchema.optional()
3742
4007
  }).passthrough();
3743
- var rootModelListOptionsSchema = z4.object({
3744
- skim: z4.boolean().optional(),
3745
- includePermissions: z4.boolean().optional(),
3746
- includeCount: z4.boolean().optional(),
3747
- populateAccess: z4.unknown().optional(),
3748
- lean: z4.boolean().optional()
4008
+ var rootModelListOptionsSchema = z5.object({
4009
+ skim: z5.boolean().optional(),
4010
+ includePermissions: z5.boolean().optional(),
4011
+ includeCount: z5.boolean().optional(),
4012
+ populateAccess: z5.unknown().optional(),
4013
+ lean: z5.boolean().optional()
3749
4014
  }).passthrough();
3750
- var rootModelReadArgsSchema = z4.object({
4015
+ var rootModelReadArgsSchema = z5.object({
3751
4016
  select: projectionSchema.optional(),
3752
4017
  populate: populateSchema.optional(),
3753
4018
  include: includeSchema.optional(),
@@ -3756,210 +4021,219 @@ var rootModelReadArgsSchema = z4.object({
3756
4021
  var rootModelReadFilterArgsSchema = rootModelReadArgsSchema.extend({
3757
4022
  sort: sortSchema.optional()
3758
4023
  });
3759
- var rootModelReadOptionsSchema = z4.object({
3760
- skim: z4.boolean().optional(),
3761
- includePermissions: z4.boolean().optional(),
3762
- tryList: z4.boolean().optional(),
3763
- populateAccess: z4.unknown().optional(),
3764
- lean: z4.boolean().optional()
4024
+ var rootModelReadOptionsSchema = z5.object({
4025
+ skim: z5.boolean().optional(),
4026
+ includePermissions: z5.boolean().optional(),
4027
+ tryList: z5.boolean().optional(),
4028
+ populateAccess: z5.unknown().optional(),
4029
+ lean: z5.boolean().optional()
3765
4030
  }).passthrough();
3766
- var rootModelCreateArgsSchema = z4.object({
4031
+ var rootModelCreateArgsSchema = z5.object({
3767
4032
  select: projectionSchema.optional(),
3768
4033
  populate: populateSchema.optional(),
3769
4034
  tasks: tasksSchema.optional()
3770
4035
  }).passthrough();
3771
- var rootModelCreateOptionsSchema = z4.object({
3772
- skim: z4.boolean().optional(),
3773
- includePermissions: z4.boolean().optional(),
3774
- populateAccess: z4.unknown().optional()
4036
+ var rootModelCreateOptionsSchema = z5.object({
4037
+ skim: z5.boolean().optional(),
4038
+ includePermissions: z5.boolean().optional(),
4039
+ populateAccess: z5.unknown().optional()
3775
4040
  }).passthrough();
3776
- var rootModelUpdateArgsSchema = z4.object({
4041
+ var rootModelUpdateArgsSchema = z5.object({
3777
4042
  select: projectionSchema.optional(),
3778
4043
  populate: populateSchema.optional(),
3779
4044
  tasks: tasksSchema.optional()
3780
4045
  }).passthrough();
3781
- var rootModelUpdateOptionsSchema = z4.object({
3782
- skim: z4.boolean().optional(),
3783
- returningAll: z4.boolean().optional(),
3784
- includePermissions: z4.boolean().optional(),
3785
- populateAccess: z4.unknown().optional()
4046
+ var rootModelUpdateOptionsSchema = z5.object({
4047
+ skim: z5.boolean().optional(),
4048
+ returningAll: z5.boolean().optional(),
4049
+ includePermissions: z5.boolean().optional(),
4050
+ populateAccess: z5.unknown().optional()
3786
4051
  }).passthrough();
3787
4052
  var rootModelUpsertArgsSchema = rootModelUpdateArgsSchema;
3788
4053
  var rootModelUpsertOptionsSchema = rootModelUpdateOptionsSchema;
3789
- var rootModelSubListArgsSchema = z4.object({
4054
+ var rootModelSubListArgsSchema = z5.object({
3790
4055
  select: fieldsSchema.optional()
3791
4056
  }).passthrough();
3792
- var rootModelSubReadArgsSchema = z4.object({
4057
+ var rootModelSubReadArgsSchema = z5.object({
3793
4058
  select: fieldsSchema.optional(),
3794
4059
  populate: subPopulateSchema.optional()
3795
4060
  }).passthrough();
3796
- var rootModelCountOptionsSchema = z4.object({
3797
- access: z4.unknown().optional()
4061
+ var rootModelCountOptionsSchema = z5.object({
4062
+ access: z5.unknown().optional()
3798
4063
  }).passthrough();
3799
- var rootDataListArgsSchema = z4.object({
4064
+ var rootDataListArgsSchema = z5.object({
3800
4065
  select: projectionSchema.optional(),
3801
- sort: z4.string().optional(),
3802
- skip: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3803
- limit: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3804
- page: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
3805
- pageSize: z4.union([nonNegativeIntegerSchema, positiveIntegerString]).optional()
4066
+ sort: z5.string().optional(),
4067
+ skip: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4068
+ limit: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4069
+ page: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional(),
4070
+ pageSize: z5.union([nonNegativeIntegerSchema, positiveIntegerString]).optional()
3806
4071
  }).passthrough();
3807
- var rootDataListOptionsSchema = z4.object({
3808
- includeCount: z4.boolean().optional()
4072
+ var rootDataListOptionsSchema = z5.object({
4073
+ includeCount: z5.boolean().optional()
3809
4074
  }).passthrough();
3810
- var rootDataReadArgsSchema = z4.object({
4075
+ var rootDataReadArgsSchema = z5.object({
3811
4076
  select: projectionSchema.optional()
3812
4077
  }).passthrough();
3813
- var rootModelQueryEntrySchema = z4.union([
3814
- z4.object({ ...rootEntryBaseSchema, target: z4.literal("model"), op: z4.literal("new") }).passthrough(),
3815
- z4.object({
4078
+ var rootModelQueryEntrySchema = z5.union([
4079
+ z5.object({ ...rootEntryBaseSchema, target: z5.literal("model"), op: z5.literal("new") }).passthrough(),
4080
+ z5.object({
3816
4081
  ...rootEntryBaseSchema,
3817
- target: z4.literal("model"),
3818
- op: z4.literal("list"),
4082
+ target: z5.literal("model"),
4083
+ op: z5.literal("list"),
3819
4084
  filter: objectOrArraySchema.optional(),
3820
4085
  args: rootModelListArgsSchema.optional(),
3821
4086
  options: rootModelListOptionsSchema.optional()
3822
4087
  }).passthrough(),
3823
- z4.object({
4088
+ z5.object({
3824
4089
  ...rootEntryBaseSchema,
3825
- target: z4.literal("model"),
3826
- op: z4.literal("read"),
3827
- id: z4.string().min(1),
4090
+ target: z5.literal("model"),
4091
+ op: z5.literal("read"),
4092
+ id: z5.string().min(1),
3828
4093
  args: rootModelReadArgsSchema.optional(),
3829
4094
  options: rootModelReadOptionsSchema.optional()
3830
4095
  }).passthrough(),
3831
- z4.object({
4096
+ z5.object({
3832
4097
  ...rootEntryBaseSchema,
3833
- target: z4.literal("model"),
3834
- op: z4.literal("read"),
4098
+ target: z5.literal("model"),
4099
+ op: z5.literal("read"),
3835
4100
  filter: objectOrArraySchema,
3836
4101
  args: rootModelReadFilterArgsSchema.optional(),
3837
4102
  options: rootModelReadOptionsSchema.optional()
3838
4103
  }).passthrough(),
3839
- z4.object({
4104
+ z5.object({
3840
4105
  ...rootEntryBaseSchema,
3841
- target: z4.literal("model"),
3842
- op: z4.literal("create"),
3843
- data: z4.unknown(),
4106
+ target: z5.literal("model"),
4107
+ op: z5.literal("create"),
4108
+ data: z5.unknown(),
3844
4109
  args: rootModelCreateArgsSchema.optional(),
3845
4110
  options: rootModelCreateOptionsSchema.optional()
3846
4111
  }).passthrough(),
3847
- z4.object({
4112
+ z5.object({
3848
4113
  ...rootEntryBaseSchema,
3849
- target: z4.literal("model"),
3850
- op: z4.literal("update"),
3851
- id: z4.string().min(1),
3852
- data: z4.unknown(),
4114
+ target: z5.literal("model"),
4115
+ op: z5.literal("update"),
4116
+ id: z5.string().min(1),
4117
+ data: z5.unknown(),
3853
4118
  args: rootModelUpdateArgsSchema.optional(),
3854
4119
  options: rootModelUpdateOptionsSchema.optional()
3855
4120
  }).passthrough(),
3856
- z4.object({
4121
+ z5.object({
3857
4122
  ...rootEntryBaseSchema,
3858
- target: z4.literal("model"),
3859
- op: z4.literal("upsert"),
3860
- data: z4.record(z4.string(), z4.unknown()),
4123
+ target: z5.literal("model"),
4124
+ op: z5.literal("upsert"),
4125
+ data: z5.record(z5.string(), z5.unknown()),
3861
4126
  args: rootModelUpsertArgsSchema.optional(),
3862
4127
  options: rootModelUpsertOptionsSchema.optional()
3863
4128
  }).passthrough(),
3864
- z4.object({ ...rootEntryBaseSchema, target: z4.literal("model"), op: z4.literal("delete"), id: z4.string().min(1) }).passthrough(),
3865
- z4.object({
4129
+ z5.object({ ...rootEntryBaseSchema, target: z5.literal("model"), op: z5.literal("delete"), id: z5.string().min(1) }).passthrough(),
4130
+ z5.object({
3866
4131
  ...rootEntryBaseSchema,
3867
- target: z4.literal("model"),
3868
- op: z4.literal("subList"),
3869
- id: z4.string().min(1),
3870
- sub: z4.string().min(1),
3871
- filter: z4.record(z4.string(), z4.unknown()).optional(),
4132
+ target: z5.literal("model"),
4133
+ op: z5.literal("subList"),
4134
+ id: z5.string().min(1),
4135
+ sub: z5.string().min(1),
4136
+ filter: z5.record(z5.string(), z5.unknown()).optional(),
3872
4137
  args: rootModelSubListArgsSchema.optional()
3873
4138
  }).passthrough(),
3874
- z4.object({
4139
+ z5.object({
3875
4140
  ...rootEntryBaseSchema,
3876
- target: z4.literal("model"),
3877
- op: z4.literal("subRead"),
3878
- id: z4.string().min(1),
3879
- sub: z4.string().min(1),
3880
- subId: z4.string().min(1),
4141
+ target: z5.literal("model"),
4142
+ op: z5.literal("subRead"),
4143
+ id: z5.string().min(1),
4144
+ sub: z5.string().min(1),
4145
+ subId: z5.string().min(1),
3881
4146
  args: rootModelSubReadArgsSchema.optional()
3882
4147
  }).passthrough(),
3883
- z4.object({
4148
+ z5.object({
3884
4149
  ...rootEntryBaseSchema,
3885
- target: z4.literal("model"),
3886
- op: z4.literal("subCreate"),
3887
- id: z4.string().min(1),
3888
- sub: z4.string().min(1),
3889
- data: z4.union([z4.record(z4.string(), z4.unknown()), z4.array(z4.record(z4.string(), z4.unknown()))])
4150
+ target: z5.literal("model"),
4151
+ op: z5.literal("subCreate"),
4152
+ id: z5.string().min(1),
4153
+ sub: z5.string().min(1),
4154
+ data: z5.union([z5.record(z5.string(), z5.unknown()), z5.array(z5.record(z5.string(), z5.unknown()))])
3890
4155
  }).passthrough(),
3891
- z4.object({
4156
+ z5.object({
3892
4157
  ...rootEntryBaseSchema,
3893
- target: z4.literal("model"),
3894
- op: z4.literal("subUpdate"),
3895
- id: z4.string().min(1),
3896
- sub: z4.string().min(1),
3897
- subId: z4.string().min(1),
3898
- data: z4.union([z4.record(z4.string(), z4.unknown()), z4.array(z4.record(z4.string(), z4.unknown()))])
4158
+ target: z5.literal("model"),
4159
+ op: z5.literal("subUpdate"),
4160
+ id: z5.string().min(1),
4161
+ sub: z5.string().min(1),
4162
+ subId: z5.string().min(1),
4163
+ data: z5.union([z5.record(z5.string(), z5.unknown()), z5.array(z5.record(z5.string(), z5.unknown()))])
3899
4164
  }).passthrough(),
3900
- z4.object({
4165
+ z5.object({
3901
4166
  ...rootEntryBaseSchema,
3902
- target: z4.literal("model"),
3903
- op: z4.literal("subBulkUpdate"),
3904
- id: z4.string().min(1),
3905
- sub: z4.string().min(1),
3906
- data: z4.union([z4.record(z4.string(), z4.unknown()), z4.array(z4.record(z4.string(), z4.unknown()))])
4167
+ target: z5.literal("model"),
4168
+ op: z5.literal("subBulkUpdate"),
4169
+ id: z5.string().min(1),
4170
+ sub: z5.string().min(1),
4171
+ data: z5.union([z5.record(z5.string(), z5.unknown()), z5.array(z5.record(z5.string(), z5.unknown()))])
3907
4172
  }).passthrough(),
3908
- z4.object({
4173
+ z5.object({
3909
4174
  ...rootEntryBaseSchema,
3910
- target: z4.literal("model"),
3911
- op: z4.literal("subDelete"),
3912
- id: z4.string().min(1),
3913
- sub: z4.string().min(1),
3914
- subId: z4.string().min(1)
4175
+ target: z5.literal("model"),
4176
+ op: z5.literal("subDelete"),
4177
+ id: z5.string().min(1),
4178
+ sub: z5.string().min(1),
4179
+ subId: z5.string().min(1)
3915
4180
  }).passthrough(),
3916
- z4.object({
4181
+ z5.object({
3917
4182
  ...rootEntryBaseSchema,
3918
- target: z4.literal("model"),
3919
- op: z4.literal("distinct"),
3920
- field: z4.string().min(1),
4183
+ target: z5.literal("model"),
4184
+ op: z5.literal("distinct"),
4185
+ field: z5.string().min(1),
3921
4186
  filter: objectOrArraySchema.optional()
3922
4187
  }).passthrough(),
3923
- z4.object({
4188
+ z5.object({
3924
4189
  ...rootEntryBaseSchema,
3925
- target: z4.literal("model"),
3926
- op: z4.literal("count"),
4190
+ target: z5.literal("model"),
4191
+ op: z5.literal("count"),
3927
4192
  filter: objectOrArraySchema.optional(),
3928
4193
  options: rootModelCountOptionsSchema.optional()
3929
4194
  }).passthrough()
3930
4195
  ]);
3931
- var rootDataQueryEntrySchema = z4.union([
3932
- z4.object({
4196
+ var rootDataQueryEntrySchema = z5.union([
4197
+ z5.object({
3933
4198
  ...rootEntryBaseSchema,
3934
- target: z4.literal("data"),
3935
- op: z4.literal("list"),
4199
+ target: z5.literal("data"),
4200
+ op: z5.literal("list"),
3936
4201
  filter: objectOrArraySchema.optional(),
3937
4202
  args: rootDataListArgsSchema.optional(),
3938
4203
  options: rootDataListOptionsSchema.optional()
3939
4204
  }).passthrough(),
3940
- z4.object({
4205
+ z5.object({
3941
4206
  ...rootEntryBaseSchema,
3942
- target: z4.literal("data"),
3943
- op: z4.literal("read"),
3944
- id: z4.string().min(1),
4207
+ target: z5.literal("data"),
4208
+ op: z5.literal("read"),
4209
+ id: z5.string().min(1),
3945
4210
  args: rootDataReadArgsSchema.optional()
3946
4211
  }).passthrough(),
3947
- z4.object({
4212
+ z5.object({
3948
4213
  ...rootEntryBaseSchema,
3949
- target: z4.literal("data"),
3950
- op: z4.literal("read"),
4214
+ target: z5.literal("data"),
4215
+ op: z5.literal("read"),
3951
4216
  filter: objectOrArraySchema,
3952
4217
  args: rootDataReadArgsSchema.optional()
3953
4218
  }).passthrough()
3954
4219
  ]);
3955
- var rootQuerySchema = z4.array(z4.union([rootModelQueryEntrySchema, rootDataQueryEntrySchema]));
4220
+ var rootQuerySchema = z5.array(z5.union([rootModelQueryEntrySchema, rootDataQueryEntrySchema]));
3956
4221
 
3957
4222
  // src/routers/shared.ts
3958
- var parseBooleanString = (str, defaultValue) => str ? str === "true" : defaultValue;
4223
+ import { parseBooleanString } from "@web-ts-toolkit/utils";
3959
4224
 
3960
4225
  // src/routers/model-router-collection-routes.ts
3961
4226
  function setModelCollectionRoutes(context) {
3962
4227
  const { router, options } = context;
4228
+ const getAdvancedCreateOpenApiBody = () => {
4229
+ const advancedCreateSchema = context.getRequestSchema("requestSchemas.advancedCreate");
4230
+ const dataSchema = context.getRequestSchema("requestSchemas.advancedCreate.data") ?? getNestedOpenApiSchemaDataSource(advancedCreateSchema);
4231
+ const bodySchema = unwrapNestedOpenApiSchemaSource(
4232
+ context.getRequestSchema("requestSchemas.advancedCreate.default") ?? advancedCreateSchema,
4233
+ advancedCreateBodySchema
4234
+ );
4235
+ return dataSchema ? patchOpenApiObjectSchema(bodySchema, { data: dataSchema }) : bodySchema;
4236
+ };
3963
4237
  router.get("", async (req) => {
3964
4238
  await context.assertAllowed(req, "list");
3965
4239
  const { skip, limit, page, page_size, skim, include_permissions, include_count, include_extra_headers } = parseQuery(requestSchemas.listQuery, req.query);
@@ -3978,6 +4252,13 @@ function setModelCollectionRoutes(context) {
3978
4252
  handleResultError(result);
3979
4253
  return formatModelListResponse(req, result, includeCount, includeExtraHeaders);
3980
4254
  });
4255
+ context.registerOpenApiRoute({
4256
+ method: "get",
4257
+ path: "",
4258
+ operationId: `${context.modelName}.list`,
4259
+ summary: `List ${context.modelName} documents`,
4260
+ query: requestSchemas.listQuery
4261
+ });
3981
4262
  router.post(`/${options.queryRouteSegment}`, async (req) => {
3982
4263
  await context.assertAllowed(req, "list");
3983
4264
  const body = await parseBodyWithSchema(
@@ -4003,6 +4284,13 @@ function setModelCollectionRoutes(context) {
4003
4284
  handleResultError(result);
4004
4285
  return formatModelListResponse(req, result, includeCount, includeExtraHeaders);
4005
4286
  });
4287
+ context.registerOpenApiRoute({
4288
+ method: "post",
4289
+ path: `/${options.queryRouteSegment}`,
4290
+ operationId: `${context.modelName}.listAdvanced`,
4291
+ summary: `Advanced list ${context.modelName} documents`,
4292
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.advancedList") ?? listBodySchema)
4293
+ });
4006
4294
  router.post("", async (req) => {
4007
4295
  await context.assertAllowed(req, "create");
4008
4296
  const { include_permissions } = parseQuery(requestSchemas.createQuery, req.query);
@@ -4016,6 +4304,14 @@ function setModelCollectionRoutes(context) {
4016
4304
  handleResultError(result);
4017
4305
  return formatModelCreatedResponse(result);
4018
4306
  });
4307
+ context.registerOpenApiRoute({
4308
+ method: "post",
4309
+ path: "",
4310
+ operationId: `${context.modelName}.create`,
4311
+ summary: `Create a ${context.modelName} document`,
4312
+ query: requestSchemas.createQuery,
4313
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.create") ?? createBodySchema)
4314
+ });
4019
4315
  router.post(`/${options.mutationRouteSegment}`, async (req) => {
4020
4316
  await context.assertAllowed(req, "create");
4021
4317
  const { include_permissions } = parseQuery(requestSchemas.createQuery, req.query);
@@ -4045,17 +4341,49 @@ function setModelCollectionRoutes(context) {
4045
4341
  handleResultError(result);
4046
4342
  return formatModelCreatedResponse(result);
4047
4343
  });
4344
+ context.registerOpenApiRoute({
4345
+ method: "post",
4346
+ path: `/${options.mutationRouteSegment}`,
4347
+ operationId: `${context.modelName}.createAdvanced`,
4348
+ summary: `Advanced create a ${context.modelName} document`,
4349
+ query: requestSchemas.createQuery,
4350
+ body: defineOpenApiSchemaResolver(getAdvancedCreateOpenApiBody)
4351
+ });
4048
4352
  router.get("/new", async (req) => {
4049
4353
  const svc = context.getPublicService(req);
4050
4354
  const result = await svc._new();
4051
4355
  handleResultError(result);
4052
4356
  return unwrapServiceData(result);
4053
4357
  });
4358
+ context.registerOpenApiRoute({
4359
+ method: "get",
4360
+ path: "/new",
4361
+ operationId: `${context.modelName}.new`,
4362
+ summary: `Get a new ${context.modelName} document template`
4363
+ });
4054
4364
  }
4055
4365
 
4056
4366
  // src/routers/model-router-document-routes.ts
4057
4367
  function setModelDocumentRoutes(context) {
4058
4368
  const { router, options, modelName } = context;
4369
+ const getAdvancedUpdateOpenApiBody = () => {
4370
+ const advancedUpdateSchema = context.getRequestSchema("requestSchemas.advancedUpdate");
4371
+ const dataSchema = context.getRequestSchema("requestSchemas.advancedUpdate.data") ?? getNestedOpenApiSchemaDataSource(advancedUpdateSchema);
4372
+ const bodySchema = unwrapNestedOpenApiSchemaSource(
4373
+ context.getRequestSchema("requestSchemas.advancedUpdate.default") ?? advancedUpdateSchema,
4374
+ advancedUpdateBodySchema
4375
+ );
4376
+ return dataSchema ? patchOpenApiObjectSchema(bodySchema, { data: dataSchema }) : bodySchema;
4377
+ };
4378
+ const getAdvancedUpsertOpenApiBody = () => {
4379
+ const advancedUpsertSchema = context.getRequestSchema("requestSchemas.advancedUpsert");
4380
+ const dataSchema = context.getRequestSchema("requestSchemas.advancedUpsert.data") ?? getNestedOpenApiSchemaDataSource(advancedUpsertSchema);
4381
+ const bodySchema = unwrapNestedOpenApiSchemaSource(
4382
+ context.getRequestSchema("requestSchemas.advancedUpsert.default") ?? advancedUpsertSchema,
4383
+ advancedUpsertBodySchema
4384
+ );
4385
+ return dataSchema ? patchOpenApiObjectSchema(bodySchema, { data: dataSchema }) : bodySchema;
4386
+ };
4059
4387
  router.get("/count", async (req) => {
4060
4388
  await context.assertAllowed(req, "count");
4061
4389
  const svc = context.getPublicService(req);
@@ -4063,6 +4391,12 @@ function setModelDocumentRoutes(context) {
4063
4391
  handleResultError(result);
4064
4392
  return unwrapServiceData(result);
4065
4393
  });
4394
+ context.registerOpenApiRoute({
4395
+ method: "get",
4396
+ path: "/count",
4397
+ operationId: `${modelName}.count`,
4398
+ summary: `Count ${modelName} documents`
4399
+ });
4066
4400
  router.post("/count", async (req) => {
4067
4401
  await context.assertAllowed(req, "count");
4068
4402
  const { filter: filter2, options: countOptions = {} } = await parseBodyWithSchema(
@@ -4078,6 +4412,13 @@ function setModelDocumentRoutes(context) {
4078
4412
  handleResultError(result);
4079
4413
  return unwrapServiceData(result);
4080
4414
  });
4415
+ context.registerOpenApiRoute({
4416
+ method: "post",
4417
+ path: "/count",
4418
+ operationId: `${modelName}.countWithFilter`,
4419
+ summary: `Count ${modelName} documents with a filter`,
4420
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.count") ?? countBodySchema)
4421
+ });
4081
4422
  router.get(`/:${options.idParam}`, async (req) => {
4082
4423
  await context.assertAllowed(req, "read");
4083
4424
  const id = parsePathParam(req.params[options.idParam], options.idParam);
@@ -4094,6 +4435,13 @@ function setModelDocumentRoutes(context) {
4094
4435
  handleResultError(result);
4095
4436
  return unwrapServiceData(result);
4096
4437
  });
4438
+ context.registerOpenApiRoute({
4439
+ method: "get",
4440
+ path: `/:${options.idParam}`,
4441
+ operationId: `${modelName}.read`,
4442
+ summary: `Read a ${modelName} document`,
4443
+ query: requestSchemas.readQuery
4444
+ });
4097
4445
  router.post(`/${options.queryRouteSegment}/__filter`, async (req) => {
4098
4446
  await context.assertAllowed(req, "read");
4099
4447
  const body = await parseBodyWithSchema(
@@ -4113,6 +4461,15 @@ function setModelDocumentRoutes(context) {
4113
4461
  handleResultError(result);
4114
4462
  return unwrapServiceData(result);
4115
4463
  });
4464
+ context.registerOpenApiRoute({
4465
+ method: "post",
4466
+ path: `/${options.queryRouteSegment}/__filter`,
4467
+ operationId: `${modelName}.readByFilterAdvanced`,
4468
+ summary: `Read a ${modelName} document by filter`,
4469
+ body: defineOpenApiSchemaResolver(
4470
+ () => context.getRequestSchema("requestSchemas.advancedReadFilter") ?? readFilterBodySchema
4471
+ )
4472
+ });
4116
4473
  router.post(`/${options.queryRouteSegment}/:${options.idParam}`, async (req) => {
4117
4474
  await context.assertAllowed(req, "read");
4118
4475
  const id = parsePathParam(req.params[options.idParam], options.idParam);
@@ -4133,6 +4490,15 @@ function setModelDocumentRoutes(context) {
4133
4490
  handleResultError(result);
4134
4491
  return unwrapServiceData(result);
4135
4492
  });
4493
+ context.registerOpenApiRoute({
4494
+ method: "post",
4495
+ path: `/${options.queryRouteSegment}/:${options.idParam}`,
4496
+ operationId: `${modelName}.readAdvanced`,
4497
+ summary: `Read a ${modelName} document with advanced options`,
4498
+ body: defineOpenApiSchemaResolver(
4499
+ () => context.getRequestSchema("requestSchemas.advancedRead") ?? readByIdBodySchema
4500
+ )
4501
+ });
4136
4502
  router.patch(`/:${options.idParam}`, async (req) => {
4137
4503
  await context.assertAllowed(req, "update");
4138
4504
  const id = parsePathParam(req.params[options.idParam], options.idParam);
@@ -4155,6 +4521,14 @@ function setModelDocumentRoutes(context) {
4155
4521
  handleResultError(result);
4156
4522
  return unwrapServiceData(result);
4157
4523
  });
4524
+ context.registerOpenApiRoute({
4525
+ method: "patch",
4526
+ path: `/:${options.idParam}`,
4527
+ operationId: `${modelName}.update`,
4528
+ summary: `Update a ${modelName} document`,
4529
+ query: requestSchemas.updateQuery,
4530
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.update") ?? updateBodySchema)
4531
+ });
4158
4532
  router.patch(`/${options.mutationRouteSegment}/:${options.idParam}`, async (req) => {
4159
4533
  await context.assertAllowed(req, "update");
4160
4534
  const id = parsePathParam(req.params[options.idParam], options.idParam);
@@ -4187,6 +4561,14 @@ function setModelDocumentRoutes(context) {
4187
4561
  handleResultError(result);
4188
4562
  return unwrapServiceData(result);
4189
4563
  });
4564
+ context.registerOpenApiRoute({
4565
+ method: "patch",
4566
+ path: `/${options.mutationRouteSegment}/:${options.idParam}`,
4567
+ operationId: `${modelName}.updateAdvanced`,
4568
+ summary: `Advanced update a ${modelName} document`,
4569
+ query: requestSchemas.updateQuery,
4570
+ body: defineOpenApiSchemaResolver(getAdvancedUpdateOpenApiBody)
4571
+ });
4190
4572
  router.put(`/`, async (req) => {
4191
4573
  await context.assertAllowed(req, "upsert");
4192
4574
  const svc = context.getPublicService(req);
@@ -4207,6 +4589,14 @@ function setModelDocumentRoutes(context) {
4207
4589
  handleResultError(result);
4208
4590
  return formatModelUpsertResponse(result);
4209
4591
  });
4592
+ context.registerOpenApiRoute({
4593
+ method: "put",
4594
+ path: "/",
4595
+ operationId: `${modelName}.upsert`,
4596
+ summary: `Upsert a ${modelName} document`,
4597
+ query: requestSchemas.upsertQuery,
4598
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.upsert") ?? upsertBodySchema)
4599
+ });
4210
4600
  router.put(`/${options.mutationRouteSegment}`, async (req) => {
4211
4601
  await context.assertAllowed(req, "upsert");
4212
4602
  const svc = context.getPublicService(req);
@@ -4237,6 +4627,14 @@ function setModelDocumentRoutes(context) {
4237
4627
  handleResultError(result);
4238
4628
  return formatModelUpsertResponse(result);
4239
4629
  });
4630
+ context.registerOpenApiRoute({
4631
+ method: "put",
4632
+ path: `/${options.mutationRouteSegment}`,
4633
+ operationId: `${modelName}.upsertAdvanced`,
4634
+ summary: `Advanced upsert a ${modelName} document`,
4635
+ query: requestSchemas.upsertQuery,
4636
+ body: defineOpenApiSchemaResolver(getAdvancedUpsertOpenApiBody)
4637
+ });
4240
4638
  router.delete(`/:${options.idParam}`, async (req) => {
4241
4639
  await context.assertAllowed(req, "delete");
4242
4640
  const id = parsePathParam(req.params[options.idParam], options.idParam);
@@ -4245,6 +4643,12 @@ function setModelDocumentRoutes(context) {
4245
4643
  handleResultError(result);
4246
4644
  return unwrapServiceData(result);
4247
4645
  });
4646
+ context.registerOpenApiRoute({
4647
+ method: "delete",
4648
+ path: `/:${options.idParam}`,
4649
+ operationId: `${modelName}.delete`,
4650
+ summary: `Delete a ${modelName} document`
4651
+ });
4248
4652
  router.get("/distinct/:field", async (req) => {
4249
4653
  await context.assertAllowed(req, "distinct");
4250
4654
  const field = parsePathParam(req.params.field, "field");
@@ -4253,6 +4657,12 @@ function setModelDocumentRoutes(context) {
4253
4657
  handleResultError(result);
4254
4658
  return unwrapServiceData(result);
4255
4659
  });
4660
+ context.registerOpenApiRoute({
4661
+ method: "get",
4662
+ path: "/distinct/:field",
4663
+ operationId: `${modelName}.distinct`,
4664
+ summary: `Get distinct values for a ${modelName} field`
4665
+ });
4256
4666
  router.post("/distinct/:field", async (req) => {
4257
4667
  await context.assertAllowed(req, "distinct");
4258
4668
  const field = parsePathParam(req.params.field, "field");
@@ -4266,6 +4676,13 @@ function setModelDocumentRoutes(context) {
4266
4676
  handleResultError(result);
4267
4677
  return unwrapServiceData(result);
4268
4678
  });
4679
+ context.registerOpenApiRoute({
4680
+ method: "post",
4681
+ path: "/distinct/:field",
4682
+ operationId: `${modelName}.distinctWithFilter`,
4683
+ summary: `Get distinct values for a ${modelName} field with a filter`,
4684
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.distinct") ?? distinctBodySchema)
4685
+ });
4269
4686
  }
4270
4687
 
4271
4688
  // src/routers/model-router-subdocument-routes.ts
@@ -4282,6 +4699,12 @@ function setModelSubDocumentRoutes(context) {
4282
4699
  handleResultError(result);
4283
4700
  return unwrapServiceData(result);
4284
4701
  });
4702
+ context.registerOpenApiRoute({
4703
+ method: "get",
4704
+ path: `/:${context.options.idParam}/${sub}`,
4705
+ operationId: `${context.modelName}.${sub}.list`,
4706
+ summary: `List ${sub} subdocuments`
4707
+ });
4285
4708
  context.router.post(
4286
4709
  `/:${context.options.idParam}/${sub}/${context.options.queryRouteSegment}`,
4287
4710
  async (req) => {
@@ -4298,6 +4721,13 @@ function setModelSubDocumentRoutes(context) {
4298
4721
  return unwrapServiceData(result);
4299
4722
  }
4300
4723
  );
4724
+ context.registerOpenApiRoute({
4725
+ method: "post",
4726
+ path: `/:${context.options.idParam}/${sub}/${context.options.queryRouteSegment}`,
4727
+ operationId: `${context.modelName}.${sub}.listAdvanced`,
4728
+ summary: `Advanced list ${sub} subdocuments`,
4729
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.subList") ?? subListBodySchema)
4730
+ });
4301
4731
  context.router.patch(`/:${context.options.idParam}/${sub}`, async (req) => {
4302
4732
  await context.assertAllowed(req, `subs.${sub}.update`);
4303
4733
  const id = parsePathParam(req.params[context.options.idParam], context.options.idParam);
@@ -4311,6 +4741,15 @@ function setModelSubDocumentRoutes(context) {
4311
4741
  handleResultError(result);
4312
4742
  return unwrapServiceData(result);
4313
4743
  });
4744
+ context.registerOpenApiRoute({
4745
+ method: "patch",
4746
+ path: `/:${context.options.idParam}/${sub}`,
4747
+ operationId: `${context.modelName}.${sub}.bulkUpdate`,
4748
+ summary: `Bulk update ${sub} subdocuments`,
4749
+ body: defineOpenApiSchemaResolver(
4750
+ () => context.getRequestSchema("requestSchemas.subBulkUpdate") ?? subMutationBodySchema
4751
+ )
4752
+ });
4314
4753
  context.router.get(`/:${context.options.idParam}/${sub}/:subId`, async (req) => {
4315
4754
  await context.assertAllowed(req, `subs.${sub}.read`);
4316
4755
  const id = parsePathParam(req.params[context.options.idParam], context.options.idParam);
@@ -4320,6 +4759,12 @@ function setModelSubDocumentRoutes(context) {
4320
4759
  handleResultError(result);
4321
4760
  return unwrapServiceData(result);
4322
4761
  });
4762
+ context.registerOpenApiRoute({
4763
+ method: "get",
4764
+ path: `/:${context.options.idParam}/${sub}/:subId`,
4765
+ operationId: `${context.modelName}.${sub}.read`,
4766
+ summary: `Read a ${sub} subdocument`
4767
+ });
4323
4768
  context.router.post(
4324
4769
  `/:${context.options.idParam}/${sub}/:subId/${context.options.queryRouteSegment}`,
4325
4770
  async (req) => {
@@ -4339,6 +4784,13 @@ function setModelSubDocumentRoutes(context) {
4339
4784
  return unwrapServiceData(result);
4340
4785
  }
4341
4786
  );
4787
+ context.registerOpenApiRoute({
4788
+ method: "post",
4789
+ path: `/:${context.options.idParam}/${sub}/:subId/${context.options.queryRouteSegment}`,
4790
+ operationId: `${context.modelName}.${sub}.readAdvanced`,
4791
+ summary: `Advanced read a ${sub} subdocument`,
4792
+ body: defineOpenApiSchemaResolver(() => context.getRequestSchema("requestSchemas.subRead") ?? subReadBodySchema)
4793
+ });
4342
4794
  context.router.patch(`/:${context.options.idParam}/${sub}/:subId`, async (req) => {
4343
4795
  await context.assertAllowed(req, `subs.${sub}.update`);
4344
4796
  const id = parsePathParam(req.params[context.options.idParam], context.options.idParam);
@@ -4353,6 +4805,15 @@ function setModelSubDocumentRoutes(context) {
4353
4805
  handleResultError(result);
4354
4806
  return unwrapServiceData(result);
4355
4807
  });
4808
+ context.registerOpenApiRoute({
4809
+ method: "patch",
4810
+ path: `/:${context.options.idParam}/${sub}/:subId`,
4811
+ operationId: `${context.modelName}.${sub}.update`,
4812
+ summary: `Update a ${sub} subdocument`,
4813
+ body: defineOpenApiSchemaResolver(
4814
+ () => context.getRequestSchema("requestSchemas.subUpdate") ?? subMutationBodySchema
4815
+ )
4816
+ });
4356
4817
  context.router.post(`/:${context.options.idParam}/${sub}`, async (req) => {
4357
4818
  await context.assertAllowed(req, `subs.${sub}.create`);
4358
4819
  const id = parsePathParam(req.params[context.options.idParam], context.options.idParam);
@@ -4366,6 +4827,15 @@ function setModelSubDocumentRoutes(context) {
4366
4827
  handleResultError(result);
4367
4828
  return formatModelCreatedResponse(result);
4368
4829
  });
4830
+ context.registerOpenApiRoute({
4831
+ method: "post",
4832
+ path: `/:${context.options.idParam}/${sub}`,
4833
+ operationId: `${context.modelName}.${sub}.create`,
4834
+ summary: `Create a ${sub} subdocument`,
4835
+ body: defineOpenApiSchemaResolver(
4836
+ () => context.getRequestSchema("requestSchemas.subCreate") ?? subMutationBodySchema
4837
+ )
4838
+ });
4369
4839
  context.router.delete(`/:${context.options.idParam}/${sub}/:subId`, async (req) => {
4370
4840
  await context.assertAllowed(req, `subs.${sub}.delete`);
4371
4841
  const id = parsePathParam(req.params[context.options.idParam], context.options.idParam);
@@ -4375,9 +4845,25 @@ function setModelSubDocumentRoutes(context) {
4375
4845
  handleResultError(result);
4376
4846
  return unwrapServiceData(result);
4377
4847
  });
4848
+ context.registerOpenApiRoute({
4849
+ method: "delete",
4850
+ path: `/:${context.options.idParam}/${sub}/:subId`,
4851
+ operationId: `${context.modelName}.${sub}.delete`,
4852
+ summary: `Delete a ${sub} subdocument`
4853
+ });
4378
4854
  }
4379
4855
  }
4380
4856
 
4857
+ // src/openapi/route-registration.ts
4858
+ import { normalizeUrlPath } from "@web-ts-toolkit/utils";
4859
+ function registerOpenApiRoute(runtime, basePath, defaultTag, route) {
4860
+ runtime.registerOpenApiRoute({
4861
+ ...route,
4862
+ path: normalizeUrlPath(basePath + route.path),
4863
+ tags: route.tags ?? [defaultTag]
4864
+ });
4865
+ }
4866
+
4381
4867
  // src/routers/model-router.ts
4382
4868
  var clientErrors2 = JsonRouter5.clientErrors;
4383
4869
  function setOption(parentKey, optionKey, option) {
@@ -4543,7 +5029,7 @@ var ModelRouter = class {
4543
5029
  this.runtime.setModelOptions(modelName, initialOptions);
4544
5030
  attachRuntimeToModel(modelName, this.runtime);
4545
5031
  this.options = this.runtime.getModelOptions(modelName);
4546
- this.fullBasePath = normalizeUrlPath(this.options.parentPath + this.options.basePath);
5032
+ this.fullBasePath = normalizeUrlPath2(this.options.parentPath + this.options.basePath);
4547
5033
  this.modelName = modelName;
4548
5034
  this.router = new JsonRouter5(this.options.basePath, createSetCore(this.runtime), accessRouterResponseHandler);
4549
5035
  this.model = new model_default(modelName);
@@ -4568,6 +5054,9 @@ var ModelRouter = class {
4568
5054
  const allowed = await req.macl.isAllowed(this.modelName, access);
4569
5055
  if (!allowed) throw new clientErrors2.UnauthorizedError();
4570
5056
  }
5057
+ registerOpenApiRoute(route) {
5058
+ registerOpenApiRoute(this.runtime, this.fullBasePath, this.modelName, route);
5059
+ }
4571
5060
  ///////////////////////
4572
5061
  // Collection Routes //
4573
5062
  ///////////////////////
@@ -4578,7 +5067,8 @@ var ModelRouter = class {
4578
5067
  options: this.options,
4579
5068
  getRequestSchema: this.getRequestSchema.bind(this),
4580
5069
  getPublicService: this.getPublicService.bind(this),
4581
- assertAllowed: this.assertAllowed.bind(this)
5070
+ assertAllowed: this.assertAllowed.bind(this),
5071
+ registerOpenApiRoute: this.registerOpenApiRoute.bind(this)
4582
5072
  });
4583
5073
  }
4584
5074
  /////////////////////
@@ -4591,7 +5081,8 @@ var ModelRouter = class {
4591
5081
  options: this.options,
4592
5082
  getRequestSchema: this.getRequestSchema.bind(this),
4593
5083
  getPublicService: this.getPublicService.bind(this),
4594
- assertAllowed: this.assertAllowed.bind(this)
5084
+ assertAllowed: this.assertAllowed.bind(this),
5085
+ registerOpenApiRoute: this.registerOpenApiRoute.bind(this)
4595
5086
  });
4596
5087
  }
4597
5088
  /////////////////////////
@@ -4604,13 +5095,14 @@ var ModelRouter = class {
4604
5095
  options: this.options,
4605
5096
  getRequestSchema: this.getRequestSchema.bind(this),
4606
5097
  getPublicService: this.getPublicService.bind(this),
4607
- assertAllowed: this.assertAllowed.bind(this)
5098
+ assertAllowed: this.assertAllowed.bind(this),
5099
+ registerOpenApiRoute: this.registerOpenApiRoute.bind(this)
4608
5100
  });
4609
5101
  }
4610
5102
  logEndpoints() {
4611
5103
  runWithRuntime(this.runtime, () => {
4612
- forEach7(this.router.endpoints, ({ method, path }) => {
4613
- logger.info(`${padEnd(method, 6)} ${normalizeUrlPath(this.options.parentPath + path)}`);
5104
+ forEach8(this.router.endpoints, ({ method, path }) => {
5105
+ logger.info(`${padEnd(method, 6)} ${normalizeUrlPath2(this.options.parentPath + path)}`);
4614
5106
  });
4615
5107
  });
4616
5108
  }
@@ -4623,7 +5115,7 @@ var ModelRouter = class {
4623
5115
  value
4624
5116
  );
4625
5117
  }
4626
- if (arguments.length === 1 && isPlainObject9(keyOrOptions)) {
5118
+ if (arguments.length === 1 && isPlainObject12(keyOrOptions)) {
4627
5119
  assertMutableRouterOptions("model", keyOrOptions);
4628
5120
  this.runtime.setModelOptions(this.modelName, keyOrOptions);
4629
5121
  }
@@ -4646,7 +5138,7 @@ var ModelRouter = class {
4646
5138
 
4647
5139
  // src/routers/root-router.ts
4648
5140
  import JsonRouter6 from "@web-ts-toolkit/express-json-router";
4649
- import { isNumber as _isNumber, isString as isString10, orderBy as _orderBy } from "@web-ts-toolkit/utils";
5141
+ import { isNumber as _isNumber, isString as isString10, normalizeUrlPath as normalizeUrlPath3, orderBy as _orderBy } from "@web-ts-toolkit/utils";
4650
5142
 
4651
5143
  // src/core-data.ts
4652
5144
  var DataCore = class {
@@ -4892,6 +5384,9 @@ var RootRouter = class {
4892
5384
  );
4893
5385
  this.setRoutes();
4894
5386
  }
5387
+ registerOpenApiRoute(route) {
5388
+ registerOpenApiRoute(this.runtime, normalizeUrlPath3(this.basename), "root", route);
5389
+ }
4895
5390
  wrapResult(index, item, result) {
4896
5391
  return {
4897
5392
  index,
@@ -4977,6 +5472,13 @@ var RootRouter = class {
4977
5472
  }
4978
5473
  return _orderBy(results, ["index"], ["asc"]);
4979
5474
  });
5475
+ this.registerOpenApiRoute({
5476
+ method: "post",
5477
+ path: "",
5478
+ operationId: "root.query",
5479
+ summary: "Execute batched model and data operations",
5480
+ body: rootQuerySchema
5481
+ });
4980
5482
  }
4981
5483
  get routes() {
4982
5484
  return this.router.original;
@@ -4985,7 +5487,7 @@ var RootRouter = class {
4985
5487
 
4986
5488
  // src/routers/data-router.ts
4987
5489
  import JsonRouter7 from "@web-ts-toolkit/express-json-router";
4988
- import { isPlainObject as isPlainObject10, isString as isString11, isUndefined as isUndefined3, normalizeUrlPath as normalizeUrlPath2 } from "@web-ts-toolkit/utils";
5490
+ import { isPlainObject as isPlainObject13, isString as isString11, isUndefined as isUndefined3, normalizeUrlPath as normalizeUrlPath4 } from "@web-ts-toolkit/utils";
4989
5491
  var clientErrors4 = JsonRouter7.clientErrors;
4990
5492
  function setOption2(parentKey, optionKey, option) {
4991
5493
  const key = isUndefined3(option) ? parentKey : `${parentKey}.${optionKey}`;
@@ -5025,7 +5527,7 @@ var DataRouter = class {
5025
5527
  this.runtime = runtime;
5026
5528
  this.runtime.setDataOptions(dataName, initialOptions);
5027
5529
  this.options = this.runtime.getDataOptions(dataName);
5028
- this.fullBasePath = normalizeUrlPath2(this.options.parentPath + this.options.basePath);
5530
+ this.fullBasePath = normalizeUrlPath4(this.options.parentPath + this.options.basePath);
5029
5531
  this.dataName = dataName;
5030
5532
  this.router = new JsonRouter7(this.options.basePath, createSetDataCore(this.runtime), accessRouterResponseHandler);
5031
5533
  this.setCollectionRoutes();
@@ -5044,6 +5546,9 @@ var DataRouter = class {
5044
5546
  const allowed = await req.dacl.isAllowed(this.dataName, access);
5045
5547
  if (!allowed) throw new clientErrors4.UnauthorizedError();
5046
5548
  }
5549
+ registerOpenApiRoute(route) {
5550
+ registerOpenApiRoute(this.runtime, this.fullBasePath, this.dataName, route);
5551
+ }
5047
5552
  ///////////////////////
5048
5553
  // Collection Routes //
5049
5554
  ///////////////////////
@@ -5068,6 +5573,13 @@ var DataRouter = class {
5068
5573
  const decoratedResult = await decorateDataListResult(svc, result);
5069
5574
  return formatListResponse(req, decoratedResult, includeCount, includeExtraHeaders);
5070
5575
  });
5576
+ this.registerOpenApiRoute({
5577
+ method: "get",
5578
+ path: "",
5579
+ operationId: `${this.dataName}.list`,
5580
+ summary: `List ${this.dataName} records`,
5581
+ query: requestSchemas.listQuery
5582
+ });
5071
5583
  this.router.post(`/${this.options.queryRouteSegment}`, async (req) => {
5072
5584
  await this.assertAllowed(req, "list");
5073
5585
  let {
@@ -5091,6 +5603,15 @@ var DataRouter = class {
5091
5603
  const decoratedResult = await decorateDataListResult(svc, result);
5092
5604
  return formatListResponse(req, decoratedResult, includeCount, includeExtraHeaders);
5093
5605
  });
5606
+ this.registerOpenApiRoute({
5607
+ method: "post",
5608
+ path: `/${this.options.queryRouteSegment}`,
5609
+ operationId: `${this.dataName}.listAdvanced`,
5610
+ summary: `Advanced list ${this.dataName} records`,
5611
+ body: defineOpenApiSchemaResolver(
5612
+ () => this.getRequestSchema("requestSchemas.advancedList") ?? dataListBodySchema
5613
+ )
5614
+ });
5094
5615
  }
5095
5616
  /////////////////////
5096
5617
  // Document Routes //
@@ -5105,6 +5626,12 @@ var DataRouter = class {
5105
5626
  const decoratedResult = await decorateDataSingleResult(svc, result);
5106
5627
  return decoratedResult.data;
5107
5628
  });
5629
+ this.registerOpenApiRoute({
5630
+ method: "get",
5631
+ path: `/:${this.options.idParam}`,
5632
+ operationId: `${this.dataName}.read`,
5633
+ summary: `Read a ${this.dataName} record`
5634
+ });
5108
5635
  this.router.post(`/${this.options.queryRouteSegment}/__filter`, async (req) => {
5109
5636
  await this.assertAllowed(req, "read");
5110
5637
  let { filter: filter2, select } = await parseBodyWithSchema(
@@ -5118,6 +5645,15 @@ var DataRouter = class {
5118
5645
  const decoratedResult = await decorateDataSingleResult(svc, result);
5119
5646
  return decoratedResult.data;
5120
5647
  });
5648
+ this.registerOpenApiRoute({
5649
+ method: "post",
5650
+ path: `/${this.options.queryRouteSegment}/__filter`,
5651
+ operationId: `${this.dataName}.readByFilter`,
5652
+ summary: `Read a ${this.dataName} record by filter`,
5653
+ body: defineOpenApiSchemaResolver(
5654
+ () => this.getRequestSchema("requestSchemas.advancedReadFilter") ?? dataReadFilterBodySchema
5655
+ )
5656
+ });
5121
5657
  this.router.post(`/${this.options.queryRouteSegment}/:${this.options.idParam}`, async (req) => {
5122
5658
  await this.assertAllowed(req, "read");
5123
5659
  const id = parsePathParam(req.params[this.options.idParam], this.options.idParam);
@@ -5132,13 +5668,22 @@ var DataRouter = class {
5132
5668
  const decoratedResult = await decorateDataSingleResult(svc, result);
5133
5669
  return decoratedResult.data;
5134
5670
  });
5671
+ this.registerOpenApiRoute({
5672
+ method: "post",
5673
+ path: `/${this.options.queryRouteSegment}/:${this.options.idParam}`,
5674
+ operationId: `${this.dataName}.readAdvanced`,
5675
+ summary: `Advanced read a ${this.dataName} record`,
5676
+ body: defineOpenApiSchemaResolver(
5677
+ () => this.getRequestSchema("requestSchemas.advancedRead") ?? dataReadByIdBodySchema
5678
+ )
5679
+ });
5135
5680
  }
5136
5681
  set(keyOrOptions, value) {
5137
5682
  if (arguments.length === 2 && isString11(keyOrOptions)) {
5138
5683
  assertMutableRouterOption("data", keyOrOptions);
5139
5684
  this.runtime.setDataOption(this.dataName, keyOrOptions, value);
5140
5685
  }
5141
- if (arguments.length === 1 && isPlainObject10(keyOrOptions)) {
5686
+ if (arguments.length === 1 && isPlainObject13(keyOrOptions)) {
5142
5687
  assertMutableRouterOptions("data", keyOrOptions);
5143
5688
  this.runtime.setDataOptions(this.dataName, keyOrOptions);
5144
5689
  }
@@ -5161,6 +5706,62 @@ var DataRouter = class {
5161
5706
 
5162
5707
  // src/routers/index.ts
5163
5708
  import JsonRouter8 from "@web-ts-toolkit/express-json-router";
5709
+
5710
+ // src/openapi/router.ts
5711
+ import express from "express";
5712
+ import { posix } from "path";
5713
+ var escapeHtml = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5714
+ var renderDocsHtml = (specPath, title, cssUrl, bundleUrl) => `<!doctype html>
5715
+ <html lang="en">
5716
+ <head>
5717
+ <meta charset="utf-8" />
5718
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
5719
+ <title>${escapeHtml(title)}</title>
5720
+ <link rel="stylesheet" href="${escapeHtml(cssUrl)}" />
5721
+ </head>
5722
+ <body>
5723
+ <div id="swagger-ui"></div>
5724
+ <script src="${escapeHtml(bundleUrl)}"></script>
5725
+ <script>
5726
+ window.ui = SwaggerUIBundle({
5727
+ url: ${JSON.stringify(specPath)},
5728
+ dom_id: '#swagger-ui',
5729
+ deepLinking: true,
5730
+ presets: [SwaggerUIBundle.presets.apis],
5731
+ layout: 'BaseLayout',
5732
+ });
5733
+ </script>
5734
+ </body>
5735
+ </html>`;
5736
+ var getRelativeSpecPath = (docsPath, jsonPath) => {
5737
+ const docsDir = posix.dirname(docsPath.startsWith("/") ? docsPath : `/${docsPath}`);
5738
+ const normalizedJsonPath = jsonPath.startsWith("/") ? jsonPath : `/${jsonPath}`;
5739
+ return posix.relative(docsDir, normalizedJsonPath) || posix.basename(normalizedJsonPath);
5740
+ };
5741
+ function createOpenApiRouter(runtime, options = {}) {
5742
+ const router = express.Router();
5743
+ const jsonPath = options.jsonPath ?? "/openapi.json";
5744
+ const docsPath = options.docsPath ?? "/docs";
5745
+ const swaggerUiCssUrl = options.swaggerUiCssUrl ?? "https://unpkg.com/swagger-ui-dist@5/swagger-ui.css";
5746
+ const swaggerUiBundleUrl = options.swaggerUiBundleUrl ?? "https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js";
5747
+ const info = {
5748
+ title: options.title ?? "Access Router API",
5749
+ version: options.version ?? "0.0.0",
5750
+ description: options.description,
5751
+ servers: options.servers
5752
+ };
5753
+ router.get(jsonPath, (_req, res) => {
5754
+ res.json(runtime.getOpenApiSpec(info));
5755
+ });
5756
+ if (docsPath !== false) {
5757
+ router.get(docsPath, (_req, res) => {
5758
+ res.type("html").send(renderDocsHtml(getRelativeSpecPath(docsPath, jsonPath), info.title, swaggerUiCssUrl, swaggerUiBundleUrl));
5759
+ });
5760
+ }
5761
+ return router;
5762
+ }
5763
+
5764
+ // src/routers/index.ts
5164
5765
  var hasRoutes = (input) => {
5165
5766
  return typeof input === "object" && input !== null && "routes" in input;
5166
5767
  };
@@ -5168,7 +5769,7 @@ var resolveRoutes = (input) => {
5168
5769
  return hasRoutes(input) ? input.routes : input;
5169
5770
  };
5170
5771
  function combineRoutes(...inputs) {
5171
- const router = express.Router();
5772
+ const router = express2.Router();
5172
5773
  inputs.forEach((input) => {
5173
5774
  router.use(resolveRoutes(input));
5174
5775
  });
@@ -5180,7 +5781,7 @@ var accessRouterResponseHandler = JsonRouter8.createHandler({
5180
5781
  });
5181
5782
  accessRouterResponseHandler.errorMessageProvider = function(error) {
5182
5783
  const errorLike = error;
5183
- console.error(error);
5784
+ logger.error(error);
5184
5785
  return errorLike.message || errorLike._message || String(error);
5185
5786
  };
5186
5787
 
@@ -5207,12 +5808,15 @@ function createRuntimeApi(runtime) {
5207
5808
  wtt2.createDataRouter = function(dataName, options) {
5208
5809
  return new DataRouter(dataName, options, runtime);
5209
5810
  };
5811
+ wtt2.createOpenApiRouter = function(options) {
5812
+ return createOpenApiRouter(runtime, options);
5813
+ };
5210
5814
  wtt2.combineRoutes = combineRoutes;
5211
5815
  wtt2.set = function(keyOrOptions, value) {
5212
5816
  if (arguments.length === 2 && isString12(keyOrOptions)) {
5213
5817
  return runtime.setGlobalOption(keyOrOptions, value);
5214
5818
  }
5215
- if (arguments.length === 1 && isPlainObject11(keyOrOptions)) {
5819
+ if (arguments.length === 1 && isPlainObject14(keyOrOptions)) {
5216
5820
  return runtime.setGlobalOptions(keyOrOptions);
5217
5821
  }
5218
5822
  };
@@ -5249,6 +5853,7 @@ export {
5249
5853
  acl,
5250
5854
  combineRoutes,
5251
5855
  createAccessRuntime,
5856
+ createOpenApiRouter,
5252
5857
  index_default as default,
5253
5858
  defineRequestSchema,
5254
5859
  fromAjv,