@web-ts-toolkit/access-router 0.52.0 → 0.53.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
@@ -49,7 +49,38 @@ function assertPublicAdmission(input, kind = "envelope") {
49
49
  for (const key of ["filter", "match", "data"]) add(record2[key], "data", key);
50
50
  }
51
51
  }
52
+ function assertHydrationDefaults(defaults) {
53
+ if (defaults && typeof defaults === "object") {
54
+ const record2 = defaults;
55
+ if ("hydration" in record2)
56
+ throw new TypeError("defaults.hydration is unsupported; use model hydration configuration");
57
+ for (const bucket of [
58
+ "publicListOptions",
59
+ "publicReadOptions",
60
+ "findOptions",
61
+ "findOneOptions",
62
+ "findByIdOptions",
63
+ "createOptions",
64
+ "updateOneOptions",
65
+ "updateByIdOptions",
66
+ "upsertOptions",
67
+ "existsOptions",
68
+ "publicCreateOptions",
69
+ "publicUpdateOptions"
70
+ ]) {
71
+ const options = record2[bucket];
72
+ if (!options || typeof options !== "object" && typeof options !== "function") continue;
73
+ for (const key of ["lean", "hydration"]) {
74
+ if (!(key in options)) continue;
75
+ const method = bucket.slice(0, -"Options".length);
76
+ const migration = ["publicList", "publicRead", "find", "findOne", "findById"].includes(method) ? `use model hydration.${method} ('lean' or 'hydrated')` : "this method has a fixed fetch mode";
77
+ throw new TypeError(`defaults.${bucket}.${key} is unsupported; ${migration}`);
78
+ }
79
+ }
80
+ }
81
+ }
52
82
  function assertPublicDefaults(defaults) {
83
+ assertHydrationDefaults(defaults);
53
84
  assertPublicAdmission(defaults);
54
85
  if (defaults && typeof defaults === "object") {
55
86
  for (const value of Object.values(defaults)) assertPublicAdmission(value);
@@ -113,21 +144,43 @@ var init_public_admission = __esm({
113
144
  "includePermissions",
114
145
  "includeFieldPermissions",
115
146
  "includeCount",
116
- "populateAccess",
117
- "lean"
118
- ];
119
- readOptions = [
120
- "skim",
121
- "includePermissions",
122
- "includeFieldPermissions",
123
- "tryList",
124
- "populateAccess",
125
- "lean"
147
+ "populateAccess"
126
148
  ];
149
+ readOptions = ["skim", "includePermissions", "includeFieldPermissions", "tryList", "populateAccess"];
127
150
  requestAuthorization = Object.freeze({ outputFields: Object.freeze({ mode: "request" }) });
128
151
  }
129
152
  });
130
153
 
154
+ // src/options/hydration.ts
155
+ function normalizeHydration(value, path = "hydration") {
156
+ if (value === void 0) return void 0;
157
+ if (value === null || typeof value !== "object" || ![Object.prototype, null].includes(Object.getPrototypeOf(value)))
158
+ throw new TypeError(`${path} must be a plain record of model hydration modes`);
159
+ const result2 = {};
160
+ for (const key of Reflect.ownKeys(value)) {
161
+ if (typeof key !== "string" || !methods.includes(key))
162
+ throw new TypeError(`${path}.${String(key)} is not a supported hydration method`);
163
+ const mode = value[key];
164
+ if (mode !== void 0 && mode !== "lean" && mode !== "hydrated")
165
+ throw new TypeError(`${path}.${key} must be 'lean', 'hydrated', or undefined`);
166
+ result2[key] = mode;
167
+ }
168
+ return Object.freeze(result2);
169
+ }
170
+ function normalizeHydrationUpdate(current, key, value) {
171
+ if (key === "hydration") return normalizeHydration(value);
172
+ const method = key.slice("hydration.".length);
173
+ if (!methods.includes(method))
174
+ throw new TypeError(`${key} is not a supported hydration method`);
175
+ return normalizeHydration({ ...normalizeHydration(current), [method]: value });
176
+ }
177
+ var methods;
178
+ var init_hydration = __esm({
179
+ "src/options/hydration.ts"() {
180
+ methods = ["publicList", "publicRead", "find", "findOne", "findById"];
181
+ }
182
+ });
183
+
131
184
  // src/helpers/collection.ts
132
185
  import sift from "sift";
133
186
  import { filter, find } from "@web-ts-toolkit/utils";
@@ -257,6 +310,50 @@ var init_concurrency = __esm({
257
310
  }
258
311
  });
259
312
 
313
+ // src/output/permissions-alias.ts
314
+ import { get } from "@web-ts-toolkit/utils";
315
+ function attachPermissionsAlias(output, field) {
316
+ if ("permissions" in output) return;
317
+ const metadata = get(output, field);
318
+ if (metadata === void 0) return;
319
+ Object.defineProperty(output, "permissions", {
320
+ value: metadata,
321
+ enumerable: false,
322
+ writable: true,
323
+ configurable: true
324
+ });
325
+ aliases.set(output, field);
326
+ }
327
+ function removeGeneratedPermissionsAlias(output) {
328
+ const field = aliases.get(output);
329
+ if (field && Object.getOwnPropertyDescriptor(output, "permissions")?.value === get(output, field)) {
330
+ delete output.permissions;
331
+ }
332
+ aliases.delete(output);
333
+ }
334
+ function copyPermissionsAlias(source, target) {
335
+ if (source && typeof source === "object" && target && typeof target === "object") {
336
+ const field = aliases.get(source);
337
+ if (field && Object.getOwnPropertyDescriptor(source, "permissions")?.value === get(source, field))
338
+ attachPermissionsAlias(target, field);
339
+ }
340
+ return target;
341
+ }
342
+ function copyPermissionsAliasGraph(source, target, seen = /* @__PURE__ */ new WeakSet()) {
343
+ if (!source || !target || typeof source !== "object" || typeof target !== "object" || seen.has(target)) return;
344
+ seen.add(target);
345
+ copyPermissionsAlias(source, target);
346
+ for (const key of Object.keys(target)) {
347
+ copyPermissionsAliasGraph(source[key], target[key], seen);
348
+ }
349
+ }
350
+ var aliases;
351
+ var init_permissions_alias = __esm({
352
+ "src/output/permissions-alias.ts"() {
353
+ aliases = /* @__PURE__ */ new WeakMap();
354
+ }
355
+ });
356
+
260
357
  // src/helpers/query.ts
261
358
  import { flattenDeep, isNil, isPlainObject as isPlainObject2, isString, reduce } from "@web-ts-toolkit/utils";
