@web-ts-toolkit/access-router 0.51.0 → 0.52.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/advanced.mjs CHANGED
@@ -41,10 +41,86 @@ var FilterOperator = /* @__PURE__ */ ((FilterOperator2) => {
41
41
  })(FilterOperator || {});
42
42
 
43
43
  // src/validation/parsers.ts
44
- import JsonRouter from "@web-ts-toolkit/express-json-router";
44
+ import JsonRouter2 from "@web-ts-toolkit/express-json-router";
45
45
 
46
46
  // src/runtime.ts
47
47
  import mongoose from "mongoose";
48
+
49
+ // src/validation/public-admission.ts
50
+ import JsonRouter from "@web-ts-toolkit/express-json-router";
51
+ import { isPlainObject } from "@web-ts-toolkit/utils";
52
+ var privateControls = [
53
+ "authorization",
54
+ "overrides",
55
+ "documentAuthorization",
56
+ "documentAuthorizationStage",
57
+ "execution",
58
+ "executionContext",
59
+ "serviceExecutionContext",
60
+ "resolvedAuthorization",
61
+ "preparedQuery",
62
+ "preparedFilter",
63
+ "preparedModelQuery",
64
+ "resolvedIdentifier",
65
+ "skipParsing",
66
+ "skipAuthorization",
67
+ "alreadyAuthorized",
68
+ "operation"
69
+ ];
70
+ var PublicAdmissionError = class extends JsonRouter.clientErrors.BadRequestError {
71
+ constructor(detail) {
72
+ const errors = [{ detail }];
73
+ super("Bad Request", { errors });
74
+ this.result = { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors };
75
+ }
76
+ };
77
+ function assertPublicAdmission(input, kind = "envelope") {
78
+ const pending = [{ value: input, kind, path: "request" }];
79
+ const seen = /* @__PURE__ */ new WeakMap();
80
+ while (pending.length) {
81
+ const { value, kind: slot, path } = pending.pop();
82
+ if (!value || typeof value !== "object" && typeof value !== "function") continue;
83
+ const kinds = seen.get(value) ?? /* @__PURE__ */ new Set();
84
+ if (kinds.has(slot)) continue;
85
+ kinds.add(slot);
86
+ seen.set(value, kinds);
87
+ const add = (child, childKind, key) => {
88
+ pending.push({ value: child, kind: childKind, path: `${path}.${key}` });
89
+ };
90
+ const record = value;
91
+ if (slot !== "data") {
92
+ for (const key of privateControls) {
93
+ if (key in record) {
94
+ throw new PublicAdmissionError(
95
+ `Unsupported public control ${path}.${key}; use explicit per-call internal service options for backend authorization`
96
+ );
97
+ }
98
+ }
99
+ }
100
+ if (Array.isArray(value)) {
101
+ value.forEach((child, index) => add(child, slot, String(index)));
102
+ continue;
103
+ }
104
+ if (slot === "data") {
105
+ if (!isPlainObject(value)) continue;
106
+ for (const [key, child] of Object.entries(value)) add(child, key === "$$sq" ? "envelope" : "data", key);
107
+ continue;
108
+ }
109
+ for (const key of ["args", "options", "sqOptions"]) add(record[key], "envelope", key);
110
+ add(record.include, "include", "include");
111
+ add(record.populate, "populate", "populate");
112
+ for (const key of ["filter", "match", "data"]) add(record[key], "data", key);
113
+ }
114
+ }
115
+ function assertPublicDefaults(defaults) {
116
+ assertPublicAdmission(defaults);
117
+ if (defaults && typeof defaults === "object") {
118
+ for (const value of Object.values(defaults)) assertPublicAdmission(value);
119
+ }
120
+ }
121
+ var requestAuthorization = Object.freeze({ outputFields: Object.freeze({ mode: "request" }) });
122
+
123
+ // src/runtime.ts
48
124
  import mschema2Jsonschema from "mongoose-schema-jsonschema";
