@web-ts-toolkit/access-router 0.55.0 → 0.57.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.js CHANGED
@@ -2161,9 +2161,34 @@ var init_field_catalog = __esm({
2161
2161
  }
2162
2162
  });
2163
2163
 
2164
+ // src/acl/populate-target-configuration.ts
2165
+ function capturePopulateTargetConfiguration(runtime, modelName, source, proposedOptions) {
2166
+ const label = `Populate target "${modelName}" for ${source}`;
2167
+ if (!proposedOptions && !runtime.hasModel(modelName))
2168
+ authorizationError(
2169
+ `${label} must be configured first in this runtime; register its Mongoose model and setModelOptions with an object permissionSchema`
2170
+ );
2171
+ const model = runtime.getModelInstance(modelName);
2172
+ if (!model) authorizationError(`${label} requires an actual registered Mongoose model in this runtime`);
2173
+ const options = proposedOptions ?? runtime.getModelOptions(modelName);
2174
+ const permissionSchema = options.permissionSchema === void 0 ? runtime.getDefaultModelOption("permissionSchema") : options.permissionSchema;
2175
+ if (!(0, import_utils15.isPlainObject)(permissionSchema))
2176
+ authorizationError(
2177
+ `${label} requires an effective object permissionSchema; configure the model or runtime model defaults ({} explicitly closes business fields)`
2178
+ );
2179
+ return { model, options: { ...options, permissionSchema } };
2180
+ }
2181
+ var import_utils15;
2182
+ var init_populate_target_configuration = __esm({
2183
+ "src/acl/populate-target-configuration.ts"() {
2184
+ import_utils15 = require("@web-ts-toolkit/utils");
2185
+ init_authorization_snapshot();
2186
+ }
2187
+ });
2188
+
2164
2189
  // src/acl/virtual-populate-dependencies.ts