262
359
  function genPagination({
@@ -323,16 +420,16 @@ var init_query = __esm({
323
420
 
324
421
  // src/helpers/document.ts
325
422
  import { Document, mongo } from "mongoose";
326
- import { get, isPlainObject as isPlainObject3, pick, set } from "@web-ts-toolkit/utils";
423
+ import { get as get2, isPlainObject as isPlainObject3, pick, set } from "@web-ts-toolkit/utils";
327
424
  import { isArray, isPromise, isString as isString2 } from "@web-ts-toolkit/utils";
328
425
  function isDocument(doc) {
329
426
  return doc instanceof Document;
330
427
  }
331
428
  function getDocValue(doc, path, defaultValue) {
332
429
  if (isDocument(doc)) {
333
- return get(doc._doc, path, defaultValue);
430
+ return get2(doc._doc, path, defaultValue);
334
431
  } else if (isPlainObject3(doc)) {
335
- return get(doc, path, defaultValue);
432
+ return get2(doc, path, defaultValue);
336
433
  }
337
434
  }
338
435
  function setDocValue(doc, path, value) {
@@ -347,15 +444,6 @@ function getDocPermissions(modelName, doc) {
347
444
  const permissions = getDocValue(doc, docPermissionField, {});
348
445
  return isPlainObject3(permissions) ? permissions : {};
349
446
  }
350
- function stripUnexposedDocPermissions(modelName, doc) {
351
- const exposed = getModelOption(modelName, "exposedDocPermissionKeys");
352
- if (exposed === void 0) return;
353
- const docPermissionField = getModelOption(modelName, "documentPermissionField");
354
- const current = getDocValue(doc, docPermissionField, void 0);
355
- if (!isPlainObject3(current)) return;
356
- const keep = /* @__PURE__ */ new Set(["_view", "_edit", ...exposed]);
357
- setDocValue(doc, docPermissionField, Object.fromEntries(Object.entries(current).filter(([key]) => keep.has(key))));
358
- }
359
447
  function toObject(doc) {
360
448
  return isDocument(doc) ? doc.toObject() : doc;
361
449
  }
@@ -375,6 +463,7 @@ async function populateDoc(doc, target) {
375
463
  var isMongooseDocument, cloneIsolatedLeaf, deepIsolateValue, isolateDocForOutput, retainedAssociations, retainRawAssociation, getRetainedAssociations, normalizeSubPopulate, genSubPopulate;
376
464
  var init_document = __esm({
377
465
  "src/helpers/document.ts"() {
466
+ init_permissions_alias();
378
467
  init_public_admission();
379
468
  init_options();
380
469
  init_query();
@@ -477,6 +566,7 @@ var init_document = __esm({
477
566
  configurable: true
478
567
  });
479
568
  }
569
+ copyPermissionsAlias(value, out);
480
570
  return out;
481
571
  }
482
572
  return value;
@@ -1206,7 +1296,7 @@ var init_logger_default = __esm({
1206
1296
  });
1207
1297
 
1208
1298
  // src/options/manager.ts
1209
- import { assign, get as get2, isPlainObject as isPlainObject9, set as set2 } from "@web-ts-toolkit/utils";
1299
+ import { assign, get as get3, isPlainObject as isPlainObject9, set as set2 } from "@web-ts-toolkit/utils";
1210
1300
  var toPath, cloneConfigValue, cloneForRead, freezeConfigValue, cloneAndFreezeForStore, getNestedOption, resolveNestedOption, OptionsManager;
1211
1301
  var init_manager = __esm({
1212
1302
  "src/options/manager.ts"() {
@@ -1316,7 +1406,7 @@ var init_manager = __esm({
1316
1406
  return this;
1317
1407
  }
1318
1408
  get(key, defaultValue) {
1319
- return get2(this.currentOptions, key, defaultValue);
1409
+ return get3(this.currentOptions, key, defaultValue);
1320
1410
  }
1321
1411
  set(key, value) {
1322
1412
  const path = toPath(key);
@@ -1325,7 +1415,7 @@ var init_manager = __esm({
1325
1415
  return;
1326
1416
  }
1327
1417
  const [rootKey, ...nestedPath] = path;
1328
- const currentRoot = get2(this.currentOptions, [rootKey], void 0);
1418
+ const currentRoot = get3(this.currentOptions, [rootKey], void 0);
1329
1419
  const baseRoot = isPlainObject9(currentRoot) ? currentRoot : {};
1330
1420
  const nextRoot = cloneConfigValue(baseRoot);
1331
1421
  set2(nextRoot, nestedPath, cloneForRead(value));
@@ -1739,7 +1829,7 @@ import mschema2Jsonschema from "mongoose-schema-jsonschema";
1739
1829
  import {
1740
1830
  addLeadingSlash,
1741
1831
  forEach as forEach2,
1742
- get as get3,
1832
+ get as get4,
1743
1833
  isArray as isArray5,
1744
1834
  isBoolean,
1745
1835
  isFunction,
@@ -1754,6 +1844,7 @@ var mongooseJsonSchemaInitialized, ensureMongooseJsonSchemaInitialized, pluraliz
1754
1844
  var init_runtime = __esm({
1755
1845
  "src/runtime.ts"() {
1756
1846
  init_public_admission();
1847
+ init_hydration();
1757
1848
  init_helpers();
1758
1849
  init_registry();
1759
1850
  init_logger_default();
@@ -1854,8 +1945,8 @@ var init_runtime = __esm({
1854
1945
  virtualPathsOverlap = (virtualPath, permissionField) => {
1855
1946
  if (!virtualPath || !permissionField) return false;
1856
1947
  try {
1857
- if (get3(set4({}, virtualPath, true), permissionField) !== void 0) return true;
1858
- if (get3(set4({}, permissionField, true), virtualPath) !== void 0) return true;
1948
+ if (get4(set4({}, virtualPath, true), permissionField) !== void 0) return true;
1949
+ if (get4(set4({}, permissionField, true), virtualPath) !== void 0) return true;
1859
1950
  } catch {
1860
1951
  return false;
1861
1952
  }
@@ -2316,9 +2407,25 @@ var init_runtime = __esm({
2316
2407
  }
2317
2408
  /** Update model starting defaults shallowly; already-stored model values are not broadcast-replaced. */
2318
2409
  setDefaultModelOptions(options) {
2410
+ assertPublicDefaults(options.defaults);
2411
+ if ("hydration" in options) options = { ...options, hydration: normalizeHydration(options.hydration) };
2319
2412
  this.defaultModelOptions.assign(options);
2320
2413
  }
2321
2414
  setDefaultModelOption(key, value) {
2415
+ const keyStr = String(key);
2416
+ if (keyStr === "hydration" || keyStr.startsWith("hydration.")) {
2417
+ this.defaultModelOptions.set(
2418
+ "hydration",
2419
+ normalizeHydrationUpdate(this.getDefaultModelOptions().hydration, keyStr, value)
2420
+ );
2421
+ return;
2422
+ }
2423
+ if (keyStr === "defaults") assertPublicDefaults(value);
2424
+ else if (keyStr.startsWith("defaults.")) {
2425
+ const proposed = {};
2426
+ set4(proposed, keyStr.slice("defaults.".length), value);
2427
+ assertPublicDefaults(proposed);
2428
+ }
2322
2429
  this.defaultModelOptions.set(key, value);
2323
2430
  }
2324
2431
  getDefaultModelOptions() {
@@ -2368,6 +2475,7 @@ var init_runtime = __esm({
2368
2475
  */
2369
2476
  setModelOptions(modelName, options) {
2370
2477
  assertPublicDefaults(options.defaults);
2478
+ if ("hydration" in options) options = { ...options, hydration: normalizeHydration(options.hydration) };
2371
2479
  const manager = this.getOrCreateModelOptions(modelName);
2372
2480
  const defaultOptions = this.getDefaultModelOptions();
2373
2481
  const currentModelOptions = manager.fetch();
@@ -2378,14 +2486,19 @@ var init_runtime = __esm({
2378
2486
  manager.assign({ ...defaultOptions, ...currentModelOptions, ...options });
2379
2487
  }
2380
2488
  setModelOption(modelName, key, value) {
2381
- const manager = this.getOrCreateModelOptions(modelName);
2382
2489
  const keyStr = String(key);
2490
+ if (keyStr === "hydration" || keyStr.startsWith("hydration.")) {
2491
+ const hydration = normalizeHydrationUpdate(this.modelOptions[modelName]?.get("hydration"), keyStr, value);
2492
+ this.getOrCreateModelOptions(modelName).set("hydration", hydration);
2493
+ return;
2494
+ }
2383
2495
  if (keyStr === "defaults") assertPublicDefaults(value);
2384
2496
  else if (keyStr.startsWith("defaults.")) {
2385
2497
  const proposed = {};
2386
2498
  set4(proposed, keyStr.slice("defaults.".length), value);
2387
2499
  assertPublicDefaults(proposed);
2388
2500
  }
2501
+ const manager = this.getOrCreateModelOptions(modelName);
2389
2502
  if (keyStr === "virtuals" || keyStr.startsWith("virtuals.") || keyStr === "documentPermissionField") {
2390
2503
  const model = this.getModelInstance(modelName);
2391
2504
  const currentVirtuals = manager.get("virtuals");
@@ -2590,16 +2703,16 @@ var init_runtime = __esm({
2590
2703
  }
2591
2704
  getModelRef(modelName, refPath) {
2592
2705
  this.ensureModelMeta(modelName);
2593
- const value = get3(this.modelRefs, `${modelName}.${refPath}`, null);
2706
+ const value = get4(this.modelRefs, `${modelName}.${refPath}`, null);
2594
2707
  return isString4(value) ? value : null;
2595
2708
  }
2596
2709
  getModelSub(modelName) {
2597
2710
  this.ensureModelMeta(modelName);
2598
- return get3(this.modelSubs, modelName, []);
2711
+ return get4(this.modelSubs, modelName, []);
2599
2712
  }
2600
2713
  getModelAtt(modelName) {
2601
2714
  this.ensureModelMeta(modelName);
2602
- return get3(this.modelAtts, modelName, []);
2715
+ return get4(this.modelAtts, modelName, []);
2603
2716
  }
2604
2717
  };
2605
2718
  defaultRuntime = new AccessRuntime({ allowGlobalModelLookup: true });
@@ -3652,7 +3765,7 @@ var init_field_authorization = __esm({
3652
3765
  });
3653
3766
 
3654
3767
  // src/acl/virtual-projection.ts
3655
- import { get as get4, isArray as isArray7, isFunction as isFunction2, isPlainObject as isPlainObject13 } from "@web-ts-toolkit/utils";
3768
+ import { get as get5, isArray as isArray7, isFunction as isFunction2, isPlainObject as isPlainObject13 } from "@web-ts-toolkit/utils";
3656
3769
  function planVirtualProjection(args) {
3657
3770
  if (args.snapshot.catalog) return planCatalogProjection(args);
3658
3771
  const {
@@ -3923,7 +4036,7 @@ var init_virtual_projection = __esm({
3923
4036
  getScopedPermissionSchema = (root, scopePath) => {
3924
4037
  if (!root || !isPlainObject13(root)) return null;
3925
4038
  if (scopePath.length === 0) return root;
3926
- const scoped = get4(root, scopePath.join("."));
4039
+ const scoped = get5(root, scopePath.join("."));
3927
4040
  return isPlainObject13(scoped) ? scoped : null;
3928
4041
  };
3929
4042
  resolveAlwaysSelectForAccess = (raw, access) => {
@@ -4173,14 +4286,13 @@ var init_output_projection = __esm({
4173
4286
  });
4174
4287
 
4175
4288
  // src/acl/model-output-planning.ts
4176
- import { get as get5 } from "@web-ts-toolkit/utils";
4289
+ import { get as get6 } from "@web-ts-toolkit/utils";
4177
4290
  function getCapturedAuthorizationOption(configuration, key) {
4178
- return resolveNestedOption((path, fallback) => get5(configuration, path, fallback), key);
4291
+ return resolveNestedOption((path, fallback) => get6(configuration, path, fallback), key);
4179
4292
  }
4180
- function captureModelAuthorizationConfiguration(runtime, modelName) {
4293
+ function captureModelAuthorizationConfiguration(runtime, modelName, options = runtime.getModelOptions(modelName)) {
4181
4294
  const model = runtime.getModelInstance(modelName);
4182
4295
  if (!model) return authorizationError(`unknown receiving model: ${modelName}`);
4183
- const options = runtime.getModelOptions(modelName);
4184
4296
  const virtuals = options.virtuals;
4185
4297
  return {
4186
4298
  catalog: captureAuthorizationFieldCatalog(model.schema, virtuals, options.documentPermissionField),
@@ -4198,7 +4310,8 @@ function captureModelAuthorizationConfiguration(runtime, modelName) {
4198
4310
  baseFilter: options.baseFilter,
4199
4311
  idField: options.idField,
4200
4312
  resolveIdFilter: options.resolveIdFilter,
4201
- operationAccess: options.operationAccess
4313
+ operationAccess: options.operationAccess,
4314
+ hydration: options.hydration
4202
4315
  };
4203
4316
  }
4204
4317
  function planModelOutputForHelper(args) {
@@ -4850,6 +4963,7 @@ function retainOutputMetadata(output, source, configuration, scope2) {
4850
4963
  target[parts[parts.length - 1]] = deepIsolateValue(metadata);
4851
4964
  transferDocumentAuthorizationGraph(output[parts[0]], copy[parts[0]]);
4852
4965
  output[parts[0]] = copy[parts[0]];
4966
+ attachPermissionsAlias(output, parts.join("."));
4853
4967
  }
4854
4968
  function helperPlan(authorization, binding) {
4855
4969
  const { configuration, authorization: policy, access } = readServiceAuthorization(authorization, binding);
@@ -4979,6 +5093,7 @@ async function filterModelOutputForHelper(args) {
4979
5093
  var unresolvedDocuments, owningDocuments;
4980
5094
  var init_output_field_filter = __esm({
4981
5095
  "src/acl/output-field-filter.ts"() {
5096
+ init_permissions_alias();
4982
5097
  init_document();
4983
5098
  init_request_work();
4984
5099
  init_logger_helpers();
@@ -5058,7 +5173,7 @@ __export(finalize_model_output_exports, {
5058
5173
  finalizeModelOutput: () => finalizeModelOutput,
5059
5174
  finalizeModelOutputs: () => finalizeModelOutputs
5060
5175
  });
5061
- import { get as get7, isPlainObject as isPlainObject18, set as set7 } from "@web-ts-toolkit/utils";
5176
+ import { get as get8, isPlainObject as isPlainObject18, set as set7 } from "@web-ts-toolkit/utils";
5062
5177
  async function finalizeSingleDoc(args, input) {
5063
5178
  const scopePath = args.scopePath;
5064
5179
  const plan = args.plan;
@@ -5177,7 +5292,7 @@ async function finalizeSingleDoc(args, input) {
5177
5292
  for (const target of relatedTargets) {
5178
5293
  let rawRelated;
5179
5294
  try {
5180
- rawRelated = target.path.includes(".") ? get7(output, target.path) : output[target.path];
5295
+ rawRelated = target.path.includes(".") ? get8(output, target.path) : output[target.path];
5181
5296
  } catch {
5182
5297
  continue;
5183
5298
  }
@@ -5434,7 +5549,7 @@ var init_finalize_model_output = __esm({
5434
5549
  if (!root || !isPlainObject18(root)) return null;
5435
5550
  if (scopePath.length === 0) return root;
5436
5551
  try {
5437
- const scoped = get7(root, scopePath.join("."));
5552
+ const scoped = get8(root, scopePath.join("."));
5438
5553
  return isPlainObject18(scoped) ? scoped : null;
5439
5554
  } catch {
5440
5555
  return null;
@@ -5569,7 +5684,7 @@ import {
5569
5684
  compact,
5570
5685
  flatten,
5571
5686
  forEach as forEach3,
5572
- get as get6,
5687
+ get as get7,
5573
5688
  isArray as isArray9,
5574
5689
  isPlainObject as isPlainObject15,
5575
5690
  set as set6,
@@ -6319,7 +6434,7 @@ function snapshotGroups(sources, valueOf, multipleKeys) {
6319
6434
  if (sources.length > MAX_GROUPS) invalid(`groups exceed ${MAX_GROUPS}`);
6320
6435
  const budget = new KeyBudget();
6321
6436
  const values = [];
6322
- const aliases = [];
6437
+ const aliases2 = [];
6323
6438
  const indices = /* @__PURE__ */ new Map();
6324
6439
  const groups = [];
6325
6440
  for (const source of sources) {
@@ -6330,7 +6445,7 @@ function snapshotGroups(sources, valueOf, multipleKeys) {
6330
6445
  if (index === void 0) {
6331
6446
  index = values.length;
6332
6447
  indices.set(alias, index);
6333
- aliases.push(alias);
6448
+ aliases2.push(alias);
6334
6449
  values.push(snapshot);
6335
6450
  }
6336
6451
  group.add(index);
@@ -6350,7 +6465,7 @@ function snapshotGroups(sources, valueOf, multipleKeys) {
6350
6465
  }
6351
6466
  return Object.freeze({
6352
6467
  values: Object.freeze(values),
6353
- aliases: Object.freeze(aliases),
6468
+ aliases: Object.freeze(aliases2),
6354
6469
  groups: Object.freeze((multipleKeys ? groups : values.map((_, i) => [i])).map((group) => Object.freeze(group)))
6355
6470
  });
6356
6471
  }
@@ -6400,7 +6515,7 @@ function getServiceExecutors(receiver) {
6400
6515
  if (!registered) authorizationError("unregistered service receiver");
6401
6516
  return registered;
6402
6517
  }
6403
- function createServiceExecution(receiver, access, authorization, applicability = "service", relatedTargets = [], parent, configuration, requestPermissions) {
6518
+ function createServiceExecution(receiver, access, authorization, applicability = "service", relatedTargets = [], parent, configuration, requestPermissions, hydration = access.operation === "list" ? "find" : "findOne") {
6404
6519
  const registered = getServiceExecutors(receiver);
6405
6520
  const receiving = registered.binding();
6406
6521
  const binding = Object.freeze({ ...receiving, scopePath: Object.freeze([...receiving.scopePath ?? []]) });
@@ -6422,11 +6537,23 @@ function createServiceExecution(receiver, access, authorization, applicability =
6422
6537
  binding,
6423
6538
  authorization: call,
6424
6539
  access: readServiceAuthorization(call, binding).access,
6425
- family: execution
6540
+ family: execution,
6541
+ hydration: resolveHydration(readServiceAuthorization(call, binding).configuration, hydration)
6426
6542
  })
6427
6543
  );
6428
6544
  return execution;
6429
6545
  }
6546
+ function resolveHydration(configuration, source) {
6547
+ if (source === "lean" || source === "hydrated") return source;
6548
+ return configuration.hydration?.[source] ?? (source === "publicList" ? "lean" : "hydrated");
6549
+ }
6550
+ function withExecutionHydration(receiver, parent, source) {
6551
+ const record2 = readServiceExecution(receiver, parent);
6552
+ const { configuration } = readServiceAuthorization(record2.authorization, record2.binding);
6553
+ const execution = Object.freeze(/* @__PURE__ */ Object.create(null));
6554
+ executions.set(execution, Object.freeze({ ...record2, hydration: resolveHydration(configuration, source) }));
6555
+ return execution;
6556
+ }
6430
6557
  function readServiceExecution(receiver, execution) {
6431
6558
  const record2 = executions.get(execution);
6432
6559
  if (!record2 || record2.receiver !== receiver) authorizationError("invalid execution receiver/call");
@@ -7015,19 +7142,27 @@ var Base = class {
7015
7142
  relatedExecution(svc, include, parentAuthorization) {
7016
7143
  const op = include.op;
7017
7144
  if (!parentAuthorization)
7018
- return createServiceExecution(svc, {
7019
- operation: op,
7020
- rowAccess: op,
7021
- virtualAccess: op,
7022
- outputAccess: op,
7023
- docPermissionsAccess: op
7024
- });
7025
- return createRelatedExecution(
7145
+ return withExecutionHydration(
7146
+ svc,
7147
+ createServiceExecution(svc, {
7148
+ operation: op,
7149
+ rowAccess: op,
7150
+ virtualAccess: op,
7151
+ outputAccess: op,
7152
+ docPermissionsAccess: op
7153
+ }),
7154
+ "lean"
7155
+ );
7156
+ return withExecutionHydration(
7026
7157
  svc,
7027
- { operation: op, rowAccess: op, virtualAccess: op, outputAccess: op, docPermissionsAccess: op },
7028
- parentAuthorization,
7029
- this.relatedBinding(),
7030
- include.path
7158
+ createRelatedExecution(
7159
+ svc,
7160
+ { operation: op, rowAccess: op, virtualAccess: op, outputAccess: op, docPermissionsAccess: op },
7161
+ parentAuthorization,
7162
+ this.relatedBinding(),
7163
+ include.path
7164
+ ),
7165
+ "lean"
7031
7166
  );
7032
7167
  }
7033
7168
  processInclude(include) {
@@ -7083,7 +7218,7 @@ var Base = class {
7083
7218
  }
7084
7219
  validateIncludeOutputPath(path, modelName) {
7085
7220
  const permissionField = getModelOption(modelName, "documentPermissionField");
7086
- if (get6(set6({}, path, true), permissionField) !== void 0 || get6(set6({}, permissionField, true), path) !== void 0) {
7221
+ if (get7(set6({}, path, true), permissionField) !== void 0 || get7(set6({}, permissionField, true), path) !== void 0) {
7087
7222
  this.throwClientRequestError(
7088
7223
  "bad_request" /* BadRequest */,
7089
7224
  `Include output path ${path} overlaps document permission field ${permissionField} on model ${modelName}`
@@ -7187,7 +7322,7 @@ var Base = class {
7187
7322
  buildForeignKeyIndex(rows, foreignField) {
7188
7323
  const index = /* @__PURE__ */ new Map();
7189
7324
  for (const row of rows) {
7190
- for (const value of this.getForeignKeyValues(get6(row, foreignField))) {
7325
+ for (const value of this.getForeignKeyValues(get7(row, foreignField))) {
7191
7326
  const key = this.getForeignKey(value);
7192
7327
  const values = index.get(key);
7193
7328
  if (values) values.push(row);
@@ -7255,7 +7390,7 @@ var Base = class {
7255
7390
  const svc = await this.getAuthorizedTargetService(model, "read", path, parentAuthorization);
7256
7391
  for (let y = 0; y < docs.length; y++) {
7257
7392
  const doc = docs[y];
7258
- const localValue = get6(doc, localField);
7393
+ const localValue = get7(doc, localField);
7259
7394
  const execution = this.relatedExecution(svc, include, parentAuthorization);
7260
7395
  const prepared = await prepareModelQuery(
7261
7396
  svc,
@@ -7269,7 +7404,6 @@ var Base = class {
7269
7404
  skim,
7270
7405
  populateAccess,
7271
7406
  access: "read",
7272
- lean: true,
7273
7407
  includePermissions: false,
7274
7408
  includeFieldPermissions: false
7275
7409
  });
@@ -7292,7 +7426,7 @@ var Base = class {
7292
7426
  const svc = await this.getAuthorizedTargetService(model, op, path, parentAuthorization);
7293
7427
  const includeLocalValues = [];
7294
7428
  forEach3(docs, (doc) => {
7295
- includeLocalValues.push(...this.getForeignKeyValues(get6(doc, localField)));
7429
+ includeLocalValues.push(...this.getForeignKeyValues(get7(doc, localField)));
7296
7430
  });
7297
7431
  const execution = this.relatedExecution(svc, include, parentAuthorization);
7298
7432
  const prepared = await prepareModelQuery(
@@ -7308,7 +7442,6 @@ var Base = class {
7308
7442
  ...requestOnlyServiceOptions({
7309
7443
  skim,
7310
7444
  populateAccess,
7311
- lean: true,
7312
7445
  includePermissions: false,
7313
7446
  includeFieldPermissions: false,
7314
7447
  includeCount: false
@@ -7343,7 +7476,7 @@ var Base = class {
7343
7476
  }
7344
7477
  for (let y = 0; y < docs.length; y++) {
7345
7478
  const doc = docs[y];
7346
- const matches = this.getIndexedMatches(index, get6(doc, localField));
7479
+ const matches = this.getIndexedMatches(index, get7(doc, localField));
7347
7480
  const isolated = matches.map((m) => copyAuthorizedOutput(m));
7348
7481
  attachIncludeOutput(doc, path, op === "list" ? isolated : isolated[0]);
7349
7482
  }
@@ -7352,7 +7485,7 @@ var Base = class {
7352
7485
  async includeDocsCount(docs, include, parentAuthorization) {
7353
7486
  const { model, path, localField, foreignField, filter: _filters } = include;
7354
7487
  const svc = await this.getAuthorizedTargetService(model, "count", path, parentAuthorization);
7355
- const groups = prepareCountGroups(docs, (doc) => get6(doc, localField));
7488
+ const groups = prepareCountGroups(docs, (doc) => get7(doc, localField));
7356
7489
  const execution = this.relatedExecution(svc, include, parentAuthorization);
7357
7490
  const prepared = await prepareModelQuery(
7358
7491
  svc,
@@ -7483,7 +7616,6 @@ var Base = class {
7483
7616
  },
7484
7617
  requestOnlyServiceOptions({
7485
7618
  access: "read",
7486
- lean: true,
7487
7619
  includePermissions: false,
7488
7620
  includeFieldPermissions: false
7489
7621
  })
@@ -7558,7 +7690,6 @@ var Base = class {
7558
7690
  },
7559
7691
  requestOnlyServiceOptions({
7560
7692
  access: "read",
7561
- lean: true,
7562
7693
  includePermissions: false,
7563
7694
  includeFieldPermissions: false
7564
7695
  })
@@ -7643,7 +7774,6 @@ var Base = class {
7643
7774
  },
7644
7775
  requestOnlyServiceOptions({
7645
7776
  includeCount: false,
7646
- lean: true,
7647
7777
  includePermissions: false,
7648
7778
  includeFieldPermissions: false
7649
7779
  })
@@ -7758,7 +7888,7 @@ var Base = class {
7758
7888
  }
7759
7889
  let ret = result2.data;
7760
7890
  if (sqOptions.path) {
7761
- ret = isArray9(ret) ? flatten(ret.map((v) => get6(v, sqOptions.path))) : get6(ret, sqOptions.path);
7891
+ ret = isArray9(ret) ? flatten(ret.map((v) => get7(v, sqOptions.path))) : get7(ret, sqOptions.path);
7762
7892
  }
7763
7893
  if (sqOptions.compact) {
7764
7894
  ret = compact(castArray2(ret));
@@ -7777,7 +7907,7 @@ import {
7777
7907
  castArray as castArray3,
7778
7908
  cloneDeep as cloneDeep4,
7779
7909
  compact as compact2,
7780
- get as get11,
7910
+ get as get12,
7781
7911
  isArray as isArray10,
7782
7912
  isBoolean as isBoolean4,
7783
7913
  isPlainObject as isPlainObject21,
@@ -8140,6 +8270,7 @@ function copySubdocumentParent(parent) {
8140
8270
  init_permission();
8141
8271
  init_core_shared();
8142
8272
  init_finalize_model_output();
8273
+ init_permissions_alias();
8143
8274
 
8144
8275
  // src/acl/populate-target.ts
8145
8276
  var POPULATE_TARGET_PLAN = /* @__PURE__ */ Symbol("accessRouter.populateTargetPlan");
@@ -8202,7 +8333,7 @@ init_document();
8202
8333
  init_request_work();
8203
8334
  init_logger_helpers();
8204
8335
  init_request_complexity();
8205
- import { get as get8, isPlainObject as isPlainObject20, set as set9 } from "@web-ts-toolkit/utils";
8336
+ import { get as get9, isPlainObject as isPlainObject20, set as set9 } from "@web-ts-toolkit/utils";
8206
8337
  import { mongo as mongo4 } from "mongoose";
8207
8338
 
8208
8339
  // src/acl/select-resolution.ts
@@ -8530,7 +8661,7 @@ async function requestInputFields(args) {
8530
8661
  const prefix = configuration.modelPermissionPrefix ?? "";
8531
8662
  return collectModelRequestFields({
8532
8663
  req: args.binding.request,
8533
- permissionSchema: args.scopePath ? get8(configuration.permissionSchema, [args.scopePath, "sub"]) : configuration.permissionSchema,
8664
+ permissionSchema: args.scopePath ? get9(configuration.permissionSchema, [args.scopePath, "sub"]) : configuration.permissionSchema,
8534
8665
  access: args.access,
8535
8666
  permissions,
8536
8667
  grants,
@@ -8576,7 +8707,7 @@ init_lib();
8576
8707
  // src/services/model-subdocument-service.ts
8577
8708
  init_helpers();
8578
8709
  init_document();
8579
- import { get as get10 } from "@web-ts-toolkit/utils";
8710
+ import { get as get11 } from "@web-ts-toolkit/utils";
8580
8711
  init_public_admission();
8581
8712
 
8582
8713
  // src/acl/subdocument-authorization.ts
@@ -8585,7 +8716,7 @@ init_document();
8585
8716
  init_core_shared();
8586
8717
  init_request_complexity();
8587
8718
  init_public_admission();
8588
- import { get as get9 } from "@web-ts-toolkit/utils";
8719
+ import { get as get10 } from "@web-ts-toolkit/utils";
8589
8720
  init_authorization_snapshot();
8590
8721
  init_service_authorization();
8591
8722
  init_field_catalog();
@@ -8767,8 +8898,8 @@ async function subdocumentGateAllowed(service, gate) {
8767
8898
  let guard2;
8768
8899
  if (access.startsWith("subs.")) {
8769
8900
  const [, sub, op] = access.split(".");
8770
- guard2 = get9(configuration, `operationAccess.${access}`);
8771
- if (guard2 === void 0) guard2 = get9(configuration, `operationAccess.subs.${sub}`);
8901
+ guard2 = get10(configuration, `operationAccess.${access}`);
8902
+ if (guard2 === void 0) guard2 = get10(configuration, `operationAccess.subs.${sub}`);
8772
8903
  if (guard2 === void 0) guard2 = getCapturedAuthorizationOption(configuration, `operationAccess.${op}`);
8773
8904
  } else guard2 = getCapturedAuthorizationOption(configuration, `operationAccess.${access}`);
8774
8905
  return evaluateRouteGuard(
@@ -8840,8 +8971,7 @@ async function mutationParent(service, id, call) {
8840
8971
  const parent = await service.findRawParentDoc({
8841
8972
  filter: filter2,
8842
8973
  select: parentSelection(service, call),
8843
- populate: [],
8844
- lean: false
8974
+ populate: []
8845
8975
  });
8846
8976
  return parent ? { parent } : { error: denied2("not_found" /* NotFound */) };
8847
8977
  }
@@ -8890,18 +9020,17 @@ async function visibleMutationRows(service, call, parentId, rows) {
8890
9020
  const identity = { _id: parentId };
8891
9021
  const filter2 = await subdocumentRows(service, visibility.parent, identity, identity);
8892
9022
  if (filter2 === false) return [];
8893
- const parent = await service.findRawParentDoc({
9023
+ const parent = await getServiceExecutors(service).subdocumentVisibility({
8894
9024
  filter: filter2,
8895
9025
  select: parentSelection(service, call),
8896
- populate: [],
8897
- lean: true
9026
+ populate: []
8898
9027
  });
8899
9028
  if (!parent) return [];
8900
9029
  const selected = call.method === "create" ? {} : { _id: { $in: rows.map((row) => row._id) } };
8901
9030
  const read = await subdocumentRows(service, visibility.child, selected, selected, call.sub);
8902
9031
  const list = visibility.list ? await subdocumentRows(service, visibility.list, {}, {}, call.sub) : {};
8903
9032
  if (read === false || list === false) return [];
8904
- const visible = filterCollection(get10(parent, call.sub), intersectFilters(read, list));
9033
+ const visible = filterCollection(get11(parent, call.sub), intersectFilters(read, list));
8905
9034
  return await finalizeSubdocumentRows(service, call.output, parent, visible);
8906
9035
  } catch {
8907
9036
  return [];
@@ -8922,11 +9051,10 @@ async function listSub(service, id, sub, options) {
8922
9051
  const parent = await service.findRawParentDoc({
8923
9052
  filter: filter2,
8924
9053
  select: parentSelection(service, call),
8925
- populate: [],
8926
- lean: false
9054
+ populate: []
8927
9055
  });
8928
9056
  if (!parent) return denied2("not_found" /* NotFound */);
8929
- const rows = filterCollection(get10(parent, sub), childFilter);
9057
+ const rows = filterCollection(get11(parent, sub), childFilter);
8930
9058
  const data = await finalizeSubdocumentRows(service, call.output, parent, rows);
8931
9059
  return { success: true, kind: "list", code: "success" /* Success */, data, count: data.length };
8932
9060
  });
@@ -8945,11 +9073,10 @@ async function readSub(service, id, sub, subId, options) {
8945
9073
  const parent = await service.findRawParentDoc({
8946
9074
  filter: filter2,
8947
9075
  select: parentSelection(service, call),
8948
- populate: entries,
8949
- lean: false
9076
+ populate: entries
8950
9077
  });
8951
9078
  if (!parent) return denied2("not_found" /* NotFound */);
8952
- const row = findElement(get10(copySubdocumentParent(parent), sub), childFilter);
9079
+ const row = findElement(get11(copySubdocumentParent(parent), sub), childFilter);
8953
9080
  if (!row) return denied2("not_found" /* NotFound */);
8954
9081
  await service.finalizePopulateForSubParent({ [sub]: [row] }, entries, "subRead");
8955
9082
  const data = await finalizeSubdocumentRows(service, call.output, parent, [row]);
@@ -8969,7 +9096,7 @@ async function updateSub(service, persist, id, sub, subId, data, options) {
8969
9096
  const identity = { _id: subId };
8970
9097
  const filter2 = await subdocumentRows(service, call.child, identity, identity, sub);
8971
9098
  if (filter2 === false) return denied2();
8972
- const row = findElement(get10(parent, sub), filter2);
9099
+ const row = findElement(get11(parent, sub), filter2);
8973
9100
  if (!row) return denied2("not_found" /* NotFound */);
8974
9101
  const original = isolateDocForOutput(row);
8975
9102
  const admit = await inputAdmission(service, call, parent);
@@ -8996,7 +9123,7 @@ async function bulkUpdateSub(service, persist, id, sub, data, options) {
8996
9123
  const selected = { _id: { $in: data.map((row) => row._id) } };
8997
9124
  const filter2 = await subdocumentRows(service, call.child, selected, selected, sub);
8998
9125
  if (filter2 === false) return denied2();
8999
- const rows = filterCollection(get10(parent, sub), filter2);
9126
+ const rows = filterCollection(get11(parent, sub), filter2);
9000
9127
  const originals = rows.map((row) => isolateDocForOutput(row));
9001
9128
  const admit = await inputAdmission(service, call, parent);
9002
9129
  for (const [index, row] of rows.entries()) {
@@ -9024,7 +9151,7 @@ async function createSub(service, persist, id, sub, data, options) {
9024
9151
  const lookup = await mutationParent(service, id, call);
9025
9152
  if ("error" in lookup) return lookup.error;
9026
9153
  const { parent } = lookup;
9027
- const rows = get10(parent, sub);
9154
+ const rows = get11(parent, sub);
9028
9155
  const admit = await inputAdmission(service, call, parent);
9029
9156
  const allowed = (Array.isArray(data) ? data : [data]).map((row) => admit(row).allowedData);
9030
9157
  if (options?.addFirst) rows.unshift(...allowed);
@@ -9045,7 +9172,7 @@ async function deleteSub(service, persist, id, sub, subId, options) {
9045
9172
  const identity = { _id: subId };
9046
9173
  const filter2 = await subdocumentRows(service, call.child, identity, identity, sub);
9047
9174
  if (filter2 === false) return denied2();
9048
- const row = findElement(get10(parent, sub), filter2);
9175
+ const row = findElement(get11(parent, sub), filter2);
9049
9176
  if (!row) return denied2("not_found" /* NotFound */);
9050
9177
  await ("deleteOne" in row ? row.deleteOne?.() : row.remove?.());
9051
9178
  await persist(() => parent.save());
@@ -9054,7 +9181,7 @@ async function deleteSub(service, persist, id, sub, subId, options) {
9054
9181
  }
9055
9182
  async function getParentDoc(service, id, sub, args, options) {
9056
9183
  assertPublicAdmission({ args, options });
9057
- const { access = "read", lean = false } = options ?? {};
9184
+ const { access = "read" } = options ?? {};
9058
9185
  const identity = deepIsolateValue(await service.genIDFilter(id));
9059
9186
  const filter2 = intersectFilters(identity, await service.genFilter(access, deepIsolateValue(identity)));
9060
9187
  if (filter2 === false) return null;
@@ -9062,8 +9189,7 @@ async function getParentDoc(service, id, sub, args, options) {
9062
9189
  return service.findRawParentDoc({
9063
9190
  filter: filter2,
9064
9191
  select: access === "read" ? "" : sub,
9065
- populate,
9066
- lean
9192
+ populate
9067
9193
  });
9068
9194
  }
9069
9195
 
@@ -9093,8 +9219,7 @@ function resolveFindOneOptions(service, options = {}) {
9093
9219
  includePermissions,
9094
9220
  includeFieldPermissions: options.includeFieldPermissions ?? service.defaults.findOneOptions?.includeFieldPermissions ?? includePermissions,
9095
9221
  access: options.access ?? service.defaults.findOneOptions?.access ?? "read",
9096
- populateAccess: options.populateAccess ?? service.defaults.findOneOptions?.populateAccess,
9097
- lean: options.lean ?? service.defaults.findOneOptions?.lean ?? false
9222
+ populateAccess: options.populateAccess ?? service.defaults.findOneOptions?.populateAccess
9098
9223
  });
9099
9224
  }
9100
9225
  function resolveFindByIdArgs(service, args = {}) {
@@ -9111,8 +9236,7 @@ function resolveFindByIdOptions(service, options = {}) {
9111
9236
  includePermissions,
9112
9237
  includeFieldPermissions: options.includeFieldPermissions ?? service.defaults.findByIdOptions?.includeFieldPermissions ?? includePermissions,
9113
9238
  access: options.access ?? service.defaults.findByIdOptions?.access ?? "read",
9114
- populateAccess: options.populateAccess ?? service.defaults.findByIdOptions?.populateAccess,
9115
- lean: options.lean ?? service.defaults.findByIdOptions?.lean ?? false
9239
+ populateAccess: options.populateAccess ?? service.defaults.findByIdOptions?.populateAccess
9116
9240
  });
9117
9241
  }
9118
9242
  function resolveFindArgs(service, args = {}) {
@@ -9134,8 +9258,7 @@ function resolveFindOptions(service, options = {}) {
9134
9258
  includePermissions,
9135
9259
  includeFieldPermissions: options.includeFieldPermissions ?? service.defaults.findOptions?.includeFieldPermissions ?? includePermissions,
9136
9260
  includeCount: options.includeCount ?? service.defaults.findOptions?.includeCount ?? false,
9137
- populateAccess: options.populateAccess ?? service.defaults.findOptions?.populateAccess ?? "read",
9138
- lean: options.lean ?? service.defaults.findOptions?.lean ?? false
9261
+ populateAccess: options.populateAccess ?? service.defaults.findOptions?.populateAccess ?? "read"
9139
9262
  });
9140
9263
  }
9141
9264
  function resolveCreateArgs(service, args = {}) {
@@ -9249,7 +9372,7 @@ var Service = class extends Base {
9249
9372
  model: this.model.mongooseModel,
9250
9373
  modelName: this.modelName
9251
9374
  }),
9252
- configuration: () => this.requestRuntime.getModelInstance(this.modelName) ? captureModelAuthorizationConfiguration(this.requestRuntime, this.modelName) : { catalog: { paths: [] }, ...this.options },
9375
+ configuration: () => this.requestRuntime.getModelInstance(this.modelName) ? captureModelAuthorizationConfiguration(this.requestRuntime, this.modelName, this.options) : { catalog: { paths: [] }, ...this.options },
9253
9376
  permissions: () => this.requestCore.getPermissions?.() ?? new permission_default({}),
9254
9377
  parse: (filter2) => this.parseClientData(filter2, this.getCorrelatedExecState().scheduler),
9255
9378
  validate: (filter2, expanded) => {
@@ -9293,26 +9416,37 @@ var Service = class extends Base {
9293
9416
  data: await this.model.countDocuments(filter2),
9294
9417
  query: { filter: filter2 }
9295
9418
  }),
9296
- groupedCount: (filter2, field, input) => this.countPreparedByFieldValueGroups(field, input, filter2)
9419
+ groupedCount: (filter2, field, input) => this.countPreparedByFieldValueGroups(field, input, filter2),
9420
+ subdocumentVisibility: ({ filter: filter2, select, populate }) => this.model.findOne({ filter: filter2, select, populate, lean: true })
9297
9421
  });
9298
9422
  }
9299
9423
  get options() {
9300
9424
  return modelServiceOptions(this, () => this.getModelRouterOptions(this.modelName));
9301
9425
  }
9426
+ /**
9427
+ * Presentation/query defaults for this service instance; an explicit assignment
9428
+ * replaces the runtime defaults bag, not a per-bucket merge. Fetch mode belongs
9429
+ * to the owning model's hydration configuration and affects all its services.
9430
+ * Legacy method-option lean/hydration keys throw on assignment and before calls
9431
+ * if an assigned JavaScript bag is later mutated.
9432
+ */
9302
9433
  get defaults() {
9303
9434
  return this.defaultsOverride ?? this.options.defaults ?? {};
9304
9435
  }
9305
9436
  set defaults(value) {
9437
+ assertHydrationDefaults(value);
9306
9438
  this.defaultsOverride = value;
9307
9439
  }
9308
9440
  get baseFieldsExt() {
9309
9441
  return this.baseFields.concat(this.options.documentPermissionField);
9310
9442
  }
9443
+ /** Raw hydrated parent/null. Fetch mode is fixed, independent of model read settings. */
9311
9444
  findRawParentDoc(args) {
9312
9445
  return this.model.findOne({
9313
- ...args,
9314
9446
  filter: args.filter,
9315
- populate: args.populate
9447
+ select: args.select,
9448
+ populate: args.populate,
9449
+ lean: false
9316
9450
  });
9317
9451
  }
9318
9452
  createModelAdapter(modelName) {
@@ -9417,6 +9551,7 @@ var Service = class extends Base {
9417
9551
  }
9418
9552
  });
9419
9553
  const output = deepIsolateValue(finalized);
9554
+ removeGeneratedPermissionsAlias(output);
9420
9555
  const includeOrigins = restoreIncludeOutput(args.doc, output);
9421
9556
  const field = configuration.documentPermissionField ?? "_permissions";
9422
9557
  unsetDocPath(output, field);
@@ -9430,10 +9565,20 @@ var Service = class extends Base {
9430
9565
  const map2 = (paths) => paths.length ? Object.fromEntries(paths.map((path) => [path, true])) : { $: "_" };
9431
9566
  set10(output, `${field}._view`, map2(views));
9432
9567
  set10(output, `${field}._edit`, map2(edits));
9433
- } else if (!args.includePermissions) this.addEmptyPermissions(output);
9434
- stripUnexposedDocPermissions(this.modelName, output);
9568
+ } else if (!args.includePermissions) set10(output, field, { _view: { $: "_" }, _edit: { $: "_" } });
9569
+ const exposed = configuration.exposedDocPermissionKeys;
9570
+ if (exposed) {
9571
+ const metadata = get12(output, field);
9572
+ set10(
9573
+ output,
9574
+ field,
9575
+ Object.fromEntries(
9576
+ Object.entries(metadata).filter(([key]) => key === "_view" || key === "_edit" || exposed.includes(key))
9577
+ )
9578
+ );
9579
+ }
9580
+ attachPermissionsAlias(output, field);
9435
9581
  }
9436
- this.preservePermissionsVirtual(getIncludeOriginal(args.doc), output, args.lean);
9437
9582
  transferDocumentAuthorizationGraph(finalized, output, includeOrigins);
9438
9583
  return {
9439
9584
  data: output,
@@ -9648,36 +9793,6 @@ var Service = class extends Base {
9648
9793
  stripVirtualsFromFilterForSnapshot(filter2, snapshot) {
9649
9794
  return stripVirtualKeysFromFilter(filter2, snapshot);
9650
9795
  }
9651
- /**
9652
- * Preserve the `permissions` Mongoose virtual (from `permissionsPlugin`) for
9653
- * hydrated outputs. `isolateDocForOutput` uses `toObject({ virtuals: false })`
9654
- * so Mongoose getter virtuals never leak into package-virtual planning;
9655
- * `lean: true` therefore drops them (explicit parity rule). For `lean: false`
9656
- * (hydrated Mongoose documents) the historical contract exposes
9657
- * `doc.permissions` as an alias of the document-permission field. The shared
9658
- * finalizer keeps only the document-permission field, so restore the alias
9659
- * here for backward compatibility when the input was hydrated and the
9660
- * virtual existed. Lean outputs stay without the virtual. Models without
9661
- * the plugin never had the virtual and stay unchanged.
9662
- */
9663
- preservePermissionsVirtual(originalDoc, finalized, lean) {
9664
- try {
9665
- if (lean) return;
9666
- if (!isDocument2(originalDoc)) return;
9667
- const schema = originalDoc.schema;
9668
- if (!schema?.virtualpath("permissions")) return;
9669
- const docField = this.options?.documentPermissionField ?? "_permissions";
9670
- if (docField in finalized && !("permissions" in finalized)) {
9671
- Object.defineProperty(finalized, "permissions", {
9672
- value: finalized[docField],
9673
- enumerable: false,
9674
- writable: true,
9675
- configurable: true
9676
- });
9677
- }
9678
- } catch {
9679
- }
9680
- }
9681
9796
  /**
9682
9797
  * VIRT-05 populate + association helpers.
9683
9798
  *
@@ -9714,7 +9829,7 @@ var Service = class extends Base {
9714
9829
  return docs.map((doc) => {
9715
9830
  try {
9716
9831
  const plain = toObject(doc);
9717
- const val = get11(plain, associationField);
9832
+ const val = get12(plain, associationField);
9718
9833
  return deepIsolateValue(val);
9719
9834
  } catch {
9720
9835
  return void 0;
@@ -9899,7 +10014,7 @@ var Service = class extends Base {
9899
10014
  child = getDocValue(current, key);
9900
10015
  if (child === void 0) {
9901
10016
  try {
9902
- child = get11(current, key);
10017
+ child = get12(current, key);
9903
10018
  } catch {
9904
10019
  return;
9905
10020
  }
@@ -10035,7 +10150,7 @@ var Service = class extends Base {
10035
10150
  async findOnePrepared(execution, filter2, args, options) {
10036
10151
  if (filter2 === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */, query: { filter: filter2 } };
10037
10152
  const { select: requestedSelect, sort, populate, include } = this.resolveFindOneArgs(args);
10038
- const { includePermissions, includeFieldPermissions, access, populateAccess, lean } = this.resolveFindOneOptions(options);
10153
+ const { includePermissions, includeFieldPermissions, access, populateAccess } = this.resolveFindOneOptions(options);
10039
10154
  const state = readServiceExecution(this, execution);
10040
10155
  const virtualSnapshot = readServiceAuthorization(state.authorization, state.binding).configuration;
10041
10156
  let processedInclude;
@@ -10097,7 +10212,7 @@ var Service = class extends Base {
10097
10212
  return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: sortErrors, query };
10098
10213
  }
10099
10214
  }
10100
- let doc = await this.model.findOne({ ...query, select: dbSelect, lean });
10215
+ let doc = await this.model.findOne({ ...query, select: dbSelect, lean: state.hydration === "lean" });
10101
10216
  if (!doc) {
10102
10217
  this.completeOp("findOne", startedAt, "not_found" /* NotFound */, _filter);
10103
10218
  return { success: false, kind: "error", code: "not_found" /* NotFound */, query };
@@ -10160,7 +10275,6 @@ var Service = class extends Base {
10160
10275
  context,
10161
10276
  includePermissions,
10162
10277
  includeFieldPermissions,
10163
- lean,
10164
10278
  sharedGate: findOneGate
10165
10279
  });
10166
10280
  } catch (error2) {
@@ -10185,7 +10299,7 @@ var Service = class extends Base {
10185
10299
  try {
10186
10300
  this.admitServiceCall(args, options);
10187
10301
  const { select, populate, include } = this.resolveFindByIdArgs(args);
10188
- const { skim, includePermissions, includeFieldPermissions, access, populateAccess, lean } = this.resolveFindByIdOptions(options);
10302
+ const { skim, includePermissions, includeFieldPermissions, access, populateAccess } = this.resolveFindByIdOptions(options);
10189
10303
  const execution = createServiceExecution(
10190
10304
  this,
10191
10305
  {
@@ -10197,7 +10311,11 @@ var Service = class extends Base {
10197
10311
  },
10198
10312
  options?.authorization,
10199
10313
  "service",
10200
- this.captureRelated(args, this.defaults.findByIdArgs)
10314
+ this.captureRelated(args, this.defaults.findByIdArgs),
10315
+ void 0,
10316
+ void 0,
10317
+ void 0,
10318
+ "findById"
10201
10319
  );
10202
10320
  const filter2 = readModelIdentifier(this, execution, await resolveModelIdentifier(this, execution, id));
10203
10321
  const query = await prepareModelQuery(this, execution, { kind: "client-read", filter: filter2 });
@@ -10210,7 +10328,7 @@ var Service = class extends Base {
10210
10328
  populate,
10211
10329
  include
10212
10330
  },
10213
- { skim, includePermissions, includeFieldPermissions, access, populateAccess, lean }
10331
+ { skim, includePermissions, includeFieldPermissions, access, populateAccess }
10214
10332
  );
10215
10333
  } catch (error2) {
10216
10334
  const result2 = this.getClientRequestErrorResult(error2);
@@ -10256,7 +10374,7 @@ var Service = class extends Base {
10256
10374
  page,
10257
10375
  pageSize
10258
10376
  } = this.resolveFindArgs(args);
10259
- const { includePermissions, includeFieldPermissions, includeCount, populateAccess, lean } = this.resolveFindOptions(options);
10377
+ const { includePermissions, includeFieldPermissions, includeCount, populateAccess } = this.resolveFindOptions(options);
10260
10378
  let processedInclude;
10261
10379
  try {
10262
10380
  processedInclude = this.processInclude(include);
@@ -10331,7 +10449,7 @@ var Service = class extends Base {
10331
10449
  ...query,
10332
10450
  select: dbSelect,
10333
10451
  hardLimit: this.options.listHardLimit,
10334
- lean
10452
+ lean: state.hydration === "lean"
10335
10453
  });
10336
10454
  const capturedAssociation = findAssociationField ? this.captureAssociationValues(docs, findAssociationField) : void 0;
10337
10455
  const correlatedSnapshots = docs.map((doc) => cloneDeep4(toObject(doc)));
@@ -10406,7 +10524,6 @@ var Service = class extends Base {
10406
10524
  context: contexts[i],
10407
10525
  includePermissions,
10408
10526
  includeFieldPermissions,
10409
- lean,
10410
10527
  sharedGate,
10411
10528
  privateAssociationField
10412
10529
  });
@@ -10596,7 +10713,6 @@ var Service = class extends Base {
10596
10713
  context: contexts[index],
10597
10714
  includePermissions,
10598
10715
  includeFieldPermissions,
10599
- lean: false,
10600
10716
  sharedGate: createGate
10601
10717
  });
10602
10718
  outputContexts[index] = output.context;
@@ -10659,8 +10775,7 @@ var Service = class extends Base {
10659
10775
  doc: data,
10660
10776
  plan: newPlan,
10661
10777
  context: newContext,
10662
- includePermissions,
10663
- lean: false
10778
+ includePermissions
10664
10779
  });
10665
10780
  return {
10666
10781
  success: true,
@@ -10828,8 +10943,7 @@ var Service = class extends Base {
10828
10943
  plan: updatePlan,
10829
10944
  context,
10830
10945
  includePermissions,
10831
- includeFieldPermissions,
10832
- lean: false
10946
+ includeFieldPermissions
10833
10947
  });
10834
10948
  const outputDoc = decorate ? await this.hookGate.run(() => decorate(output.data, output.context)) : output.data;
10835
10949
  this.completeOp("updateOne", startedAt, "success" /* Success */, _filter);
@@ -11411,6 +11525,7 @@ var Service = class extends Base {
11411
11525
  async deleteSub(id, sub, subId, options) {
11412
11526
  return deleteSub(this, this.persist, id, sub, subId, options);
11413
11527
  }
11528
+ /** Raw hydrated parent/null, with row policy and populate; no finalized permission metadata. */
11414
11529
  async getParentDoc(id, sub, args, options) {
11415
11530
  return getParentDoc(this, id, sub, args, options);
11416
11531
  }
@@ -11418,6 +11533,7 @@ var Service = class extends Base {
11418
11533
 
11419
11534
  // src/services/public-service.ts
11420
11535
  init_helpers();
11536
+ init_permissions_alias();
11421
11537
  import { pick as pick3 } from "@web-ts-toolkit/utils";
11422
11538
  init_public_admission();
11423
11539
  var PublicService = class extends Service {
@@ -11456,36 +11572,61 @@ var PublicService = class extends Service {
11456
11572
  const admission = this.admitPublicCall({ args, options, filter: filter2 });
11457
11573
  if (admission) return admission;
11458
11574
  const { select, populate, include, sort, skip, limit, page, pageSize, tasks } = this.resolvePublicListArgs(args);
11459
- const { skim, includePermissions, includeFieldPermissions, includeCount, populateAccess, lean } = this.resolvePublicListOptions(options);
11460
- const result2 = await this.find(
11461
- filter2,
11462
- { select, populate, include, sort, skip, limit, page, pageSize },
11463
- requestOnlyServiceOptions({
11464
- skim,
11465
- includePermissions,
11466
- includeFieldPermissions,
11467
- includeCount,
11468
- populateAccess,
11469
- lean
11470
- }),
11471
- async (doc, context) => {
11472
- doc = toObject(doc);
11473
- return this.decorate(doc, "list", context);
11575
+ const { skim, includePermissions, includeFieldPermissions, includeCount, populateAccess } = this.resolvePublicListOptions(options);
11576
+ try {
11577
+ const execution = withExecutionHydration(
11578
+ this,
11579
+ createServiceExecution(
11580
+ this,
11581
+ {
11582
+ operation: "list",
11583
+ rowAccess: "list",
11584
+ virtualAccess: "list",
11585
+ outputAccess: "list",
11586
+ docPermissionsAccess: "list"
11587
+ },
11588
+ requestOnlyServiceOptions({}).authorization,
11589
+ "service",
11590
+ this.captureRelated({ populate, include }, this.defaults.findArgs)
11591
+ ),
11592
+ "publicList"
11593
+ );
11594
+ const query = await prepareModelQuery(this, execution, { kind: "client-read", filter: filter2 });
11595
+ const result2 = await executePreparedFind(
11596
+ this,
11597
+ execution,
11598
+ query,
11599
+ { select, populate, include, sort, skip, limit, page, pageSize },
11600
+ requestOnlyServiceOptions({
11601
+ skim,
11602
+ includePermissions,
11603
+ includeFieldPermissions,
11604
+ includeCount,
11605
+ populateAccess
11606
+ }),
11607
+ async (doc, context) => {
11608
+ doc = toObject(doc);
11609
+ return this.decorate(doc, "list", context);
11610
+ }
11611
+ );
11612
+ if (!result2.success) {
11613
+ return result2;
11474
11614
  }
11475
- );
11476
- if (!result2.success) {
11477
- return result2;
11615
+ const docs = await this.decorateAll(result2.data, "list", {
11616
+ mongooseModel: this.model.mongooseModel,
11617
+ modelName: this.modelName,
11618
+ operation: "list",
11619
+ resolvedQuery: result2.query
11620
+ });
11621
+ const transformedDocs = docs.map(
11622
+ (row) => this.runTasks(row, tasks)
11623
+ );
11624
+ return { ...result2, data: transformedDocs };
11625
+ } catch (error2) {
11626
+ const result2 = this.getClientRequestErrorResult(error2);
11627
+ if (result2) return result2;
11628
+ throw error2;
11478
11629
  }
11479
- const docs = await this.decorateAll(result2.data, "list", {
11480
- mongooseModel: this.model.mongooseModel,
11481
- modelName: this.modelName,
11482
- operation: "list",
11483
- resolvedQuery: result2.query
11484
- });
11485
- const transformedDocs = docs.map(
11486
- (row) => this.runTasks(row, tasks)
11487
- );
11488
- return { ...result2, data: transformedDocs };
11489
11630
  }
11490
11631
  async _create(data, args, options) {
11491
11632
  const admission = this.admitPublicCall({ args, options, data });
@@ -11501,7 +11642,7 @@ var PublicService = class extends Service {
11501
11642
  let d = toObject(doc);
11502
11643
  d = await this.decorate(d, "create", context);
11503
11644
  d = this.runTasks(d, tasks);
11504
- if (select) d = pick3(d, [...normalizeSelect(select), ...this.baseFieldsExt]);
11645
+ if (select) d = copyPermissionsAlias(d, pick3(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
11505
11646
  return d;
11506
11647
  }
11507
11648
  );
@@ -11522,21 +11663,25 @@ var PublicService = class extends Service {
11522
11663
  const admission = this.admitPublicCall({ args, options });
11523
11664
  if (admission) return admission;
11524
11665
  const { select, populate, include, tasks } = this.resolvePublicReadArgs(args);
11525
- const { skim, includePermissions, includeFieldPermissions, tryList, populateAccess, lean } = this.resolvePublicReadOptions(options);
11666
+ const { skim, includePermissions, includeFieldPermissions, tryList, populateAccess } = this.resolvePublicReadOptions(options);
11526
11667
  try {
11527
11668
  let access = "read";
11528
- let execution = createServiceExecution(
11669
+ let execution = withExecutionHydration(
11529
11670
  this,
11530
- {
11531
- operation: "read",
11532
- rowAccess: access,
11533
- virtualAccess: access,
11534
- outputAccess: access,
11535
- docPermissionsAccess: access
11536
- },
11537
- requestOnlyServiceOptions({}).authorization,
11538
- "service",
11539
- this.captureRelated({ populate, include }, this.defaults.findOneArgs)
11671
+ createServiceExecution(
11672
+ this,
11673
+ {
11674
+ operation: "read",
11675
+ rowAccess: access,
11676
+ virtualAccess: access,
11677
+ outputAccess: access,
11678
+ docPermissionsAccess: access
11679
+ },
11680
+ requestOnlyServiceOptions({}).authorization,
11681
+ "service",
11682
+ this.captureRelated({ populate, include }, this.defaults.findOneArgs)
11683
+ ),
11684
+ "publicRead"
11540
11685
  );
11541
11686
  const identifier = await resolveModelIdentifier(this, execution, id);
11542
11687
  const query = await prepareModelQuery(this, execution, {
@@ -11548,7 +11693,7 @@ var PublicService = class extends Service {
11548
11693
  execution,
11549
11694
  query,
11550
11695
  { select, populate, include },
11551
- requestOnlyServiceOptions({ skim, includePermissions, includeFieldPermissions, access, populateAccess, lean })
11696
+ requestOnlyServiceOptions({ skim, includePermissions, includeFieldPermissions, access, populateAccess })
11552
11697
  );
11553
11698
  if (!result2.success && (result2.code === "bad_request" /* BadRequest */ || result2.code === "forbidden" /* Forbidden */)) return result2;
11554
11699
  if (tryList && (!result2.success || !result2.data)) {
@@ -11578,8 +11723,7 @@ var PublicService = class extends Service {
11578
11723
  includePermissions,
11579
11724
  includeFieldPermissions,
11580
11725
  access,
11581
- populateAccess,
11582
- lean
11726
+ populateAccess
11583
11727
  })
11584
11728
  );
11585
11729
  }
@@ -11600,43 +11744,79 @@ var PublicService = class extends Service {
11600
11744
  const admission = this.admitPublicCall({ args, options, filter: filter2 });
11601
11745
  if (admission) return admission;
11602
11746
  const { select, sort, populate, include, tasks } = this.resolvePublicReadFilterArgs(args);
11603
- const { skim, includePermissions, includeFieldPermissions, tryList, populateAccess, lean } = this.resolvePublicReadOptions(options);
11747
+ const { skim, includePermissions, includeFieldPermissions, tryList, populateAccess } = this.resolvePublicReadOptions(options);
11604
11748
  let access = "read";
11605
- let result2 = await this.findOne(
11606
- filter2,
11607
- {
11608
- select,
11609
- sort,
11610
- populate,
11611
- include
11612
- },
11613
- requestOnlyServiceOptions({ skim, includePermissions, includeFieldPermissions, access, populateAccess, lean })
11614
- );
11615
- if (!result2.success && (result2.code === "bad_request" /* BadRequest */ || result2.code === "forbidden" /* Forbidden */)) return result2;
11616
- if (tryList && (!result2.success || !result2.data)) {
11617
- const listAllowed = await this.requestCore.isAllowed(this.modelName, "list");
11618
- if (!listAllowed) {
11619
- return { success: false, kind: "error", code: "unauthorized" /* Unauthorized */, errors: ["Unauthorized"] };
11620
- }
11621
- access = "list";
11622
- result2 = await this.findOne(
11623
- filter2,
11749
+ try {
11750
+ let execution = withExecutionHydration(
11751
+ this,
11752
+ createServiceExecution(
11753
+ this,
11754
+ {
11755
+ operation: "read",
11756
+ rowAccess: access,
11757
+ virtualAccess: access,
11758
+ outputAccess: access,
11759
+ docPermissionsAccess: access
11760
+ },
11761
+ requestOnlyServiceOptions({}).authorization,
11762
+ "service",
11763
+ this.captureRelated({ populate, include }, this.defaults.findOneArgs)
11764
+ ),
11765
+ "publicRead"
11766
+ );
11767
+ const query = await prepareModelQuery(this, execution, { kind: "client-read", filter: filter2 });
11768
+ let result2 = await executePreparedFindOne(
11769
+ this,
11770
+ execution,
11771
+ query,
11624
11772
  {
11625
11773
  select,
11626
11774
  sort,
11627
11775
  populate,
11628
11776
  include
11629
11777
  },
11630
- requestOnlyServiceOptions({ skim, includePermissions, includeFieldPermissions, access, populateAccess, lean })
11778
+ requestOnlyServiceOptions({ skim, includePermissions, includeFieldPermissions, access, populateAccess })
11631
11779
  );
11780
+ if (!result2.success && (result2.code === "bad_request" /* BadRequest */ || result2.code === "forbidden" /* Forbidden */)) return result2;
11781
+ if (tryList && (!result2.success || !result2.data)) {
11782
+ const listAllowed = await this.requestCore.isAllowed(this.modelName, "list");
11783
+ if (!listAllowed) {
11784
+ return { success: false, kind: "error", code: "unauthorized" /* Unauthorized */, errors: ["Unauthorized"] };
11785
+ }
11786
+ access = "list";
11787
+ execution = deriveServiceExecution(this, execution, {
11788
+ operation: "read",
11789
+ rowAccess: access,
11790
+ virtualAccess: access,
11791
+ outputAccess: access,
11792
+ docPermissionsAccess: access
11793
+ });
11794
+ const fallback = await prepareModelQuery(this, execution, { kind: "client-read", filter: filter2 });
11795
+ result2 = await executePreparedFindOne(
11796
+ this,
11797
+ execution,
11798
+ fallback,
11799
+ {
11800
+ select,
11801
+ sort,
11802
+ populate,
11803
+ include
11804
+ },
11805
+ requestOnlyServiceOptions({ skim, includePermissions, includeFieldPermissions, access, populateAccess })
11806
+ );
11807
+ }
11808
+ if (!result2.success) {
11809
+ return result2;
11810
+ }
11811
+ let doc = toObject(result2.data);
11812
+ doc = await this.decorate(doc, access, result2.context);
11813
+ doc = this.runTasks(doc, tasks);
11814
+ return { ...result2, data: doc };
11815
+ } catch (error2) {
11816
+ const result2 = this.getClientRequestErrorResult(error2);
11817
+ if (result2) return result2;
11818
+ throw error2;
11632
11819
  }
11633
- if (!result2.success) {
11634
- return result2;
11635
- }
11636
- let doc = toObject(result2.data);
11637
- doc = await this.decorate(doc, access, result2.context);
11638
- doc = this.runTasks(doc, tasks);
11639
- return { ...result2, data: doc };
11640
11820
  }
11641
11821
  async _update(id, data, args, options) {
11642
11822
  const admission = this.admitPublicCall({ args, options, data });
@@ -11657,8 +11837,8 @@ var PublicService = class extends Service {
11657
11837
  let d = toObject(doc);
11658
11838
  d = await this.decorate(d, "update", context);
11659
11839
  d = this.runTasks(d, tasks);
11660
- if (select) d = pick3(d, [...normalizeSelect(select), ...this.baseFieldsExt]);
11661
- else if (!returningAll) d = pick3(d, [...Object.keys(data), "_id"]);
11840
+ if (select) d = copyPermissionsAlias(d, pick3(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
11841
+ else if (!returningAll) d = copyPermissionsAlias(d, pick3(d, [...Object.keys(data), "_id"]));
11662
11842
  return d;
11663
11843
  }
11664
11844
  );
@@ -11738,8 +11918,8 @@ var PublicService = class extends Service {
11738
11918
  let d = toObject(doc);
11739
11919
  d = await this.decorate(d, "update", context);
11740
11920
  d = this.runTasks(d, tasks2);
11741
- if (select2) d = pick3(d, [...normalizeSelect(select2), ...this.baseFieldsExt]);
11742
- else if (!returningAll) d = pick3(d, [...Object.keys(otherData), "_id"]);
11921
+ if (select2) d = copyPermissionsAlias(d, pick3(d, [...normalizeSelect(select2), ...this.baseFieldsExt]));
11922
+ else if (!returningAll) d = copyPermissionsAlias(d, pick3(d, [...Object.keys(otherData), "_id"]));
11743
11923
  return d;
11744
11924
  }
11745
11925
  );
@@ -11768,7 +11948,7 @@ var PublicService = class extends Service {
11768
11948
  let d = toObject(doc);
11769
11949
  d = await this.decorate(d, "create", context);
11770
11950
  d = this.runTasks(d, tasks);
11771
- if (select) d = pick3(d, [...normalizeSelect(select), ...this.baseFieldsExt]);
11951
+ if (select) d = copyPermissionsAlias(d, pick3(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
11772
11952
  return d;
11773
11953
  }
11774
11954
  );
@@ -11829,8 +12009,7 @@ var PublicService = class extends Service {
11829
12009
  includePermissions,
11830
12010
  includeFieldPermissions: options.includeFieldPermissions ?? this.defaults.publicListOptions?.includeFieldPermissions ?? includePermissions,
11831
12011
  includeCount: options.includeCount ?? this.defaults.publicListOptions?.includeCount ?? false,
11832
- populateAccess: options.populateAccess ?? this.defaults.publicListOptions?.populateAccess ?? "read",
11833
- lean: options.lean ?? this.defaults.publicListOptions?.lean ?? true
12012
+ populateAccess: options.populateAccess ?? this.defaults.publicListOptions?.populateAccess ?? "read"
11834
12013
  };
11835
12014
  }
11836
12015
  resolvePublicCreateArgs(args = {}) {
@@ -11871,8 +12050,7 @@ var PublicService = class extends Service {
11871
12050
  includePermissions,
11872
12051
  includeFieldPermissions: options.includeFieldPermissions ?? this.defaults.publicReadOptions?.includeFieldPermissions ?? includePermissions,
11873
12052
  tryList: options.tryList ?? this.defaults.publicReadOptions?.tryList ?? true,
11874
- populateAccess: options.populateAccess ?? this.defaults.publicReadOptions?.populateAccess,
11875
- lean: options.lean ?? this.defaults.publicReadOptions?.lean ?? false
12053
+ populateAccess: options.populateAccess ?? this.defaults.publicReadOptions?.populateAccess
11876
12054
  };
11877
12055
  }
11878
12056
  resolvePublicUpdateArgs(args = {}) {
@@ -12054,7 +12232,13 @@ var DataService = class {
12054
12232
  init_helpers();
12055
12233
 
12056
12234
  // src/processors.ts
12057
- import { cloneDeep as cloneDeep5, forEach as forEach5, get as get12, hasOwn as hasOwn3, isArray as isArray11, isPlainObject as isPlainObject22, map, set as set11 } from "@web-ts-toolkit/utils";
12235
+ init_permissions_alias();
12236
+ import { cloneDeep as cloneDeep5, forEach as forEach5, get as get13, hasOwn as hasOwn3, isArray as isArray11, isPlainObject as isPlainObject22, map, set as set11 } from "@web-ts-toolkit/utils";
12237
+ function cloneProcessorValue(value) {
12238
+ const copy = cloneDeep5(value);
12239
+ copyPermissionsAliasGraph(value, copy);
12240
+ return copy;
12241
+ }
12058
12242
  var UNSAFE_PATH_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
12059
12243
  var DEFAULT_MAX_SLICE = 1e3;
12060
12244
  var DEFAULT_MASK_REPLACEMENT = "***";
@@ -12111,7 +12295,7 @@ function resolveLeafParents(obj, src) {
12111
12295
  var copyAndDepopulate = (docObject, operations, options = { mutable: true, idField: "_id" }) => {
12112
12296
  const mutable = options.mutable !== false;
12113
12297
  const idField = options.idField ?? "_id";
12114
- const obj = mutable ? docObject : cloneDeep5(docObject);
12298
+ const obj = mutable ? docObject : cloneProcessorValue(docObject);
12115
12299
  forEach5(Array.isArray(operations) ? operations : [], (op) => {
12116
12300
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
12117
12301
  const src = op.src;
@@ -12143,7 +12327,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
12143
12327
  return;
12144
12328
  }
12145
12329
  } else if (isPlainObject22(leaf)) {
12146
- const id = get12(leaf, idField);
12330
+ const id = get13(leaf, idField);
12147
12331
  if (id === void 0) {
12148
12332
  failMissingId(src);
12149
12333
  }
@@ -12173,7 +12357,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
12173
12357
  };
12174
12358
  var copyPaths = (docObject, operations, options = { mutable: true }) => {
12175
12359
  const mutable = options.mutable !== false;
12176
- const obj = mutable ? docObject : cloneDeep5(docObject);
12360
+ const obj = mutable ? docObject : cloneProcessorValue(docObject);
12177
12361
  forEach5(Array.isArray(operations) ? operations : [], (op) => {
12178
12362
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
12179
12363
  const src = op.src;
@@ -12184,14 +12368,14 @@ var copyPaths = (docObject, operations, options = { mutable: true }) => {
12184
12368
  if (src === dest) return;
12185
12369
  forEach5(resolveLeafParents(obj, src), ({ parent, leaf }) => {
12186
12370
  if (!hasOwn3(parent, leaf)) return;
12187
- set11(parent, dest, cloneDeep5(parent[leaf]));
12371
+ set11(parent, dest, cloneProcessorValue(parent[leaf]));
12188
12372
  });
12189
12373
  });
12190
12374
  return obj;
12191
12375
  };
12192
12376
  var movePaths = (docObject, operations, options = { mutable: true }) => {
12193
12377
  const mutable = options.mutable !== false;
12194
- const obj = mutable ? docObject : cloneDeep5(docObject);
12378
+ const obj = mutable ? docObject : cloneProcessorValue(docObject);
12195
12379
  forEach5(Array.isArray(operations) ? operations : [], (op) => {
12196
12380
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
12197
12381
  const src = op.src;
@@ -12202,7 +12386,7 @@ var movePaths = (docObject, operations, options = { mutable: true }) => {
12202
12386
  if (src === dest) return;
12203
12387
  forEach5(resolveLeafParents(obj, src), ({ parent, leaf }) => {
12204
12388
  if (!hasOwn3(parent, leaf)) return;
12205
- const value = cloneDeep5(parent[leaf]);
12389
+ const value = cloneProcessorValue(parent[leaf]);
12206
12390
  set11(parent, dest, value);
12207
12391
  if (dest === leaf || dest.startsWith(`${leaf}.`)) return;
12208
12392
  delete parent[leaf];
@@ -12214,7 +12398,7 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
12214
12398
  const mutable = options.mutable !== false;
12215
12399
  const maxSlice = options.maxSlice ?? DEFAULT_MAX_SLICE;
12216
12400
  assertNonNegativeSafeInteger(maxSlice, "maxSlice", "sliceArrays");
12217
- const obj = mutable ? docObject : cloneDeep5(docObject);
12401
+ const obj = mutable ? docObject : cloneProcessorValue(docObject);
12218
12402
  forEach5(Array.isArray(operations) ? operations : [], (op) => {
12219
12403
  if (!op || typeof op.src !== "string") return;
12220
12404
  const src = op.src;
@@ -12248,7 +12432,7 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
12248
12432
  };
12249
12433
  var countPaths = (docObject, operations, options = { mutable: true }) => {
12250
12434
  const mutable = options.mutable !== false;
12251
- const obj = mutable ? docObject : cloneDeep5(docObject);
12435
+ const obj = mutable ? docObject : cloneProcessorValue(docObject);
12252
12436
  forEach5(Array.isArray(operations) ? operations : [], (op) => {
12253
12437
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
12254
12438
  const src = op.src;
@@ -12276,7 +12460,7 @@ var countPaths = (docObject, operations, options = { mutable: true }) => {
12276
12460
  };
12277
12461
  var maskPaths = (docObject, operations, options = { mutable: true }) => {
12278
12462
  const mutable = options.mutable !== false;
12279
- const obj = mutable ? docObject : cloneDeep5(docObject);
12463
+ const obj = mutable ? docObject : cloneProcessorValue(docObject);
12280
12464
  forEach5(Array.isArray(operations) ? operations : [], (op) => {
12281
12465
  if (!op || typeof op.src !== "string") return;
12282
12466
  const src = op.src;
@@ -14062,8 +14246,7 @@ var rootModelListOptionsSchema = z5.object({
14062
14246
  includePermissions: z5.boolean().optional(),
14063
14247
  includeFieldPermissions: z5.boolean().optional(),
14064
14248
  includeCount: z5.boolean().optional(),
14065
- populateAccess: populateAccessSchema.optional(),
14066
- lean: z5.boolean().optional()
14249
+ populateAccess: populateAccessSchema.optional()
14067
14250
  }).passthrough();
14068
14251
  var rootModelReadArgsSchema = z5.object({
14069
14252
  select: projectionSchema.optional(),
@@ -14079,8 +14262,7 @@ var rootModelReadOptionsSchema = z5.object({
14079
14262
  includePermissions: z5.boolean().optional(),
14080
14263
  includeFieldPermissions: z5.boolean().optional(),
14081
14264
  tryList: z5.boolean().optional(),
14082
- populateAccess: populateAccessSchema.optional(),
14083
- lean: z5.boolean().optional()
14265
+ populateAccess: populateAccessSchema.optional()
14084
14266
  }).passthrough();
14085
14267
  var rootModelCreateArgsSchema = z5.object({
14086
14268
  select: projectionSchema.optional(),
@@ -15712,8 +15894,8 @@ var RootRouter = class {
15712
15894
  const presentation = ["skim", "includePermissions", "includeFieldPermissions"];
15713
15895
  const optionKeys = {
15714
15896
  new: presentation,
15715
- list: [...presentation, "includeCount", "populateAccess", "lean"],
15716
- read: [...presentation, "populateAccess", "lean", "tryList"],
15897
+ list: [...presentation, "includeCount", "populateAccess"],
15898
+ read: [...presentation, "populateAccess", "tryList"],
15717
15899
  create: [...presentation, "populateAccess"],
15718
15900
  update: [...presentation, "populateAccess", "returningAll"],
15719
15901
  upsert: [...presentation, "populateAccess", "returningAll"]