49
125
  import {
50
126
  addLeadingSlash,
@@ -54,15 +130,15 @@ import {
54
130
  isBoolean,
55
131
  isFunction,
56
132
  isNil as isNil2,
57
- isPlainObject as isPlainObject9,
133
+ isPlainObject as isPlainObject10,
58
134
  isString as isString3,
59
135
  keys,
60
136
  normalizeUrlPath,
61
- set as set2
137
+ set as set3
62
138
  } from "@web-ts-toolkit/utils";
63
139
 
64
140
  // src/helpers/query.ts
65
- import { flattenDeep, isNil, isPlainObject, isString, reduce } from "@web-ts-toolkit/utils";
141
+ import { flattenDeep, isNil, isPlainObject as isPlainObject2, isString, reduce } from "@web-ts-toolkit/utils";
66
142
  var DEFAULT_LIST_HARD_LIMIT = 1e3;
67
143
 
68
144
  // src/helpers/sort-policy.ts
@@ -72,14 +148,14 @@ function isValidFieldPath(field) {
72
148
  }
73
149
 
74
150
  // src/helpers/index.ts
75
- import { forEach, isArray, isEmpty, isObject, isPlainObject as isPlainObject3, isString as isString2 } from "@web-ts-toolkit/utils";
151
+ import { forEach, isArray, isEmpty, isObject, isPlainObject as isPlainObject4, isString as isString2 } from "@web-ts-toolkit/utils";
76
152
 
77
153
  // src/lib.ts
78
154
  import { Document, Schema } from "mongoose";
79
- import { isPlainObject as isPlainObject2 } from "@web-ts-toolkit/utils";
155
+ import { isPlainObject as isPlainObject3 } from "@web-ts-toolkit/utils";
80
156
  var isSchema = (val) => val instanceof Schema;
81
157
  var isObjectIdType = (val) => val === "ObjectId" || val === Schema.Types.ObjectId;
82
- var isReference = (val) => isPlainObject2(val) && !!val.ref && isObjectIdType(val.type);
158
+ var isReference = (val) => isPlainObject3(val) && !!val.ref && isObjectIdType(val.type);
83
159
 
84
160
  // src/helpers/index.ts
85
161
  function recurseObject(obj) {
@@ -109,7 +185,7 @@ function buildRefs(schema) {
109
185
  }
110
186
  const target = isObject(val) && "type" in val ? val.type ?? val : val;
111
187
  if (isArray(target) && target.length > 0) {
112
- if (isSchema(target[0]) || isPlainObject3(target[0])) {
188
+ if (isSchema(target[0]) || isPlainObject4(target[0])) {
113
189
  return;
114
190
  }
115
191
  }
@@ -122,7 +198,7 @@ function buildSubPaths(schema) {
122
198
  forEach(schema, (val, key) => {
123
199
  const target = isObject(val) && "type" in val ? val.type ?? val : val;
124
200
  if (isArray(target) && target.length > 0) {
125
- if (isSchema(target[0]) || isPlainObject3(target[0]) && !isReference(target[0])) {
201
+ if (isSchema(target[0]) || isPlainObject4(target[0]) && !isReference(target[0])) {
126
202
  subPaths.push(key);
127
203
  }
128
204
  }
@@ -131,7 +207,7 @@ function buildSubPaths(schema) {
131
207
  }
132
208
 
133
209
  // src/openapi/build-spec.ts
134
- import { isArray as isArray2, isPlainObject as isPlainObject5 } from "@web-ts-toolkit/utils";
210
+ import { isArray as isArray2, isPlainObject as isPlainObject6 } from "@web-ts-toolkit/utils";
135
211
 
136
212
  // src/openapi/responses.ts
137
213
  var json = (schema) => ({
@@ -202,19 +278,19 @@ var openApiResponses = {
202
278
 
203
279
  // src/openapi/schemas.ts
204
280
  import { z } from "zod";
205
- import { isPlainObject as isPlainObject4 } from "@web-ts-toolkit/utils";
281
+ import { isPlainObject as isPlainObject5 } from "@web-ts-toolkit/utils";
206
282
  var fallbackObjectSchema = { type: "object", additionalProperties: true };
207
283
  function isOpenApiSchemaPatch(source) {
208
- return isPlainObject4(source) && source.kind === "objectProperties";
284
+ return isPlainObject5(source) && source.kind === "objectProperties";
209
285
  }
210
286
  function isOpenApiSchemaResolver(source) {
211
- return isPlainObject4(source) && source.kind === "schemaResolver" && typeof source.resolve === "function";
287
+ return isPlainObject5(source) && source.kind === "schemaResolver" && typeof source.resolve === "function";
212
288
  }
213
289
  function isJsonSchemaLike(source) {
214
- return isPlainObject4(source) && ("type" in source || "properties" in source || "$ref" in source || "anyOf" in source);
290
+ return isPlainObject5(source) && ("type" in source || "properties" in source || "$ref" in source || "anyOf" in source);
215
291
  }
216
292
  function hasOpenApiSchema(source) {
217
- return isPlainObject4(source) && isJsonSchemaLike(source.openapi);
293
+ return isPlainObject5(source) && isJsonSchemaLike(source.openapi);
218
294
  }
219
295
  function toOpenApiSchema(source) {
220
296
  if (!source) return void 0;
@@ -222,7 +298,7 @@ function toOpenApiSchema(source) {
222
298
  if (!resolvedSource) return void 0;
223
299
  if (isOpenApiSchemaPatch(resolvedSource)) {
224
300
  const schema = toOpenApiSchema(resolvedSource.source) ?? { ...fallbackObjectSchema };
225
- const properties = isPlainObject4(schema.properties) ? { ...schema.properties } : {};
301
+ const properties = isPlainObject5(schema.properties) ? { ...schema.properties } : {};
226
302
  for (const [key, value] of Object.entries(resolvedSource.properties)) {
227
303
  properties[key] = toOpenApiSchema(value) ?? fallbackObjectSchema;
228
304
  }
@@ -255,7 +331,7 @@ var toOpenApiPath = (path) => normalizePath(path).replace(/:([A-Za-z0-9_]+)/g, "
255
331
  var schemaToQueryParameters = (schema) => {
256
332
  const jsonSchema = toOpenApiSchema(schema);
257
333
  if (!jsonSchema || jsonSchema.type !== "object") return [];
258
- const properties = isPlainObject5(jsonSchema.properties) ? jsonSchema.properties : {};
334
+ const properties = isPlainObject6(jsonSchema.properties) ? jsonSchema.properties : {};
259
335
  const required = new Set(
260
336
  isArray2(jsonSchema.required) ? jsonSchema.required.filter((item) => typeof item === "string") : []
261
337
  );
@@ -348,7 +424,7 @@ var OpenApiCollisionError = class extends Error {
348
424
  };
349
425
 
350
426
  // src/openapi/registry.ts
351
- var isPlainObject6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
427
+ var isPlainObject7 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
352
428
  var stableKey = (value) => {
353
429
  if (value === null || typeof value === "undefined") return "null";
354
430
  if (typeof value === "function") return "[Function]";
@@ -383,7 +459,7 @@ var OpenApiRegistry = class {
383
459
  this.routes[existingIndex] = route;
384
460
  return;
385
461
  }
386
- if (descriptorsEqual(existing, route) && (route.idempotent || isPlainObject6(existing) && existing.idempotent)) {
462
+ if (descriptorsEqual(existing, route) && (route.idempotent || isPlainObject7(existing) && existing.idempotent)) {
387
463
  return;
388
464
  }
389
465
  if (this.options.rejectConflicts) {
@@ -472,7 +548,7 @@ var defaultLogger = createLogger({
472
548
  });
473
549
 
474
550
  // src/options/manager.ts
475
- import { assign, get, isPlainObject as isPlainObject7, set } from "@web-ts-toolkit/utils";
551
+ import { assign, get, isPlainObject as isPlainObject8, set } from "@web-ts-toolkit/utils";
476
552
  var toPath = (key) => {
477
553
  if (Array.isArray(key)) return key;
478
554
  return typeof key === "string" ? key.split(".") : [key];
@@ -533,19 +609,20 @@ var freezeConfigValue = (value) => {
533
609
  return value;
534
610
  };
535
611
  var cloneAndFreezeForStore = (value) => freezeConfigValue(cloneForRead(value));
536
- var getNestedOption = (manager, key, defaultValue) => {
537
- const keys2 = String(key).split(".");
612
+ var getNestedOption = (manager, key, defaultValue) => resolveNestedOption((path, fallback) => manager.get(path, fallback), String(key), defaultValue);
613
+ var resolveNestedOption = (read, key, defaultValue) => {
614
+ const keys2 = key.split(".");
538
615
  if (keys2.length === 1) {
539
- return manager.get(key, defaultValue);
616
+ return read(key, defaultValue);
540
617
  }
541
- let option = manager.get(key, void 0);
618
+ let option = read(key);
542
619
  if (option !== void 0) {
543
620
  return option;
544
621
  }
545
622
  const parentKey = keys2.slice(0, -1).join(".");
546
- option = manager.get(`${parentKey}.default`, void 0);
623
+ option = read(`${parentKey}.default`);
547
624
  if (option === void 0) {
548
- option = manager.get(parentKey, defaultValue);
625
+ option = read(parentKey, defaultValue);
549
626
  }
550
627
  return option;
551
628
  };
@@ -588,7 +665,7 @@ var OptionsManager = class {
588
665
  }
589
666
  const [rootKey, ...nestedPath] = path;
590
667
  const currentRoot = get(this.currentOptions, [rootKey], void 0);
591
- const baseRoot = isPlainObject7(currentRoot) ? currentRoot : {};
668
+ const baseRoot = isPlainObject8(currentRoot) ? currentRoot : {};
592
669
  const nextRoot = cloneConfigValue(baseRoot);
593
670
  set(nextRoot, nestedPath, cloneForRead(value));
594
671
  set(this.currentOptions, [rootKey], freezeConfigValue(nextRoot));
@@ -642,8 +719,226 @@ var OptionsManager = class {
642
719
  }
643
720
  };
644
721
 
722
+ // src/options/data-manager.ts
723
+ import { set as set2 } from "@web-ts-toolkit/utils";
724
+
725
+ // src/options/data-values.ts
726
+ import { types } from "util";
727
+ var typedArrays = [
728
+ Int8Array,
729
+ Uint8Array,
730
+ Uint8ClampedArray,
731
+ Int16Array,
732
+ Uint16Array,
733
+ Int32Array,
734
+ Uint32Array,
735
+ Float32Array,
736
+ Float64Array,
737
+ BigInt64Array,
738
+ BigUint64Array
739
+ ];
740
+ var unsupported = (path, reason) => {
741
+ throw new TypeError(`Unsupported data value at ${path}: ${reason}`);
742
+ };
743
+ var isPlainContainer = (value) => {
744
+ const prototype = Object.getPrototypeOf(value);
745
+ return prototype === Object.prototype || prototype === null || prototype === Array.prototype;
746
+ };
747
+ var defineValue = (target, key, value) => {
748
+ Object.defineProperty(target, key, { value, enumerable: true, configurable: true, writable: true });
749
+ };
750
+ var assertNativeProperties = (value, path, allowed = () => false) => {
751
+ for (const key of Reflect.ownKeys(value)) {
752
+ if (typeof key !== "string" || !allowed(key)) unsupported(path, "custom native properties are not supported");
753
+ }
754
+ };
755
+ var copyBytes = (buffer, path, start = 0, end) => {
756
+ if (!types.isArrayBuffer(buffer) || Object.getPrototypeOf(buffer) !== ArrayBuffer.prototype) {
757
+ return unsupported(path, "binary storage must be a fixed, non-shared ArrayBuffer");
758
+ }
759
+ assertNativeProperties(buffer, path);
760
+ if (buffer.resizable) {
761
+ return unsupported(path, "resizable binary storage is not supported");
762
+ }
763
+ try {
764
+ return ArrayBuffer.prototype.slice.call(buffer, start, end);
765
+ } catch {
766
+ return unsupported(path, "detached binary storage is not supported");
767
+ }
768
+ };
769
+ function copyValue(input, freezePlain, rootPath) {
770
+ const copies = /* @__PURE__ */ new WeakMap();
771
+ const active = /* @__PURE__ */ new WeakSet();
772
+ const visit = (value, path) => {
773
+ if (typeof value === "function" || typeof value === "symbol") {
774
+ return unsupported(path, `${typeof value} values are not supported`);
775
+ }
776
+ if (value === null || typeof value !== "object") return value;
777
+ if (types.isProxy(value)) return unsupported(path, "proxies are not supported");
778
+ if (active.has(value)) return unsupported(path, "cycles are not supported");
779
+ const previous = copies.get(value);
780
+ if (previous) return previous;
781
+ active.add(value);
782
+ try {
783
+ const prototype = Object.getPrototypeOf(value);
784
+ if (isPlainContainer(value)) {
785
+ const array = Array.isArray(value);
786
+ if (array && prototype !== Array.prototype) return unsupported(path, "unsupported array prototype");
787
+ if (prototype === Array.prototype && !array) return unsupported(path, "unsupported object prototype");
788
+ if (Object.getOwnPropertySymbols(value).length) return unsupported(path, "symbol keys are not supported");
789
+ const output2 = array ? new Array(value.length) : Object.create(prototype);
790
+ copies.set(value, output2);
791
+ for (const key of Object.keys(value)) {
792
+ const childPath = array ? `${path}[${key}]` : `${path}.${key}`;
793
+ defineValue(output2, key, visit(value[key], childPath));
794
+ }
795
+ return freezePlain ? Object.freeze(output2) : output2;
796
+ }
797
+ let output;
798
+ if (prototype === Date.prototype && types.isDate(value)) {
799
+ assertNativeProperties(value, path);
800
+ output = new Date(Date.prototype.getTime.call(value));
801
+ } else if (prototype === Map.prototype && types.isMap(value)) {
802
+ assertNativeProperties(value, path);
803
+ const map = /* @__PURE__ */ new Map();
804
+ copies.set(value, map);
805
+ let index = 0;
806
+ for (const [key, entry] of Map.prototype.entries.call(value)) {
807
+ map.set(visit(key, `${path}.<key:${index}>`), visit(entry, `${path}.<value:${index}>`));
808
+ index += 1;
809
+ }
810
+ output = map;
811
+ } else if (prototype === Set.prototype && types.isSet(value)) {
812
+ assertNativeProperties(value, path);
813
+ const set4 = /* @__PURE__ */ new Set();
814
+ copies.set(value, set4);
815
+ let index = 0;
816
+ for (const entry of Set.prototype.values.call(value)) {
817
+ set4.add(visit(entry, `${path}.<entry:${index}>`));
818
+ index += 1;
819
+ }
820
+ output = set4;
821
+ } else if (prototype === RegExp.prototype && types.isRegExp(value)) {
822
+ assertNativeProperties(value, path, (key) => key === "lastIndex");
823
+ const regexp = value;
824
+ if (typeof regexp.lastIndex !== "number") return unsupported(path, "RegExp.lastIndex must be a number");
825
+ const copy = new RegExp(regexp.source, regexp.flags);
826
+ copy.lastIndex = regexp.lastIndex;
827
+ output = copy;
828
+ } else if (prototype === ArrayBuffer.prototype) {
829
+ output = copyBytes(value, path);
830
+ } else if (ArrayBuffer.isView(value)) {
831
+ const Type = typedArrays.find((candidate) => candidate.prototype === prototype);
832
+ const buffer = prototype === Buffer.prototype && Buffer.isBuffer(value);
833
+ const dataView = prototype === DataView.prototype;
834
+ if (!Type && !buffer && !dataView) return unsupported(path, "unsupported binary view prototype");
835
+ assertNativeProperties(
836
+ value,
837
+ path,
838
+ (key) => !dataView && /^(0|[1-9]\d*)$/.test(key) && Number(key) < value.length
839
+ );
840
+ let bytes;
841
+ try {
842
+ bytes = copyBytes(value.buffer, path, value.byteOffset, value.byteOffset + value.byteLength);
843
+ } catch (error) {
844
+ if (error instanceof TypeError && error.message.startsWith("Unsupported data value at ")) throw error;
845
+ return unsupported(path, "detached binary storage is not supported");
846
+ }
847
+ output = buffer ? Buffer.from(bytes) : dataView ? new DataView(bytes) : new Type(bytes);
848
+ } else {
849
+ return unsupported(path, "unsupported object prototype");
850
+ }
851
+ copies.set(value, output);
852
+ return output;
853
+ } finally {
854
+ active.delete(value);
855
+ }
856
+ };
857
+ return visit(input, rootPath);
858
+ }
859
+ var copyDataValue = (value) => copyValue(value, false, "data");
860
+ function exposeSnapshot(root) {
861
+ const views = /* @__PURE__ */ new WeakMap();
862
+ const visit = (value) => {
863
+ const previous = views.get(value);
864
+ if (previous) return previous;
865
+ let exposed;
866
+ const keys2 = Object.keys(value);
867
+ const mutableView = () => {
868
+ if (!exposed) {
869
+ exposed = Array.isArray(value) ? new Array(value.length) : Object.create(Object.getPrototypeOf(value));
870
+ for (const key of keys2) defineValue(exposed, key, value[key]);
871
+ }
872
+ return exposed;
873
+ };
874
+ for (const key of keys2) {
875
+ const child = value[key];
876
+ if (child === null || typeof child !== "object") continue;
877
+ if (isPlainContainer(child)) {
878
+ const view2 = visit(child);
879
+ if (view2 !== child) defineValue(mutableView(), key, view2);
880
+ } else {
881
+ Object.defineProperty(mutableView(), key, {
882
+ enumerable: true,
883
+ configurable: true,
884
+ get: () => copyDataValue(child)
885
+ });
886
+ }
887
+ }
888
+ const view = exposed ? Object.freeze(exposed) : value;
889
+ views.set(value, view);
890
+ return view;
891
+ };
892
+ return visit(root);
893
+ }
894
+ var emptyDataSnapshot = Object.freeze([]);
895
+ var ownedSnapshots = new WeakMap([[emptyDataSnapshot, emptyDataSnapshot]]);
896
+ function createDataSnapshot(data) {
897
+ if (data === void 0) return void 0;
898
+ if (!Array.isArray(data) || types.isProxy(data) || Object.getPrototypeOf(data) !== Array.prototype) {
899
+ return unsupported("data", "expected an ordinary array or undefined");
900
+ }
901
+ if (ownedSnapshots.has(data)) return data;
902
+ const owned = copyValue(data, true, "data");
903
+ const exposed = exposeSnapshot(owned);
904
+ ownedSnapshots.set(exposed, owned);
905
+ return exposed;
906
+ }
907
+ function getOwnedDataSnapshot(snapshot = emptyDataSnapshot) {
908
+ const owned = ownedSnapshots.get(snapshot);
909
+ if (!owned) throw new TypeError("DataService requires an admitted data snapshot");
910
+ return owned;
911
+ }
912
+
913
+ // src/options/data-manager.ts
914
+ var admitData = (options) => {
915
+ if (!Object.hasOwn(options, "data")) return options;
916
+ const { data, ...otherOptions } = options;
917
+ return { ...otherOptions, data: createDataSnapshot(data) };
918
+ };
919
+ var DataOptionsManager = class extends OptionsManager {
920
+ assign(options) {
921
+ super.assign(admitData(options));
922
+ }
923
+ set(key, value) {
924
+ const path = String(key);
925
+ if (path === "data") {
926
+ super.set("data", createDataSnapshot(value));
927
+ } else if (path.startsWith("data.")) {
928
+ const next = copyDataValue(getOwnedDataSnapshot(super.get("data")));
929
+ set2(next, path.slice("data.".length), value);
930
+ super.set("data", createDataSnapshot(next));
931
+ } else {
932
+ super.set(key, value);
933
+ }
934
+ }
935
+ restore(snapshot) {
936
+ super.restore(admitData(snapshot));
937
+ }
938
+ };
939
+
645
940
  // src/request-complexity.ts
646
- import { isArray as isArray3, isPlainObject as isPlainObject8 } from "@web-ts-toolkit/utils";
941
+ import { isArray as isArray3, isPlainObject as isPlainObject9 } from "@web-ts-toolkit/utils";
647
942
  var defaultRequestComplexity = {
648
943
  maxDepth: 8,
649
944
  maxNodes: 500,
@@ -729,7 +1024,7 @@ function validateRequestComplexity(value, options, scope = "request") {
729
1024
  }
730
1025
  return;
731
1026
  }
732
- if (!isPlainObject8(current)) return;
1027
+ if (!isPlainObject9(current)) return;
733
1028
  for (const [key, child] of Object.entries(current)) {
734
1029
  if (key === "__proto__" || key === "prototype" || key === "constructor") {
735
1030
  pushError(`Unsupported key: ${key}`, path.concat(key));
@@ -808,7 +1103,7 @@ var classifyPermissionSchema = (permissionSchema, modelPermissionPrefix) => {
808
1103
  const modelPermissionKeys = {};
809
1104
  forEach2(schemaKeys, (schemaKey) => {
810
1105
  const schemaRule = permissionSchema[schemaKey];
811
- const ruleEntries = isPlainObject9(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
1106
+ const ruleEntries = isPlainObject10(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
812
1107
  for (let x = 0; x < ruleEntries.length; x++) {
813
1108
  const [accessKey, value] = ruleEntries[x];
814
1109
  if (!isArray4(globalPermissionKeys[accessKey])) {
@@ -849,13 +1144,13 @@ var VIRTUAL_UNSUPPORTED_ACCESSES = ["delete", "distinct", "count"];
849
1144
  var VIRTUAL_RESERVED_NAMES = /* @__PURE__ */ new Set(["_id", "__v", "id"]);
850
1145
  var VIRTUAL_DANGEROUS_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
851
1146
  var VIRTUAL_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
852
- var isVirtualContainerValue = (value) => isPlainObject9(value) && "sub" in value;
1147
+ var isVirtualContainerValue = (value) => isPlainObject10(value) && "sub" in value;
853
1148
  var virtualFullPath = (prefix, name) => prefix ? `${prefix}.${name}` : name;
854
1149
  var virtualPathsOverlap = (virtualPath, permissionField) => {
855
1150
  if (!virtualPath || !permissionField) return false;
856
1151
  try {
857
- if (get2(set2({}, virtualPath, true), permissionField) !== void 0) return true;
858
- if (get2(set2({}, permissionField, true), virtualPath) !== void 0) return true;
1152
+ if (get2(set3({}, virtualPath, true), permissionField) !== void 0) return true;
1153
+ if (get2(set3({}, permissionField, true), virtualPath) !== void 0) return true;
859
1154
  } catch {
860
1155
  return false;
861
1156
  }
@@ -944,7 +1239,7 @@ var validateVirtualDependsOn = (dependsOn, entryLabel, storedFields, siblingVirt
944
1239
  };
945
1240
  var validateVirtualLeafValue = (value, entryLabel, storedFields, siblingVirtualNames, sharedDependsOn) => {
946
1241
  if (isFunction(value)) return;
947
- if (!isPlainObject9(value)) {
1242
+ if (!isPlainObject10(value)) {
948
1243
  throw new Error(`Virtual ${entryLabel}: descriptor must be a getter function or { get, dependsOn }`);
949
1244
  }
950
1245
  const record = value;
@@ -988,7 +1283,7 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
988
1283
  `Virtual ${scopeLabel}${name}: scope-container must only hold "sub" (embedded container "${name}" is not a virtual-leaf collision)`
989
1284
  );
990
1285
  }
991
- if (!isPlainObject9(record2.sub)) {
1286
+ if (!isPlainObject10(record2.sub)) {
992
1287
  throw new Error(`Virtual ${scopeLabel}${name}: scope-container "sub" must be a plain object`);
993
1288
  }
994
1289
  continue;
@@ -999,7 +1294,7 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
999
1294
  );
1000
1295
  }
1001
1296
  if (isFunction(raw)) continue;
1002
- if (!isPlainObject9(raw)) {
1297
+ if (!isPlainObject10(raw)) {
1003
1298
  throw new Error(
1004
1299
  `Virtual ${scopeLabel}${name}: malformed descriptor (expected getter, { get, dependsOn }, or per-access record)`
1005
1300
  );
@@ -1007,7 +1302,7 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1007
1302
  const record = raw;
1008
1303
  const hasGet = "get" in record;
1009
1304
  const accessKeys = Object.keys(record).filter((k) => VIRTUAL_SUPPORTED_ACCESSES.includes(k));
1010
- const unsupported = Object.keys(record).filter(
1305
+ const unsupported2 = Object.keys(record).filter(
1011
1306
  (k) => k !== "get" && k !== "dependsOn" && k !== "sub" && !VIRTUAL_SUPPORTED_ACCESSES.includes(k)
1012
1307
  );
1013
1308
  for (const key of Object.keys(record)) {
@@ -1017,9 +1312,9 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1017
1312
  );
1018
1313
  }
1019
1314
  }
1020
- if (unsupported.length > 0) {
1315
+ if (unsupported2.length > 0) {
1021
1316
  throw new Error(
1022
- `Virtual ${scopeLabel}${name}: unsupported access/key "${unsupported[0]}" (supported: default + list/create/read/update)`
1317
+ `Virtual ${scopeLabel}${name}: unsupported access/key "${unsupported2[0]}" (supported: default + list/create/read/update)`
1023
1318
  );
1024
1319
  }
1025
1320
  if (hasGet) {
@@ -1053,7 +1348,7 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1053
1348
  };
1054
1349
  var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName) => {
1055
1350
  if (virtuals === void 0 || virtuals === null) return;
1056
- if (!isPlainObject9(virtuals)) {
1351
+ if (!isPlainObject10(virtuals)) {
1057
1352
  throw new Error(`Virtuals for model "${modelName}": virtuals must be a plain object mapping names to descriptors`);
1058
1353
  }
1059
1354
  const rootSchema = model?.schema ?? null;
@@ -1100,25 +1395,25 @@ var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName)
1100
1395
  visitContainers(rootVirtuals, rootSchema, "");
1101
1396
  };
1102
1397
  var getScopeVirtualsObject = (rootVirtuals, scopePath) => {
1103
- if (!rootVirtuals || !isPlainObject9(rootVirtuals)) return null;
1398
+ if (!rootVirtuals || !isPlainObject10(rootVirtuals)) return null;
1104
1399
  if (!scopePath || scopePath.length === 0) return rootVirtuals;
1105
1400
  let current = rootVirtuals;
1106
1401
  for (let i = 0; i < scopePath.length; i += 2) {
1107
1402
  const field = scopePath[i];
1108
1403
  const subMarker = scopePath[i + 1];
1109
1404
  if (!field || subMarker !== "sub") return null;
1110
- if (!isPlainObject9(current)) return null;
1405
+ if (!isPlainObject10(current)) return null;
1111
1406
  const container = current[field];
1112
1407
  if (!isVirtualContainerValue(container)) return null;
1113
1408
  current = container.sub;
1114
- if (!isPlainObject9(current)) return null;
1409
+ if (!isPlainObject10(current)) return null;
1115
1410
  }
1116
1411
  return current;
1117
1412
  };
1118
1413
  var toVirtualDescriptor = (leaf, sharedDependsOn) => {
1119
1414
  if (isFunction(leaf))
1120
1415
  return { get: leaf, dependsOn: sharedDependsOn ?? [] };
1121
- if (!isPlainObject9(leaf)) return null;
1416
+ if (!isPlainObject10(leaf)) return null;
1122
1417
  const record = leaf;
1123
1418
  if (!isFunction(record.get)) return null;
1124
1419
  const dependsOn = record.dependsOn ?? sharedDependsOn ?? [];
@@ -1301,6 +1596,7 @@ var AccessRuntime = class {
1301
1596
  Object.assign(this.modelAtts, snapshot.modelAtts);
1302
1597
  this.openApiRegistry.restore(snapshot.openApi);
1303
1598
  }
1599
+ /** Shallowly replace supplied global values; nested objects such as requestComplexity are not deep-merged. */
1304
1600
  setGlobalOptions(options) {
1305
1601
  this.globalOptions.assign(options);
1306
1602
  }
@@ -1313,6 +1609,7 @@ var AccessRuntime = class {
1313
1609
  getGlobalOption(key, defaultValue) {
1314
1610
  return this.globalOptions.get(key, defaultValue);
1315
1611
  }
1612
+ /** Update model starting defaults shallowly; already-stored model values are not broadcast-replaced. */
1316
1613
  setDefaultModelOptions(options) {
1317
1614
  this.defaultModelOptions.assign(options);
1318
1615
  }
@@ -1357,7 +1654,15 @@ var AccessRuntime = class {
1357
1654
  }
1358
1655
  return manager;
1359
1656
  }
1657
+ /**
1658
+ * Assign `{ ...modelDefaults, ...storedOptions, ...options }` shallowly. A supplied
1659
+ * operationAccess/defaults object replaces that whole value. Defaults accept only
1660
+ * query/presentation settings; virtual configuration is validated before assignment.
1661
+ * Existing router.options remains its construction-time snapshot. Fresh model-service
1662
+ * calls capture the owner's current options/defaults; in-flight calls retain their snapshot.
1663
+ */
1360
1664
  setModelOptions(modelName, options) {
1665
+ assertPublicDefaults(options.defaults);
1361
1666
  const manager = this.getOrCreateModelOptions(modelName);
1362
1667
  const defaultOptions = this.getDefaultModelOptions();
1363
1668
  const currentModelOptions = manager.fetch();
@@ -1370,6 +1675,12 @@ var AccessRuntime = class {
1370
1675
  setModelOption(modelName, key, value) {
1371
1676
  const manager = this.getOrCreateModelOptions(modelName);
1372
1677
  const keyStr = String(key);
1678
+ if (keyStr === "defaults") assertPublicDefaults(value);
1679
+ else if (keyStr.startsWith("defaults.")) {
1680
+ const proposed = {};
1681
+ set3(proposed, keyStr.slice("defaults.".length), value);
1682
+ assertPublicDefaults(proposed);
1683
+ }
1373
1684
  if (keyStr === "virtuals" || keyStr.startsWith("virtuals.") || keyStr === "documentPermissionField") {
1374
1685
  const model = this.getModelInstance(modelName);
1375
1686
  const currentVirtuals = manager.get("virtuals");
@@ -1387,15 +1698,15 @@ var AccessRuntime = class {
1387
1698
  const segments = nestedPath.split(".");
1388
1699
  let cursor = cloned;
1389
1700
  for (let i = 0; i < segments.length - 1; i++) {
1390
- if (!isPlainObject9(cursor)) break;
1701
+ if (!isPlainObject10(cursor)) break;
1391
1702
  cursor = cursor[segments[i]];
1392
1703
  }
1393
- if (isPlainObject9(cursor)) {
1704
+ if (isPlainObject10(cursor)) {
1394
1705
  delete cursor[segments[segments.length - 1]];
1395
1706
  }
1396
1707
  proposedVirtuals = cloned;
1397
1708
  } else {
1398
- set2(cloned, nestedPath, value);
1709
+ set3(cloned, nestedPath, value);
1399
1710
  proposedVirtuals = cloned;
1400
1711
  }
1401
1712
  }
@@ -1403,10 +1714,17 @@ var AccessRuntime = class {
1403
1714
  }
1404
1715
  manager.set(key, value);
1405
1716
  }
1717
+ /** Frozen stored snapshot, not fully resolved per-path defaults. Read again for current configuration. */
1406
1718
  getModelOptions(modelName) {
1407
1719
  const manager = this.getOrCreateModelOptions(modelName);
1408
1720
  return manager.fetch();
1409
1721
  }
1722
+ /**
1723
+ * Generic stored exact → parent.default → parent lookup; only undefined falls through.
1724
+ * The exact runtime-model-default path is the final fallback if the stored parent is
1725
+ * absent. This is not the route-specific variant-to-base resolver; use
1726
+ * getExactModelOption to inspect a variant including its exact model-default fallback.
1727
+ */
1410
1728
  getModelOption(modelName, key, defaultValue) {
1411
1729
  const manager = this.getOrCreateModelOptions(modelName);
1412
1730
  const defaultModelValue = this.getDefaultModelOption(
@@ -1415,6 +1733,7 @@ var AccessRuntime = class {
1415
1733
  );
1416
1734
  return getNestedOption(manager, key, defaultModelValue);
1417
1735
  }
1736
+ /** Exact stored path, then the same runtime-model-default path; no parent/default or variant-to-base lookup. */
1418
1737
  getExactModelOption(modelName, key) {
1419
1738
  const manager = this.getOrCreateModelOptions(modelName);
1420
1739
  const defaultModelValue = this.getDefaultModelOption(key);
@@ -1466,7 +1785,7 @@ var AccessRuntime = class {
1466
1785
  const entry = scopeVirtuals[virtualName];
1467
1786
  if (entry === void 0 || isVirtualContainerValue(entry)) return void 0;
1468
1787
  if (isFunction(entry)) return { get: entry, dependsOn: [] };
1469
- if (!isPlainObject9(entry)) return void 0;
1788
+ if (!isPlainObject10(entry)) return void 0;
1470
1789
  const record = entry;
1471
1790
  if ("get" in record) {
1472
1791
  const descriptor = toVirtualDescriptor(entry, void 0);
@@ -1495,7 +1814,7 @@ var AccessRuntime = class {
1495
1814
  return this.modelJsonSchemas[modelName];
1496
1815
  }
1497
1816
  createDataOptions(dataName) {
1498
- const manager = new OptionsManager({
1817
+ const manager = new DataOptionsManager({
1499
1818
  ...defaultDataOptions,
1500
1819
  dataName
1501
1820
  });
@@ -1527,10 +1846,15 @@ var AccessRuntime = class {
1527
1846
  const manager = this.getOrCreateDataOptions(dataName);
1528
1847
  return manager.fetch();
1529
1848
  }
1849
+ /**
1850
+ * Reusable configured data view: plain containers are frozen; native properties
1851
+ * return detached mutable copies on access. Native identity is not stable.
1852
+ * Replacement leaves previously captured views on their original data version.
1853
+ */
1530
1854
  getDataSnapshot(dataName) {
1531
1855
  const manager = this.getOrCreateDataOptions(dataName);
1532
1856
  const snapshot = manager.get("data");
1533
- return snapshot ?? [];
1857
+ return snapshot ?? emptyDataSnapshot;
1534
1858
  }
1535
1859
  getDataOption(dataName, key, defaultValue) {
1536
1860
  const manager = this.getOrCreateDataOptions(dataName);
@@ -1590,10 +1914,29 @@ var getGlobalOption = (key, defaultValue) => {
1590
1914
 
1591
1915
  // src/validation/common.ts
1592
1916
  import { z as z2 } from "zod";
1593
- import { isPlainObject as isPlainObject11 } from "@web-ts-toolkit/utils";
1917
+ import { isPlainObject as isPlainObject12 } from "@web-ts-toolkit/utils";
1918
+
1919
+ // src/validation/public-admission-schema.ts
1920
+ var admissions = /* @__PURE__ */ new WeakMap();
1921
+ function publicBoundarySchema(schema, kind = "envelope") {
1922
+ const checked = schema.superRefine((value, ctx) => {
1923
+ try {
1924
+ assertPublicAdmission(value, kind);
1925
+ } catch (error) {
1926
+ if (!(error instanceof PublicAdmissionError)) throw error;
1927
+ ctx.addIssue({ code: "custom", message: error.result.errors[0].detail });
1928
+ }
1929
+ });
1930
+ admissions.set(checked, kind);
1931
+ return checked;
1932
+ }
1933
+ function assertTransformedPublicAdmission(schema, value) {
1934
+ const kind = admissions.get(schema);
1935
+ if (kind) assertPublicAdmission(value, kind);
1936
+ }
1594
1937
 
1595
1938
  // src/correlated-includes.ts
1596
- import { cloneDeep, isArray as isArray5, isPlainObject as isPlainObject10 } from "@web-ts-toolkit/utils";
1939
+ import { cloneDeep, isArray as isArray5, isPlainObject as isPlainObject11 } from "@web-ts-toolkit/utils";
1597
1940
  var PARENT_MARKER_KEY = "$parent";
1598
1941
  var ESCAPE_WRAPPER_KEY = "$escape";
1599
1942
  var SUBQUERY_PAYLOAD_KEYS = /* @__PURE__ */ new Set(["$$sq", "$$date"]);
@@ -1604,10 +1947,10 @@ var FIELD_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
1604
1947
  var ARRAY_INDEX_SEGMENT_PATTERN = /^(0|[1-9]\d*)$/;
1605
1948
  var ownKeys = (value) => Object.keys(value);
1606
1949
  function isParentRefMarker(value) {
1607
- return isPlainObject10(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
1950
+ return isPlainObject11(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
1608
1951
  }
1609
1952
  function isEscapedParentRef(value) {
1610
- return isPlainObject10(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
1953
+ return isPlainObject11(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
1611
1954
  }
1612
1955
  function hasMarkerKey(value) {
1613
1956
  return ownKeys(value).includes(PARENT_MARKER_KEY) || ownKeys(value).includes(ESCAPE_WRAPPER_KEY);
@@ -1631,7 +1974,7 @@ function containsParentMarkerShape(value) {
1631
1974
  seen.add(current);
1632
1975
  return current.some(visit);
1633
1976
  }
1634
- if (isPlainObject10(current)) {
1977
+ if (isPlainObject11(current)) {
1635
1978
  if (seen.has(current)) return false;
1636
1979
  seen.add(current);
1637
1980
  if (hasMarkerKey(current)) return true;
@@ -1661,7 +2004,7 @@ function scanTemplateValueNode(value, path, issues) {
1661
2004
  }
1662
2005
  return;
1663
2006
  }
1664
- if (isPlainObject10(value)) {
2007
+ if (isPlainObject11(value)) {
1665
2008
  if (hasMarkerKey(value)) {
1666
2009
  issues.push({
1667
2010
  message: 'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }',
@@ -1726,7 +2069,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
1726
2069
  });
1727
2070
  return;
1728
2071
  }
1729
- if (isPlainObject10(clause)) {
2072
+ if (isPlainObject11(clause)) {
1730
2073
  scanTemplateObjectEntries(clause, clausePath, issues);
1731
2074
  }
1732
2075
  });
@@ -1737,7 +2080,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
1737
2080
  }
1738
2081
  function validateCorrelatedFilterTemplate(filter) {
1739
2082
  const issues = [];
1740
- if (!isPlainObject10(filter)) {
2083
+ if (!isPlainObject11(filter)) {
1741
2084
  issues.push({ message: "Correlated include filter must be an object", path: [] });
1742
2085
  return issues;
1743
2086
  }
@@ -1784,42 +2127,48 @@ var sortSchema = z2.union([
1784
2127
  z2.null()
1785
2128
  ]);
1786
2129
  var populateAccessSchema = z2.enum(["list", "read"]);
1787
- var populateSchema = z2.union([
1788
- z2.string(),
1789
- z2.array(
1790
- z2.union([
1791
- z2.string(),
1792
- z2.object({
1793
- path: z2.string().min(1),
1794
- select: projectionSchema.optional(),
1795
- match: z2.unknown().optional(),
1796
- access: populateAccessSchema.optional()
1797
- }).passthrough()
1798
- ])
1799
- ),
1800
- z2.object({
1801
- path: z2.string().min(1),
1802
- select: projectionSchema.optional(),
1803
- match: z2.unknown().optional(),
1804
- access: populateAccessSchema.optional()
1805
- }).passthrough()
1806
- ]);
1807
- var subPopulateSchema = z2.union([
1808
- z2.string(),
1809
- z2.array(
1810
- z2.union([
1811
- z2.string(),
1812
- z2.object({
1813
- path: z2.string().min(1),
1814
- select: projectionSchema.optional()
1815
- }).passthrough()
1816
- ])
1817
- ),
1818
- z2.object({
1819
- path: z2.string().min(1),
1820
- select: projectionSchema.optional()
1821
- }).passthrough()
1822
- ]);
2130
+ var populateSchema = publicBoundarySchema(
2131
+ z2.union([
2132
+ z2.string(),
2133
+ z2.array(
2134
+ z2.union([
2135
+ z2.string(),
2136
+ z2.object({
2137
+ path: z2.string().min(1),
2138
+ select: projectionSchema.optional(),
2139
+ match: z2.unknown().optional(),
2140
+ access: populateAccessSchema.optional()
2141
+ }).passthrough()
2142
+ ])
2143
+ ),
2144
+ z2.object({
2145
+ path: z2.string().min(1),
2146
+ select: projectionSchema.optional(),
2147
+ match: z2.unknown().optional(),
2148
+ access: populateAccessSchema.optional()
2149
+ }).passthrough()
2150
+ ]),
2151
+ "populate"
2152
+ );
2153
+ var subPopulateSchema = publicBoundarySchema(
2154
+ z2.union([
2155
+ z2.string(),
2156
+ z2.array(
2157
+ z2.union([
2158
+ z2.string(),
2159
+ z2.object({
2160
+ path: z2.string().min(1),
2161
+ select: projectionSchema.optional()
2162
+ }).passthrough()
2163
+ ])
2164
+ ),
2165
+ z2.object({
2166
+ path: z2.string().min(1),
2167
+ select: projectionSchema.optional()
2168
+ }).passthrough()
2169
+ ]),
2170
+ "populate"
2171
+ );
1823
2172
  var legacyIncludeItemSchema = z2.object({
1824
2173
  mode: z2.enum(["legacy"]).optional(),
1825
2174
  model: z2.string().min(1),
@@ -1859,7 +2208,7 @@ var correlatedFilterSchema = z2.record(z2.string(), z2.unknown()).superRefine((f
1859
2208
  }
1860
2209
  });
1861
2210
  var correlatedEmptyOptionsSchema = z2.unknown().refine(
1862
- (value) => value === void 0 || isPlainObject11(value) && Object.keys(value).length === 0,
2211
+ (value) => value === void 0 || isPlainObject12(value) && Object.keys(value).length === 0,
1863
2212
  "Correlated include options must be absent or empty"
1864
2213
  ).optional();
1865
2214
  var correlatedPathSchema = z2.string().min(1).superRefine((path, ctx) => {
@@ -1896,7 +2245,7 @@ var correlatedListArgsSchema = z2.object({
1896
2245
  include: z2.lazy(() => correlatedNestedIncludeSchema).optional()
1897
2246
  }).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
1898
2247
  var correlatedCountArgsSchema = z2.unknown().refine(
1899
- (value) => value === void 0 || isPlainObject11(value) && Object.keys(value).length === 0,
2248
+ (value) => value === void 0 || isPlainObject12(value) && Object.keys(value).length === 0,
1900
2249
  "Count includes accept no args"
1901
2250
  ).optional();
1902
2251
  var correlatedReadByIdSchema = z2.object({
@@ -1935,18 +2284,21 @@ var correlatedCountSchema = z2.object({
1935
2284
  args: correlatedCountArgsSchema,
1936
2285
  options: correlatedEmptyOptionsSchema
1937
2286
  }).strict();
1938
- var includeItemSchema = z2.union([
1939
- legacyIncludeItemSchema,
1940
- correlatedReadByIdSchema,
1941
- correlatedReadByFilterSchema,
1942
- correlatedListSchema,
1943
- correlatedCountSchema
1944
- ]);
2287
+ var includeItemSchema = publicBoundarySchema(
2288
+ z2.union([
2289
+ legacyIncludeItemSchema,
2290
+ correlatedReadByIdSchema,
2291
+ correlatedReadByFilterSchema,
2292
+ correlatedListSchema,
2293
+ correlatedCountSchema
2294
+ ]),
2295
+ "include"
2296
+ );
1945
2297
  var correlatedNestedIncludeSchema = z2.union([includeItemSchema, z2.array(includeItemSchema)]);
1946
2298
  var rejectDuplicateCorrelatedPaths = (items, ctx) => {
1947
2299
  const seen = /* @__PURE__ */ new Set();
1948
2300
  items.forEach((item, index) => {
1949
- if (isPlainObject11(item) && item.mode === "correlated" && typeof item.path === "string") {
2301
+ if (isPlainObject12(item) && item.mode === "correlated" && typeof item.path === "string") {
1950
2302
  if (seen.has(item.path)) {
1951
2303
  ctx.addIssue({
1952
2304
  code: z2.ZodIssueCode.custom,
@@ -1984,7 +2336,7 @@ function rejectKeys(body, ctx, keys2) {
1984
2336
  }
1985
2337
 
1986
2338
  // src/validation/parsers.ts
1987
- var clientErrors = JsonRouter.clientErrors;
2339
+ var clientErrors = JsonRouter2.clientErrors;
1988
2340
  function parsePathParam(value, parameter) {
1989
2341
  const result = stringOrStringArray.safeParse(value);
1990
2342
  if (!result.success) {
@@ -1999,6 +2351,7 @@ function parsePathParam(value, parameter) {
1999
2351
  return param;
2000
2352
  }
2001
2353
  function parseQuery(schema, value) {
2354
+ assertTransformedPublicAdmission(schema, value);
2002
2355
  const complexityErrors = validateRequestComplexity(value, getGlobalOption("requestComplexity"), "request");
2003
2356
  if (complexityErrors.length > 0) {
2004
2357
  throw new clientErrors.BadRequestError("Bad Request", { errors: complexityErrors });
@@ -2010,6 +2363,7 @@ function parseQuery(schema, value) {
2010
2363
  return result.data;
2011
2364
  }
2012
2365
  function parseBody(schema, value) {
2366
+ assertTransformedPublicAdmission(schema, value);
2013
2367
  const complexityErrors = validateRequestComplexity(value ?? {}, getGlobalOption("requestComplexity"), "request");
2014
2368
  if (complexityErrors.length > 0) {
2015
2369
  throw new clientErrors.BadRequestError("Bad Request", { errors: complexityErrors });
@@ -2020,17 +2374,22 @@ function parseBody(schema, value) {
2020
2374
  }
2021
2375
  return result.data;
2022
2376
  }
2023
- function parseBodyWithSchema(schema, value, userSchema) {
2377
+ async function parseBodyWithSchema(schema, value, userSchema) {
2024
2378
  const body = parseBody(schema, value);
2025
- return isRequestSchema(userSchema) ? parseUserSchema(userSchema, body) : Promise.resolve(body);
2379
+ if (!isRequestSchema(userSchema)) return body;
2380
+ const transformed = await parseUserSchema(userSchema, body);
2381
+ assertTransformedPublicAdmission(schema, transformed);
2382
+ return transformed;
2026
2383
  }
2027
2384
  async function parseNestedBodyWithSchema(schema, value, nestedKey, userSchema) {
2028
2385
  const body = parseBody(schema, value);
2029
2386
  if (!isRequestSchema(userSchema)) return body;
2030
- return {
2387
+ const transformed = {
2031
2388
  ...body,
2032
2389
  [nestedKey]: await parseUserSchema(userSchema, body?.[nestedKey], [nestedKey])
2033
2390
  };
2391
+ assertTransformedPublicAdmission(schema, transformed);
2392
+ return transformed;
2034
2393
  }
2035
2394
  function throwValidationError(issues, key, location = "pointer") {
2036
2395
  const errors = issues.map((issue) => formatIssue(issue, key, location));
@@ -2458,147 +2817,177 @@ function buildPointer(path) {
2458
2817
 
2459
2818
  // src/validation/model-router.ts
2460
2819
  import { z as z3 } from "zod";
2461
- var listQuerySchema = z3.object({
2462
- skip: nonNegativeIntegerString.optional(),
2463
- limit: positiveIntegerString.optional(),
2464
- page: nonNegativeIntegerString.optional(),
2465
- page_size: positiveIntegerString.optional(),
2466
- skim: queryBooleanString.optional(),
2467
- include_permissions: queryBooleanString.optional(),
2468
- include_field_permissions: queryBooleanString.optional(),
2469
- include_count: queryBooleanString.optional(),
2470
- include_extra_headers: queryBooleanString.optional(),
2471
- select: stringOrStringArray.optional(),
2472
- sort: z3.string().optional().describe("Space-separated sort fields; prefix a field with - for descending order.")
2473
- }).passthrough();
2474
- var createQuerySchema = z3.object({
2475
- include_permissions: queryBooleanString.optional(),
2476
- include_field_permissions: queryBooleanString.optional()
2477
- }).passthrough();
2478
- var readQuerySchema = z3.object({
2479
- include_permissions: queryBooleanString.optional(),
2480
- include_field_permissions: queryBooleanString.optional(),
2481
- try_list: queryBooleanString.optional(),
2482
- select: stringOrStringArray.optional()
2483
- }).passthrough();
2484
- var updateQuerySchema = z3.object({
2485
- returning_all: queryBooleanString.optional(),
2486
- include_permissions: queryBooleanString.optional(),
2487
- include_field_permissions: queryBooleanString.optional(),
2488
- select: stringOrStringArray.optional()
2489
- }).passthrough();
2490
- var upsertQuerySchema = z3.object({
2491
- returning_all: queryBooleanString.optional(),
2492
- include_permissions: queryBooleanString.optional(),
2493
- include_field_permissions: queryBooleanString.optional()
2494
- }).passthrough();
2495
- var listBodySchema = z3.object({
2496
- filter: objectOrArraySchema.optional(),
2497
- select: projectionSchema.optional(),
2498
- sort: sortSchema.optional(),
2499
- populate: populateSchema.optional(),
2500
- include: includeSchema.optional(),
2501
- tasks: tasksSchema.optional(),
2502
- skip: z3.union([nonNegativeIntegerSchema, nonNegativeIntegerString]).optional(),
2503
- limit: z3.union([positiveIntegerSchema, positiveIntegerString]).optional(),
2504
- page: z3.union([nonNegativeIntegerSchema, nonNegativeIntegerString]).optional(),
2505
- pageSize: z3.union([positiveIntegerSchema, positiveIntegerString]).optional(),
2506
- options: z3.object({
2507
- skim: z3.boolean().optional(),
2508
- includePermissions: z3.boolean().optional(),
2509
- includeFieldPermissions: z3.boolean().optional(),
2510
- includeCount: z3.boolean().optional(),
2511
- includeExtraHeaders: z3.boolean().optional(),
2512
- populateAccess: populateAccessSchema.optional()
2513
- }).passthrough().optional()
2514
- }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]));
2515
- var countBodySchema = z3.object({
2516
- filter: objectOrArraySchema.optional()
2517
- }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query", "access", "options", "include"]));
2518
- var readFilterBodySchema = z3.object({
2519
- filter: objectOrArraySchema.optional(),
2520
- select: projectionSchema.optional(),
2521
- sort: sortSchema.optional(),
2522
- populate: populateSchema.optional(),
2523
- include: includeSchema.optional(),
2524
- tasks: tasksSchema.optional(),
2525
- options: z3.object({
2526
- skim: z3.boolean().optional(),
2527
- includePermissions: z3.boolean().optional(),
2528
- includeFieldPermissions: z3.boolean().optional(),
2529
- tryList: z3.boolean().optional(),
2530
- populateAccess: populateAccessSchema.optional()
2531
- }).passthrough().optional()
2532
- }).passthrough();
2533
- var readByIdBodySchema = z3.object({
2534
- select: projectionSchema.optional(),
2535
- populate: populateSchema.optional(),
2536
- include: includeSchema.optional(),
2537
- tasks: tasksSchema.optional(),
2538
- options: z3.object({
2539
- skim: z3.boolean().optional(),
2540
- includePermissions: z3.boolean().optional(),
2541
- includeFieldPermissions: z3.boolean().optional(),
2542
- tryList: z3.boolean().optional(),
2543
- populateAccess: populateAccessSchema.optional()
2544
- }).passthrough().optional()
2545
- }).passthrough();
2546
- var advancedCreateBodySchema = z3.object({
2547
- data: z3.unknown(),
2548
- select: projectionSchema.optional(),
2549
- populate: populateSchema.optional(),
2550
- tasks: tasksSchema.optional(),
2551
- options: z3.object({
2552
- includePermissions: z3.boolean().optional(),
2553
- includeFieldPermissions: z3.boolean().optional(),
2554
- populateAccess: populateAccessSchema.optional()
2555
- }).passthrough().optional()
2556
- }).passthrough();
2557
- var createBodySchema = z3.union([
2558
- z3.record(z3.string(), z3.unknown()),
2559
- z3.array(z3.record(z3.string(), z3.unknown()))
2560
- ]);
2561
- var updateBodySchema = z3.record(z3.string(), z3.unknown());
2562
- var advancedUpdateBodySchema = z3.object({
2563
- data: z3.unknown(),
2564
- select: projectionSchema.optional(),
2565
- populate: populateSchema.optional(),
2566
- tasks: tasksSchema.optional(),
2567
- options: z3.object({
2568
- returningAll: z3.boolean().optional(),
2569
- includePermissions: z3.boolean().optional(),
2570
- includeFieldPermissions: z3.boolean().optional(),
2571
- populateAccess: populateAccessSchema.optional()
2572
- }).passthrough().optional()
2573
- }).passthrough();
2574
- var upsertBodySchema = z3.record(z3.string(), z3.unknown());
2575
- var advancedUpsertBodySchema = z3.object({
2576
- data: z3.record(z3.string(), z3.unknown()),
2577
- select: projectionSchema.optional(),
2578
- populate: populateSchema.optional(),
2579
- tasks: tasksSchema.optional(),
2580
- options: z3.object({
2581
- returningAll: z3.boolean().optional(),
2582
- includePermissions: z3.boolean().optional(),
2583
- includeFieldPermissions: z3.boolean().optional(),
2584
- populateAccess: populateAccessSchema.optional()
2585
- }).passthrough().optional()
2586
- }).passthrough();
2587
- var distinctBodySchema = z3.object({
2588
- filter: objectOrArraySchema.optional()
2589
- }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]));
2590
- var subListBodySchema = z3.object({
2591
- filter: z3.record(z3.string(), z3.unknown()).optional(),
2592
- select: fieldsSchema.optional()
2593
- }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["fields"]));
2594
- var subMutationBodySchema = z3.union([
2595
- z3.record(z3.string(), z3.unknown()),
2596
- z3.array(z3.record(z3.string(), z3.unknown()))
2597
- ]);
2598
- var subReadBodySchema = z3.object({
2599
- select: fieldsSchema.optional(),
2600
- populate: subPopulateSchema.optional()
2601
- }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["fields"]));
2820
+ var listQuerySchema = publicBoundarySchema(
2821
+ z3.object({
2822
+ skip: nonNegativeIntegerString.optional(),
2823
+ limit: positiveIntegerString.optional(),
2824
+ page: nonNegativeIntegerString.optional(),
2825
+ page_size: positiveIntegerString.optional(),
2826
+ skim: queryBooleanString.optional(),
2827
+ include_permissions: queryBooleanString.optional(),
2828
+ include_field_permissions: queryBooleanString.optional(),
2829
+ include_count: queryBooleanString.optional(),
2830
+ include_extra_headers: queryBooleanString.optional(),
2831
+ select: stringOrStringArray.optional(),
2832
+ sort: z3.string().optional().describe("Space-separated sort fields; prefix a field with - for descending order.")
2833
+ }).passthrough()
2834
+ );
2835
+ var createQuerySchema = publicBoundarySchema(
2836
+ z3.object({
2837
+ include_permissions: queryBooleanString.optional(),
2838
+ include_field_permissions: queryBooleanString.optional()
2839
+ }).passthrough()
2840
+ );
2841
+ var readQuerySchema = publicBoundarySchema(
2842
+ z3.object({
2843
+ include_permissions: queryBooleanString.optional(),
2844
+ include_field_permissions: queryBooleanString.optional(),
2845
+ try_list: queryBooleanString.optional(),
2846
+ select: stringOrStringArray.optional()
2847
+ }).passthrough()
2848
+ );
2849
+ var updateQuerySchema = publicBoundarySchema(
2850
+ z3.object({
2851
+ returning_all: queryBooleanString.optional(),
2852
+ include_permissions: queryBooleanString.optional(),
2853
+ include_field_permissions: queryBooleanString.optional(),
2854
+ select: stringOrStringArray.optional()
2855
+ }).passthrough()
2856
+ );
2857
+ var upsertQuerySchema = publicBoundarySchema(
2858
+ z3.object({
2859
+ returning_all: queryBooleanString.optional(),
2860
+ include_permissions: queryBooleanString.optional(),
2861
+ include_field_permissions: queryBooleanString.optional()
2862
+ }).passthrough()
2863
+ );
2864
+ var listBodySchema = publicBoundarySchema(
2865
+ z3.object({
2866
+ filter: objectOrArraySchema.optional(),
2867
+ select: projectionSchema.optional(),
2868
+ sort: sortSchema.optional(),
2869
+ populate: populateSchema.optional(),
2870
+ include: includeSchema.optional(),
2871
+ tasks: tasksSchema.optional(),
2872
+ skip: z3.union([nonNegativeIntegerSchema, nonNegativeIntegerString]).optional(),
2873
+ limit: z3.union([positiveIntegerSchema, positiveIntegerString]).optional(),
2874
+ page: z3.union([nonNegativeIntegerSchema, nonNegativeIntegerString]).optional(),
2875
+ pageSize: z3.union([positiveIntegerSchema, positiveIntegerString]).optional(),
2876
+ options: z3.object({
2877
+ skim: z3.boolean().optional(),
2878
+ includePermissions: z3.boolean().optional(),
2879
+ includeFieldPermissions: z3.boolean().optional(),
2880
+ includeCount: z3.boolean().optional(),
2881
+ includeExtraHeaders: z3.boolean().optional(),
2882
+ populateAccess: populateAccessSchema.optional()
2883
+ }).passthrough().optional()
2884
+ }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]))
2885
+ );
2886
+ var countBodySchema = publicBoundarySchema(
2887
+ z3.object({
2888
+ filter: objectOrArraySchema.optional()
2889
+ }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query", "access", "options", "include"]))
2890
+ );
2891
+ var readFilterBodySchema = publicBoundarySchema(
2892
+ z3.object({
2893
+ filter: objectOrArraySchema.optional(),
2894
+ select: projectionSchema.optional(),
2895
+ sort: sortSchema.optional(),
2896
+ populate: populateSchema.optional(),
2897
+ include: includeSchema.optional(),
2898
+ tasks: tasksSchema.optional(),
2899
+ options: z3.object({
2900
+ skim: z3.boolean().optional(),
2901
+ includePermissions: z3.boolean().optional(),
2902
+ includeFieldPermissions: z3.boolean().optional(),
2903
+ tryList: z3.boolean().optional(),
2904
+ populateAccess: populateAccessSchema.optional()
2905
+ }).passthrough().optional()
2906
+ }).passthrough()
2907
+ );
2908
+ var readByIdBodySchema = publicBoundarySchema(
2909
+ z3.object({
2910
+ select: projectionSchema.optional(),
2911
+ populate: populateSchema.optional(),
2912
+ include: includeSchema.optional(),
2913
+ tasks: tasksSchema.optional(),
2914
+ options: z3.object({
2915
+ skim: z3.boolean().optional(),
2916
+ includePermissions: z3.boolean().optional(),
2917
+ includeFieldPermissions: z3.boolean().optional(),
2918
+ tryList: z3.boolean().optional(),
2919
+ populateAccess: populateAccessSchema.optional()
2920
+ }).passthrough().optional()
2921
+ }).passthrough()
2922
+ );
2923
+ var advancedCreateBodySchema = publicBoundarySchema(
2924
+ z3.object({
2925
+ data: z3.unknown(),
2926
+ select: projectionSchema.optional(),
2927
+ populate: populateSchema.optional(),
2928
+ tasks: tasksSchema.optional(),
2929
+ options: z3.object({
2930
+ includePermissions: z3.boolean().optional(),
2931
+ includeFieldPermissions: z3.boolean().optional(),
2932
+ populateAccess: populateAccessSchema.optional()
2933
+ }).passthrough().optional()
2934
+ }).passthrough()
2935
+ );
2936
+ var createBodySchema = publicBoundarySchema(
2937
+ z3.union([z3.record(z3.string(), z3.unknown()), z3.array(z3.record(z3.string(), z3.unknown()))]),
2938
+ "data"
2939
+ );
2940
+ var updateBodySchema = publicBoundarySchema(z3.record(z3.string(), z3.unknown()), "data");
2941
+ var advancedUpdateBodySchema = publicBoundarySchema(
2942
+ z3.object({
2943
+ data: z3.unknown(),
2944
+ select: projectionSchema.optional(),
2945
+ populate: populateSchema.optional(),
2946
+ tasks: tasksSchema.optional(),
2947
+ options: z3.object({
2948
+ returningAll: z3.boolean().optional(),
2949
+ includePermissions: z3.boolean().optional(),
2950
+ includeFieldPermissions: z3.boolean().optional(),
2951
+ populateAccess: populateAccessSchema.optional()
2952
+ }).passthrough().optional()
2953
+ }).passthrough()
2954
+ );
2955
+ var upsertBodySchema = publicBoundarySchema(z3.record(z3.string(), z3.unknown()), "data");
2956
+ var advancedUpsertBodySchema = publicBoundarySchema(
2957
+ z3.object({
2958
+ data: z3.record(z3.string(), z3.unknown()),
2959
+ select: projectionSchema.optional(),
2960
+ populate: populateSchema.optional(),
2961
+ tasks: tasksSchema.optional(),
2962
+ options: z3.object({
2963
+ returningAll: z3.boolean().optional(),
2964
+ includePermissions: z3.boolean().optional(),
2965
+ includeFieldPermissions: z3.boolean().optional(),
2966
+ populateAccess: populateAccessSchema.optional()
2967
+ }).passthrough().optional()
2968
+ }).passthrough()
2969
+ );
2970
+ var distinctBodySchema = publicBoundarySchema(
2971
+ z3.object({
2972
+ filter: objectOrArraySchema.optional()
2973
+ }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]))
2974
+ );
2975
+ var subListBodySchema = publicBoundarySchema(
2976
+ z3.object({
2977
+ filter: z3.record(z3.string(), z3.unknown()).optional(),
2978
+ select: fieldsSchema.optional()
2979
+ }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["fields"]))
2980
+ );
2981
+ var subMutationBodySchema = publicBoundarySchema(
2982
+ z3.union([z3.record(z3.string(), z3.unknown()), z3.array(z3.record(z3.string(), z3.unknown()))]),
2983
+ "data"
2984
+ );
2985
+ var subReadBodySchema = publicBoundarySchema(
2986
+ z3.object({
2987
+ select: fieldsSchema.optional(),
2988
+ populate: subPopulateSchema.optional()
2989
+ }).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["fields"]))
2990
+ );
2602
2991
  var requestSchemas = {
2603
2992
  listQuery: listQuerySchema,
2604
2993
  createQuery: createQuerySchema,
@@ -2876,7 +3265,9 @@ var rootDataQueryEntrySchema = z5.union([
2876
3265
  args: rootDataReadArgsSchema.optional()
2877
3266
  }).passthrough()
2878
3267
  ]);
2879
- var rootQuerySchema = z5.array(z5.union([rootModelQueryEntrySchema, rootDataQueryEntrySchema]));
3268
+ var rootQuerySchema = publicBoundarySchema(
3269
+ z5.array(z5.union([rootModelQueryEntrySchema, rootDataQueryEntrySchema]))
3270
+ );
2880
3271
  export {
2881
3272
  Codes,
2882
3273
  CustomHeaders,