2165
2190
  function record(value, label) {
2166
- if (!(0, import_utils15.isPlainObject)(value)) return fail(label, "entries must be plain { path, select? } objects");
2191
+ if (!(0, import_utils16.isPlainObject)(value)) return fail(label, "entries must be plain { path, select? } objects");
2167
2192
  for (const key of Reflect.ownKeys(value)) {
2168
2193
  const property = Object.getOwnPropertyDescriptor(value, key);
2169
2194
  if (typeof key !== "string" || !property.enumerable || !("value" in property))
@@ -2251,7 +2276,9 @@ function normalizeSelection(select, catalog, label) {
2251
2276
  includeId: selection.includes("_id")
2252
2277
  };
2253
2278
  }
2254
- function captureVirtualPopulateDependencies(runtime, modelName, options) {
2279
+ function captureVirtualPopulateDependencies(runtime, modelName, options, globalOptions = runtime.getGlobalOptions()) {
2280
+ const requireOperationAccessForPopulateDependencies = globalOptions.requireOperationAccessForPopulateDependencies !== false;
2281
+ const requireOperationAccessForPopulateQueries = globalOptions.requireOperationAccessForPopulateQueries !== false;
2255
2282
  const model = runtime.getModelInstance(modelName);
2256
2283
  const targets = /* @__PURE__ */ new Map();
2257
2284
  const scopes = [];
@@ -2291,15 +2318,23 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
2291
2318
  label,
2292
2319
  `target "${ref}" requires a registered same-connection non-discriminator ObjectId model bound to the source ref`
2293
2320
  );
2294
- const targetOptions = ref === modelName ? options : runtime.getModelOptions(ref);
2321
+ const { options: targetOptions } = capturePopulateTargetConfiguration(
2322
+ runtime,
2323
+ ref,
2324
+ `dependsOnPopulate virtual "${label}"`,
2325
+ ref === modelName ? options : void 0
2326
+ );
2295
2327
  const defaults = runtime.getDefaultModelOptions();
2296
- const readOption = (key) => resolveNestedOption((path2, fallback) => (0, import_utils15.get)(targetOptions, path2, fallback), key, (0, import_utils15.get)(defaults, key));
2328
+ const readOption = (key) => resolveNestedOption((path2, fallback) => (0, import_utils16.get)(targetOptions, path2, fallback), key, (0, import_utils16.get)(defaults, key));
2297
2329
  const documentPermissionField = targetOptions.documentPermissionField ?? defaults.documentPermissionField;
2298
2330
  const catalog = captureAuthorizationFieldCatalog(targetModel.schema, void 0, documentPermissionField);
2299
2331
  const configuration = copyAuthorizationValue(
2300
2332
  {
2301
2333
  catalog,
2302
2334
  documentPermissionField,
2335
+ requireOperationAccessForPopulateDependencies,
2336
+ requireOperationAccessForPopulateQueries,
2337
+ permissionSchema: targetOptions.permissionSchema,
2303
2338
  operationAccess: { read: readOption("operationAccess.read") },
2304
2339
  baseFilter: { read: readOption("baseFilter.read") },
2305
2340
  overrideFilter: { read: readOption("overrideFilter.read") },
@@ -2348,13 +2383,13 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
2348
2383
  );
2349
2384
  continue;
2350
2385
  }
2351
- if (!(0, import_utils15.isPlainObject)(raw)) continue;
2386
+ if (!(0, import_utils16.isPlainObject)(raw)) continue;
2352
2387
  const entry = raw;
2353
2388
  const label = join(sourcePrefix, name);
2354
2389
  captureList(entry.dependsOnPopulate, label);
2355
2390
  if (!("get" in entry))
2356
2391
  for (const access of accesses) {
2357
- if ((0, import_utils15.isPlainObject)(entry[access]))
2392
+ if ((0, import_utils16.isPlainObject)(entry[access]))
2358
2393
  captureList(entry[access].dependsOnPopulate, `${label}.${access}`);
2359
2394
  }
2360
2395
  const byAccess = {};
@@ -2379,8 +2414,8 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
2379
2414
  visit(options.virtuals ?? {}, model?.schema, "", [], !!model && varyingModel(model));
2380
2415
  return Object.freeze({ scopes: Object.freeze(scopes) });
2381
2416
  }
2382
- function captureVirtualPopulateSnapshot(runtime, modelName, options) {
2383
- const snapshot = captureVirtualPopulateDependencies(runtime, modelName, options);
2417
+ function captureVirtualPopulateSnapshot(runtime, modelName, options, globalOptions = runtime.getGlobalOptions()) {
2418
+ const snapshot = captureVirtualPopulateDependencies(runtime, modelName, options, globalOptions);
2384
2419
  const token = () => {
2385
2420
  };
2386
2421
  snapshots.set(token, snapshot);
@@ -2404,15 +2439,16 @@ function resolveVirtualPopulateDependencies(configuration, scopePath, virtualNam
2404
2439
  )
2405
2440
  );
2406
2441
  }
2407
- var import_utils15, elementType, join, within, accesses, fail, varyingSchema, varyingModel, snapshots;
2442
+ var import_utils16, elementType, join, within, accesses, fail, varyingSchema, varyingModel, snapshots;
2408
2443
  var init_virtual_populate_dependencies = __esm({
2409
2444
  "src/acl/virtual-populate-dependencies.ts"() {
2410
- import_utils15 = require("@web-ts-toolkit/utils");
2445
+ import_utils16 = require("@web-ts-toolkit/utils");
2411
2446
  init_query();
2412
2447
  init_manager();
2413
2448
  init_authorization_snapshot();
2414
2449
  init_field_catalog();
2415
2450
  init_virtual_descriptor();
2451
+ init_populate_target_configuration();
2416
2452
  elementType = (type) => type.$embeddedSchemaType ?? type.embeddedSchemaType ?? type.caster;
2417
2453
  join = (prefix, path) => prefix ? `${prefix}.${path}` : path;
2418
2454
  within = (path, parent) => path === parent || path.startsWith(`${parent}.`);
@@ -2427,14 +2463,14 @@ var init_virtual_populate_dependencies = __esm({
2427
2463
  });
2428
2464
 
2429
2465
  // src/runtime.ts
2430
- var import_mongoose4, import_mongoose_schema_jsonschema, import_utils16, mongooseJsonSchemaInitialized, ensureMongooseJsonSchemaInitialized, pluralize, FIELD_ACCESS_KEYS, defaultModelOptions, defaultDataOptions, normalizeBasePath, hasModelPermission, classifyPermissionSchema, refreshPermissionMetadata, VIRTUAL_SUPPORTED_ACCESSES, VIRTUAL_UNSUPPORTED_ACCESSES, VIRTUAL_RESERVED_NAMES, VIRTUAL_DANGEROUS_SEGMENTS, VIRTUAL_NAME_PATTERN, isVirtualContainerValue2, virtualFullPath, virtualPathsOverlap, collectStoredTopLevel, getChildSchemaForField, getNestedChildFields, cloneVirtualsForValidation, validateVirtualDependsOn, validateVirtualLeafValue, validateVirtualsScope, validateVirtualsTree, AccessRuntime, defaultRuntime;
2466
+ var import_mongoose4, import_mongoose_schema_jsonschema, import_utils17, mongooseJsonSchemaInitialized, ensureMongooseJsonSchemaInitialized, pluralize, FIELD_ACCESS_KEYS, defaultModelOptions, defaultDataOptions, normalizeBasePath, hasModelPermission, classifyPermissionSchema, refreshPermissionMetadata, VIRTUAL_SUPPORTED_ACCESSES, VIRTUAL_UNSUPPORTED_ACCESSES, VIRTUAL_RESERVED_NAMES, VIRTUAL_DANGEROUS_SEGMENTS, VIRTUAL_NAME_PATTERN, isVirtualContainerValue2, virtualFullPath, virtualPathsOverlap, collectStoredTopLevel, getChildSchemaForField, getNestedChildFields, cloneVirtualsForValidation, validateVirtualDependsOn, validateVirtualLeafValue, validateVirtualsScope, validateVirtualsTree, AccessRuntime, defaultRuntime;
2431
2467
  var init_runtime = __esm({
2432
2468
  "src/runtime.ts"() {
2433
2469
  import_mongoose4 = __toESM(require("mongoose"));
2434
2470
  init_public_admission();
2435
2471
  init_hydration();
2436
2472
  import_mongoose_schema_jsonschema = __toESM(require("mongoose-schema-jsonschema"));
2437
- import_utils16 = require("@web-ts-toolkit/utils");
2473
+ import_utils17 = require("@web-ts-toolkit/utils");
2438
2474
  init_helpers();
2439
2475
  init_registry();
2440
2476
  init_logger_default();
@@ -2463,44 +2499,44 @@ var init_runtime = __esm({
2463
2499
  listHardLimit: DEFAULT_LIST_HARD_LIMIT
2464
2500
  };
2465
2501
  normalizeBasePath = (name, value) => {
2466
- if ((0, import_utils16.isNil)(value)) {
2502
+ if ((0, import_utils17.isNil)(value)) {
2467
2503
  return `/${pluralize(name)}`;
2468
2504
  }
2469
- return (0, import_utils16.isString)(value) ? (0, import_utils16.addLeadingSlash)(value) : "";
2505
+ return (0, import_utils17.isString)(value) ? (0, import_utils17.addLeadingSlash)(value) : "";
2470
2506
  };
2471
2507
  hasModelPermission = (value, modelPermissionPrefix) => {
2472
2508
  if (!modelPermissionPrefix) {
2473
2509
  return true;
2474
2510
  }
2475
- if ((0, import_utils16.isString)(value)) {
2511
+ if ((0, import_utils17.isString)(value)) {
2476
2512
  return value.trim().split(" ").some((item) => item.startsWith(modelPermissionPrefix));
2477
2513
  }
2478
- if ((0, import_utils16.isArray)(value)) {
2514
+ if ((0, import_utils17.isArray)(value)) {
2479
2515
  return value.some((item) => {
2480
- if ((0, import_utils16.isString)(item) || (0, import_utils16.isArray)(item)) {
2516
+ if ((0, import_utils17.isString)(item) || (0, import_utils17.isArray)(item)) {
2481
2517
  return hasModelPermission(item, modelPermissionPrefix);
2482
2518
  }
2483
2519
  return true;
2484
2520
  });
2485
2521
  }
2486
- return (0, import_utils16.isFunction)(value);
2522
+ return (0, import_utils17.isFunction)(value);
2487
2523
  };
2488
2524
  classifyPermissionSchema = (permissionSchema, modelPermissionPrefix) => {
2489
2525
  const schemaKeys = Object.keys(permissionSchema);
2490
2526
  const globalPermissionKeys = {};
2491
2527
  const modelPermissionKeys = {};
2492
- (0, import_utils16.forEach)(schemaKeys, (schemaKey) => {
2528
+ (0, import_utils17.forEach)(schemaKeys, (schemaKey) => {
2493
2529
  const schemaRule = permissionSchema[schemaKey];
2494
- const ruleEntries = (0, import_utils16.isPlainObject)(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
2530
+ const ruleEntries = (0, import_utils17.isPlainObject)(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
2495
2531
  for (let x = 0; x < ruleEntries.length; x++) {
2496
2532
  const [accessKey, value] = ruleEntries[x];
2497
- if (!(0, import_utils16.isArray)(globalPermissionKeys[accessKey])) {
2533
+ if (!(0, import_utils17.isArray)(globalPermissionKeys[accessKey])) {
2498
2534
  globalPermissionKeys[accessKey] = [];
2499
2535
  }
2500
- if (!(0, import_utils16.isArray)(modelPermissionKeys[accessKey])) {
2536
+ if (!(0, import_utils17.isArray)(modelPermissionKeys[accessKey])) {
2501
2537
  modelPermissionKeys[accessKey] = [];
2502
2538
  }
2503
- if ((0, import_utils16.isBoolean)(value)) {
2539
+ if ((0, import_utils17.isBoolean)(value)) {
2504
2540
  globalPermissionKeys[accessKey].push(schemaKey);
2505
2541
  continue;
2506
2542
  }
@@ -2532,13 +2568,13 @@ var init_runtime = __esm({
2532
2568
  VIRTUAL_RESERVED_NAMES = /* @__PURE__ */ new Set(["_id", "__v", "id"]);
2533
2569
  VIRTUAL_DANGEROUS_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
2534
2570
  VIRTUAL_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
2535
- isVirtualContainerValue2 = (value) => (0, import_utils16.isPlainObject)(value) && "sub" in value;
2571
+ isVirtualContainerValue2 = (value) => (0, import_utils17.isPlainObject)(value) && "sub" in value;
2536
2572
  virtualFullPath = (prefix, name) => prefix ? `${prefix}.${name}` : name;
2537
2573
  virtualPathsOverlap = (virtualPath, permissionField) => {
2538
2574
  if (!virtualPath || !permissionField) return false;
2539
2575
  try {
2540
- if ((0, import_utils16.get)((0, import_utils16.set)({}, virtualPath, true), permissionField) !== void 0) return true;
2541
- if ((0, import_utils16.get)((0, import_utils16.set)({}, permissionField, true), virtualPath) !== void 0) return true;
2576
+ if ((0, import_utils17.get)((0, import_utils17.set)({}, virtualPath, true), permissionField) !== void 0) return true;
2577
+ if ((0, import_utils17.get)((0, import_utils17.set)({}, permissionField, true), virtualPath) !== void 0) return true;
2542
2578
  } catch {
2543
2579
  return false;
2544
2580
  }
@@ -2599,12 +2635,12 @@ var init_runtime = __esm({
2599
2635
  };
2600
2636
  validateVirtualDependsOn = (dependsOn, entryLabel, storedFields, siblingVirtualNames) => {
2601
2637
  if (dependsOn === void 0) return [];
2602
- if (!(0, import_utils16.isArray)(dependsOn)) {
2638
+ if (!(0, import_utils17.isArray)(dependsOn)) {
2603
2639
  throw new Error(`Virtual ${entryLabel}: dependsOn must be an array of top-level persisted field names`);
2604
2640
  }
2605
2641
  const list = dependsOn;
2606
2642
  for (const dep of list) {
2607
- if (!(0, import_utils16.isString)(dep) || dep.length === 0) {
2643
+ if (!(0, import_utils17.isString)(dep) || dep.length === 0) {
2608
2644
  throw new Error(`Virtual ${entryLabel}: dependsOn entries must be non-empty strings`);
2609
2645
  }
2610
2646
  if (dep.includes(".")) {
@@ -2626,12 +2662,12 @@ var init_runtime = __esm({
2626
2662
  return list;
2627
2663
  };
2628
2664
  validateVirtualLeafValue = (value, entryLabel, storedFields, siblingVirtualNames, sharedDependsOn) => {
2629
- if ((0, import_utils16.isFunction)(value)) return;
2630
- if (!(0, import_utils16.isPlainObject)(value)) {
2665
+ if ((0, import_utils17.isFunction)(value)) return;
2666
+ if (!(0, import_utils17.isPlainObject)(value)) {
2631
2667
  throw new Error(`Virtual ${entryLabel}: descriptor must be a getter function or { get, dependsOn }`);
2632
2668
  }
2633
2669
  const record3 = value;
2634
- if (!(0, import_utils16.isFunction)(record3.get)) {
2670
+ if (!(0, import_utils17.isFunction)(record3.get)) {
2635
2671
  throw new Error(`Virtual ${entryLabel}: descriptor.get must be a callable getter function`);
2636
2672
  }
2637
2673
  validateVirtualDependsOn(record3.dependsOn ?? sharedDependsOn, entryLabel, storedFields, siblingVirtualNames);
@@ -2673,7 +2709,7 @@ var init_runtime = __esm({
2673
2709
  `Virtual ${scopeLabel}${name}: scope-container must only hold "sub" (embedded container "${name}" is not a virtual-leaf collision)`
2674
2710
  );
2675
2711
  }
2676
- if (!(0, import_utils16.isPlainObject)(record4.sub)) {
2712
+ if (!(0, import_utils17.isPlainObject)(record4.sub)) {
2677
2713
  throw new Error(`Virtual ${scopeLabel}${name}: scope-container "sub" must be a plain object`);
2678
2714
  }
2679
2715
  continue;
@@ -2683,8 +2719,8 @@ var init_runtime = __esm({
2683
2719
  `Virtual ${scopeLabel}${name}: collides with a stored path (inspected actual Mongoose schema/child scope; getModelAtt alone is insufficient)`
2684
2720
  );
2685
2721
  }
2686
- if ((0, import_utils16.isFunction)(raw)) continue;
2687
- if (!(0, import_utils16.isPlainObject)(raw)) {
2722
+ if ((0, import_utils17.isFunction)(raw)) continue;
2723
+ if (!(0, import_utils17.isPlainObject)(raw)) {
2688
2724
  throw new Error(
2689
2725
  `Virtual ${scopeLabel}${name}: malformed descriptor (expected getter, { get, dependsOn }, or per-access record)`
2690
2726
  );
@@ -2738,7 +2774,7 @@ var init_runtime = __esm({
2738
2774
  };
2739
2775
  validateVirtualsTree = (model, virtuals, documentPermissionField, modelName) => {
2740
2776
  if (virtuals === void 0 || virtuals === null) return;
2741
- if (!(0, import_utils16.isPlainObject)(virtuals)) {
2777
+ if (!(0, import_utils17.isPlainObject)(virtuals)) {
2742
2778
  throw new Error(`Virtuals for model "${modelName}": virtuals must be a plain object mapping names to descriptors`);
2743
2779
  }
2744
2780
  const rootSchema = model?.schema ?? null;
@@ -2790,7 +2826,8 @@ var init_runtime = __esm({
2790
2826
  {
2791
2827
  requestPermissionField: "_permissions",
2792
2828
  globalPermissions: () => ({}),
2793
- requireRegisteredPopulateModels: true,
2829
+ requireOperationAccessForPopulateQueries: true,
2830
+ requireOperationAccessForPopulateDependencies: true,
2794
2831
  logger: defaultLogger,
2795
2832
  requestComplexity: defaultRequestComplexity
2796
2833
  },
@@ -2845,7 +2882,7 @@ var init_runtime = __esm({
2845
2882
  }
2846
2883
  registerOpenApiRoute(route) {
2847
2884
  this.openApiRegistry.register(
2848
- this.openApiPathPrefix ? { ...route, path: (0, import_utils16.normalizeUrlPath)(`${this.openApiPathPrefix}/${route.path}`) } : route
2885
+ this.openApiPathPrefix ? { ...route, path: (0, import_utils17.normalizeUrlPath)(`${this.openApiPathPrefix}/${route.path}`) } : route
2849
2886
  );
2850
2887
  }
2851
2888
  /**
@@ -2856,7 +2893,7 @@ var init_runtime = __esm({
2856
2893
  */
2857
2894
  withOpenApiPathPrefix(prefix, build) {
2858
2895
  const previous = this.openApiPathPrefix;
2859
- this.openApiPathPrefix = (0, import_utils16.normalizeUrlPath)(`${previous}/${prefix}`);
2896
+ this.openApiPathPrefix = (0, import_utils17.normalizeUrlPath)(`${previous}/${prefix}`);
2860
2897
  try {
2861
2898
  return build();
2862
2899
  } finally {
@@ -2963,9 +3000,18 @@ var init_runtime = __esm({
2963
3000
  }
2964
3001
  /** Shallowly replace supplied global values; nested objects such as requestComplexity are not deep-merged. */
2965
3002
  setGlobalOptions(options) {
2966
- this.globalOptions.assign(options);
3003
+ const next = { ...options };
3004
+ if ("requireOperationAccessForPopulateQueries" in next)
3005
+ next.requireOperationAccessForPopulateQueries = next.requireOperationAccessForPopulateQueries !== false;
3006
+ if ("requireOperationAccessForPopulateDependencies" in next)
3007
+ next.requireOperationAccessForPopulateDependencies = next.requireOperationAccessForPopulateDependencies !== false;
3008
+ this.globalOptions.assign(next);
2967
3009
  }
2968
3010
  setGlobalOption(key, value) {
3011
+ if (key === "requireOperationAccessForPopulateQueries" || key === "requireOperationAccessForPopulateDependencies") {
3012
+ this.globalOptions.set(key, value !== false);
3013
+ return;
3014
+ }
2969
3015
  this.globalOptions.set(key, value);
2970
3016
  }
2971
3017
  getGlobalOptions() {
@@ -2992,7 +3038,7 @@ var init_runtime = __esm({
2992
3038
  if (keyStr === "defaults") assertPublicDefaults(value);
2993
3039
  else if (keyStr.startsWith("defaults.")) {
2994
3040
  const proposed = {};
2995
- (0, import_utils16.set)(proposed, keyStr.slice("defaults.".length), value);
3041
+ (0, import_utils17.set)(proposed, keyStr.slice("defaults.".length), value);
2996
3042
  assertPublicDefaults(proposed);
2997
3043
  }
2998
3044
  this.defaultModelOptions.set(key, value);
@@ -3021,7 +3067,7 @@ var init_runtime = __esm({
3021
3067
  }).onchange("basePath", function(newval, key, target) {
3022
3068
  target[key] = normalizeBasePath(
3023
3069
  modelName,
3024
- (0, import_utils16.isString)(newval) || (0, import_utils16.isNil)(newval) ? newval : void 0
3070
+ (0, import_utils17.isString)(newval) || (0, import_utils17.isNil)(newval) ? newval : void 0
3025
3071
  );
3026
3072
  }).build();
3027
3073
  this.modelJsonSchemas[modelName] = model.jsonSchema();
@@ -3065,7 +3111,7 @@ var init_runtime = __esm({
3065
3111
  if (keyStr === "defaults") assertPublicDefaults(value);
3066
3112
  else if (keyStr.startsWith("defaults.")) {
3067
3113
  const proposed = {};
3068
- (0, import_utils16.set)(proposed, keyStr.slice("defaults.".length), value);
3114
+ (0, import_utils17.set)(proposed, keyStr.slice("defaults.".length), value);
3069
3115
  assertPublicDefaults(proposed);
3070
3116
  }
3071
3117
  const manager = this.modelOptions[modelName];
@@ -3086,15 +3132,15 @@ var init_runtime = __esm({
3086
3132
  const segments = nestedPath.split(".");
3087
3133
  let cursor = cloned;
3088
3134
  for (let i = 0; i < segments.length - 1; i++) {
3089
- if (!(0, import_utils16.isPlainObject)(cursor)) break;
3135
+ if (!(0, import_utils17.isPlainObject)(cursor)) break;
3090
3136
  cursor = cursor[segments[i]];
3091
3137
  }
3092
- if ((0, import_utils16.isPlainObject)(cursor)) {
3138
+ if ((0, import_utils17.isPlainObject)(cursor)) {
3093
3139
  delete cursor[segments[segments.length - 1]];
3094
3140
  }
3095
3141
  proposedVirtuals = cloned;
3096
3142
  } else {
3097
- (0, import_utils16.set)(cloned, nestedPath, value);
3143
+ (0, import_utils17.set)(cloned, nestedPath, value);
3098
3144
  proposedVirtuals = cloned;
3099
3145
  }
3100
3146
  }
@@ -3195,7 +3241,7 @@ var init_runtime = __esm({
3195
3241
  manager.onchange("basePath", function(newval, key, target) {
3196
3242
  target[key] = normalizeBasePath(
3197
3243
  dataName,
3198
- (0, import_utils16.isString)(newval) || (0, import_utils16.isNil)(newval) ? newval : void 0
3244
+ (0, import_utils17.isString)(newval) || (0, import_utils17.isNil)(newval) ? newval : void 0
3199
3245
  );
3200
3246
  }).build();
3201
3247
  return manager;
@@ -3255,20 +3301,20 @@ var init_runtime = __esm({
3255
3301
  const schema = model.schema;
3256
3302
  this.modelRefs[modelName] = buildRefs(schema.tree);
3257
3303
  this.modelSubs[modelName] = buildSubPaths(schema.tree);
3258
- this.modelAtts[modelName] = (0, import_utils16.keys)(schema.obj);
3304
+ this.modelAtts[modelName] = (0, import_utils17.keys)(schema.obj);
3259
3305
  }
3260
3306
  getModelRef(modelName, refPath) {
3261
3307
  this.ensureModelMeta(modelName);
3262
- const value = (0, import_utils16.get)(this.modelRefs, `${modelName}.${refPath}`, null);
3263
- return (0, import_utils16.isString)(value) ? value : null;
3308
+ const value = (0, import_utils17.get)(this.modelRefs, `${modelName}.${refPath}`, null);
3309
+ return (0, import_utils17.isString)(value) ? value : null;
3264
3310
  }
3265
3311
  getModelSub(modelName) {
3266
3312
  this.ensureModelMeta(modelName);
3267
- return (0, import_utils16.get)(this.modelSubs, modelName, []);
3313
+ return (0, import_utils17.get)(this.modelSubs, modelName, []);
3268
3314
  }
3269
3315
  getModelAtt(modelName) {
3270
3316
  this.ensureModelMeta(modelName);
3271
- return (0, import_utils16.get)(this.modelAtts, modelName, []);
3317
+ return (0, import_utils17.get)(this.modelAtts, modelName, []);
3272
3318
  }
3273
3319
  };
3274
3320
  defaultRuntime = new AccessRuntime({ allowGlobalModelLookup: true });
@@ -3444,10 +3490,10 @@ var init_options = __esm({
3444
3490
  });
3445
3491
 
3446
3492
  // src/permission.ts
3447
- var import_utils17, Permission, permission_default;
3493
+ var import_utils18, Permission, permission_default;
3448
3494
  var init_permission = __esm({
3449
3495
  "src/permission.ts"() {
3450
- import_utils17 = require("@web-ts-toolkit/utils");
3496
+ import_utils18 = require("@web-ts-toolkit/utils");
3451
3497
  Permission = class {
3452
3498
  constructor(permissions) {
3453
3499
  this.permissions = { ...permissions };
@@ -3463,7 +3509,7 @@ var init_permission = __esm({
3463
3509
  return [permissionOrPermissions].concat(permissions);
3464
3510
  }
3465
3511
  hasKey(permission) {
3466
- return (0, import_utils17.hasOwn)(this.permissions, permission);
3512
+ return (0, import_utils18.hasOwn)(this.permissions, permission);
3467
3513
  }
3468
3514
  has(permission) {
3469
3515
  return this.permissions[permission] === true;
@@ -3581,7 +3627,6 @@ function normalizePolicy(value, applicability, configuration, targets) {
3581
3627
  const matches = targets.filter((target2) => target2.path === path);
3582
3628
  if (matches.length !== 1) authorizationError(`unused or ambiguous related path: ${path}`);
3583
3629
  const target = matches[0];
3584
- if (target.kind === "passthrough") authorizationError(`related policy requires a registered target: ${path}`);
3585
3630
  const child = authorizationRecord(entry, `related.${path}`);
3586
3631
  assertAuthorizationKeys(
3587
3632
  child,
@@ -3950,7 +3995,7 @@ function attachIncludeOutput(doc, path, value) {
3950
3995
  const state = stateFor(doc);
3951
3996
  if (!state) throw new Error("Include attachment requires a prepared output row");
3952
3997
  state.attachments.push({ path, value });
3953
- (0, import_utils18.set)(doc, path, deepIsolateValue(value));
3998
+ (0, import_utils19.set)(doc, path, deepIsolateValue(value));
3954
3999
  }
3955
4000
  function getIncludeSource(doc) {
3956
4001
  return stateFor(doc)?.source ?? doc;
@@ -3965,14 +4010,14 @@ function restoreIncludeOutput(doc, output) {
3965
4010
  for (const { path, value } of attachments) {
3966
4011
  const copy = deepIsolateValue(value);
3967
4012
  if (copy !== null && typeof copy === "object") origins.set(copy, value);
3968
- (0, import_utils18.set)(output, path, copy);
4013
+ (0, import_utils19.set)(output, path, copy);
3969
4014
  }
3970
4015
  return origins;
3971
4016
  }
3972
- var import_utils18, outputs2, stateFor;
4017
+ var import_utils19, outputs2, stateFor;
3973
4018
  var init_include_output = __esm({
3974
4019
  "src/output/include-output.ts"() {
3975
- import_utils18 = require("@web-ts-toolkit/utils");
4020
+ import_utils19 = require("@web-ts-toolkit/utils");
3976
4021
  init_document_authorization();
3977
4022
  init_document();
3978
4023
  outputs2 = /* @__PURE__ */ new WeakMap();
@@ -4314,10 +4359,10 @@ function planVirtualProjection(args) {
4314
4359
  relatedPlans
4315
4360
  };
4316
4361
  }
4317
- var import_utils20, getScopedPermissionSchema, resolveAlwaysSelectForAccess, stripVirtualsFromNormalizedSelect, snapshotVirtualPaths, stripLeadingDash, dbPrefixForScope, toDbPath;
4362
+ var import_utils21, getScopedPermissionSchema, resolveAlwaysSelectForAccess, stripVirtualsFromNormalizedSelect, snapshotVirtualPaths, stripLeadingDash, dbPrefixForScope, toDbPath;
4318
4363
  var init_virtual_projection = __esm({
4319
4364
  "src/acl/virtual-projection.ts"() {
4320
- import_utils20 = require("@web-ts-toolkit/utils");
4365
+ import_utils21 = require("@web-ts-toolkit/utils");
4321
4366
  init_query();
4322
4367
  init_field_authorization();
4323
4368
  init_output_projection();
@@ -4325,20 +4370,20 @@ var init_virtual_projection = __esm({
4325
4370
  init_virtual_populate_dependencies();
4326
4371
  init_virtual_descriptor();
4327
4372
  getScopedPermissionSchema = (root, scopePath) => {
4328
- if (!root || !(0, import_utils20.isPlainObject)(root)) return null;
4373
+ if (!root || !(0, import_utils21.isPlainObject)(root)) return null;
4329
4374
  if (scopePath.length === 0) return root;
4330
- const scoped = (0, import_utils20.get)(root, scopePath.join("."));
4331
- return (0, import_utils20.isPlainObject)(scoped) ? scoped : null;
4375
+ const scoped = (0, import_utils21.get)(root, scopePath.join("."));
4376
+ return (0, import_utils21.isPlainObject)(scoped) ? scoped : null;
4332
4377
  };
4333
4378
  resolveAlwaysSelectForAccess = (raw, access) => {
4334
4379
  if (!raw) return [];
4335
- if ((0, import_utils20.isArray)(raw)) return [...raw];
4336
- if ((0, import_utils20.isPlainObject)(raw)) {
4380
+ if ((0, import_utils21.isArray)(raw)) return [...raw];
4381
+ if ((0, import_utils21.isPlainObject)(raw)) {
4337
4382
  const record3 = raw;
4338
4383
  const exact = record3[access];
4339
- if ((0, import_utils20.isArray)(exact)) return [...exact];
4384
+ if ((0, import_utils21.isArray)(exact)) return [...exact];
4340
4385
  const def = record3.default;
4341
- if ((0, import_utils20.isArray)(def)) return [...def];
4386
+ if ((0, import_utils21.isArray)(def)) return [...def];
4342
4387
  return [];
4343
4388
  }
4344
4389
  return [];
@@ -4603,18 +4648,25 @@ var init_output_projection = __esm({
4603
4648
 
4604
4649
  // src/acl/model-output-planning.ts
4605
4650
  function getCapturedAuthorizationOption(configuration, key) {
4606
- const defaultValue = key.startsWith("operationAccess.") ? (0, import_utils21.get)(configuration.operationAccessDefaults, key.slice("operationAccess.".length)) : void 0;
4607
- return resolveNestedOption((path, fallback) => (0, import_utils21.get)(configuration, path, fallback), key, defaultValue);
4651
+ const defaultValue = key.startsWith("operationAccess.") ? (0, import_utils22.get)(configuration.operationAccessDefaults, key.slice("operationAccess.".length)) : void 0;
4652
+ return resolveNestedOption((path, fallback) => (0, import_utils22.get)(configuration, path, fallback), key, defaultValue);
4608
4653
  }
4609
- function captureModelAuthorizationConfiguration(runtime, modelName, options = runtime.getModelOptions(modelName)) {
4654
+ function captureModelAuthorizationConfiguration(runtime, modelName, options = runtime.getModelOptions(modelName), globalOptions = runtime.getGlobalOptions()) {
4610
4655
  const model = runtime.getModelInstance(modelName);
4611
4656
  if (!model) return authorizationError(`unknown receiving model: ${modelName}`);
4612
4657
  const virtuals = options.virtuals;
4613
4658
  return copyAuthorizationValue(
4614
4659
  {
4615
4660
  catalog: captureAuthorizationFieldCatalog(model.schema, virtuals, options.documentPermissionField),
4616
- virtualPopulateSnapshot: captureVirtualPopulateSnapshot(runtime, modelName, options),
4617
- permissionSchema: options.permissionSchema,
4661
+ virtualPopulateSnapshot: captureVirtualPopulateSnapshot(
4662
+ runtime,
4663
+ modelName,
4664
+ options,
4665
+ globalOptions
4666
+ ),
4667
+ requireOperationAccessForPopulateDependencies: globalOptions.requireOperationAccessForPopulateDependencies !== false,
4668
+ requireOperationAccessForPopulateQueries: globalOptions.requireOperationAccessForPopulateQueries !== false,
4669
+ permissionSchema: options.permissionSchema === void 0 ? runtime.getDefaultModelOption("permissionSchema") : options.permissionSchema,
4618
4670
  virtuals,
4619
4671
  alwaysSelectFields: options.alwaysSelectFields,
4620
4672
  modelPermissionPrefix: options.modelPermissionPrefix,
@@ -4660,10 +4712,10 @@ function planModelOutputForHelper(args) {
4660
4712
  requestedSelect: args.select
4661
4713
  });
4662
4714
  }
4663
- var import_utils21;
4715
+ var import_utils22;
4664
4716
  var init_model_output_planning = __esm({
4665
4717
  "src/acl/model-output-planning.ts"() {
4666
- import_utils21 = require("@web-ts-toolkit/utils");
4718
+ import_utils22 = require("@web-ts-toolkit/utils");
4667
4719
  init_manager();
4668
4720
  init_field_catalog();
4669
4721
  init_authorization_snapshot();
@@ -4675,10 +4727,10 @@ var init_model_output_planning = __esm({
4675
4727
 
4676
4728
  // src/core-shared.ts
4677
4729
  function isAndFilter(filter2) {
4678
- return !!filter2 && (0, import_utils22.isPlainObject)(filter2) && Object.keys(filter2).length === 1 && (0, import_utils22.isArray)(filter2.$and);
4730
+ return !!filter2 && (0, import_utils23.isPlainObject)(filter2) && Object.keys(filter2).length === 1 && (0, import_utils23.isArray)(filter2.$and);
4679
4731
  }
4680
4732
  function isMergeableClause(filter2) {
4681
- return !!filter2 && (0, import_utils22.isPlainObject)(filter2) && Object.keys(filter2).every((key) => !key.startsWith("$"));
4733
+ return !!filter2 && (0, import_utils23.isPlainObject)(filter2) && Object.keys(filter2).every((key) => !key.startsWith("$"));
4682
4734
  }
4683
4735
  function optimizeAndFilter(clausesInput) {
4684
4736
  const clauses = [];
@@ -4695,11 +4747,11 @@ function optimizeAndFilter(clausesInput) {
4695
4747
  const dedupeKey = (value) => {
4696
4748
  if (value instanceof RegExp) return `regexp:${JSON.stringify([value.source, value.flags])}`;
4697
4749
  if (value instanceof Date) return `date:${value.getTime()}`;
4698
- if ((0, import_utils22.isArray)(value)) {
4750
+ if ((0, import_utils23.isArray)(value)) {
4699
4751
  const entries = Array.from(value, dedupeKey);
4700
4752
  return entries.every((entry) => entry !== void 0) ? `array:${JSON.stringify(entries)}` : void 0;
4701
4753
  }
4702
- if ((0, import_utils22.isPlainObject)(value)) {
4754
+ if ((0, import_utils23.isPlainObject)(value)) {
4703
4755
  const entries = Object.keys(value).sort().map((key) => [key, dedupeKey(value[key])]);
4704
4756
  return entries.every(([, entry]) => entry !== void 0) ? `object:${JSON.stringify(entries)}` : void 0;
4705
4757
  }
@@ -4729,7 +4781,7 @@ function optimizeAndFilter(clausesInput) {
4729
4781
  }
4730
4782
  let canMerge = true;
4731
4783
  for (const [key, value] of Object.entries(clause)) {
4732
- if ((0, import_utils22.hasOwn)(mergedClause, key) && !(0, import_node_util4.isDeepStrictEqual)(mergedClause[key], value)) {
4784
+ if ((0, import_utils23.hasOwn)(mergedClause, key) && !(0, import_node_util4.isDeepStrictEqual)(mergedClause[key], value)) {
4733
4785
  canMerge = false;
4734
4786
  break;
4735
4787
  }
@@ -4740,24 +4792,24 @@ function optimizeAndFilter(clausesInput) {
4740
4792
  }
4741
4793
  Object.assign(mergedClause, clause);
4742
4794
  }
4743
- const finalClauses = (0, import_utils22.isEmpty)(mergedClause) ? remainingClauses : [mergedClause, ...remainingClauses];
4795
+ const finalClauses = (0, import_utils23.isEmpty)(mergedClause) ? remainingClauses : [mergedClause, ...remainingClauses];
4744
4796
  if (finalClauses.length === 0) return null;
4745
4797
  if (finalClauses.length === 1) return finalClauses[0];
4746
4798
  return { $and: finalClauses };
4747
4799
  }
4748
4800
  function normalizeFilter(filter2) {
4749
4801
  if (filter2 === false) return false;
4750
- if (!filter2 || !(0, import_utils22.isPlainObject)(filter2) || (0, import_utils22.isEmpty)(filter2)) return null;
4802
+ if (!filter2 || !(0, import_utils23.isPlainObject)(filter2) || (0, import_utils23.isEmpty)(filter2)) return null;
4751
4803
  if (!isAndFilter(filter2)) {
4752
4804
  return filter2;
4753
4805
  }
4754
4806
  return optimizeAndFilter(filter2.$and);
4755
4807
  }
4756
4808
  async function resolveIdentifierFilter(req, idField, resolveIdFilter, id) {
4757
- if ((0, import_utils22.isFunction)(resolveIdFilter)) {
4809
+ if ((0, import_utils23.isFunction)(resolveIdFilter)) {
4758
4810
  return await resolveIdFilter.call(req, id);
4759
4811
  }
4760
- if ((0, import_utils22.isString)(idField)) {
4812
+ if ((0, import_utils23.isString)(idField)) {
4761
4813
  return { [idField]: id };
4762
4814
  }
4763
4815
  return { _id: id };
@@ -4781,7 +4833,7 @@ async function resolveAccessFilterParts({
4781
4833
  }
4782
4834
  const overrideFilterFn = getOption(`overrideFilter.${access}`, null);
4783
4835
  const baseFilterFn = rows2.mode === "request" ? getOption(`baseFilter.${access}`, null) : null;
4784
- if (nextFilter !== false && (0, import_utils22.isFunction)(overrideFilterFn)) {
4836
+ if (nextFilter !== false && (0, import_utils23.isFunction)(overrideFilterFn)) {
4785
4837
  nextFilter = normalizeFilter(await overrideFilterFn.call(req, nextFilter, permissions));
4786
4838
  }
4787
4839
  if (nextFilter === false) return { transformed: false, scope: {}, filter: false };
@@ -4789,7 +4841,7 @@ async function resolveAccessFilterParts({
4789
4841
  const scope2 = rows2.mode === "scope" ? rows2.filter : {};
4790
4842
  return { transformed: nextFilter ?? {}, scope: scope2, filter: intersectFilters(nextFilter, scope2) };
4791
4843
  }
4792
- if (!(0, import_utils22.isFunction)(baseFilterFn)) return { transformed: nextFilter ?? {}, scope: {}, filter: nextFilter ?? {} };
4844
+ if (!(0, import_utils23.isFunction)(baseFilterFn)) return { transformed: nextFilter ?? {}, scope: {}, filter: nextFilter ?? {} };
4793
4845
  const cached = cache.get(cacheKey);
4794
4846
  const reusable = cached?.resolver === baseFilterFn;
4795
4847
  const baseFilter = normalizeFilter(
@@ -4824,34 +4876,34 @@ async function setRequestPermissions(req) {
4824
4876
  if (owner === activeRuntime) return;
4825
4877
  if (hasFieldValue && owner === void 0) return;
4826
4878
  const globalPermissions = getGlobalOption("globalPermissions");
4827
- const permissions = (0, import_utils22.isFunction)(globalPermissions) ? await globalPermissions.call(req, req) : void 0;
4828
- if ((0, import_utils22.isPlainObject)(permissions)) req[requestPermissionField] = permissions;
4829
- else if ((0, import_utils22.isArray)(permissions)) req[requestPermissionField] = (0, import_utils22.arrayToRecord)(permissions);
4830
- else if ((0, import_utils22.isString)(permissions)) req[requestPermissionField] = { [permissions]: true };
4879
+ const permissions = (0, import_utils23.isFunction)(globalPermissions) ? await globalPermissions.call(req, req) : void 0;
4880
+ if ((0, import_utils23.isPlainObject)(permissions)) req[requestPermissionField] = permissions;
4881
+ else if ((0, import_utils23.isArray)(permissions)) req[requestPermissionField] = (0, import_utils23.arrayToRecord)(permissions);
4882
+ else if ((0, import_utils23.isString)(permissions)) req[requestPermissionField] = { [permissions]: true };
4831
4883
  else req[requestPermissionField] = {};
4832
4884
  owners.set(requestPermissionField, activeRuntime);
4833
4885
  }
4834
4886
  async function evaluateRouteGuard(req, permissions, routeGuard) {
4835
4887
  const phas = (key) => permissions.has(key);
4836
4888
  const { stringHandler, arrayHandler } = createValidator(phas);
4837
- if ((0, import_utils22.isBoolean)(routeGuard)) {
4889
+ if ((0, import_utils23.isBoolean)(routeGuard)) {
4838
4890
  return routeGuard === true;
4839
4891
  }
4840
- if ((0, import_utils22.isString)(routeGuard)) {
4892
+ if ((0, import_utils23.isString)(routeGuard)) {
4841
4893
  return stringHandler(routeGuard);
4842
4894
  }
4843
- if ((0, import_utils22.isArray)(routeGuard)) {
4895
+ if ((0, import_utils23.isArray)(routeGuard)) {
4844
4896
  return arrayHandler(routeGuard);
4845
4897
  }
4846
- if ((0, import_utils22.isFunction)(routeGuard)) {
4898
+ if ((0, import_utils23.isFunction)(routeGuard)) {
4847
4899
  return routeGuard.call(req, permissions);
4848
4900
  }
4849
4901
  return false;
4850
4902
  }
4851
4903
  async function callHookChain(req, hook, doc, permissions, context) {
4852
- const hooks = (0, import_utils22.castArray)(hook);
4904
+ const hooks = (0, import_utils23.castArray)(hook);
4853
4905
  for (let x = 0; x < hooks.length; x++) {
4854
- if ((0, import_utils22.isFunction)(hooks[x])) {
4906
+ if ((0, import_utils23.isFunction)(hooks[x])) {
4855
4907
  doc = await hooks[x].call(req, doc, permissions, context);
4856
4908
  }
4857
4909
  }
@@ -4871,22 +4923,22 @@ async function collectSchemaFields({
4871
4923
  for (let x = 0; x < keys2.length; x++) {
4872
4924
  const key = keys2[x];
4873
4925
  const value = extractScopedOutputRule(permissionSchema, key, access);
4874
- if ((0, import_utils22.isBoolean)(value)) {
4926
+ if ((0, import_utils23.isBoolean)(value)) {
4875
4927
  if (value) fields.push(key);
4876
- } else if ((0, import_utils22.isString)(value)) {
4928
+ } else if ((0, import_utils23.isString)(value)) {
4877
4929
  if (stringHandler(value)) fields.push(key);
4878
- } else if ((0, import_utils22.isArray)(value)) {
4930
+ } else if ((0, import_utils23.isArray)(value)) {
4879
4931
  if (arrayHandler(value)) fields.push(key);
4880
- } else if ((0, import_utils22.isFunction)(value)) {
4932
+ } else if ((0, import_utils23.isFunction)(value)) {
4881
4933
  if (await value.call(req, ...functionArgs)) fields.push(key);
4882
4934
  }
4883
4935
  }
4884
4936
  return fields;
4885
4937
  }
4886
- var import_utils22, import_node_util4, permissionFieldOwners;
4938
+ var import_utils23, import_node_util4, permissionFieldOwners;
4887
4939
  var init_core_shared = __esm({
4888
4940
  "src/core-shared.ts"() {
4889
- import_utils22 = require("@web-ts-toolkit/utils");
4941
+ import_utils23 = require("@web-ts-toolkit/utils");
4890
4942
  import_node_util4 = require("util");
4891
4943
  init_helpers();
4892
4944
  init_options();
@@ -5255,8 +5307,8 @@ function equivalentVirtualPopulatePredicate(left, right) {
5255
5307
  }
5256
5308
  if (Array.isArray(left) || Array.isArray(right))
5257
5309
  return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((entry, index) => equivalentVirtualPopulatePredicate(entry, right[index]));
5258
- if ((0, import_utils26.isPlainObject)(left) || (0, import_utils26.isPlainObject)(right)) {
5259
- if (!(0, import_utils26.isPlainObject)(left) || !(0, import_utils26.isPlainObject)(right)) return false;
5310
+ if ((0, import_utils27.isPlainObject)(left) || (0, import_utils27.isPlainObject)(right)) {
5311
+ if (!(0, import_utils27.isPlainObject)(left) || !(0, import_utils27.isPlainObject)(right)) return false;
5260
5312
  const a = Object.keys(left), b = Object.keys(right);
5261
5313
  return a.length === b.length && a.every(
5262
5314
  (key, index) => key === b[index] && equivalentVirtualPopulatePredicate(
@@ -5273,7 +5325,8 @@ function createVirtualPopulateBatch(owner) {
5273
5325
  owner: { ...owner },
5274
5326
  rows: [],
5275
5327
  requests: [],
5276
- rowCache: owner.core && getRequestRowCache(owner.core) || new Cache()
5328
+ rowCache: owner.core && getRequestRowCache(owner.core) || new Cache(),
5329
+ readGuards: /* @__PURE__ */ new Map()
5277
5330
  });
5278
5331
  return batch;
5279
5332
  }
@@ -5322,7 +5375,12 @@ function captureVirtualPopulateRows(batch, inputs, plan, publicPopulate = [], so
5322
5375
  }
5323
5376
  const record3 = storage(value);
5324
5377
  if (!record3) return;
5325
- const occurrence = { address, plan: currentPlan, refs: /* @__PURE__ */ new Map(), dependencies: /* @__PURE__ */ new Map() };
5378
+ const occurrence = {
5379
+ address,
5380
+ plan: currentPlan,
5381
+ refs: /* @__PURE__ */ new Map(),
5382
+ dependencies: /* @__PURE__ */ new Map()
5383
+ };
5326
5384
  row.occurrences.set(addressKey(address), occurrence);
5327
5385
  for (const candidate of currentPlan.candidates) {
5328
5386
  const dependencies = (candidate.populateDependencies ?? []).map((dependency) => {
@@ -5388,6 +5446,27 @@ function referenceIds(original) {
5388
5446
  if (!original.present || original.value == null) return [];
5389
5447
  return (Array.isArray(original.value) ? original.value : [original.value]).filter((id) => id != null);
5390
5448
  }
5449
+ function targetReadAllowed(state, target) {
5450
+ let pending = state.readGuards.get(target.identity);
5451
+ if (!pending) {
5452
+ const { owner } = state;
5453
+ pending = getRequestWorkState(owner.request, owner.runtime).hookGate.run(
5454
+ () => evaluateRouteGuard(
5455
+ owner.request,
5456
+ owner.permissions,
5457
+ getCapturedAuthorizationOption(target.configuration, "operationAccess.read")
5458
+ )
5459
+ ).then(
5460
+ (allowed) => !!allowed,
5461
+ () => {
5462
+ warn("Virtual populated dependency unavailable", { modelName: target.modelName, category: "policy" });
5463
+ return false;
5464
+ }
5465
+ );
5466
+ state.readGuards.set(target.identity, pending);
5467
+ }
5468
+ return pending;
5469
+ }
5391
5470
  function executeVirtualPopulateBatch(batch) {
5392
5471
  const state = batches.get(batch);
5393
5472
  if (!state) throw new Error("Unknown private populate batch");
@@ -5404,14 +5483,8 @@ async function execute(state) {
5404
5483
  if (!pending) {
5405
5484
  pending = (async () => {
5406
5485
  try {
5407
- const allowed = await work.hookGate.run(
5408
- () => evaluateRouteGuard(
5409
- owner.request,
5410
- owner.permissions,
5411
- getCapturedAuthorizationOption(target.configuration, "operationAccess.read")
5412
- )
5413
- );
5414
- if (!allowed) return void 0;
5486
+ if (target.configuration.requireOperationAccessForPopulateDependencies !== false && !await targetReadAllowed(state, target))
5487
+ return void 0;
5415
5488
  const parts = await work.hookGate.run(
5416
5489
  () => resolveAccessFilterParts({
5417
5490
  req: owner.request,
@@ -5619,12 +5692,12 @@ async function loadVirtualPopulateOutputRows(owner, inputs, plan, publicPopulate
5619
5692
  }
5620
5693
  return output;
5621
5694
  }
5622
- var import_mongoose7, import_node_util5, import_utils26, batches, rows, outputRows, fetchedPublicIdentities, publicViewIdentities, familyRawFetches, addressKey, storage, originalRef, copyOriginalValue, readPolicy, compatible, idKey, logUnavailable;
5695
+ var import_mongoose7, import_node_util5, import_utils27, batches, rows, outputRows, fetchedPublicIdentities, publicViewIdentities, familyRawFetches, addressKey, storage, originalRef, copyOriginalValue, readPolicy, compatible, idKey, logUnavailable;
5623
5696
  var init_virtual_populate_execution = __esm({
5624
5697
  "src/acl/virtual-populate-execution.ts"() {
5625
5698
  import_mongoose7 = require("mongoose");
5626
5699
  import_node_util5 = require("util");
5627
- import_utils26 = require("@web-ts-toolkit/utils");
5700
+ import_utils27 = require("@web-ts-toolkit/utils");
5628
5701
  init_cache();
5629
5702
  init_core_shared();
5630
5703
  init_document();
@@ -5641,7 +5714,7 @@ var init_virtual_populate_execution = __esm({
5641
5714
  publicViewIdentities = /* @__PURE__ */ new WeakMap();
5642
5715
  familyRawFetches = /* @__PURE__ */ new WeakMap();
5643
5716
  addressKey = (address) => JSON.stringify(address);
5644
- storage = (value) => value instanceof import_mongoose7.Document ? value._doc : (0, import_utils26.isPlainObject)(value) ? value : void 0;
5717
+ storage = (value) => value instanceof import_mongoose7.Document ? value._doc : (0, import_utils27.isPlainObject)(value) ? value : void 0;
5645
5718
  originalRef = (source, key) => {
5646
5719
  const record3 = storage(source);
5647
5720
  return {
@@ -5654,7 +5727,7 @@ var init_virtual_populate_execution = __esm({
5654
5727
  const option = getCapturedAuthorizationOption(configuration, `${key}.${access}`);
5655
5728
  return key === "operationAccess" || typeof option === "function" ? option : void 0;
5656
5729
  });
5657
- compatible = (a, b) => a.binding.runtime === b.binding.runtime && a.binding.model === b.binding.model && a.binding.schema === b.binding.schema && a.access === b.access && a.requestRead === b.requestRead && // Different captures may share only an equivalent terminal persisted binding/policy.
5730
+ compatible = (a, b) => a.binding.runtime === b.binding.runtime && a.binding.model === b.binding.model && a.binding.schema === b.binding.schema && a.access === b.access && a.requestRead === b.requestRead && a.binding.configuration.requireOperationAccessForPopulateDependencies === b.binding.configuration.requireOperationAccessForPopulateDependencies && // Different captures may share only an equivalent terminal persisted binding/policy.
5658
5731
  equivalentVirtualPopulatePredicate(
5659
5732
  a.binding.configuration.catalog.persistedPaths,
5660
5733
  b.binding.configuration.catalog.persistedPaths
@@ -5681,7 +5754,7 @@ async function resolveOutputDocumentAuthorization(args) {
5681
5754
  try {
5682
5755
  const run = () => hook.call(this, doc, permissions, args.context);
5683
5756
  const grants = await getRequestWorkState(binding.request, binding.runtime).hookGate.run(run);
5684
- return (0, import_utils27.isPlainObject)(grants) ? grants : {};
5757
+ return (0, import_utils28.isPlainObject)(grants) ? grants : {};
5685
5758
  } catch (error2) {
5686
5759
  warn("docPermissions hook failed; applying empty document permissions", {
5687
5760
  modelName: binding.modelName,
@@ -5796,7 +5869,7 @@ function copyOutputValue(value, plan, path) {
5796
5869
  const visit = (input, current) => {
5797
5870
  if (Array.isArray(input)) return input.map((entry) => visit(entry, current));
5798
5871
  if (input instanceof Map) return visit(Object.fromEntries(input), current);
5799
- if (!(0, import_utils27.isPlainObject)(input)) return deepIsolateValue(input);
5872
+ if (!(0, import_utils28.isPlainObject)(input)) return deepIsolateValue(input);
5800
5873
  const output = {};
5801
5874
  for (const [key, entry] of Object.entries(input)) {
5802
5875
  const child = `${current}.${key}`;
@@ -5812,25 +5885,21 @@ function copyOutputValue(value, plan, path) {
5812
5885
  }
5813
5886
  function copyAuthorizedReference(value, plan, path) {
5814
5887
  if (Array.isArray(value)) return value.map((entry) => copyAuthorizedReference(entry, plan, path));
5815
- if (!(0, import_utils27.isPlainObject)(value)) return deepIsolateValue(value);
5888
+ if (!(0, import_utils28.isPlainObject)(value)) return deepIsolateValue(value);
5816
5889
  const handle = getAssociatedDocumentAuthorization(value, plan.authorization);
5817
5890
  if (handle) {
5818
5891
  const copy = deepIsolateValue(value);
5819
5892
  transferDocumentAuthorizationGraph(value, copy);
5820
5893
  return copy;
5821
5894
  }
5822
- const { relatedTargets } = readServiceAuthorization(plan.authorization, plan.authorizationBinding);
5823
- if (relatedTargets.some((target) => target.path === path && target.kind === "passthrough")) {
5824
- return deepIsolateValue(value);
5825
- }
5826
5895
  return Object.prototype.hasOwnProperty.call(value, "_id") ? deepIsolateValue(value._id) : void 0;
5827
5896
  }
5828
5897
  function retainOutputMetadata(output, source, configuration, scope2) {
5829
5898
  if (scope2.length || configuration.stripPermissionsField) return;
5830
5899
  const parts = (configuration.documentPermissionField ?? "_permissions").split(".");
5831
5900
  let value = source;
5832
- for (const part of parts) value = (0, import_utils27.isPlainObject)(value) ? value[part] : void 0;
5833
- if (!(0, import_utils27.isPlainObject)(value)) return;
5901
+ for (const part of parts) value = (0, import_utils28.isPlainObject)(value) ? value[part] : void 0;
5902
+ if (!(0, import_utils28.isPlainObject)(value)) return;
5834
5903
  const keys2 = configuration.exposedDocPermissionKeys;
5835
5904
  const metadata = Object.fromEntries(
5836
5905
  Object.entries(value).filter(
@@ -5840,7 +5909,7 @@ function retainOutputMetadata(output, source, configuration, scope2) {
5840
5909
  const copy = { ...output };
5841
5910
  let target = copy;
5842
5911
  for (const part of parts.slice(0, -1)) {
5843
- target[part] = (0, import_utils27.isPlainObject)(target[part]) ? { ...target[part] } : {};
5912
+ target[part] = (0, import_utils28.isPlainObject)(target[part]) ? { ...target[part] } : {};
5844
5913
  target = target[part];
5845
5914
  }
5846
5915
  target[parts[parts.length - 1]] = deepIsolateValue(metadata);
@@ -5882,7 +5951,7 @@ async function filterExistingOutput(source, plan, handle, associated) {
5882
5951
  for (const entry of value2) values.push(await one(entry) ?? null);
5883
5952
  return values;
5884
5953
  }
5885
- if (!(0, import_utils27.isPlainObject)(value2)) return value2 === null ? null : void 0;
5954
+ if (!(0, import_utils28.isPlainObject)(value2)) return value2 === null ? null : void 0;
5886
5955
  const childHandle = associated ? getAssociatedDocumentAuthorization(value2) : void 0;
5887
5956
  let child = scoped;
5888
5957
  if (childHandle) {
@@ -5962,7 +6031,7 @@ async function filterModelOutputForHelper(args) {
5962
6031
  const plan = helperPlan(normalized.authorization, binding);
5963
6032
  if (args.doc == null) return { output: args.doc, fields: [] };
5964
6033
  const source = isolateDocForOutput(args.doc);
5965
- if (!(0, import_utils27.isPlainObject)(source)) return authorizationError("output helper requires one plain or hydrated document");
6034
+ if (!(0, import_utils28.isPlainObject)(source)) return authorizationError("output helper requires one plain or hydrated document");
5966
6035
  const knownOutput = !!args.doc && typeof args.doc === "object" && isKnownAuthorizationOutput(args.doc);
5967
6036
  const handle = await resolveOutputDocumentAuthorization({
5968
6037
  authorization: normalized.authorization,
@@ -5973,10 +6042,10 @@ async function filterModelOutputForHelper(args) {
5973
6042
  });
5974
6043
  return filterExistingOutput(source, plan, handle, false);
5975
6044
  }
5976
- var import_utils27, unresolvedDocuments, owningDocuments;
6045
+ var import_utils28, unresolvedDocuments, owningDocuments;
5977
6046
  var init_output_field_filter = __esm({
5978
6047
  "src/acl/output-field-filter.ts"() {
5979
- import_utils27 = require("@web-ts-toolkit/utils");
6048
+ import_utils28 = require("@web-ts-toolkit/utils");
5980
6049
  init_permissions_alias();
5981
6050
  init_document();
5982
6051
  init_request_work();
@@ -6073,8 +6142,8 @@ async function finalizeSingleDoc(args, input) {
6073
6142
  const privateRow = args.virtualPopulateRow ?? (original && typeof original === "object" ? getVirtualPopulateRow(original) : void 0);
6074
6143
  const privateAddress = args.virtualPopulateAddress ?? [];
6075
6144
  const isolated = isolateDocForOutput(input);
6076
- const output = (0, import_utils28.isPlainObject)(isolated) ? isolated : {};
6077
- if (captured && (0, import_utils28.isPlainObject)(input))
6145
+ const output = (0, import_utils29.isPlainObject)(isolated) ? isolated : {};
6146
+ if (captured && (0, import_utils29.isPlainObject)(input))
6078
6147
  for (const key of Object.keys(output)) {
6079
6148
  transferDocumentAuthorizationGraph(input[key], output[key]);
6080
6149
  }
@@ -6129,7 +6198,7 @@ async function finalizeSingleDoc(args, input) {
6129
6198
  );
6130
6199
  continue;
6131
6200
  }
6132
- if (captured && !(0, import_utils28.isPlainObject)(rawContainer) && !Array.isArray(rawContainer)) {
6201
+ if (captured && !(0, import_utils29.isPlainObject)(rawContainer) && !Array.isArray(rawContainer)) {
6133
6202
  delete output[containerName];
6134
6203
  continue;
6135
6204
  }
@@ -6153,7 +6222,7 @@ async function finalizeSingleDoc(args, input) {
6153
6222
  const finalizeOneChild = async (rawChild, address) => {
6154
6223
  if (captured && Array.isArray(rawChild))
6155
6224
  return mapWithConcurrencyLimit(rawChild, limit, (entry, index) => finalizeOneChild(entry, [...address, index]));
6156
- if (!(0, import_utils28.isPlainObject)(rawChild) && !Array.isArray(rawChild)) return captured ? null : deepIsolateValue(rawChild);
6225
+ if (!(0, import_utils29.isPlainObject)(rawChild) && !Array.isArray(rawChild)) return captured ? null : deepIsolateValue(rawChild);
6157
6226
  if (args.traversal?.finalizeEmbeddedChildren) {
6158
6227
  return args.traversal.finalizeEmbeddedChildren({
6159
6228
  containerName,
@@ -6179,7 +6248,7 @@ async function finalizeSingleDoc(args, input) {
6179
6248
  (entry, index) => finalizeOneChild(entry, [...privateAddress, containerName, index])
6180
6249
  );
6181
6250
  output[containerName] = finalized;
6182
- } else if ((0, import_utils28.isPlainObject)(rawContainer)) {
6251
+ } else if ((0, import_utils29.isPlainObject)(rawContainer)) {
6183
6252
  output[containerName] = await finalizeOneChild(rawContainer, [
6184
6253
  ...privateAddress,
6185
6254
  containerName
@@ -6191,8 +6260,8 @@ async function finalizeSingleDoc(args, input) {
6191
6260
  let rawRelated;
6192
6261
  let originalRelated;
6193
6262
  try {
6194
- rawRelated = target.path.includes(".") ? (0, import_utils28.get)(output, target.path) : output[target.path];
6195
- originalRelated = (0, import_utils28.get)(original, target.path);
6263
+ rawRelated = target.path.includes(".") ? (0, import_utils29.get)(output, target.path) : output[target.path];
6264
+ originalRelated = (0, import_utils29.get)(original, target.path);
6196
6265
  } catch {
6197
6266
  continue;
6198
6267
  }
@@ -6223,7 +6292,7 @@ async function finalizeSingleDoc(args, input) {
6223
6292
  related: target.plan.relatedPlans?.length ? (args.related ?? []).filter((entry) => entry.path.startsWith(`${target.path}.`)) : []
6224
6293
  };
6225
6294
  const finalizeOneRelated = async (rawChild, originalChild = rawChild) => {
6226
- if (!(0, import_utils28.isPlainObject)(rawChild) && !Array.isArray(rawChild)) return rawChild;
6295
+ if (!(0, import_utils29.isPlainObject)(rawChild) && !Array.isArray(rawChild)) return rawChild;
6227
6296
  if (typeof rawChild?._bsontype === "string") return rawChild;
6228
6297
  const childOriginal = getIncludeOriginal(originalChild);
6229
6298
  const childRow = childOriginal && typeof childOriginal === "object" ? getVirtualPopulateRow(childOriginal) : void 0;
@@ -6244,13 +6313,13 @@ async function finalizeSingleDoc(args, input) {
6244
6313
  limit,
6245
6314
  (entry, index) => finalizeOneRelated(entry, Array.isArray(originalRelated) ? originalRelated[index] : void 0)
6246
6315
  );
6247
- } else if ((0, import_utils28.isPlainObject)(rawRelated)) {
6316
+ } else if ((0, import_utils29.isPlainObject)(rawRelated)) {
6248
6317
  finalized = await finalizeOneRelated(rawRelated, originalRelated);
6249
6318
  } else {
6250
6319
  continue;
6251
6320
  }
6252
6321
  try {
6253
- if (target.path.includes(".")) (0, import_utils28.set)(output, target.path, finalized);
6322
+ if (target.path.includes(".")) (0, import_utils29.set)(output, target.path, finalized);
6254
6323
  else output[target.path] = finalized;
6255
6324
  } catch {
6256
6325
  }
@@ -6430,10 +6499,10 @@ async function finalizeModelOutputs(args) {
6430
6499
  return finalizeSingleDoc(internal, input);
6431
6500
  });
6432
6501
  }
6433
- var import_utils28, isVirtualContainerValue3, getScopeVirtualsObject2, getScopeVirtualNames, getScopedPermissionSchema2, resolveGlobalPermissions, resolveDocPermissions, isAbsentDependency, __finalizeInternals;
6502
+ var import_utils29, isVirtualContainerValue3, getScopeVirtualsObject2, getScopeVirtualNames, getScopedPermissionSchema2, resolveGlobalPermissions, resolveDocPermissions, isAbsentDependency, __finalizeInternals;
6434
6503
  var init_finalize_model_output = __esm({
6435
6504
  "src/output/finalize-model-output.ts"() {
6436
- import_utils28 = require("@web-ts-toolkit/utils");
6505
+ import_utils29 = require("@web-ts-toolkit/utils");
6437
6506
  init_document();
6438
6507
  init_concurrency();
6439
6508
  init_request_work();
@@ -6446,20 +6515,20 @@ var init_finalize_model_output = __esm({
6446
6515
  init_field_catalog();
6447
6516
  init_virtual_populate_execution();
6448
6517
  init_include_output();
6449
- isVirtualContainerValue3 = (value) => (0, import_utils28.isPlainObject)(value) && "sub" in value;
6518
+ isVirtualContainerValue3 = (value) => (0, import_utils29.isPlainObject)(value) && "sub" in value;
6450
6519
  getScopeVirtualsObject2 = (rootVirtuals, scopePath) => {
6451
- if (!rootVirtuals || !(0, import_utils28.isPlainObject)(rootVirtuals)) return null;
6520
+ if (!rootVirtuals || !(0, import_utils29.isPlainObject)(rootVirtuals)) return null;
6452
6521
  if (scopePath.length === 0) return rootVirtuals;
6453
6522
  let current = rootVirtuals;
6454
6523
  for (let i = 0; i < scopePath.length; i += 2) {
6455
6524
  const field = scopePath[i];
6456
6525
  const subMarker = scopePath[i + 1];
6457
6526
  if (!field || subMarker !== "sub") return null;
6458
- if (!(0, import_utils28.isPlainObject)(current)) return null;
6527
+ if (!(0, import_utils29.isPlainObject)(current)) return null;
6459
6528
  const container = current[field];
6460
6529
  if (!isVirtualContainerValue3(container)) return null;
6461
6530
  current = container.sub;
6462
- if (!(0, import_utils28.isPlainObject)(current)) return null;
6531
+ if (!(0, import_utils29.isPlainObject)(current)) return null;
6463
6532
  }
6464
6533
  return current;
6465
6534
  };
@@ -6472,11 +6541,11 @@ var init_finalize_model_output = __esm({
6472
6541
  return Object.entries(scopeVirtuals).filter(([, v]) => v !== void 0 && !isVirtualContainerValue3(v)).map(([k]) => k);
6473
6542
  };
6474
6543
  getScopedPermissionSchema2 = (root, scopePath) => {
6475
- if (!root || !(0, import_utils28.isPlainObject)(root)) return null;
6544
+ if (!root || !(0, import_utils29.isPlainObject)(root)) return null;
6476
6545
  if (scopePath.length === 0) return root;
6477
6546
  try {
6478
- const scoped = (0, import_utils28.get)(root, scopePath.join("."));
6479
- return (0, import_utils28.isPlainObject)(scoped) ? scoped : null;
6547
+ const scoped = (0, import_utils29.get)(root, scopePath.join("."));
6548
+ return (0, import_utils29.isPlainObject)(scoped) ? scoped : null;
6480
6549
  } catch {
6481
6550
  return null;
6482
6551
  }
@@ -6535,7 +6604,7 @@ var init_finalize_model_output = __esm({
6535
6604
  const grants = await args.sharedGate.run(
6536
6605
  () => hook.call(args.request, isolatedForHook, globalPerms, scopeContext)
6537
6606
  );
6538
- const normalized = (0, import_utils28.isPlainObject)(grants) ? grants : {};
6607
+ const normalized = (0, import_utils29.isPlainObject)(grants) ? grants : {};
6539
6608
  scopeContext.docPermissions = normalized;
6540
6609
  return normalized;
6541
6610
  }
@@ -6607,40 +6676,20 @@ __export(index_exports, {
6607
6676
  setModelOptions: () => setModelOptions
6608
6677
  });
6609
6678
  module.exports = __toCommonJS(index_exports);
6610
- var import_utils46 = require("@web-ts-toolkit/utils");
6679
+ var import_utils47 = require("@web-ts-toolkit/utils");
6611
6680
 
6612
6681
  // src/middleware.ts
6613
6682
  var import_express_json_router5 = __toESM(require("@web-ts-toolkit/express-json-router"));
6614
- var import_utils39 = require("@web-ts-toolkit/utils");
6683
+ var import_utils40 = require("@web-ts-toolkit/utils");
6615
6684
 
6616
6685
  // src/core.ts
6617
6686
  init_public_admission();
6618
- var import_utils38 = require("@web-ts-toolkit/utils");
6687
+ var import_utils39 = require("@web-ts-toolkit/utils");
6619
6688
  init_options();
6620
-
6621
- // src/meta.ts
6622
- init_runtime();
6623
- init_runtime_context();
6624
- var getRuntime5 = () => getActiveRuntime() ?? defaultRuntime;
6625
- var getModelRef = (modelName, refPath) => {
6626
- const direct = getRuntime5().getModelRef(modelName, refPath);
6627
- if (direct) return direct;
6628
- if (!refPath.includes(".")) return null;
6629
- try {
6630
- const runtime = getRuntime5();
6631
- const instance = runtime.getModelInstance?.(
6632
- modelName
6633
- );
6634
- const schemaPath = instance?.schema?.path?.(refPath);
6635
- const ref = schemaPath?.options?.ref ?? schemaPath?.caster?.options?.ref ?? null;
6636
- return typeof ref === "string" && ref.length > 0 ? ref : null;
6637
- } catch {
6638
- return null;
6639
- }
6640
- };
6689
+ init_permission();
6641
6690
 
6642
6691
  // src/services/base.ts
6643
- var import_utils23 = require("@web-ts-toolkit/utils");
6692
+ var import_utils24 = require("@web-ts-toolkit/utils");
6644
6693
  init_options();
6645
6694
  init_helpers();
6646
6695
  init_document();
@@ -6766,7 +6815,7 @@ function requestFieldScope(options) {
6766
6815
  init_public_admission();
6767
6816
 
6768
6817
  // src/correlated-includes.ts
6769
- var import_utils19 = require("@web-ts-toolkit/utils");
6818
+ var import_utils20 = require("@web-ts-toolkit/utils");
6770
6819
  init_request_complexity();
6771
6820
  init_sort_policy();
6772
6821
  var PARENT_MARKER_KEY = "$parent";
@@ -6779,10 +6828,10 @@ var FIELD_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
6779
6828
  var ARRAY_INDEX_SEGMENT_PATTERN = /^(0|[1-9]\d*)$/;
6780
6829
  var ownKeys = (value) => Object.keys(value);
6781
6830
  function isParentRefMarker(value) {
6782
- return (0, import_utils19.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
6831
+ return (0, import_utils20.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
6783
6832
  }
6784
6833
  function isEscapedParentRef(value) {
6785
- return (0, import_utils19.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
6834
+ return (0, import_utils20.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
6786
6835
  }
6787
6836
  function hasMarkerKey(value) {
6788
6837
  return ownKeys(value).includes(PARENT_MARKER_KEY) || ownKeys(value).includes(ESCAPE_WRAPPER_KEY);
@@ -6801,12 +6850,12 @@ function containsParentMarkerShape(value) {
6801
6850
  const seen = /* @__PURE__ */ new Set();
6802
6851
  const visit = (current) => {
6803
6852
  if (isParentRefMarker(current) || isEscapedParentRef(current)) return true;
6804
- if ((0, import_utils19.isArray)(current)) {
6853
+ if ((0, import_utils20.isArray)(current)) {
6805
6854
  if (seen.has(current)) return false;
6806
6855
  seen.add(current);
6807
6856
  return current.some(visit);
6808
6857
  }
6809
- if ((0, import_utils19.isPlainObject)(current)) {
6858
+ if ((0, import_utils20.isPlainObject)(current)) {
6810
6859
  if (seen.has(current)) return false;
6811
6860
  seen.add(current);
6812
6861
  if (hasMarkerKey(current)) return true;
@@ -6836,7 +6885,7 @@ function scanTemplateValueNode(value, path, issues) {
6836
6885
  }
6837
6886
  return;
6838
6887
  }
6839
- if ((0, import_utils19.isPlainObject)(value)) {
6888
+ if ((0, import_utils20.isPlainObject)(value)) {
6840
6889
  if (hasMarkerKey(value)) {
6841
6890
  issues.push({
6842
6891
  message: 'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }',
@@ -6847,7 +6896,7 @@ function scanTemplateValueNode(value, path, issues) {
6847
6896
  scanTemplateObjectEntries(value, path, issues);
6848
6897
  return;
6849
6898
  }
6850
- if ((0, import_utils19.isArray)(value)) {
6899
+ if ((0, import_utils20.isArray)(value)) {
6851
6900
  value.forEach((item, index) => scanTemplateValueNode(item, [...path, index], issues));
6852
6901
  }
6853
6902
  }
@@ -6888,7 +6937,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
6888
6937
  continue;
6889
6938
  }
6890
6939
  if (LOGICAL_CLAUSE_KEYS.has(key)) {
6891
- if (!(0, import_utils19.isArray)(child)) {
6940
+ if (!(0, import_utils20.isArray)(child)) {
6892
6941
  scanTemplateValueNode(child, childPath, issues);
6893
6942
  continue;
6894
6943
  }
@@ -6901,7 +6950,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
6901
6950
  });
6902
6951
  return;
6903
6952
  }
6904
- if ((0, import_utils19.isPlainObject)(clause)) {
6953
+ if ((0, import_utils20.isPlainObject)(clause)) {
6905
6954
  scanTemplateObjectEntries(clause, clausePath, issues);
6906
6955
  }
6907
6956
  });
@@ -6912,7 +6961,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
6912
6961
  }
6913
6962
  function validateCorrelatedFilterTemplate(filter2) {
6914
6963
  const issues = [];
6915
- if (!(0, import_utils19.isPlainObject)(filter2)) {
6964
+ if (!(0, import_utils20.isPlainObject)(filter2)) {
6916
6965
  issues.push({ message: "Correlated include filter must be an object", path: [] });
6917
6966
  return issues;
6918
6967
  }
@@ -6955,13 +7004,13 @@ function collectFilterReferencePaths(filter2) {
6955
7004
  return;
6956
7005
  }
6957
7006
  if (isEscapedParentRef(value)) return;
6958
- if ((0, import_utils19.isArray)(value)) {
7007
+ if ((0, import_utils20.isArray)(value)) {
6959
7008
  if (seen.has(value)) return;
6960
7009
  seen.add(value);
6961
7010
  value.forEach(visitValue);
6962
7011
  return;
6963
7012
  }
6964
- if ((0, import_utils19.isPlainObject)(value)) {
7013
+ if ((0, import_utils20.isPlainObject)(value)) {
6965
7014
  if (seen.has(value)) return;
6966
7015
  seen.add(value);
6967
7016
  for (const [key, child] of Object.entries(value)) {
@@ -7007,7 +7056,7 @@ function getOwnPathValue(parent, path) {
7007
7056
  return current;
7008
7057
  }
7009
7058
  function cloneSubstitutedValue(value) {
7010
- if ((0, import_utils19.isPlainObject)(value) || (0, import_utils19.isArray)(value)) return (0, import_utils19.cloneDeep)(value);
7059
+ if ((0, import_utils20.isPlainObject)(value) || (0, import_utils20.isArray)(value)) return (0, import_utils20.cloneDeep)(value);
7011
7060
  return value;
7012
7061
  }
7013
7062
  function literalParentRefObject(path) {
@@ -7048,7 +7097,7 @@ function resolveObjectEntries(obj, parent) {
7048
7097
  continue;
7049
7098
  }
7050
7099
  if (LOGICAL_CLAUSE_KEYS.has(key)) {
7051
- if (!(0, import_utils19.isArray)(child)) {
7100
+ if (!(0, import_utils20.isArray)(child)) {
7052
7101
  out[key] = resolveValueNode(child, parent, false);
7053
7102
  continue;
7054
7103
  }
@@ -7056,7 +7105,7 @@ function resolveObjectEntries(obj, parent) {
7056
7105
  if (isParentRefMarker(clause) || isEscapedParentRef(clause)) {
7057
7106
  throw new CorrelatedReferenceError(`Unsupported $parent reference as a direct ${key} clause`);
7058
7107
  }
7059
- if (!(0, import_utils19.isPlainObject)(clause)) return cloneSubstitutedValue(clause);
7108
+ if (!(0, import_utils20.isPlainObject)(clause)) return cloneSubstitutedValue(clause);
7060
7109
  return resolveObjectEntries(clause, parent);
7061
7110
  });
7062
7111
  continue;
@@ -7085,10 +7134,10 @@ function resolveValueNode(template, parent, bare) {
7085
7134
  }
7086
7135
  const value = getOwnPathValue(parent, path);
7087
7136
  if (value === void 0 || value === null) throw UNRESOLVABLE;
7088
- if (bare && (0, import_utils19.isPlainObject)(value)) return { $eq: (0, import_utils19.cloneDeep)(value) };
7137
+ if (bare && (0, import_utils20.isPlainObject)(value)) return { $eq: (0, import_utils20.cloneDeep)(value) };
7089
7138
  return cloneSubstitutedValue(value);
7090
7139
  }
7091
- if ((0, import_utils19.isPlainObject)(template)) {
7140
+ if ((0, import_utils20.isPlainObject)(template)) {
7092
7141
  if (hasMarkerKey(template)) {
7093
7142
  throw new CorrelatedReferenceError(
7094
7143
  'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }'
@@ -7096,7 +7145,7 @@ function resolveValueNode(template, parent, bare) {
7096
7145
  }
7097
7146
  return resolveObjectEntries(template, parent);
7098
7147
  }
7099
- if ((0, import_utils19.isArray)(template)) {
7148
+ if ((0, import_utils20.isArray)(template)) {
7100
7149
  return template.map((item) => resolveValueNode(item, parent, false));
7101
7150
  }
7102
7151
  return template;
@@ -7130,7 +7179,7 @@ function resolveCorrelatedIdTemplate(id, parent) {
7130
7179
  }
7131
7180
  function resolveCorrelatedFilterTemplate(filter2, parent) {
7132
7181
  try {
7133
- if (!(0, import_utils19.isPlainObject)(filter2) || isParentRefMarker(filter2) || isEscapedParentRef(filter2)) {
7182
+ if (!(0, import_utils20.isPlainObject)(filter2) || isParentRefMarker(filter2) || isEscapedParentRef(filter2)) {
7134
7183
  throw new CorrelatedReferenceError("Correlated include filter must be an object");
7135
7184
  }
7136
7185
  return { status: "resolved", filter: resolveObjectEntries(filter2, parent) };
@@ -7145,7 +7194,7 @@ function validateExpandedCorrelatedOperands(expanded, limits) {
7145
7194
  var MAX_NESTED_INCLUDE_DEPTH = 10;
7146
7195
  function validateCorrelatedArgsShape(args, op, depth) {
7147
7196
  if (args === void 0) return [];
7148
- if (!(0, import_utils19.isPlainObject)(args)) return ["Correlated include args must be an object"];
7197
+ if (!(0, import_utils20.isPlainObject)(args)) return ["Correlated include args must be an object"];
7149
7198
  const record3 = args;
7150
7199
  const allowed = op === "list" ? /* @__PURE__ */ new Set(["select", "sort", "skip", "limit", "page", "pageSize", "include"]) : /* @__PURE__ */ new Set(["select", "sort", "include"]);
7151
7200
  for (const key of Object.keys(record3)) {
@@ -7167,7 +7216,7 @@ function validateCorrelatedArgsShape(args, op, depth) {
7167
7216
  return [];
7168
7217
  }
7169
7218
  function validateCorrelatedIncludeShape(entry, depth = 0) {
7170
- if (!(0, import_utils19.isPlainObject)(entry)) return ["Correlated include must be an object"];
7219
+ if (!(0, import_utils20.isPlainObject)(entry)) return ["Correlated include must be an object"];
7171
7220
  const record3 = entry;
7172
7221
  if (record3.mode !== "correlated") return ['Correlated include mode must be "correlated"'];
7173
7222
  if (typeof record3.model !== "string" || record3.model.length === 0)
@@ -7180,7 +7229,7 @@ function validateCorrelatedIncludeShape(entry, depth = 0) {
7180
7229
  if ("localField" in record3 || "foreignField" in record3) {
7181
7230
  return ["Correlated includes must not carry localField or foreignField"];
7182
7231
  }
7183
- if (record3.options !== void 0 && !((0, import_utils19.isPlainObject)(record3.options) && Object.keys(record3.options).length === 0)) {
7232
+ if (record3.options !== void 0 && !((0, import_utils20.isPlainObject)(record3.options) && Object.keys(record3.options).length === 0)) {
7184
7233
  return ["Correlated include options must be absent or empty"];
7185
7234
  }
7186
7235
  const hasId = record3.id !== void 0;
@@ -7202,7 +7251,7 @@ function validateCorrelatedIncludeShape(entry, depth = 0) {
7202
7251
  return validateCorrelatedArgsShape(record3.args, record3.op, depth);
7203
7252
  }
7204
7253
  function isCorrelatedInclude(value) {
7205
- return (0, import_utils19.isPlainObject)(value) && value.mode === "correlated";
7254
+ return (0, import_utils20.isPlainObject)(value) && value.mode === "correlated";
7206
7255
  }
7207
7256
 
7208
7257
  // src/services/base.ts
@@ -7269,6 +7318,11 @@ function modelServiceOptions(receiver, read) {
7269
7318
  if (call?.receiver !== receiver) return read();
7270
7319
  return call.options ??= read();
7271
7320
  }
7321
+ function modelServiceGlobalOptions(receiver, runtime) {
7322
+ const call = dispatch.getStore();
7323
+ if (call?.receiver !== receiver) return runtime.getGlobalOptions();
7324
+ return call.globalOptions ??= runtime.getGlobalOptions();
7325
+ }
7272
7326
 
7273
7327
  // src/services/base.ts
7274
7328
  init_request_work();
@@ -7421,9 +7475,31 @@ function castCountGroups(input, values) {
7421
7475
  // src/services/base.ts
7422
7476
  init_service_authorization();
7423
7477
 
7478
+ // src/meta.ts
7479
+ init_runtime();
7480
+ init_runtime_context();
7481
+ var getRuntime5 = () => getActiveRuntime() ?? defaultRuntime;
7482
+ var getModelRef = (modelName, refPath, runtime = getRuntime5()) => {
7483
+ const direct = runtime.getModelRef(modelName, refPath);
7484
+ if (direct) return direct;
7485
+ if (!refPath.includes(".")) return null;
7486
+ try {
7487
+ const instance = runtime.getModelInstance?.(
7488
+ modelName
7489
+ );
7490
+ const schemaPath = instance?.schema?.path?.(refPath);
7491
+ const element = schemaPath?.$embeddedSchemaType ?? schemaPath?.embeddedSchemaType ?? schemaPath?.caster;
7492
+ const ref = schemaPath?.options?.ref ?? element?.options?.ref ?? null;
7493
+ return typeof ref === "string" && ref.length > 0 ? ref : null;
7494
+ } catch {
7495
+ return null;
7496
+ }
7497
+ };
7498
+
7424
7499
  // src/acl/related-execution.ts
7425
7500
  init_public_admission();
7426
7501
  init_model_output_planning();
7502
+ init_populate_target_configuration();
7427
7503
  init_authorization_snapshot();
7428
7504
 
7429
7505
  // src/acl/service-execution.ts
@@ -7709,7 +7785,7 @@ function staticObjectIdReference(runtime, source, path, target) {
7709
7785
  const scalar = type?.instance === "Array" ? type.$embeddedSchemaType ?? type.embeddedSchemaType ?? type.caster : type;
7710
7786
  return scalar?.instance === "ObjectId" && (type?.options?.ref ?? scalar.options?.ref) === target && type?.options?.refPath === void 0 && scalar.options?.refPath === void 0;
7711
7787
  }
7712
- function captureRelatedTargets(runtime, modelName, args = {}, depth = 0) {
7788
+ function captureRelatedTargets(runtime, modelName, args = {}, depth = 0, globalOptions = runtime.getGlobalOptions()) {
7713
7789
  if (depth > 32) authorizationError("related descriptor depth exceeded");
7714
7790
  assertPublicAdmission(args.populate, "populate");
7715
7791
  assertPublicAdmission(args.include, "include");
@@ -7718,21 +7794,20 @@ function captureRelatedTargets(runtime, modelName, args = {}, depth = 0) {
7718
7794
  for (const entry of entries(args.populate)) {
7719
7795
  const path = typeof entry === "string" ? entry : entry.path;
7720
7796
  if (typeof entry !== "string") assertPopulateAccess(entry.access);
7721
- const model = getModelRef(modelName, path);
7722
- if (model && runtime.hasModel(model))
7797
+ const model = getModelRef(modelName, path, runtime);
7798
+ if (model) {
7799
+ const target = capturePopulateTargetConfiguration(runtime, model, `${modelName}.${path}`);
7723
7800
  targets.push({
7724
7801
  path,
7725
7802
  modelName: model,
7726
- configuration: captureModelAuthorizationConfiguration(runtime, model),
7803
+ configuration: captureModelAuthorizationConfiguration(runtime, model, target.options, globalOptions),
7727
7804
  staticObjectIdReference: staticObjectIdReference(runtime, modelName, path, model)
7728
7805
  });
7729
- else if (model && !runtime.getGlobalOption("requireRegisteredPopulateModels", true)) {
7730
- targets.push({ path, modelName: model, kind: "passthrough", configuration: { catalog: { paths: [] } } });
7731
7806
  }
7732
7807
  }
7733
7808
  for (const entry of entries(args.include)) {
7734
7809
  if (!runtime.hasModel(entry.model)) authorizationError(`Model ${entry.model} not found`);
7735
- const configuration = captureModelAuthorizationConfiguration(runtime, entry.model);
7810
+ const configuration = captureModelAuthorizationConfiguration(runtime, entry.model, void 0, globalOptions);
7736
7811
  const queryIntent = entry.op === "count" ? void 0 : captureModelServiceIntent(
7737
7812
  {
7738
7813
  defaults: configuration.defaults ?? {},
@@ -7758,7 +7833,13 @@ function captureRelatedTargets(runtime, modelName, args = {}, depth = 0) {
7758
7833
  configuration,
7759
7834
  queryIntent,
7760
7835
  operationGuard: runtime.getModelOption(entry.model, `operationAccess.${entry.op}`),
7761
- relatedTargets: captureRelatedTargets(runtime, entry.model, queryIntent?.args ?? entry.args ?? {}, depth + 1)
7836
+ relatedTargets: captureRelatedTargets(
7837
+ runtime,
7838
+ entry.model,
7839
+ queryIntent?.args ?? entry.args ?? {},
7840
+ depth + 1,
7841
+ globalOptions
7842
+ )
7762
7843
  });
7763
7844
  }
7764
7845
  if (new Set(targets.map((target) => target.path)).size !== targets.length)
@@ -7907,20 +7988,20 @@ var copyAuthorizedOutput = (value) => {
7907
7988
  transferDocumentAuthorizationGraph(value, copy);
7908
7989
  return copy;
7909
7990
  };
7910
- var isVirtualContainerValueForGuard = (value) => (0, import_utils23.isPlainObject)(value) && "sub" in value;
7991
+ var isVirtualContainerValueForGuard = (value) => (0, import_utils24.isPlainObject)(value) && "sub" in value;
7911
7992
  var getScopeVirtualsForGuard = (rootVirtuals, scopePath) => {
7912
- if (!rootVirtuals || !(0, import_utils23.isPlainObject)(rootVirtuals)) return null;
7993
+ if (!rootVirtuals || !(0, import_utils24.isPlainObject)(rootVirtuals)) return null;
7913
7994
  if (scopePath.length === 0) return rootVirtuals;
7914
7995
  let current = rootVirtuals;
7915
7996
  for (let i = 0; i < scopePath.length; i += 2) {
7916
7997
  const field = scopePath[i];
7917
7998
  const subMarker = scopePath[i + 1];
7918
7999
  if (!field || subMarker !== "sub") return null;
7919
- if (!(0, import_utils23.isPlainObject)(current)) return null;
8000
+ if (!(0, import_utils24.isPlainObject)(current)) return null;
7920
8001
  const container = current[field];
7921
8002
  if (!isVirtualContainerValueForGuard(container)) return null;
7922
8003
  current = container.sub;
7923
- if (!(0, import_utils23.isPlainObject)(current)) return null;
8004
+ if (!(0, import_utils24.isPlainObject)(current)) return null;
7924
8005
  }
7925
8006
  return current;
7926
8007
  };
@@ -7986,7 +8067,7 @@ var sanitizeSubScopeVirtualKeys = (data, snapshot, sub) => {
7986
8067
  for (const entry of value) stripScope(entry, currentScope);
7987
8068
  return;
7988
8069
  }
7989
- if (!(0, import_utils23.isPlainObject)(value)) return;
8070
+ if (!(0, import_utils24.isPlainObject)(value)) return;
7990
8071
  const record3 = value;
7991
8072
  const leaves = getScopeVirtualLeafNames(snapshot, currentScope);
7992
8073
  for (const leaf of leaves) {
@@ -7999,7 +8080,7 @@ var sanitizeSubScopeVirtualKeys = (data, snapshot, sub) => {
7999
8080
  for (const key of Object.keys(record3)) {
8000
8081
  if (leaves.has(key) || containers.has(key)) continue;
8001
8082
  const child = record3[key];
8002
- if (Array.isArray(child) || (0, import_utils23.isPlainObject)(child)) {
8083
+ if (Array.isArray(child) || (0, import_utils24.isPlainObject)(child)) {
8003
8084
  stripScope(child, currentScope);
8004
8085
  }
8005
8086
  }
@@ -8011,7 +8092,7 @@ var LOGICAL_FILTER_KEYS = /* @__PURE__ */ new Set(["$and", "$or", "$nor"]);
8011
8092
  var isOperatorKey = (key) => key.startsWith("$");
8012
8093
  var REMOVED_VIRTUAL_FILTER = /* @__PURE__ */ Symbol("removed virtual filter clause");
8013
8094
  var rewriteFilterObject = (value, visit) => {
8014
- if (!(0, import_utils23.isPlainObject)(value)) return value;
8095
+ if (!(0, import_utils24.isPlainObject)(value)) return value;
8015
8096
  let changed = false;
8016
8097
  const entries = [];
8017
8098
  for (const [key, child] of Object.entries(value)) {
@@ -8042,7 +8123,7 @@ var resolveVirtualFilterField = (path, scope2) => {
8042
8123
  if (!Object.hasOwn(scope2, segment) || scope2[segment] === void 0) return null;
8043
8124
  const definition = scope2[segment];
8044
8125
  if (!isVirtualContainerValueForGuard(definition)) return REMOVED_VIRTUAL_FILTER;
8045
- scope2 = (0, import_utils23.isPlainObject)(definition.sub) ? definition.sub : null;
8126
+ scope2 = (0, import_utils24.isPlainObject)(definition.sub) ? definition.sub : null;
8046
8127
  inContainer = true;
8047
8128
  }
8048
8129
  return scope2;
@@ -8054,7 +8135,7 @@ var stripVirtualFilterOperator = (key, value, scope2) => {
8054
8135
  }
8055
8136
  if (key === "$all") {
8056
8137
  return rewriteFilterClauses(value, (entry) => {
8057
- if (!(0, import_utils23.isPlainObject)(entry) || Object.keys(entry).length !== 1 || !Object.hasOwn(entry, "$elemMatch")) return entry;
8138
+ if (!(0, import_utils24.isPlainObject)(entry) || Object.keys(entry).length !== 1 || !Object.hasOwn(entry, "$elemMatch")) return entry;
8058
8139
  return rewriteFilterObject(entry, (operator, operand) => stripVirtualFilterOperator(operator, operand, scope2));
8059
8140
  });
8060
8141
  }
@@ -8069,7 +8150,7 @@ var stripVirtualFilterQuery = (value, scope2, element = false) => {
8069
8150
  if (isOperatorKey(key)) return element ? stripVirtualFilterOperator(key, child, scope2) : child;
8070
8151
  const fieldScope = resolveVirtualFilterField(key, scope2);
8071
8152
  if (fieldScope === REMOVED_VIRTUAL_FILTER) return REMOVED_VIRTUAL_FILTER;
8072
- if (!fieldScope || !(0, import_utils23.isPlainObject)(child)) return child;
8153
+ if (!fieldScope || !(0, import_utils24.isPlainObject)(child)) return child;
8073
8154
  if (Object.keys(child).some(isOperatorKey)) {
8074
8155
  return rewriteFilterObject(
8075
8156
  child,
@@ -8091,9 +8172,9 @@ var stripSubVirtualKeysFromFilter = (filter2, snapshot, sub) => {
8091
8172
  function getCorrelatedTemplateDepth(includes) {
8092
8173
  let max = 0;
8093
8174
  const visit = (entries, depth) => {
8094
- const list = (0, import_utils23.castArray)(entries).filter(Boolean);
8175
+ const list = (0, import_utils24.castArray)(entries).filter(Boolean);
8095
8176
  for (const entry of list) {
8096
- if (!(0, import_utils23.isPlainObject)(entry)) continue;
8177
+ if (!(0, import_utils24.isPlainObject)(entry)) continue;
8097
8178
  max = Math.max(max, depth);
8098
8179
  const nested = entry.args?.include;
8099
8180
  if (nested !== void 0) {
@@ -8118,11 +8199,11 @@ function validateClientFilter(filter2) {
8118
8199
  }
8119
8200
  const blockedOperators = /* @__PURE__ */ new Set(["$where", "$expr", "$function", "$accumulator"]);
8120
8201
  const visit = (value, path) => {
8121
- if ((0, import_utils23.isArray)(value)) {
8202
+ if ((0, import_utils24.isArray)(value)) {
8122
8203
  value.forEach((item, index) => visit(item, `${path}[${index}]`));
8123
8204
  return;
8124
8205
  }
8125
- if (!(0, import_utils23.isPlainObject)(value)) return;
8206
+ if (!(0, import_utils24.isPlainObject)(value)) return;
8126
8207
  Object.entries(value).forEach(([key, child]) => {
8127
8208
  const nextPath = path ? `${path}.${key}` : key;
8128
8209
  if (blockedOperators.has(key)) {
@@ -8327,7 +8408,7 @@ var Base = class {
8327
8408
  }
8328
8409
  processInclude(include, authorization) {
8329
8410
  assertPublicAdmission(include, "include");
8330
- const items = (0, import_utils23.compact)((0, import_utils23.castArray)(include));
8411
+ const items = (0, import_utils24.compact)((0, import_utils24.castArray)(include));
8331
8412
  const legacy = [];
8332
8413
  const correlated = [];
8333
8414
  const correlatedReferenceFields = [];
@@ -8363,23 +8444,23 @@ var Base = class {
8363
8444
  else this.assertIncludeOutputPaths([...legacy, ...correlated]);
8364
8445
  let includeLocalFields = [];
8365
8446
  let includePaths = [];
8366
- (0, import_utils23.forEach)(legacy, (inc) => {
8447
+ (0, import_utils24.forEach)(legacy, (inc) => {
8367
8448
  includeLocalFields.push(inc.localField);
8368
8449
  includePaths.push(inc.path);
8369
8450
  });
8370
- includeLocalFields = (0, import_utils23.uniq)((0, import_utils23.compact)(includeLocalFields));
8371
- includePaths = (0, import_utils23.uniq)((0, import_utils23.compact)(includePaths));
8451
+ includeLocalFields = (0, import_utils24.uniq)((0, import_utils24.compact)(includeLocalFields));
8452
+ includePaths = (0, import_utils24.uniq)((0, import_utils24.compact)(includePaths));
8372
8453
  return {
8373
8454
  includes: legacy,
8374
8455
  correlatedIncludes: correlated,
8375
8456
  includeLocalFields,
8376
8457
  includePaths,
8377
- correlatedReferenceFields: (0, import_utils23.uniq)((0, import_utils23.compact)(correlatedReferenceFields))
8458
+ correlatedReferenceFields: (0, import_utils24.uniq)((0, import_utils24.compact)(correlatedReferenceFields))
8378
8459
  };
8379
8460
  }
8380
8461
  validateIncludeOutputPath(path, modelName, configuration) {
8381
8462
  const permissionField = configuration ? configuration.documentPermissionField ?? "_permissions" : getModelOption(modelName, "documentPermissionField");
8382
- if ((0, import_utils23.get)((0, import_utils23.set)({}, path, true), permissionField) !== void 0 || (0, import_utils23.get)((0, import_utils23.set)({}, permissionField, true), path) !== void 0) {
8463
+ if ((0, import_utils24.get)((0, import_utils24.set)({}, path, true), permissionField) !== void 0 || (0, import_utils24.get)((0, import_utils24.set)({}, permissionField, true), path) !== void 0) {
8383
8464
  this.throwClientRequestError(
8384
8465
  "bad_request" /* BadRequest */,
8385
8466
  `Include output path ${path} overlaps document permission field ${permissionField} on model ${modelName}`
@@ -8404,9 +8485,9 @@ var Base = class {
8404
8485
  const walk = (node, prefix) => {
8405
8486
  for (const [key, value] of Object.entries(node)) {
8406
8487
  if (value === void 0) continue;
8407
- if ((0, import_utils23.isPlainObject)(value) && "sub" in value) {
8488
+ if ((0, import_utils24.isPlainObject)(value) && "sub" in value) {
8408
8489
  const sub = value.sub;
8409
- if ((0, import_utils23.isPlainObject)(sub)) walk(sub, prefix ? `${prefix}.${key}` : key);
8490
+ if ((0, import_utils24.isPlainObject)(sub)) walk(sub, prefix ? `${prefix}.${key}` : key);
8410
8491
  continue;
8411
8492
  }
8412
8493
  out.push(prefix ? `${prefix}.${key}` : key);
@@ -8459,7 +8540,7 @@ var Base = class {
8459
8540
  this.throwClientRequestError("bad_request" /* BadRequest */, `Model ${modelName} not found`);
8460
8541
  }
8461
8542
  for (const entry of entries) {
8462
- if (!(0, import_utils23.isPlainObject)(entry)) continue;
8543
+ if (!(0, import_utils24.isPlainObject)(entry)) continue;
8463
8544
  const models = visited.get(entry) ?? /* @__PURE__ */ new Set();
8464
8545
  if (models.has(modelName)) continue;
8465
8546
  models.add(modelName);
@@ -8472,7 +8553,7 @@ var Base = class {
8472
8553
  const target = targets?.find((target2) => target2.path === entry.path);
8473
8554
  if (nested)
8474
8555
  pending.push({
8475
- entries: (0, import_utils23.compact)((0, import_utils23.castArray)(nested)),
8556
+ entries: (0, import_utils24.compact)((0, import_utils24.castArray)(nested)),
8476
8557
  modelName: entry.model,
8477
8558
  configuration: target?.configuration,
8478
8559
  targets: target?.relatedTargets
@@ -8482,7 +8563,7 @@ var Base = class {
8482
8563
  }
8483
8564
  }
8484
8565
  getForeignKeyValues(value) {
8485
- return (0, import_utils23.flatten)((0, import_utils23.castArray)(value));
8566
+ return (0, import_utils24.flatten)((0, import_utils24.castArray)(value));
8486
8567
  }
8487
8568
  getForeignKey(value) {
8488
8569
  return String(value);
@@ -8490,7 +8571,7 @@ var Base = class {
8490
8571
  buildForeignKeyIndex(rows2, foreignField) {
8491
8572
  const index = /* @__PURE__ */ new Map();
8492
8573
  for (const row of rows2) {
8493
- for (const value of this.getForeignKeyValues((0, import_utils23.get)(row, foreignField))) {
8574
+ for (const value of this.getForeignKeyValues((0, import_utils24.get)(row, foreignField))) {
8494
8575
  const key = this.getForeignKey(value);
8495
8576
  const values = index.get(key);
8496
8577
  if (values) values.push(row);
@@ -8526,9 +8607,9 @@ var Base = class {
8526
8607
  async includeDocs(docs, include, parentAuthorization) {
8527
8608
  assertPublicAdmission(include, "include");
8528
8609
  if (!include) return docs;
8529
- const includes = (0, import_utils23.compact)((0, import_utils23.castArray)(include));
8610
+ const includes = (0, import_utils24.compact)((0, import_utils24.castArray)(include));
8530
8611
  if (includes.length === 0) return docs;
8531
- const isSingle = !(0, import_utils23.isArray)(docs);
8612
+ const isSingle = !(0, import_utils24.isArray)(docs);
8532
8613
  let docList = (isSingle ? [docs] : docs).map(prepareIncludeOutput);
8533
8614
  for (let x = 0; x < includes.length; x++) {
8534
8615
  const include2 = includes[x];
@@ -8558,7 +8639,7 @@ var Base = class {
8558
8639
  const svc = await this.getAuthorizedTargetService(model, "read", path, parentAuthorization);
8559
8640
  for (let y = 0; y < docs.length; y++) {
8560
8641
  const doc = docs[y];
8561
- const localValue = (0, import_utils23.get)(doc, localField);
8642
+ const localValue = (0, import_utils24.get)(doc, localField);
8562
8643
  const execution = this.relatedExecution(svc, include, parentAuthorization);
8563
8644
  const prepared = await prepareModelQuery(
8564
8645
  svc,
@@ -8593,15 +8674,15 @@ var Base = class {
8593
8674
  const { model, op, path, localField, foreignField, filter: _filters, args = {}, options = {} } = include;
8594
8675
  const svc = await this.getAuthorizedTargetService(model, op, path, parentAuthorization);
8595
8676
  const includeLocalValues = [];
8596
- (0, import_utils23.forEach)(docs, (doc) => {
8597
- includeLocalValues.push(...this.getForeignKeyValues((0, import_utils23.get)(doc, localField)));
8677
+ (0, import_utils24.forEach)(docs, (doc) => {
8678
+ includeLocalValues.push(...this.getForeignKeyValues((0, import_utils24.get)(doc, localField)));
8598
8679
  });
8599
8680
  const execution = this.relatedExecution(svc, include, parentAuthorization);
8600
8681
  const prepared = await prepareModelQuery(
8601
8682
  svc,
8602
8683
  execution,
8603
8684
  { kind: "client-read", filter: _filters ?? {} },
8604
- { [foreignField]: { $in: (0, import_utils23.flatten)(includeLocalValues) } },
8685
+ { [foreignField]: { $in: (0, import_utils24.flatten)(includeLocalValues) } },
8605
8686
  true
8606
8687
  );
8607
8688
  const trustedArgs = this.sanitizeIncludeArgs(args, "list");
@@ -8644,7 +8725,7 @@ var Base = class {
8644
8725
  }
8645
8726
  for (let y = 0; y < docs.length; y++) {
8646
8727
  const doc = docs[y];
8647
- const matches = this.getIndexedMatches(index, (0, import_utils23.get)(doc, localField));
8728
+ const matches = this.getIndexedMatches(index, (0, import_utils24.get)(doc, localField));
8648
8729
  const isolated = matches.map((m) => copyAuthorizedOutput(m));
8649
8730
  attachIncludeOutput(doc, path, op === "list" ? isolated : isolated[0]);
8650
8731
  }
@@ -8653,7 +8734,7 @@ var Base = class {
8653
8734
  async includeDocsCount(docs, include, parentAuthorization) {
8654
8735
  const { model, path, localField, foreignField, filter: _filters } = include;
8655
8736
  const svc = await this.getAuthorizedTargetService(model, "count", path, parentAuthorization);
8656
- const groups = prepareCountGroups(docs, (doc) => (0, import_utils23.get)(doc, localField));
8737
+ const groups = prepareCountGroups(docs, (doc) => (0, import_utils24.get)(doc, localField));
8657
8738
  const execution = this.relatedExecution(svc, include, parentAuthorization);
8658
8739
  const prepared = await prepareModelQuery(
8659
8740
  svc,
@@ -8707,7 +8788,7 @@ var Base = class {
8707
8788
  }
8708
8789
  const state = this.getCorrelatedExecState();
8709
8790
  docs = docs.map(prepareIncludeOutput);
8710
- const resolvedSnapshots = snapshots2 ?? docs.map((doc) => (0, import_utils23.cloneDeep)(toObject(getIncludeSource(doc))));
8791
+ const resolvedSnapshots = snapshots2 ?? docs.map((doc) => (0, import_utils24.cloneDeep)(toObject(getIncludeSource(doc))));
8711
8792
  for (const include of correlatedIncludes) {
8712
8793
  switch (include.op) {
8713
8794
  case "read":
@@ -9056,10 +9137,10 @@ var Base = class {
9056
9137
  }
9057
9138
  let ret = result2.data;
9058
9139
  if (sqOptions.path) {
9059
- ret = (0, import_utils23.isArray)(ret) ? (0, import_utils23.flatten)(ret.map((v) => (0, import_utils23.get)(v, sqOptions.path))) : (0, import_utils23.get)(ret, sqOptions.path);
9140
+ ret = (0, import_utils24.isArray)(ret) ? (0, import_utils24.flatten)(ret.map((v) => (0, import_utils24.get)(v, sqOptions.path))) : (0, import_utils24.get)(ret, sqOptions.path);
9060
9141
  }
9061
9142
  if (sqOptions.compact) {
9062
- ret = (0, import_utils23.compact)((0, import_utils23.castArray)(ret));
9143
+ ret = (0, import_utils24.compact)((0, import_utils24.castArray)(ret));
9063
9144
  }
9064
9145
  return ret;
9065
9146
  }
@@ -9071,11 +9152,11 @@ var Base = class {
9071
9152
  };
9072
9153
 
9073
9154
  // src/services/service.ts
9074
- var import_utils34 = require("@web-ts-toolkit/utils");
9155
+ var import_utils35 = require("@web-ts-toolkit/utils");
9075
9156
  var import_just_diff = require("just-diff");
9076
9157
 
9077
9158
  // src/model.ts
9078
- var import_utils24 = require("@web-ts-toolkit/utils");
9159
+ var import_utils25 = require("@web-ts-toolkit/utils");
9079
9160
  init_runtime_context();
9080
9161
  init_runtime();
9081
9162
  function admitModelPersistence(adapter, scheduler) {
@@ -9151,7 +9232,7 @@ var Model = class {
9151
9232
  }
9152
9233
  /** Cast a copy using this model's query schema/setters, without executing query middleware or persistence. */
9153
9234
  castFilter(filter2) {
9154
- const query = this.mongooseModel.countDocuments((0, import_utils24.cloneDeep)(filter2));
9235
+ const query = this.mongooseModel.countDocuments((0, import_utils25.cloneDeep)(filter2));
9155
9236
  return query.cast(this.mongooseModel);
9156
9237
  }
9157
9238
  // see https://mongoosejs.com/docs/api.html#model_Model.distinct
@@ -9165,7 +9246,7 @@ var Model = class {
9165
9246
  var model_default = Model;
9166
9247
 
9167
9248
  // src/acl/distinct-field-authorization.ts
9168
- var import_utils25 = require("@web-ts-toolkit/utils");
9249
+ var import_utils26 = require("@web-ts-toolkit/utils");
9169
9250
  init_field_authorization();
9170
9251
  init_field_catalog();
9171
9252
  var schemaVariants = (schema) => Object.values(schema.discriminators ?? {});
@@ -9247,8 +9328,8 @@ function isDistinctFieldAuthorized(args) {
9247
9328
  if (path !== field && !path.startsWith(`${field}.`) && !field.startsWith(`${path}.`)) continue;
9248
9329
  if (path.startsWith(`${field}.`) && (!eligible(path) || !schemaShape(schema, path) || !granted(path)))
9249
9330
  return false;
9250
- if ((0, import_utils25.isPlainObject)(raw) && raw.sub !== void 0) {
9251
- if (!(0, import_utils25.isPlainObject)(raw.sub) || !declaredRulesSafe(raw.sub, path, next)) return false;
9331
+ if ((0, import_utils26.isPlainObject)(raw) && raw.sub !== void 0) {
9332
+ if (!(0, import_utils26.isPlainObject)(raw.sub) || !declaredRulesSafe(raw.sub, path, next)) return false;
9252
9333
  }
9253
9334
  }
9254
9335
  return true;
@@ -9330,7 +9411,9 @@ function prepareSubdocumentOutput(service, sub, operation, virtualAccess, output
9330
9411
  captureRelatedTargets(
9331
9412
  getServiceExecutors(service).binding().runtime,
9332
9413
  service.getServiceModelName(),
9333
- { populate }
9414
+ { populate },
9415
+ 0,
9416
+ configuration
9334
9417
  ),
9335
9418
  void 0,
9336
9419
  configuration,
@@ -9423,7 +9506,7 @@ init_document();
9423
9506
  init_populate_target();
9424
9507
 
9425
9508
  // src/helpers/apply-update.ts
9426
- var import_utils29 = require("@web-ts-toolkit/utils");
9509
+ var import_utils30 = require("@web-ts-toolkit/utils");
9427
9510
  init_lib();
9428
9511
  function applyUpdate(target, data, allowedFields) {
9429
9512
  const wholeFields = /* @__PURE__ */ new Set();
@@ -9439,17 +9522,17 @@ function applyUpdate(target, data, allowedFields) {
9439
9522
  }
9440
9523
  };
9441
9524
  for (const field of allowedFields) {
9442
- collectBoundary((0, import_utils29.set)({}, field, true));
9525
+ collectBoundary((0, import_utils30.set)({}, field, true));
9443
9526
  }
9444
9527
  const apply = (values, prefix = "") => {
9445
9528
  for (const [key, value] of Object.entries(values)) {
9446
9529
  const path = prefix ? `${prefix}.${key}` : key;
9447
- if (partialContainers.has(path) && !wholeFields.has(path) && ((0, import_utils29.isPlainObject)(value) || Array.isArray(value))) {
9530
+ if (partialContainers.has(path) && !wholeFields.has(path) && ((0, import_utils30.isPlainObject)(value) || Array.isArray(value))) {
9448
9531
  apply(value, path);
9449
9532
  } else if (isDocument2(target)) {
9450
9533
  target.set(path, value);
9451
9534
  } else {
9452
- (0, import_utils29.set)(target, path, value);
9535
+ (0, import_utils30.set)(target, path, value);
9453
9536
  }
9454
9537
  }
9455
9538
  };
@@ -9457,7 +9540,7 @@ function applyUpdate(target, data, allowedFields) {
9457
9540
  }
9458
9541
 
9459
9542
  // src/acl/model-input-admission.ts
9460
- var import_utils31 = require("@web-ts-toolkit/utils");
9543
+ var import_utils32 = require("@web-ts-toolkit/utils");
9461
9544
  var import_mongoose8 = require("mongoose");
9462
9545
  init_document();
9463
9546
  init_request_work();
@@ -9465,7 +9548,7 @@ init_logger_helpers();
9465
9548
  init_request_complexity();
9466
9549
 
9467
9550
  // src/acl/select-resolution.ts
9468
- var import_utils30 = require("@web-ts-toolkit/utils");
9551
+ var import_utils31 = require("@web-ts-toolkit/utils");
9469
9552
  init_core_shared();
9470
9553
  init_helpers();
9471
9554
  async function collectAllowedFieldsForRequest({
@@ -9539,15 +9622,15 @@ async function resolveSelectForRequest({
9539
9622
  const excludeall = normalizedSelect.every((v) => v.startsWith("-"));
9540
9623
  if (excludeall) {
9541
9624
  normalizedSelect = normalizedSelect.map((v) => v.substring(1));
9542
- fields = (0, import_utils30.difference)(fields, normalizedSelect);
9625
+ fields = (0, import_utils31.difference)(fields, normalizedSelect);
9543
9626
  if (excludeid) fields.push("-_id");
9544
9627
  } else {
9545
- fields = (0, import_utils30.intersection)(normalizedSelect, fields.concat(excludeid ? "-_id" : "_id"));
9628
+ fields = (0, import_utils31.intersection)(normalizedSelect, fields.concat(excludeid ? "-_id" : "_id"));
9546
9629
  }
9547
9630
  }
9548
9631
  return fields.concat(strippedAlways);
9549
9632
  }
9550
- return (0, import_utils30.intersection)(normalizedSelect, fields);
9633
+ return (0, import_utils31.intersection)(normalizedSelect, fields);
9551
9634
  }
9552
9635
  function stripVirtuals(fields, virtualNames) {
9553
9636
  const set13 = virtualNames instanceof Set ? virtualNames : new Set(virtualNames ?? []);
@@ -9578,7 +9661,7 @@ init_field_catalog();
9578
9661
  init_service_authorization();
9579
9662
  var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
9580
9663
  var inside = (path, root) => path === root || path.startsWith(`${root}.`);
9581
- var record2 = (value) => (0, import_utils31.isPlainObject)(value);
9664
+ var record2 = (value) => (0, import_utils32.isPlainObject)(value);
9582
9665
  function inputValue(value) {
9583
9666
  if (typeof value === "function" || typeof value === "symbol") {
9584
9667
  authorizationError("input values must be persisted data, not functions or symbols");
@@ -9647,7 +9730,7 @@ function requestBoundaries(fields) {
9647
9730
  else visit(value, path);
9648
9731
  }
9649
9732
  };
9650
- for (const field of fields) visit((0, import_utils31.set)({}, field, true));
9733
+ for (const field of fields) visit((0, import_utils32.set)({}, field, true));
9651
9734
  return [...new Set(result2)];
9652
9735
  }
9653
9736
  function ownValue(data, parts) {
@@ -9777,7 +9860,7 @@ function admitModelInput(args) {
9777
9860
  if (forbidden(catalog, path, requested)) continue;
9778
9861
  const supplied = ownValue(data, parts);
9779
9862
  if (!supplied) continue;
9780
- (0, import_utils31.set)(allowedData, field, copyInputValue(supplied.value, path, catalog, scopedRequests, logicalPath(field)));
9863
+ (0, import_utils32.set)(allowedData, field, copyInputValue(supplied.value, path, catalog, scopedRequests, logicalPath(field)));
9781
9864
  selected.push(field);
9782
9865
  }
9783
9866
  return { allowedData, allowedFields };
@@ -9789,7 +9872,7 @@ async function requestInputFields(args) {
9789
9872
  const prefix = configuration.modelPermissionPrefix ?? "";
9790
9873
  return collectModelRequestFields({
9791
9874
  req: args.binding.request,
9792
- permissionSchema: args.scopePath ? (0, import_utils31.get)(configuration.permissionSchema, [args.scopePath, "sub"]) : configuration.permissionSchema,
9875
+ permissionSchema: args.scopePath ? (0, import_utils32.get)(configuration.permissionSchema, [args.scopePath, "sub"]) : configuration.permissionSchema,
9793
9876
  access: args.access,
9794
9877
  permissions,
9795
9878
  grants,
@@ -9833,13 +9916,13 @@ init_logger_helpers();
9833
9916
  init_lib();
9834
9917
 
9835
9918
  // src/services/model-subdocument-service.ts
9836
- var import_utils33 = require("@web-ts-toolkit/utils");
9919
+ var import_utils34 = require("@web-ts-toolkit/utils");
9837
9920
  init_helpers();
9838
9921
  init_document();
9839
9922
  init_public_admission();
9840
9923
 
9841
9924
  // src/acl/subdocument-authorization.ts
9842
- var import_utils32 = require("@web-ts-toolkit/utils");
9925
+ var import_utils33 = require("@web-ts-toolkit/utils");
9843
9926
  init_helpers();
9844
9927
  init_document();
9845
9928
  init_core_shared();
@@ -10028,8 +10111,8 @@ async function subdocumentGateAllowed(service, gate) {
10028
10111
  let guard2;
10029
10112
  if (access.startsWith("subs.")) {
10030
10113
  const [, sub, op] = access.split(".");
10031
- guard2 = (0, import_utils32.get)(configuration, `operationAccess.${access}`);
10032
- if (guard2 === void 0) guard2 = (0, import_utils32.get)(configuration, `operationAccess.subs.${sub}`);
10114
+ guard2 = (0, import_utils33.get)(configuration, `operationAccess.${access}`);
10115
+ if (guard2 === void 0) guard2 = (0, import_utils33.get)(configuration, `operationAccess.subs.${sub}`);
10033
10116
  if (guard2 === void 0) guard2 = getCapturedAuthorizationOption(configuration, `operationAccess.${op}`);
10034
10117
  } else guard2 = getCapturedAuthorizationOption(configuration, `operationAccess.${access}`);
10035
10118
  return evaluateRouteGuard(
@@ -10160,7 +10243,7 @@ async function visibleMutationRows(service, call, parentId, rows2) {
10160
10243
  const read = await subdocumentRows(service, visibility.child, selected, selected, call.sub);
10161
10244
  const list = visibility.list ? await subdocumentRows(service, visibility.list, {}, {}, call.sub) : {};
10162
10245
  if (read === false || list === false) return [];
10163
- const visible = filterCollection((0, import_utils33.get)(parent, call.sub), intersectFilters(read, list));
10246
+ const visible = filterCollection((0, import_utils34.get)(parent, call.sub), intersectFilters(read, list));
10164
10247
  return await finalizeSubdocumentRows(service, call.output, parent, visible);
10165
10248
  } catch {
10166
10249
  return [];
@@ -10185,7 +10268,7 @@ async function listSub(service, id, sub, options) {
10185
10268
  populate: []
10186
10269
  });
10187
10270
  if (!parent) return denied2("not_found" /* NotFound */);
10188
- const rows2 = filterCollection((0, import_utils33.get)(parent, sub), childFilter);
10271
+ const rows2 = filterCollection((0, import_utils34.get)(parent, sub), childFilter);
10189
10272
  const data = await finalizeSubdocumentRows(service, call.output, parent, rows2);
10190
10273
  return { success: true, kind: "list", code: "success" /* Success */, data, count: data.length };
10191
10274
  });
@@ -10209,7 +10292,7 @@ async function readSub(service, id, sub, subId, options) {
10209
10292
  });
10210
10293
  if (!parent) return denied2("not_found" /* NotFound */);
10211
10294
  const row = findElement(
10212
- (0, import_utils33.get)(capture ? parent : copySubdocumentParent(parent), sub),
10295
+ (0, import_utils34.get)(capture ? parent : copySubdocumentParent(parent), sub),
10213
10296
  childFilter
10214
10297
  );
10215
10298
  if (!row) return denied2("not_found" /* NotFound */);
@@ -10230,7 +10313,7 @@ async function updateSub(service, persist, id, sub, subId, data, options) {
10230
10313
  const identity = { _id: subId };
10231
10314
  const filter2 = await subdocumentRows(service, call.child, identity, identity, sub);
10232
10315
  if (filter2 === false) return denied2();
10233
- const row = findElement((0, import_utils33.get)(parent, sub), filter2);
10316
+ const row = findElement((0, import_utils34.get)(parent, sub), filter2);
10234
10317
  if (!row) return denied2("not_found" /* NotFound */);
10235
10318
  const original = isolateDocForOutput(row);
10236
10319
  const admit = await inputAdmission(service, call, parent);
@@ -10257,7 +10340,7 @@ async function bulkUpdateSub(service, persist, id, sub, data, options) {
10257
10340
  const selected = { _id: { $in: data.map((row) => row._id) } };
10258
10341
  const filter2 = await subdocumentRows(service, call.child, selected, selected, sub);
10259
10342
  if (filter2 === false) return denied2();
10260
- const rows2 = filterCollection((0, import_utils33.get)(parent, sub), filter2);
10343
+ const rows2 = filterCollection((0, import_utils34.get)(parent, sub), filter2);
10261
10344
  const originals = rows2.map((row) => isolateDocForOutput(row));
10262
10345
  const admit = await inputAdmission(service, call, parent);
10263
10346
  for (const [index, row] of rows2.entries()) {
@@ -10286,7 +10369,7 @@ async function createSub(service, persist, id, sub, data, options) {
10286
10369
  const lookup = await mutationParent(service, id, call);
10287
10370
  if ("error" in lookup) return lookup.error;
10288
10371
  const { parent } = lookup;
10289
- const rows2 = (0, import_utils33.get)(parent, sub);
10372
+ const rows2 = (0, import_utils34.get)(parent, sub);
10290
10373
  const admit = await inputAdmission(service, call, parent);
10291
10374
  const allowed = (Array.isArray(data) ? data : [data]).map((row) => admit(row).allowedData);
10292
10375
  if (addFirst) rows2.unshift(...allowed);
@@ -10307,7 +10390,7 @@ async function deleteSub(service, persist, id, sub, subId, options) {
10307
10390
  const identity = { _id: subId };
10308
10391
  const filter2 = await subdocumentRows(service, call.child, identity, identity, sub);
10309
10392
  if (filter2 === false) return denied2();
10310
- const row = findElement((0, import_utils33.get)(parent, sub), filter2);
10393
+ const row = findElement((0, import_utils34.get)(parent, sub), filter2);
10311
10394
  if (!row) return denied2("not_found" /* NotFound */);
10312
10395
  await ("deleteOne" in row ? row.deleteOne?.() : row.remove?.());
10313
10396
  await persist(() => parent.save());
@@ -10369,10 +10452,12 @@ var Service = class extends Base {
10369
10452
  model: this.model.mongooseModel,
10370
10453
  modelName: this.modelName
10371
10454
  }),
10372
- configuration: () => this.requestRuntime.getModelInstance(this.modelName) ? captureModelAuthorizationConfiguration(this.requestRuntime, this.modelName, {
10373
- ...this.options,
10374
- defaults: this.defaults
10375
- }) : { catalog: { paths: [] }, ...this.options },
10455
+ configuration: () => this.requestRuntime.getModelInstance(this.modelName) ? captureModelAuthorizationConfiguration(
10456
+ this.requestRuntime,
10457
+ this.modelName,
10458
+ { ...this.options, defaults: this.defaults },
10459
+ modelServiceGlobalOptions(this, this.requestRuntime)
10460
+ ) : { catalog: { paths: [] }, ...this.options },
10376
10461
  permissions: () => this.requestCore.getPermissions?.() ?? new permission_default({}),
10377
10462
  parse: (filter2) => this.parseClientData(filter2, this.getCorrelatedExecState().scheduler),
10378
10463
  validate: (filter2, expanded) => {
@@ -10619,20 +10704,20 @@ var Service = class extends Base {
10619
10704
  const field = configuration.documentPermissionField ?? "_permissions";
10620
10705
  unsetDocPath(output, field);
10621
10706
  if (!configuration.stripPermissionsField) {
10622
- (0, import_utils34.set)(output, field, args.includePermissions || args.includeFieldPermissions ? deepIsolateValue(grants) : {});
10707
+ (0, import_utils35.set)(output, field, args.includePermissions || args.includeFieldPermissions ? deepIsolateValue(grants) : {});
10623
10708
  if (args.includeFieldPermissions && !configuration.disableFieldPermissions) {
10624
10709
  const rowAccess = this.asServiceHookContext(context).fieldPermissionAccess ?? await this.getFieldPermissionAccess([snapshot._id]);
10625
10710
  const id = String(snapshot._id);
10626
10711
  const views = rowAccess.readIds?.has(id) ? await requestOutputFieldPaths(handle, binding, "read") : [];
10627
10712
  const edits = rowAccess.updateIds?.has(id) ? await requestOutputFieldPaths(handle, binding, "update") : [];
10628
10713
  const map2 = (paths) => paths.length ? Object.fromEntries(paths.map((path) => [path, true])) : { $: "_" };
10629
- (0, import_utils34.set)(output, `${field}._view`, map2(views));
10630
- (0, import_utils34.set)(output, `${field}._edit`, map2(edits));
10631
- } else if (!args.includePermissions) (0, import_utils34.set)(output, field, { _view: { $: "_" }, _edit: { $: "_" } });
10714
+ (0, import_utils35.set)(output, `${field}._view`, map2(views));
10715
+ (0, import_utils35.set)(output, `${field}._edit`, map2(edits));
10716
+ } else if (!args.includePermissions) (0, import_utils35.set)(output, field, { _view: { $: "_" }, _edit: { $: "_" } });
10632
10717
  const exposed = configuration.exposedDocPermissionKeys;
10633
10718
  if (exposed) {
10634
- const metadata = (0, import_utils34.get)(output, field);
10635
- (0, import_utils34.set)(
10719
+ const metadata = (0, import_utils35.get)(output, field);
10720
+ (0, import_utils35.set)(
10636
10721
  output,
10637
10722
  field,
10638
10723
  Object.fromEntries(
@@ -10893,7 +10978,7 @@ var Service = class extends Base {
10893
10978
  return docs.map((doc) => {
10894
10979
  try {
10895
10980
  const plain = toObject(doc);
10896
- const val = (0, import_utils34.get)(plain, associationField);
10981
+ const val = (0, import_utils35.get)(plain, associationField);
10897
10982
  return deepIsolateValue(val);
10898
10983
  } catch {
10899
10984
  return void 0;
@@ -10901,12 +10986,13 @@ var Service = class extends Base {
10901
10986
  });
10902
10987
  }
10903
10988
  captureRelated(args, defaults) {
10989
+ const globalOptions = modelServiceGlobalOptions(this, this.requestRuntime);
10904
10990
  const effective = { populate: args?.populate ?? defaults?.populate, include: args?.include ?? defaults?.include };
10905
10991
  if (effective.include) {
10906
10992
  const processed = this.processInclude(effective.include);
10907
10993
  effective.include = [...processed.includes, ...processed.correlatedIncludes];
10908
10994
  }
10909
- return captureRelatedTargets(this.requestRuntime, this.modelName, effective);
10995
+ return captureRelatedTargets(this.requestRuntime, this.modelName, effective, 0, globalOptions);
10910
10996
  }
10911
10997
  /** Canonical population uses the target's retained policy for both fetch and output. */
10912
10998
  async genExecutionPopulate(execution, access, populate) {
@@ -10928,14 +11014,9 @@ var Service = class extends Base {
10928
11014
  modelPermissionPrefix: captured.configuration.modelPermissionPrefix
10929
11015
  });
10930
11016
  if (sourceState === "denied") continue;
10931
- const modelName = getModelRef(this.modelName, descriptor.path);
11017
+ const target = captured.relatedTargets.find((target2) => target2.path === descriptor.path);
11018
+ const modelName = target?.modelName;
10932
11019
  if (!modelName) continue;
10933
- if (!this.requestRuntime.hasModel(modelName)) {
10934
- if (captured.relatedTargets.some((target) => target.path === descriptor.path && target.kind === "passthrough")) {
10935
- result2.push({ path: descriptor.path, select: descriptor.select });
10936
- }
10937
- continue;
10938
- }
10939
11020
  const policy = relatedPolicy(state.authorization, state.binding, descriptor.path);
10940
11021
  const svc = this.requestCore.getPublicService(modelName);
10941
11022
  const child = createRelatedExecution(
@@ -10954,7 +11035,7 @@ var Service = class extends Base {
10954
11035
  if (isExecutionRowDenied(svc, child)) continue;
10955
11036
  const childState = readServiceExecution(svc, child);
10956
11037
  const targetConfiguration = readServiceAuthorization(childState.authorization, childState.binding).configuration;
10957
- if (policy?.operation.mode !== "grant" && !await this.hookGate.run(
11038
+ if (targetConfiguration.requireOperationAccessForPopulateQueries !== false && policy?.operation.mode !== "grant" && !await this.hookGate.run(
10958
11039
  () => evaluateRouteGuard(
10959
11040
  this.req,
10960
11041
  getAuthorizationPermissions(childState.authorization, childState.binding),
@@ -10986,7 +11067,7 @@ var Service = class extends Base {
10986
11067
  schema: childState.binding.model.schema,
10987
11068
  configuration: targetConfiguration,
10988
11069
  requestRead: targetAccess === "read" && policy?.operation.mode !== "grant" && readServiceAuthorization(childState.authorization, childState.binding).authorization.rows.mode === "request",
10989
- staticObjectIdReference: captured.relatedTargets.find((target) => target.path === descriptor.path)?.staticObjectIdReference
11070
+ staticObjectIdReference: captured.relatedTargets.find((target2) => target2.path === descriptor.path)?.staticObjectIdReference
10990
11071
  }
10991
11072
  });
10992
11073
  result2.push(ret);
@@ -11006,7 +11087,7 @@ var Service = class extends Base {
11006
11087
  if (this.isScalarPopulateValue(rawTarget)) return rawTarget;
11007
11088
  const isDoc = (() => {
11008
11089
  try {
11009
- if ((0, import_utils34.isPlainObject)(rawTarget)) return true;
11090
+ if ((0, import_utils35.isPlainObject)(rawTarget)) return true;
11010
11091
  const maybe = rawTarget;
11011
11092
  if (maybe && typeof maybe === "object" && "_doc" in maybe) return true;
11012
11093
  if (maybe && typeof maybe.toObject === "function") return true;
@@ -11030,15 +11111,13 @@ var Service = class extends Base {
11030
11111
  transferDocumentAuthorizationGraph(source, copy2);
11031
11112
  return copy2;
11032
11113
  }
11033
- let targetMongooseModel;
11034
- try {
11035
- const inst = this.requestRuntime.getModelInstance?.(
11036
- meta.targetModelName
11037
- );
11038
- void inst;
11039
- targetMongooseModel = inst;
11040
- } catch {
11041
- targetMongooseModel = parentContext.mongooseModel;
11114
+ let targetMongooseModel = meta.fetchBinding?.model;
11115
+ if (!targetMongooseModel) {
11116
+ try {
11117
+ targetMongooseModel = this.requestRuntime.getModelInstance(meta.targetModelName);
11118
+ } catch {
11119
+ targetMongooseModel = parentContext.mongooseModel;
11120
+ }
11042
11121
  }
11043
11122
  const targetContext = {
11044
11123
  mongooseModel: targetMongooseModel ?? parentContext.mongooseModel,
@@ -11096,7 +11175,7 @@ var Service = class extends Base {
11096
11175
  child = getDocValue(current, key);
11097
11176
  if (child === void 0) {
11098
11177
  try {
11099
- child = (0, import_utils34.get)(current, key);
11178
+ child = (0, import_utils35.get)(current, key);
11100
11179
  } catch {
11101
11180
  return;
11102
11181
  }
@@ -11331,7 +11410,7 @@ var Service = class extends Base {
11331
11410
  originalDocumentSnapshot: toObject(doc),
11332
11411
  resolvedQuery: query
11333
11412
  };
11334
- const correlatedSnapshots = [(0, import_utils34.cloneDeep)(toObject(doc))];
11413
+ const correlatedSnapshots = [(0, import_utils35.cloneDeep)(toObject(doc))];
11335
11414
  try {
11336
11415
  doc = await this.includeDocs(doc, includes, state.authorization);
11337
11416
  if (correlatedIncludes.length > 0) {
@@ -11513,7 +11592,7 @@ var Service = class extends Base {
11513
11592
  const findAssociationField = this.getAssociationFieldFromOptions(options);
11514
11593
  const withAssocSelect = findAssociationField && !finalSelect.includes(findAssociationField) ? [...finalSelect, findAssociationField] : finalSelect;
11515
11594
  const dbSelect = this.buildDbSelectForAssociation(withAssocSelect, findAssociationField);
11516
- const filteredPopulate = (0, import_utils34.isArray)(withAssocSelect) && (0, import_utils34.isArray)(_populate) ? _populate.filter(
11595
+ const filteredPopulate = (0, import_utils35.isArray)(withAssocSelect) && (0, import_utils35.isArray)(_populate) ? _populate.filter(
11517
11596
  (p) => [
11518
11597
  ...virtualPlan.publicPersistedFetchSelection,
11519
11598
  ...findAssociationField ? [findAssociationField] : []
@@ -11573,7 +11652,7 @@ var Service = class extends Base {
11573
11652
  findAssociationField ? [findAssociationField] : []
11574
11653
  );
11575
11654
  const capturedAssociation = findAssociationField ? this.captureAssociationValues(docs, findAssociationField) : void 0;
11576
- const correlatedSnapshots = docs.map((doc) => (0, import_utils34.cloneDeep)(toObject(doc)));
11655
+ const correlatedSnapshots = docs.map((doc) => (0, import_utils35.cloneDeep)(toObject(doc)));
11577
11656
  try {
11578
11657
  docs = await this.includeDocs(docs, includes, state.authorization);
11579
11658
  if (correlatedIncludes.length > 0) {
@@ -11772,12 +11851,12 @@ var Service = class extends Base {
11772
11851
  context.allowedFields = allowedFields;
11773
11852
  context.allowedData = allowedData;
11774
11853
  const validated = await this.validate(allowedData, "create", context);
11775
- if ((0, import_utils34.isBoolean)(validated)) {
11854
+ if ((0, import_utils35.isBoolean)(validated)) {
11776
11855
  if (!validated) {
11777
11856
  validationErrors.push({ index, errors: [] });
11778
11857
  return void 0;
11779
11858
  }
11780
- } else if ((0, import_utils34.isArray)(validated)) {
11859
+ } else if ((0, import_utils35.isArray)(validated)) {
11781
11860
  if (validated.length > 0) {
11782
11861
  validationErrors.push({
11783
11862
  index,
@@ -11988,7 +12067,7 @@ var Service = class extends Base {
11988
12067
  }
11989
12068
  let doc = await this.model.findOne({
11990
12069
  filter: _filter,
11991
- select: (0, import_utils34.uniq)([...updatePlan.persistedFetchSelection, ...inputFetchPaths(captured.configuration.catalog)]).map(
12070
+ select: (0, import_utils35.uniq)([...updatePlan.persistedFetchSelection, ...inputFetchPaths(captured.configuration.catalog)]).map(
11992
12071
  (path) => `+${path}`
11993
12072
  )
11994
12073
  });
@@ -12027,12 +12106,12 @@ var Service = class extends Base {
12027
12106
  context.allowedFields = allowedFields;
12028
12107
  context.allowedData = allowedData;
12029
12108
  const validated = await this.validate(allowedData, "update", context);
12030
- if ((0, import_utils34.isBoolean)(validated)) {
12109
+ if ((0, import_utils35.isBoolean)(validated)) {
12031
12110
  if (!validated) {
12032
12111
  this.completeOp("updateOne", startedAt, "bad_request" /* BadRequest */, _filter);
12033
12112
  return { success: false, kind: "error", code: "bad_request" /* BadRequest */ };
12034
12113
  }
12035
- } else if ((0, import_utils34.isArray)(validated)) {
12114
+ } else if ((0, import_utils35.isArray)(validated)) {
12036
12115
  if (validated.length > 0) {
12037
12116
  this.completeOp("updateOne", startedAt, "bad_request" /* BadRequest */, _filter);
12038
12117
  return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: validated };
@@ -12052,10 +12131,10 @@ var Service = class extends Base {
12052
12131
  const diffExcludeFields = [this.options.documentPermissionField, "__v"];
12053
12132
  this.asServiceHookContext(context).diff = (d) => {
12054
12133
  context.changes = (0, import_just_diff.diff)(
12055
- (0, import_utils34.omit)(context.originalDocumentSnapshot, diffExcludeFields),
12056
- (0, import_utils34.omit)(d.toObject({ virtuals: false }), diffExcludeFields)
12134
+ (0, import_utils35.omit)(context.originalDocumentSnapshot, diffExcludeFields),
12135
+ (0, import_utils35.omit)(d.toObject({ virtuals: false }), diffExcludeFields)
12057
12136
  ) || [];
12058
- context.modifiedPaths = (0, import_utils34.uniq)(context.changes.map((di) => di.path.length > 0 ? String(di.path[0]) : ""));
12137
+ context.modifiedPaths = (0, import_utils35.uniq)(context.changes.map((di) => di.path.length > 0 ? String(di.path[0]) : ""));
12059
12138
  };
12060
12139
  doc = assertModelDocument(await this.afterPersist(doc, "update", context), this.modelName, "afterPersist");
12061
12140
  context.currentDocument = doc;
@@ -12143,7 +12222,7 @@ var Service = class extends Base {
12143
12222
  const upsertOptions = this.resolveUpsertOptions(options);
12144
12223
  const updateIntent = captureModelServiceIntent(this, "updateOne", upsertArgs, upsertOptions);
12145
12224
  const createIntent = captureModelServiceIntent(this, "create", upsertArgs, upsertOptions);
12146
- const related = (0, import_utils34.uniqBy)(
12225
+ const related = (0, import_utils35.uniqBy)(
12147
12226
  [...this.captureRelated(updateIntent.args), ...this.captureRelated(createIntent.args)],
12148
12227
  (target) => target.path
12149
12228
  );
@@ -12584,7 +12663,7 @@ var Service = class extends Base {
12584
12663
  return resolveExistsOptions(this, options);
12585
12664
  }
12586
12665
  async getFieldPermissionAccess(ids) {
12587
- const uniqueIds = (0, import_utils34.compact)((0, import_utils34.uniqBy)(ids, (id) => String(id)).map((id) => String(id)));
12666
+ const uniqueIds = (0, import_utils35.compact)((0, import_utils35.uniqBy)(ids, (id) => String(id)).map((id) => String(id)));
12588
12667
  if (uniqueIds.length === 0) {
12589
12668
  return {
12590
12669
  readIds: /* @__PURE__ */ new Set(),
@@ -12630,7 +12709,7 @@ var Service = class extends Base {
12630
12709
  * (direct/root-entry 200); count measures visible rows, not all updated rows.
12631
12710
  */
12632
12711
  async bulkUpdateSub(id, sub, data, options) {
12633
- return bulkUpdateSub(this, this.persist, id, sub, (0, import_utils34.castArray)(data), options);
12712
+ return bulkUpdateSub(this, this.persist, id, sub, (0, import_utils35.castArray)(data), options);
12634
12713
  }
12635
12714
  /**
12636
12715
  * Append/prepend admitted rows, then return the visible full array (including when
@@ -12654,7 +12733,7 @@ var Service = class extends Base {
12654
12733
  };
12655
12734
 
12656
12735
  // src/services/public-service.ts
12657
- var import_utils35 = require("@web-ts-toolkit/utils");
12736
+ var import_utils36 = require("@web-ts-toolkit/utils");
12658
12737
  init_helpers();
12659
12738
  init_permissions_alias();
12660
12739
  init_document();
@@ -12780,7 +12859,7 @@ var PublicService = class extends Service {
12780
12859
  let d = toObject(doc);
12781
12860
  d = await this.decorate(d, "create", context);
12782
12861
  d = this.runTasks(d, tasks);
12783
- if (select) d = copyPermissionsAlias(d, (0, import_utils35.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
12862
+ if (select) d = copyPermissionsAlias(d, (0, import_utils36.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
12784
12863
  return d;
12785
12864
  }
12786
12865
  );
@@ -12999,8 +13078,8 @@ var PublicService = class extends Service {
12999
13078
  let d = toObject(doc);
13000
13079
  d = await this.decorate(d, "update", context);
13001
13080
  d = this.runTasks(d, tasks);
13002
- if (select) d = copyPermissionsAlias(d, (0, import_utils35.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
13003
- else if (!returningAll) d = copyPermissionsAlias(d, (0, import_utils35.pick)(d, returningKeys));
13081
+ if (select) d = copyPermissionsAlias(d, (0, import_utils36.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
13082
+ else if (!returningAll) d = copyPermissionsAlias(d, (0, import_utils36.pick)(d, returningKeys));
13004
13083
  return d;
13005
13084
  }
13006
13085
  );
@@ -13083,8 +13162,8 @@ var PublicService = class extends Service {
13083
13162
  let d = toObject(doc);
13084
13163
  d = await this.decorate(d, "update", context);
13085
13164
  d = this.runTasks(d, tasks2);
13086
- if (select) d = copyPermissionsAlias(d, (0, import_utils35.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
13087
- else if (!returningAll) d = copyPermissionsAlias(d, (0, import_utils35.pick)(d, returningKeys));
13165
+ if (select) d = copyPermissionsAlias(d, (0, import_utils36.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]));
13166
+ else if (!returningAll) d = copyPermissionsAlias(d, (0, import_utils36.pick)(d, returningKeys));
13088
13167
  return d;
13089
13168
  }
13090
13169
  );
@@ -13109,7 +13188,7 @@ var PublicService = class extends Service {
13109
13188
  d = await this.decorate(d, "create", context);
13110
13189
  d = this.runTasks(d, tasks);
13111
13190
  if (createSelect)
13112
- d = copyPermissionsAlias(d, (0, import_utils35.pick)(d, [...normalizeSelect(createSelect), ...this.baseFieldsExt]));
13191
+ d = copyPermissionsAlias(d, (0, import_utils36.pick)(d, [...normalizeSelect(createSelect), ...this.baseFieldsExt]));
13113
13192
  return d;
13114
13193
  }
13115
13194
  );
@@ -13254,7 +13333,7 @@ var PublicService = class extends Service {
13254
13333
  init_options();
13255
13334
  init_data_values();
13256
13335
  init_helpers();
13257
- var import_utils36 = require("@web-ts-toolkit/utils");
13336
+ var import_utils37 = require("@web-ts-toolkit/utils");
13258
13337
  init_request_complexity();
13259
13338
  init_runtime_context();
13260
13339
  init_runtime();
@@ -13283,7 +13362,7 @@ var DataService = class {
13283
13362
  let doc = await findElement(this.data, _filter);
13284
13363
  if (!doc) return { success: false, kind: "error", code: "not_found" /* NotFound */, query };
13285
13364
  doc = await this.trimOutputFields(doc, access);
13286
- if (_select.length > 0) doc = (0, import_utils36.pick)(doc, _select);
13365
+ if (_select.length > 0) doc = (0, import_utils37.pick)(doc, _select);
13287
13366
  return {
13288
13367
  success: true,
13289
13368
  kind: "single",
@@ -13329,13 +13408,13 @@ var DataService = class {
13329
13408
  const totalCount = docs.length;
13330
13409
  if (sort) {
13331
13410
  const normalizedSort = normalizeSortForOrderBy(sort);
13332
- docs = (0, import_utils36.orderBy)(docs, normalizedSort.fields, normalizedSort.orders);
13411
+ docs = (0, import_utils37.orderBy)(docs, normalizedSort.fields, normalizedSort.orders);
13333
13412
  }
13334
13413
  const pagedDocs = docs.slice(query.skip, query.limit && query.skip + query.limit);
13335
13414
  const { maxHookConcurrency } = this.getRequestComplexity();
13336
13415
  const trimmed = await mapWithConcurrencyLimit(pagedDocs, maxHookConcurrency, async (doc) => {
13337
13416
  doc = await this.trimOutputFields(doc, "list");
13338
- if (_select.length > 0) doc = (0, import_utils36.pick)(doc, _select);
13417
+ if (_select.length > 0) doc = (0, import_utils37.pick)(doc, _select);
13339
13418
  return copyDataValue(doc);
13340
13419
  });
13341
13420
  if (!hasExplicitLimit && trimmed.length === totalCount) {
@@ -13410,10 +13489,10 @@ var DataService = class {
13410
13489
  init_helpers();
13411
13490
 
13412
13491
  // src/processors.ts
13413
- var import_utils37 = require("@web-ts-toolkit/utils");
13492
+ var import_utils38 = require("@web-ts-toolkit/utils");
13414
13493
  init_permissions_alias();
13415
13494
  function cloneProcessorValue(value) {
13416
- const copy = (0, import_utils37.cloneDeep)(value);
13495
+ const copy = (0, import_utils38.cloneDeep)(value);
13417
13496
  copyPermissionsAliasGraph(value, copy);
13418
13497
  return copy;
13419
13498
  }
@@ -13451,10 +13530,10 @@ function resolveLeafParents(obj, src) {
13451
13530
  for (let ind = 0; ind < segs.length - 1; ind += 1) {
13452
13531
  const seg = segs[ind];
13453
13532
  targets = targets.reduce((ret, target) => {
13454
- if (!(0, import_utils37.isPlainObject)(target)) return ret;
13533
+ if (!(0, import_utils38.isPlainObject)(target)) return ret;
13455
13534
  const targetObject = target;
13456
13535
  const next = targetObject[seg];
13457
- if ((0, import_utils37.isArray)(next)) {
13536
+ if ((0, import_utils38.isArray)(next)) {
13458
13537
  for (const item of next) {
13459
13538
  ret.push(item);
13460
13539
  }
@@ -13464,8 +13543,8 @@ function resolveLeafParents(obj, src) {
13464
13543
  }
13465
13544
  const leaf = segs[segs.length - 1];
13466
13545
  const pairs = [];
13467
- (0, import_utils37.forEach)(targets, (target) => {
13468
- if (!(0, import_utils37.isPlainObject)(target)) return;
13546
+ (0, import_utils38.forEach)(targets, (target) => {
13547
+ if (!(0, import_utils38.isPlainObject)(target)) return;
13469
13548
  pairs.push({ parent: target, leaf });
13470
13549
  });
13471
13550
  return pairs;
@@ -13474,7 +13553,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
13474
13553
  const mutable = options.mutable !== false;
13475
13554
  const idField = options.idField ?? "_id";
13476
13555
  const obj = mutable ? docObject : cloneProcessorValue(docObject);
13477
- (0, import_utils37.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13556
+ (0, import_utils38.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13478
13557
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
13479
13558
  const src = op.src;
13480
13559
  const dest = op.dest;
@@ -13483,19 +13562,19 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
13483
13562
  assertSafePath(dest);
13484
13563
  let targets = [obj];
13485
13564
  const segs = src.split(".");
13486
- (0, import_utils37.forEach)(segs, (seg, ind) => {
13565
+ (0, import_utils38.forEach)(segs, (seg, ind) => {
13487
13566
  if (segs.length === ind + 1) {
13488
- (0, import_utils37.forEach)(targets, (target) => {
13489
- if (!(0, import_utils37.isPlainObject)(target)) return;
13567
+ (0, import_utils38.forEach)(targets, (target) => {
13568
+ if (!(0, import_utils38.isPlainObject)(target)) return;
13490
13569
  const targetObject = target;
13491
13570
  const leaf = targetObject[seg];
13492
13571
  const sourceForDest = leaf;
13493
13572
  let depopulated;
13494
- if ((0, import_utils37.isArray)(leaf)) {
13573
+ if ((0, import_utils38.isArray)(leaf)) {
13495
13574
  if (leaf.length === 0) {
13496
13575
  depopulated = [];
13497
- } else if (leaf.every((item) => (0, import_utils37.isPlainObject)(item))) {
13498
- depopulated = (0, import_utils37.map)(leaf, idField).map((id, i) => {
13576
+ } else if (leaf.every((item) => (0, import_utils38.isPlainObject)(item))) {
13577
+ depopulated = (0, import_utils38.map)(leaf, idField).map((id, i) => {
13499
13578
  if (id === void 0) {
13500
13579
  failMissingId(`${src}[${i}]`);
13501
13580
  }
@@ -13504,8 +13583,8 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
13504
13583
  } else {
13505
13584
  return;
13506
13585
  }
13507
- } else if ((0, import_utils37.isPlainObject)(leaf)) {
13508
- const id = (0, import_utils37.get)(leaf, idField);
13586
+ } else if ((0, import_utils38.isPlainObject)(leaf)) {
13587
+ const id = (0, import_utils38.get)(leaf, idField);
13509
13588
  if (id === void 0) {
13510
13589
  failMissingId(src);
13511
13590
  }
@@ -13513,15 +13592,15 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
13513
13592
  } else {
13514
13593
  return;
13515
13594
  }
13516
- (0, import_utils37.set)(targetObject, dest, sourceForDest);
13517
- (0, import_utils37.set)(targetObject, seg, depopulated);
13595
+ (0, import_utils38.set)(targetObject, dest, sourceForDest);
13596
+ (0, import_utils38.set)(targetObject, seg, depopulated);
13518
13597
  });
13519
13598
  } else {
13520
13599
  targets = targets.reduce((ret, target) => {
13521
- if (!(0, import_utils37.isPlainObject)(target)) return ret;
13600
+ if (!(0, import_utils38.isPlainObject)(target)) return ret;
13522
13601
  const targetObject = target;
13523
13602
  const next = targetObject[seg];
13524
- if ((0, import_utils37.isArray)(next)) {
13603
+ if ((0, import_utils38.isArray)(next)) {
13525
13604
  for (const item of next) {
13526
13605
  ret.push(item);
13527
13606
  }
@@ -13536,7 +13615,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
13536
13615
  var copyPaths = (docObject, operations, options = { mutable: true }) => {
13537
13616
  const mutable = options.mutable !== false;
13538
13617
  const obj = mutable ? docObject : cloneProcessorValue(docObject);
13539
- (0, import_utils37.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13618
+ (0, import_utils38.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13540
13619
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
13541
13620
  const src = op.src;
13542
13621
  const dest = op.dest;
@@ -13544,9 +13623,9 @@ var copyPaths = (docObject, operations, options = { mutable: true }) => {
13544
13623
  assertSafePath(src, "copyPaths");
13545
13624
  assertSafePath(dest, "copyPaths");
13546
13625
  if (src === dest) return;
13547
- (0, import_utils37.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13548
- if (!(0, import_utils37.hasOwn)(parent, leaf)) return;
13549
- (0, import_utils37.set)(parent, dest, cloneProcessorValue(parent[leaf]));
13626
+ (0, import_utils38.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13627
+ if (!(0, import_utils38.hasOwn)(parent, leaf)) return;
13628
+ (0, import_utils38.set)(parent, dest, cloneProcessorValue(parent[leaf]));
13550
13629
  });
13551
13630
  });
13552
13631
  return obj;
@@ -13554,7 +13633,7 @@ var copyPaths = (docObject, operations, options = { mutable: true }) => {
13554
13633
  var movePaths = (docObject, operations, options = { mutable: true }) => {
13555
13634
  const mutable = options.mutable !== false;
13556
13635
  const obj = mutable ? docObject : cloneProcessorValue(docObject);
13557
- (0, import_utils37.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13636
+ (0, import_utils38.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13558
13637
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
13559
13638
  const src = op.src;
13560
13639
  const dest = op.dest;
@@ -13562,10 +13641,10 @@ var movePaths = (docObject, operations, options = { mutable: true }) => {
13562
13641
  assertSafePath(src, "movePaths");
13563
13642
  assertSafePath(dest, "movePaths");
13564
13643
  if (src === dest) return;
13565
- (0, import_utils37.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13566
- if (!(0, import_utils37.hasOwn)(parent, leaf)) return;
13644
+ (0, import_utils38.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13645
+ if (!(0, import_utils38.hasOwn)(parent, leaf)) return;
13567
13646
  const value = cloneProcessorValue(parent[leaf]);
13568
- (0, import_utils37.set)(parent, dest, value);
13647
+ (0, import_utils38.set)(parent, dest, value);
13569
13648
  if (dest === leaf || dest.startsWith(`${leaf}.`)) return;
13570
13649
  delete parent[leaf];
13571
13650
  });
@@ -13577,7 +13656,7 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
13577
13656
  const maxSlice = options.maxSlice ?? DEFAULT_MAX_SLICE;
13578
13657
  assertNonNegativeSafeInteger(maxSlice, "maxSlice", "sliceArrays");
13579
13658
  const obj = mutable ? docObject : cloneProcessorValue(docObject);
13580
- (0, import_utils37.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13659
+ (0, import_utils38.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13581
13660
  if (!op || typeof op.src !== "string") return;
13582
13661
  const src = op.src;
13583
13662
  if (src.length === 0) return;
@@ -13594,15 +13673,15 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
13594
13673
  assertNonNegativeSafeInteger(op.limit, "limit", "sliceArrays");
13595
13674
  limit = Math.min(op.limit, maxSlice);
13596
13675
  }
13597
- (0, import_utils37.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13676
+ (0, import_utils38.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13598
13677
  const leafValue = parent[leaf];
13599
- if (!(0, import_utils37.isArray)(leafValue)) return;
13678
+ if (!(0, import_utils38.isArray)(leafValue)) return;
13600
13679
  const end = typeof limit === "undefined" ? void 0 : skip + limit;
13601
13680
  const window = leafValue.slice(skip, end);
13602
13681
  if (typeof rawDest === "undefined") {
13603
- (0, import_utils37.set)(parent, leaf, window);
13682
+ (0, import_utils38.set)(parent, leaf, window);
13604
13683
  } else {
13605
- (0, import_utils37.set)(parent, rawDest, window);
13684
+ (0, import_utils38.set)(parent, rawDest, window);
13606
13685
  }
13607
13686
  });
13608
13687
  });
@@ -13611,27 +13690,27 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
13611
13690
  var countPaths = (docObject, operations, options = { mutable: true }) => {
13612
13691
  const mutable = options.mutable !== false;
13613
13692
  const obj = mutable ? docObject : cloneProcessorValue(docObject);
13614
- (0, import_utils37.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13693
+ (0, import_utils38.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13615
13694
  if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
13616
13695
  const src = op.src;
13617
13696
  const dest = op.dest;
13618
13697
  if (src.length === 0 || dest.length === 0) return;
13619
13698
  assertSafePath(src, "countPaths");
13620
13699
  assertSafePath(dest, "countPaths");
13621
- (0, import_utils37.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13622
- if (!(0, import_utils37.hasOwn)(parent, leaf)) return;
13700
+ (0, import_utils38.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13701
+ if (!(0, import_utils38.hasOwn)(parent, leaf)) return;
13623
13702
  const leafValue = parent[leaf];
13624
13703
  let count;
13625
- if ((0, import_utils37.isArray)(leafValue)) {
13704
+ if ((0, import_utils38.isArray)(leafValue)) {
13626
13705
  count = leafValue.length;
13627
- } else if ((0, import_utils37.isPlainObject)(leafValue)) {
13706
+ } else if ((0, import_utils38.isPlainObject)(leafValue)) {
13628
13707
  count = Object.keys(leafValue).length;
13629
13708
  } else if (leafValue === null || typeof leafValue === "undefined") {
13630
13709
  count = 0;
13631
13710
  } else {
13632
13711
  count = 1;
13633
13712
  }
13634
- (0, import_utils37.set)(parent, dest, count);
13713
+ (0, import_utils38.set)(parent, dest, count);
13635
13714
  });
13636
13715
  });
13637
13716
  return obj;
@@ -13639,15 +13718,15 @@ var countPaths = (docObject, operations, options = { mutable: true }) => {
13639
13718
  var maskPaths = (docObject, operations, options = { mutable: true }) => {
13640
13719
  const mutable = options.mutable !== false;
13641
13720
  const obj = mutable ? docObject : cloneProcessorValue(docObject);
13642
- (0, import_utils37.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13721
+ (0, import_utils38.forEach)(Array.isArray(operations) ? operations : [], (op) => {
13643
13722
  if (!op || typeof op.src !== "string") return;
13644
13723
  const src = op.src;
13645
13724
  if (src.length === 0) return;
13646
13725
  assertSafePath(src, "maskPaths");
13647
13726
  const replacement = Object.prototype.hasOwnProperty.call(op, "replacement") ? op.replacement : DEFAULT_MASK_REPLACEMENT;
13648
- (0, import_utils37.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13649
- if (!(0, import_utils37.hasOwn)(parent, leaf)) return;
13650
- (0, import_utils37.set)(parent, leaf, replacement);
13727
+ (0, import_utils38.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
13728
+ if (!(0, import_utils38.hasOwn)(parent, leaf)) return;
13729
+ (0, import_utils38.set)(parent, leaf, replacement);
13651
13730
  });
13652
13731
  });
13653
13732
  return obj;
@@ -13702,6 +13781,8 @@ init_core_shared();
13702
13781
  init_virtual_projection();
13703
13782
  init_populate_target();
13704
13783
  init_model_output_planning();
13784
+ init_authorization_snapshot();
13785
+ init_document();
13705
13786
  init_output_field_filter();
13706
13787
  init_request_work();
13707
13788
  var emptyPermissionLeaf = () => ({ $: "_" });
@@ -13719,10 +13800,10 @@ var Core = class {
13719
13800
  getIdentifier(modelName) {
13720
13801
  const resolveIdFilter = getModelOption(modelName, "resolveIdFilter");
13721
13802
  const idField = getModelOption(modelName, "idField");
13722
- if ((0, import_utils38.isFunction)(resolveIdFilter)) {
13803
+ if ((0, import_utils39.isFunction)(resolveIdFilter)) {
13723
13804
  return null;
13724
13805
  }
13725
- if ((0, import_utils38.isString)(idField)) {
13806
+ if ((0, import_utils39.isString)(idField)) {
13726
13807
  return idField;
13727
13808
  }
13728
13809
  return "_id";
@@ -13812,17 +13893,11 @@ var Core = class {
13812
13893
  return this.genSelect(modelName, access, targetFields, options);
13813
13894
  }
13814
13895
  /** Persisted request-only populate admission; fetch planning is not field authority. */
13815
- async requestPopulateSelect(modelName, access, targetFields = null, scopePath = []) {
13896
+ async requestPopulateSelect(configuration, permissions, access, targetFields = null, scopePath = []) {
13816
13897
  const subPaths = scopePath.flatMap((part) => [part, "sub"]);
13817
- const permissionSchema = getModelOption(modelName, ["permissionSchema"].concat(subPaths).join("."));
13818
- const permissions = this.getGlobalPermissions();
13819
- let virtualNames;
13820
- try {
13821
- const runtime = getActiveRuntime() ?? defaultRuntime;
13822
- virtualNames = runtime.getVirtualNames(modelName, subPaths);
13823
- } catch {
13824
- virtualNames = [];
13825
- }
13898
+ const permissionSchema = (0, import_utils39.get)(configuration, ["permissionSchema", ...subPaths]);
13899
+ const prefix = scopePath.length ? `${scopePath.join(".")}.` : "";
13900
+ const virtualNames = (configuration.catalog.virtualPaths ?? []).filter((path) => path.startsWith(prefix)).map((path) => path.slice(prefix.length)).filter((path) => !path.includes("."));
13826
13901
  return resolveSelectForRequest({
13827
13902
  req: this.req,
13828
13903
  permissionSchema,
@@ -13841,17 +13916,25 @@ var Core = class {
13841
13916
  assertPublicAdmission(_populate, "populate");
13842
13917
  assertPopulateAccess(access);
13843
13918
  if (!_populate) return [];
13844
- let populate = Array.isArray(_populate) ? _populate : [_populate];
13845
- for (const p of populate) {
13846
- if (!(0, import_utils38.isString)(p)) assertPopulateAccess(p.access);
13847
- }
13848
- populate = (0, import_utils38.compact)(
13919
+ const descriptors = copyAuthorizationValue(Array.isArray(_populate) ? _populate : [_populate], true);
13920
+ for (const p of descriptors) {
13921
+ if (!(0, import_utils39.isString)(p)) assertPopulateAccess(p.access);
13922
+ }
13923
+ const runtime = this.requestRuntime;
13924
+ const globalOptions = modelServiceGlobalOptions(this, runtime);
13925
+ const relatedTargets = captureRelatedTargets(runtime, modelName, { populate: descriptors }, 0, globalOptions);
13926
+ const sourceConfiguration = captureModelAuthorizationConfiguration(runtime, modelName, void 0, globalOptions);
13927
+ const originalPermissions = this.getGlobalPermissions();
13928
+ const permissions = new permission_default(
13929
+ Object.fromEntries(originalPermissions.keys.map((key) => [key, originalPermissions.has(key)]))
13930
+ );
13931
+ const populate = (0, import_utils39.compact)(
13849
13932
  await Promise.all(
13850
- populate.map(async (p) => {
13851
- const populateAccess = !(0, import_utils38.isString)(p) && p.access ? p.access : access;
13933
+ descriptors.map(async (p) => {
13934
+ const populateAccess = !(0, import_utils39.isString)(p) && p.access ? p.access : access;
13852
13935
  assertPopulateAccess(populateAccess);
13853
- const originalSelect = (0, import_utils38.isString)(p) ? void 0 : p.select;
13854
- const ret = (0, import_utils38.isString)(p) ? { path: p } : {
13936
+ const originalSelect = (0, import_utils39.isString)(p) ? void 0 : p.select;
13937
+ const ret = (0, import_utils39.isString)(p) ? { path: p } : {
13855
13938
  path: p.path,
13856
13939
  select: normalizeSelect(p.select)
13857
13940
  };
@@ -13859,78 +13942,86 @@ var Core = class {
13859
13942
  const pathForSourcePermission = scopePrefix && ret.path.startsWith(`${scopePrefix}.`) ? ret.path.slice(scopePrefix.length + 1) : ret.path;
13860
13943
  const parentPath = pathForSourcePermission.includes(".") ? pathForSourcePermission.split(".")[0] : pathForSourcePermission;
13861
13944
  const allowedParentPaths = await this.requestPopulateSelect(
13862
- modelName,
13945
+ sourceConfiguration,
13946
+ permissions,
13863
13947
  populateAccess,
13864
13948
  [parentPath],
13865
13949
  scopePath
13866
13950
  );
13867
13951
  if (!allowedParentPaths.includes(parentPath)) return null;
13868
- const refModelName = getModelRef(modelName, ret.path);
13869
- if (!refModelName) return null;
13870
- const runtime = getActiveRuntime();
13871
- if (!runtime) return null;
13872
- const requireRegisteredPopulateModels = getGlobalOption("requireRegisteredPopulateModels", true);
13873
- if (!runtime.hasModel(refModelName)) {
13874
- return requireRegisteredPopulateModels ? null : ret;
13875
- }
13876
- const allowedTargetOperation = await this.isAllowed(refModelName, populateAccess);
13877
- if (!allowedTargetOperation) {
13952
+ const target = relatedTargets.find((entry) => entry.path === ret.path);
13953
+ if (!target) return null;
13954
+ const refModelName = target.modelName;
13955
+ const targetConfiguration = target.configuration;
13956
+ if (targetConfiguration.requireOperationAccessForPopulateQueries !== false && !await withCapturedModelOperationGuard(
13957
+ this,
13958
+ refModelName,
13959
+ populateAccess,
13960
+ getCapturedAuthorizationOption(targetConfiguration, `operationAccess.${populateAccess}`),
13961
+ permissions,
13962
+ () => this.isAllowed(refModelName, populateAccess)
13963
+ )) {
13878
13964
  return null;
13879
13965
  }
13880
- ret.select = await this.requestPopulateSelect(refModelName, populateAccess, ret.select);
13881
- const hookInputs = getModelOption(refModelName, `alwaysSelectFields.${populateAccess}`, []);
13882
- ret.select = (0, import_utils38.uniq)([...ret.select, ...stripVirtuals(hookInputs, runtime.getVirtualNames(refModelName))]);
13883
- const filter2 = await this.genFilter(refModelName, populateAccess, null);
13966
+ ret.select = await this.requestPopulateSelect(
13967
+ targetConfiguration,
13968
+ permissions,
13969
+ populateAccess,
13970
+ ret.select
13971
+ );
13972
+ const hookInputs = resolveAlwaysSelectForAccess(
13973
+ targetConfiguration.alwaysSelectFields,
13974
+ populateAccess
13975
+ );
13976
+ ret.select = (0, import_utils39.uniq)([
13977
+ ...ret.select,
13978
+ ...stripVirtuals(hookInputs, [...targetConfiguration.catalog.virtualPaths ?? []])
13979
+ ]);
13980
+ const match = (0, import_utils39.isString)(p) ? {} : p.match ?? {};
13981
+ const filter2 = await resolveAccessFilterForRequest({
13982
+ req: this.req,
13983
+ permissions,
13984
+ cache: this.caches.baseFilter,
13985
+ cacheKey: `${refModelName}_baseFilter_${populateAccess}`,
13986
+ access: populateAccess,
13987
+ filter: deepIsolateValue(match),
13988
+ getOption: (key) => getCapturedAuthorizationOption(targetConfiguration, key)
13989
+ });
13884
13990
  if (filter2 === false) return null;
13885
- ret.match = filter2;
13886
- try {
13887
- const planAccess = populateAccess;
13888
- const targetSnapshot = {
13889
- permissionSchema: getModelOption(refModelName, "permissionSchema", null) ?? null,
13890
- virtuals: getModelOption(refModelName, "virtuals", null) ?? null,
13891
- alwaysSelectFields: getModelOption(refModelName, "alwaysSelectFields", null) ?? null,
13892
- modelPermissionPrefix: getModelOption(refModelName, "modelPermissionPrefix", "") ?? "",
13893
- requireExplicitSelect: getModelOption(refModelName, "requireExplicitSelect", false) ?? false,
13894
- documentPermissionField: getModelOption(refModelName, "documentPermissionField", "_permissions") ?? "_permissions",
13895
- exposedDocPermissionKeys: getModelOption(refModelName, "exposedDocPermissionKeys", void 0),
13896
- stripPermissionsField: getModelOption(refModelName, "stripPermissionsField", false) ?? false,
13897
- disableFieldPermissions: getModelOption(refModelName, "disableFieldPermissions", false) ?? false
13898
- };
13899
- const perms = this.getPermissions();
13900
- const globalForPlan = perms && typeof perms.has === "function" && typeof perms.hasKey === "function" ? perms : { has: () => false, hasKey: () => false };
13901
- const targetPlan = planVirtualProjection({
13902
- receivingModelName: refModelName,
13903
- snapshot: {
13904
- permissionSchema: targetSnapshot.permissionSchema,
13905
- virtuals: targetSnapshot.virtuals,
13906
- alwaysSelectFields: targetSnapshot.alwaysSelectFields,
13907
- modelPermissionPrefix: targetSnapshot.modelPermissionPrefix,
13908
- requireExplicitSelect: targetSnapshot.requireExplicitSelect,
13909
- documentPermissionField: targetSnapshot.documentPermissionField
13910
- },
13911
- virtualAccess: planAccess,
13912
- outputAccess: planAccess,
13913
- docPermissionsAccess: planAccess,
13914
- requestedSelect: originalSelect,
13915
- internalFetch: { baseFields: ["_id"] },
13916
- globalPermissions: globalForPlan
13917
- });
13918
- const merged = (0, import_utils38.uniq)([...normalizeSelect(ret.select), ...targetPlan.virtualOnlyDeps ?? []]).filter(
13919
- (t) => t !== "-_id" && !t.includes(".sub.")
13920
- );
13921
- if (!merged.includes("_id")) merged.push("_id");
13922
- ret.select = merged;
13923
- setPopulateTargetMeta(ret, {
13924
- targetModelName: refModelName,
13925
- virtualAccess: planAccess,
13926
- outputAccess: planAccess,
13927
- docPermissionsAccess: planAccess,
13928
- requestedSelect: originalSelect,
13929
- plan: targetPlan,
13930
- snapshot: targetSnapshot
13931
- });
13932
- } catch {
13933
- }
13991
+ ret.match = deepIsolateValue(intersectFilters(match, filter2));
13992
+ const planAccess = populateAccess;
13993
+ const targetSnapshot = targetConfiguration;
13994
+ const targetPlan = planVirtualProjection({
13995
+ receivingModelName: refModelName,
13996
+ snapshot: {
13997
+ permissionSchema: targetSnapshot.permissionSchema,
13998
+ virtuals: targetSnapshot.virtuals,
13999
+ alwaysSelectFields: targetSnapshot.alwaysSelectFields,
14000
+ modelPermissionPrefix: targetSnapshot.modelPermissionPrefix,
14001
+ requireExplicitSelect: targetSnapshot.requireExplicitSelect,
14002
+ documentPermissionField: targetSnapshot.documentPermissionField
14003
+ },
14004
+ virtualAccess: planAccess,
14005
+ outputAccess: planAccess,
14006
+ docPermissionsAccess: planAccess,
14007
+ requestedSelect: originalSelect,
14008
+ internalFetch: { baseFields: ["_id"] },
14009
+ globalPermissions: permissions
14010
+ });
14011
+ const merged = (0, import_utils39.uniq)([...normalizeSelect(ret.select), ...targetPlan.virtualOnlyDeps ?? []]).filter(
14012
+ (t) => t !== "-_id" && !t.includes(".sub.")
14013
+ );
14014
+ if (!merged.includes("_id")) merged.push("_id");
14015
+ ret.select = merged;
14016
+ setPopulateTargetMeta(ret, {
14017
+ targetModelName: refModelName,
14018
+ virtualAccess: planAccess,
14019
+ outputAccess: planAccess,
14020
+ docPermissionsAccess: planAccess,
14021
+ requestedSelect: originalSelect,
14022
+ plan: targetPlan,
14023
+ snapshot: targetSnapshot
14024
+ });
13934
14025
  return ret;
13935
14026
  })
13936
14027
  )
@@ -13939,10 +14030,10 @@ var Core = class {
13939
14030
  }
13940
14031
  async validate(modelName, allowedData, access, context) {
13941
14032
  const validate = getModelOption(modelName, `validate.${access}`, null);
13942
- if ((0, import_utils38.isFunction)(validate)) {
14033
+ if ((0, import_utils39.isFunction)(validate)) {
13943
14034
  const permissions = this.getGlobalPermissions();
13944
14035
  return validate.call(this.req, allowedData, permissions, context);
13945
- } else if ((0, import_utils38.isBoolean)(validate) || (0, import_utils38.isArray)(validate)) {
14036
+ } else if ((0, import_utils39.isBoolean)(validate) || (0, import_utils39.isArray)(validate)) {
13946
14037
  return validate;
13947
14038
  } else {
13948
14039
  return true;
@@ -13967,7 +14058,7 @@ var Core = class {
13967
14058
  const changeOptions = getModelOption(modelName, `onChange`, {});
13968
14059
  for (let x = 0; x < context.modifiedPaths.length; x++) {
13969
14060
  const mpath = context.modifiedPaths[x];
13970
- if ((0, import_utils38.isFunction)(changeOptions[mpath])) {
14061
+ if ((0, import_utils39.isFunction)(changeOptions[mpath])) {
13971
14062
  await changeOptions[mpath].call(
13972
14063
  this.req,
13973
14064
  context.originalDocumentSnapshot[mpath],
@@ -13991,7 +14082,7 @@ var Core = class {
13991
14082
  async genDocPermissions(modelName, doc, access, context) {
13992
14083
  const docPermissionsFn = getModelOption(modelName, `docPermissions.${access}`, null);
13993
14084
  let docPermissions = {};
13994
- if ((0, import_utils38.isFunction)(docPermissionsFn)) {
14085
+ if ((0, import_utils39.isFunction)(docPermissionsFn)) {
13995
14086
  const permissions = this.getGlobalPermissions();
13996
14087
  try {
13997
14088
  docPermissions = await getRequestWorkState(this.req, this.requestRuntime).hookGate.run(
@@ -14075,7 +14166,7 @@ var Core = class {
14075
14166
  readExists ? requestFields("read") : [],
14076
14167
  updateExists ? requestFields("update") : []
14077
14168
  ]);
14078
- const viewObj = (0, import_utils38.reduce)(
14169
+ const viewObj = (0, import_utils39.reduce)(
14079
14170
  views,
14080
14171
  (ret, view) => {
14081
14172
  ret[view] = true;
@@ -14083,7 +14174,7 @@ var Core = class {
14083
14174
  },
14084
14175
  {}
14085
14176
  );
14086
- const editObj = (0, import_utils38.reduce)(
14177
+ const editObj = (0, import_utils39.reduce)(
14087
14178
  edits,
14088
14179
  (ret, view) => {
14089
14180
  ret[view] = true;
@@ -14114,9 +14205,9 @@ var Core = class {
14114
14205
  });
14115
14206
  }
14116
14207
  runTasks(modelName, docObject, task) {
14117
- const tasks = (0, import_utils38.compact)((0, import_utils38.castArray)(task));
14208
+ const tasks = (0, import_utils39.compact)((0, import_utils39.castArray)(task));
14118
14209
  if (tasks.length === 0) return docObject;
14119
- (0, import_utils38.forEach)(tasks, (task2) => {
14210
+ (0, import_utils39.forEach)(tasks, (task2) => {
14120
14211
  const { type, args, options } = task2;
14121
14212
  switch (type) {
14122
14213
  case "COPY_AND_DEPOPULATE":
@@ -14186,9 +14277,9 @@ var Core = class {
14186
14277
  }
14187
14278
  const [, field, op] = keys2;
14188
14279
  const subOption = getExactModelOption(modelName, `operationAccess.${access}`);
14189
- if ((0, import_utils38.isUndefined)(subOption)) {
14280
+ if ((0, import_utils39.isUndefined)(subOption)) {
14190
14281
  const subFieldOption = getExactModelOption(modelName, `operationAccess.subs.${field}`);
14191
- if ((0, import_utils38.isUndefined)(subFieldOption)) {
14282
+ if ((0, import_utils39.isUndefined)(subFieldOption)) {
14192
14283
  const opOption = getModelOption(modelName, `operationAccess.${op}`);
14193
14284
  return this.canActivate(opOption);
14194
14285
  }
@@ -14254,25 +14345,25 @@ function guard(condition) {
14254
14345
  const permissions = req[PERMISSIONS];
14255
14346
  let cond = condition;
14256
14347
  let phas = (key) => permissions.has(key);
14257
- if ((0, import_utils39.isPlainObject)(condition)) {
14348
+ if ((0, import_utils40.isPlainObject)(condition)) {
14258
14349
  const { modelName, id, condition: _cond } = condition;
14259
14350
  const svc = req.macl.getPublicService(modelName);
14260
14351
  const select = getModelOption(modelName, `alwaysSelectFields.read`, void 0);
14261
- let _id = (0, import_utils39.isString)(id) ? id : null;
14262
- if ((0, import_utils39.isPlainObject)(id)) {
14352
+ let _id = (0, import_utils40.isString)(id) ? id : null;
14353
+ if ((0, import_utils40.isPlainObject)(id)) {
14263
14354
  const { type = "param", key } = id;
14264
14355
  if (type === "param") {
14265
14356
  const paramValue = req.params[key];
14266
- _id = (0, import_utils39.isArray)(paramValue) ? paramValue[0] ?? null : paramValue ?? null;
14357
+ _id = (0, import_utils40.isArray)(paramValue) ? paramValue[0] ?? null : paramValue ?? null;
14267
14358
  } else if (type === "query") {
14268
14359
  const _qval = req.query[key];
14269
- if ((0, import_utils39.isArray)(_qval)) _id = _qval.length > 0 ? _qval[0] : null;
14360
+ if ((0, import_utils40.isArray)(_qval)) _id = _qval.length > 0 ? _qval[0] : null;
14270
14361
  else _id = _qval;
14271
14362
  } else {
14272
14363
  _id = null;
14273
14364
  }
14274
14365
  }
14275
- if (!(0, import_utils39.isString)(_id) || !_id) {
14366
+ if (!(0, import_utils40.isString)(_id) || !_id) {
14276
14367
  return next(new import_express_json_router5.default.clientErrors.BadRequestError());
14277
14368
  }
14278
14369
  const result2 = await svc._read(_id, { select });
@@ -14284,11 +14375,11 @@ function guard(condition) {
14284
14375
  cond = _cond;
14285
14376
  }
14286
14377
  const { stringHandler, arrayHandler } = createValidator(phas);
14287
- if ((0, import_utils39.isString)(cond)) {
14378
+ if ((0, import_utils40.isString)(cond)) {
14288
14379
  if (stringHandler(cond)) return next();
14289
- } else if ((0, import_utils39.isArray)(cond)) {
14380
+ } else if ((0, import_utils40.isArray)(cond)) {
14290
14381
  if (arrayHandler(cond)) return next();
14291
- } else if ((0, import_utils39.isFunction)(cond)) {
14382
+ } else if ((0, import_utils40.isFunction)(cond)) {
14292
14383
  const result2 = await cond.call(req, permissions);
14293
14384
  if (!!result2) return next();
14294
14385
  }
@@ -14301,7 +14392,7 @@ var import_express2 = __toESM(require("express"));
14301
14392
 
14302
14393
  // src/routers/model-router.ts
14303
14394
  var import_express_json_router8 = __toESM(require("@web-ts-toolkit/express-json-router"));
14304
- var import_utils43 = require("@web-ts-toolkit/utils");
14395
+ var import_utils44 = require("@web-ts-toolkit/utils");
14305
14396
  init_logger_helpers();
14306
14397
  init_runtime();
14307
14398
  init_runtime_context();
@@ -14435,7 +14526,7 @@ init_request_complexity();
14435
14526
 
14436
14527
  // src/validation/common.ts
14437
14528
  var import_zod2 = require("zod");
14438
- var import_utils40 = require("@web-ts-toolkit/utils");
14529
+ var import_utils41 = require("@web-ts-toolkit/utils");
14439
14530
 
14440
14531
  // src/validation/public-admission-schema.ts
14441
14532
  init_public_admission();
@@ -14564,7 +14655,7 @@ var correlatedFilterSchema = import_zod2.z.record(import_zod2.z.string(), import
14564
14655
  }
14565
14656
  });
14566
14657
  var correlatedEmptyOptionsSchema = import_zod2.z.unknown().refine(
14567
- (value) => value === void 0 || (0, import_utils40.isPlainObject)(value) && Object.keys(value).length === 0,
14658
+ (value) => value === void 0 || (0, import_utils41.isPlainObject)(value) && Object.keys(value).length === 0,
14568
14659
  "Correlated include options must be absent or empty"
14569
14660
  ).optional();
14570
14661
  var correlatedPathSchema = import_zod2.z.string().min(1).superRefine((path, ctx) => {
@@ -14601,7 +14692,7 @@ var correlatedListArgsSchema = import_zod2.z.object({
14601
14692
  include: import_zod2.z.lazy(() => correlatedNestedIncludeSchema).optional()
14602
14693
  }).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
14603
14694
  var correlatedCountArgsSchema = import_zod2.z.unknown().refine(
14604
- (value) => value === void 0 || (0, import_utils40.isPlainObject)(value) && Object.keys(value).length === 0,
14695
+ (value) => value === void 0 || (0, import_utils41.isPlainObject)(value) && Object.keys(value).length === 0,
14605
14696
  "Count includes accept no args"
14606
14697
  ).optional();
14607
14698
  var correlatedReadByIdSchema = import_zod2.z.object({
@@ -14654,7 +14745,7 @@ var correlatedNestedIncludeSchema = import_zod2.z.union([includeItemSchema, impo
14654
14745
  var rejectDuplicateCorrelatedPaths = (items, ctx) => {
14655
14746
  const seen = /* @__PURE__ */ new Set();
14656
14747
  items.forEach((item, index) => {
14657
- if ((0, import_utils40.isPlainObject)(item) && item.mode === "correlated" && typeof item.path === "string") {
14748
+ if ((0, import_utils41.isPlainObject)(item) && item.mode === "correlated" && typeof item.path === "string") {
14658
14749
  if (seen.has(item.path)) {
14659
14750
  ctx.addIssue({
14660
14751
  code: import_zod2.z.ZodIssueCode.custom,
@@ -15627,7 +15718,7 @@ var rootQuerySchema = publicBoundarySchema(
15627
15718
  init_helpers();
15628
15719
 
15629
15720
  // src/routers/shared.ts
15630
- var import_utils41 = require("@web-ts-toolkit/utils");
15721
+ var import_utils42 = require("@web-ts-toolkit/utils");
15631
15722
 
15632
15723
  // src/routers/model-router-collection-routes.ts
15633
15724
  init_schemas();
@@ -15658,15 +15749,15 @@ function setModelCollectionRoutes(context) {
15658
15749
  sort
15659
15750
  } = parseQuery(requestSchemas.listQuery, req.query);
15660
15751
  const svc = context.getPublicService(req);
15661
- const includeCount = (0, import_utils41.parseBooleanString)(include_count);
15662
- const includeExtraHeaders = (0, import_utils41.parseBooleanString)(include_extra_headers);
15752
+ const includeCount = (0, import_utils42.parseBooleanString)(include_count);
15753
+ const includeExtraHeaders = (0, import_utils42.parseBooleanString)(include_extra_headers);
15663
15754
  const result2 = await svc._list(
15664
15755
  {},
15665
15756
  { select: parseSelectParam(select), sort, skip, limit, page, pageSize: page_size },
15666
15757
  {
15667
- skim: (0, import_utils41.parseBooleanString)(skim),
15668
- includePermissions: (0, import_utils41.parseBooleanString)(include_permissions),
15669
- includeFieldPermissions: (0, import_utils41.parseBooleanString)(include_field_permissions),
15758
+ skim: (0, import_utils42.parseBooleanString)(skim),
15759
+ includePermissions: (0, import_utils42.parseBooleanString)(include_permissions),
15760
+ includeFieldPermissions: (0, import_utils42.parseBooleanString)(include_field_permissions),
15670
15761
  includeCount
15671
15762
  }
15672
15763
  );
@@ -15726,8 +15817,8 @@ function setModelCollectionRoutes(context) {
15726
15817
  data,
15727
15818
  {},
15728
15819
  {
15729
- includePermissions: (0, import_utils41.parseBooleanString)(include_permissions),
15730
- includeFieldPermissions: (0, import_utils41.parseBooleanString)(include_field_permissions)
15820
+ includePermissions: (0, import_utils42.parseBooleanString)(include_permissions),
15821
+ includeFieldPermissions: (0, import_utils42.parseBooleanString)(include_field_permissions)
15731
15822
  }
15732
15823
  );
15733
15824
  handleResultError(result2);
@@ -15765,8 +15856,8 @@ function setModelCollectionRoutes(context) {
15765
15856
  finalData,
15766
15857
  { select: finalSelect, populate: finalPopulate, tasks: finalTasks },
15767
15858
  {
15768
- includePermissions: includePermissions ?? (0, import_utils41.parseBooleanString)(include_permissions),
15769
- includeFieldPermissions: includeFieldPermissions ?? (0, import_utils41.parseBooleanString)(include_field_permissions),
15859
+ includePermissions: includePermissions ?? (0, import_utils42.parseBooleanString)(include_permissions),
15860
+ includeFieldPermissions: includeFieldPermissions ?? (0, import_utils42.parseBooleanString)(include_field_permissions),
15770
15861
  populateAccess
15771
15862
  }
15772
15863
  );
@@ -15863,9 +15954,9 @@ function setModelDocumentRoutes(context) {
15863
15954
  id,
15864
15955
  { select: parseSelectParam(select) },
15865
15956
  {
15866
- includePermissions: (0, import_utils41.parseBooleanString)(include_permissions),
15867
- includeFieldPermissions: (0, import_utils41.parseBooleanString)(include_field_permissions),
15868
- tryList: (0, import_utils41.parseBooleanString)(try_list)
15957
+ includePermissions: (0, import_utils42.parseBooleanString)(include_permissions),
15958
+ includeFieldPermissions: (0, import_utils42.parseBooleanString)(include_field_permissions),
15959
+ tryList: (0, import_utils42.parseBooleanString)(try_list)
15869
15960
  }
15870
15961
  );
15871
15962
  handleResultError(result2);
@@ -15965,9 +16056,9 @@ function setModelDocumentRoutes(context) {
15965
16056
  data,
15966
16057
  { select: parseSelectParam(select) },
15967
16058
  {
15968
- returningAll: (0, import_utils41.parseBooleanString)(returning_all),
15969
- includePermissions: (0, import_utils41.parseBooleanString)(include_permissions),
15970
- includeFieldPermissions: (0, import_utils41.parseBooleanString)(include_field_permissions)
16059
+ returningAll: (0, import_utils42.parseBooleanString)(returning_all),
16060
+ includePermissions: (0, import_utils42.parseBooleanString)(include_permissions),
16061
+ includeFieldPermissions: (0, import_utils42.parseBooleanString)(include_field_permissions)
15971
16062
  }
15972
16063
  );
15973
16064
  handleResultError(result2);
@@ -16016,9 +16107,9 @@ function setModelDocumentRoutes(context) {
16016
16107
  finalData,
16017
16108
  { select: finalSelect, populate: finalPopulate, tasks: finalTasks },
16018
16109
  {
16019
- returningAll: returningAll ?? (0, import_utils41.parseBooleanString)(returning_all),
16020
- includePermissions: includePermissions ?? (0, import_utils41.parseBooleanString)(include_permissions),
16021
- includeFieldPermissions: includeFieldPermissions ?? (0, import_utils41.parseBooleanString)(include_field_permissions),
16110
+ returningAll: returningAll ?? (0, import_utils42.parseBooleanString)(returning_all),
16111
+ includePermissions: includePermissions ?? (0, import_utils42.parseBooleanString)(include_permissions),
16112
+ includeFieldPermissions: includeFieldPermissions ?? (0, import_utils42.parseBooleanString)(include_field_permissions),
16022
16113
  populateAccess
16023
16114
  }
16024
16115
  );
@@ -16049,9 +16140,9 @@ function setModelDocumentRoutes(context) {
16049
16140
  body,
16050
16141
  {},
16051
16142
  {
16052
- returningAll: (0, import_utils41.parseBooleanString)(returning_all),
16053
- includePermissions: (0, import_utils41.parseBooleanString)(include_permissions),
16054
- includeFieldPermissions: (0, import_utils41.parseBooleanString)(include_field_permissions)
16143
+ returningAll: (0, import_utils42.parseBooleanString)(returning_all),
16144
+ includePermissions: (0, import_utils42.parseBooleanString)(include_permissions),
16145
+ includeFieldPermissions: (0, import_utils42.parseBooleanString)(include_field_permissions)
16055
16146
  }
16056
16147
  );
16057
16148
  handleResultError(result2);
@@ -16098,9 +16189,9 @@ function setModelDocumentRoutes(context) {
16098
16189
  finalData,
16099
16190
  { select: finalSelect, populate: finalPopulate, tasks: finalTasks },
16100
16191
  {
16101
- returningAll: returningAll ?? (0, import_utils41.parseBooleanString)(returning_all),
16102
- includePermissions: includePermissions ?? (0, import_utils41.parseBooleanString)(include_permissions),
16103
- includeFieldPermissions: includeFieldPermissions ?? (0, import_utils41.parseBooleanString)(include_field_permissions),
16192
+ returningAll: returningAll ?? (0, import_utils42.parseBooleanString)(returning_all),
16193
+ includePermissions: includePermissions ?? (0, import_utils42.parseBooleanString)(include_permissions),
16194
+ includeFieldPermissions: includeFieldPermissions ?? (0, import_utils42.parseBooleanString)(include_field_permissions),
16104
16195
  populateAccess
16105
16196
  }
16106
16197
  );
@@ -16340,11 +16431,11 @@ function setModelSubDocumentRoutes(context) {
16340
16431
  }
16341
16432
 
16342
16433
  // src/openapi/route-registration.ts
16343
- var import_utils42 = require("@web-ts-toolkit/utils");
16434
+ var import_utils43 = require("@web-ts-toolkit/utils");
16344
16435
  function registerOpenApiRoute(runtime, basePath, defaultTag, route) {
16345
16436
  runtime.registerOpenApiRoute({
16346
16437
  ...route,
16347
- path: (0, import_utils42.normalizeUrlPath)(basePath + route.path),
16438
+ path: (0, import_utils43.normalizeUrlPath)(basePath + route.path),
16348
16439
  tags: route.tags ?? [defaultTag]
16349
16440
  });
16350
16441
  }
@@ -16352,8 +16443,8 @@ function registerOpenApiRoute(runtime, basePath, defaultTag, route) {
16352
16443
  // src/routers/model-router.ts
16353
16444
  var clientErrors2 = import_express_json_router8.default.clientErrors;
16354
16445
  function setOption(parentKey, optionKey, option) {
16355
- const key = (0, import_utils43.isUndefined)(option) ? parentKey : `${parentKey}.${optionKey}`;
16356
- const value = (0, import_utils43.isUndefined)(option) ? optionKey : option;
16446
+ const key = (0, import_utils44.isUndefined)(option) ? parentKey : `${parentKey}.${optionKey}`;
16447
+ const value = (0, import_utils44.isUndefined)(option) ? optionKey : option;
16357
16448
  assertMutableRouterOption("model", key);
16358
16449
  this.runtime.setModelOption(
16359
16450
  this.modelName,
@@ -16555,7 +16646,7 @@ var ModelRouter = class _ModelRouter {
16555
16646
  this.runtime = runtime;
16556
16647
  this.runtime.setModelOptions(modelName, initialOptions);
16557
16648
  this.options = this.runtime.getModelOptions(modelName);
16558
- this.fullBasePath = (0, import_utils43.normalizeUrlPath)(this.options.parentPath + this.options.basePath);
16649
+ this.fullBasePath = (0, import_utils44.normalizeUrlPath)(this.options.parentPath + this.options.basePath);
16559
16650
  this.modelName = modelName;
16560
16651
  this.router = new import_express_json_router8.default(this.options.basePath, createSetCore(this.runtime), accessRouterResponseHandler);
16561
16652
  this.model = new model_default(modelName, this.runtime);
@@ -16641,13 +16732,13 @@ var ModelRouter = class _ModelRouter {
16641
16732
  }
16642
16733
  logEndpoints() {
16643
16734
  runWithRuntime(this.runtime, () => {
16644
- (0, import_utils43.forEach)(this.router.getEndpoints(), ({ method, path }) => {
16645
- logInfoMessage(`${(0, import_utils43.padEnd)(method, 6)} ${(0, import_utils43.normalizeUrlPath)(this.options.parentPath + path)}`);
16735
+ (0, import_utils44.forEach)(this.router.getEndpoints(), ({ method, path }) => {
16736
+ logInfoMessage(`${(0, import_utils44.padEnd)(method, 6)} ${(0, import_utils44.normalizeUrlPath)(this.options.parentPath + path)}`);
16646
16737
  });
16647
16738
  });
16648
16739
  }
16649
16740
  set(keyOrOptions, value) {
16650
- if (arguments.length === 2 && (0, import_utils43.isString)(keyOrOptions)) {
16741
+ if (arguments.length === 2 && (0, import_utils44.isString)(keyOrOptions)) {
16651
16742
  assertMutableRouterOption("model", keyOrOptions);
16652
16743
  this.runtime.setModelOption(
16653
16744
  this.modelName,
@@ -16655,7 +16746,7 @@ var ModelRouter = class _ModelRouter {
16655
16746
  value
16656
16747
  );
16657
16748
  }
16658
- if (arguments.length === 1 && (0, import_utils43.isPlainObject)(keyOrOptions)) {
16749
+ if (arguments.length === 1 && (0, import_utils44.isPlainObject)(keyOrOptions)) {
16659
16750
  assertMutableRouterOptions("model", keyOrOptions);
16660
16751
  this.runtime.setModelOptions(
16661
16752
  this.modelName,
@@ -16683,7 +16774,7 @@ var ModelRouter = class _ModelRouter {
16683
16774
 
16684
16775
  // src/routers/root-router.ts
16685
16776
  var import_express_json_router9 = __toESM(require("@web-ts-toolkit/express-json-router"));
16686
- var import_utils44 = require("@web-ts-toolkit/utils");
16777
+ var import_utils45 = require("@web-ts-toolkit/utils");
16687
16778
 
16688
16779
  // src/core-data.ts
16689
16780
  init_options();
@@ -16991,7 +17082,7 @@ var RootRouter = class {
16991
17082
  this.setRoutes();
16992
17083
  }
16993
17084
  registerOpenApiRoute(route) {
16994
- registerOpenApiRoute(this.runtime, (0, import_utils44.normalizeUrlPath)(this.basename), "root", route);
17085
+ registerOpenApiRoute(this.runtime, (0, import_utils45.normalizeUrlPath)(this.basename), "root", route);
16995
17086
  }
16996
17087
  wrapResult(index, item, result2) {
16997
17088
  return {
@@ -17100,7 +17191,7 @@ var RootRouter = class {
17100
17191
  groupItemsByOrder(items) {
17101
17192
  const groups = /* @__PURE__ */ new Map();
17102
17193
  items.forEach((item, index) => {
17103
- const order = (0, import_utils44.isNumber)(item.order) ? item.order : 0;
17194
+ const order = (0, import_utils45.isNumber)(item.order) ? item.order : 0;
17104
17195
  const group = groups.get(order);
17105
17196
  if (group) {
17106
17197
  group.push({ index, item });
@@ -17171,7 +17262,7 @@ var RootRouter = class {
17171
17262
  const arrResult = await this.runGroup(req, groupedItems[x]);
17172
17263
  results.push(...arrResult);
17173
17264
  }
17174
- return (0, import_utils44.orderBy)(results, ["index"], ["asc"]);
17265
+ return (0, import_utils45.orderBy)(results, ["index"], ["asc"]);
17175
17266
  });
17176
17267
  this.registerOpenApiRoute({
17177
17268
  method: "post",
@@ -17189,14 +17280,14 @@ var RootRouter = class {
17189
17280
 
17190
17281
  // src/routers/data-router.ts
17191
17282
  var import_express_json_router10 = __toESM(require("@web-ts-toolkit/express-json-router"));
17192
- var import_utils45 = require("@web-ts-toolkit/utils");
17283
+ var import_utils46 = require("@web-ts-toolkit/utils");
17193
17284
  init_runtime();
17194
17285
  init_helpers();
17195
17286
  init_schemas();
17196
17287
  var clientErrors4 = import_express_json_router10.default.clientErrors;
17197
17288
  function setOption2(parentKey, optionKey, option) {
17198
- const key = (0, import_utils45.isUndefined)(option) ? parentKey : `${parentKey}.${optionKey}`;
17199
- const value = (0, import_utils45.isUndefined)(option) ? optionKey : option;
17289
+ const key = (0, import_utils46.isUndefined)(option) ? parentKey : `${parentKey}.${optionKey}`;
17290
+ const value = (0, import_utils46.isUndefined)(option) ? optionKey : option;
17200
17291
  assertMutableRouterOption("data", key);
17201
17292
  this.runtime.setDataOption(this.dataName, key, value);
17202
17293
  return this;
@@ -17245,7 +17336,7 @@ var DataRouter = class {
17245
17336
  this.runtime = runtime;
17246
17337
  this.runtime.setDataOptions(dataName, initialOptions);
17247
17338
  this.options = this.runtime.getDataOptions(dataName);
17248
- this.fullBasePath = (0, import_utils45.normalizeUrlPath)(this.options.parentPath + this.options.basePath);
17339
+ this.fullBasePath = (0, import_utils46.normalizeUrlPath)(this.options.parentPath + this.options.basePath);
17249
17340
  this.dataName = dataName;
17250
17341
  this.router = new import_express_json_router10.default(this.options.basePath, createSetDataCore(this.runtime), accessRouterResponseHandler);
17251
17342
  this.setCollectionRoutes();
@@ -17278,8 +17369,8 @@ var DataRouter = class {
17278
17369
  req.query
17279
17370
  );
17280
17371
  const svc = this.getService(req);
17281
- const includeCount = (0, import_utils41.parseBooleanString)(include_count);
17282
- const includeExtraHeaders = (0, import_utils41.parseBooleanString)(include_extra_headers);
17372
+ const includeCount = (0, import_utils42.parseBooleanString)(include_count);
17373
+ const includeExtraHeaders = (0, import_utils42.parseBooleanString)(include_extra_headers);
17283
17374
  const result2 = await svc.find(
17284
17375
  {},
17285
17376
  { select: parseSelectParam(select), sort, skip, limit, page, pageSize: page_size },
@@ -17397,7 +17488,7 @@ var DataRouter = class {
17397
17488
  });
17398
17489
  }
17399
17490
  set(keyOrOptions, value) {
17400
- if (arguments.length === 2 && (0, import_utils45.isString)(keyOrOptions)) {
17491
+ if (arguments.length === 2 && (0, import_utils46.isString)(keyOrOptions)) {
17401
17492
  assertMutableRouterOption("data", keyOrOptions);
17402
17493
  this.runtime.setDataOption(
17403
17494
  this.dataName,
@@ -17405,7 +17496,7 @@ var DataRouter = class {
17405
17496
  value
17406
17497
  );
17407
17498
  }
17408
- if (arguments.length === 1 && (0, import_utils45.isPlainObject)(keyOrOptions)) {
17499
+ if (arguments.length === 1 && (0, import_utils46.isPlainObject)(keyOrOptions)) {
17409
17500
  assertMutableRouterOptions("data", keyOrOptions);
17410
17501
  this.runtime.setDataOptions(this.dataName, keyOrOptions);
17411
17502
  }
@@ -17540,7 +17631,7 @@ function createRuntimeApi(runtime) {
17540
17631
  const wtt2 = runtimeMiddleware;
17541
17632
  wtt2.runtime = runtime;
17542
17633
  wtt2.createRouter = function(modelName, options) {
17543
- if ((0, import_utils46.isUndefined)(options)) {
17634
+ if ((0, import_utils47.isUndefined)(options)) {
17544
17635
  return new RootRouter(modelName, runtime);
17545
17636
  }
17546
17637
  if (typeof modelName === "string") {
@@ -17561,10 +17652,10 @@ function createRuntimeApi(runtime) {
17561
17652
  };
17562
17653
  wtt2.combineRoutes = combineRoutes;
17563
17654
  wtt2.set = function(keyOrOptions, value) {
17564
- if (arguments.length === 2 && (0, import_utils46.isString)(keyOrOptions)) {
17655
+ if (arguments.length === 2 && (0, import_utils47.isString)(keyOrOptions)) {
17565
17656
  return runtime.setGlobalOption(keyOrOptions, value);
17566
17657
  }
17567
- if (arguments.length === 1 && (0, import_utils46.isPlainObject)(keyOrOptions)) {
17658
+ if (arguments.length === 1 && (0, import_utils47.isPlainObject)(keyOrOptions)) {
17568
17659
  return runtime.setGlobalOptions(keyOrOptions);
17569
17660
  }
17570
17661
  };