@web-ts-toolkit/access-router 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/advanced.js CHANGED
@@ -123,10 +123,10 @@ var FilterOperator = /* @__PURE__ */ ((FilterOperator2) => {
123
123
  })(FilterOperator || {});
124
124
 
125
125
  // src/validation/parsers.ts
126
- var import_express_json_router2 = __toESM(require("@web-ts-toolkit/express-json-router"));
126
+ var import_express_json_router3 = __toESM(require("@web-ts-toolkit/express-json-router"));
127
127
 
128
128
  // src/runtime.ts
129
- var import_mongoose2 = __toESM(require("mongoose"));
129
+ var import_mongoose3 = __toESM(require("mongoose"));
130
130
 
131
131
  // src/validation/public-admission.ts
132
132
  var import_express_json_router = __toESM(require("@web-ts-toolkit/express-json-router"));
@@ -169,10 +169,10 @@ function assertPublicAdmission(input, kind = "envelope") {
169
169
  const add = (child, childKind, key) => {
170
170
  pending.push({ value: child, kind: childKind, path: `${path}.${key}` });
171
171
  };
172
- const record = value;
172
+ const record2 = value;
173
173
  if (slot !== "data") {
174
174
  for (const key of privateControls) {
175
- if (key in record) {
175
+ if (key in record2) {
176
176
  throw new PublicAdmissionError(
177
177
  `Unsupported public control ${path}.${key}; use explicit per-call internal service options for backend authorization`
178
178
  );
@@ -188,16 +188,16 @@ function assertPublicAdmission(input, kind = "envelope") {
188
188
  for (const [key, child] of Object.entries(value)) add(child, key === "$$sq" ? "envelope" : "data", key);
189
189
  continue;
190
190
  }
191
- for (const key of ["args", "options", "sqOptions"]) add(record[key], "envelope", key);
192
- add(record.include, "include", "include");
193
- add(record.populate, "populate", "populate");
194
- for (const key of ["filter", "match", "data"]) add(record[key], "data", key);
191
+ for (const key of ["args", "options", "sqOptions"]) add(record2[key], "envelope", key);
192
+ add(record2.include, "include", "include");
193
+ add(record2.populate, "populate", "populate");
194
+ for (const key of ["filter", "match", "data"]) add(record2[key], "data", key);
195
195
  }
196
196
  }
197
197
  function assertHydrationDefaults(defaults) {
198
198
  if (defaults && typeof defaults === "object") {
199
- const record = defaults;
200
- if ("hydration" in record)
199
+ const record2 = defaults;
200
+ if ("hydration" in record2)
201
201
  throw new TypeError("defaults.hydration is unsupported; use model hydration configuration");
202
202
  for (const bucket of [
203
203
  "publicListOptions",
@@ -213,7 +213,7 @@ function assertHydrationDefaults(defaults) {
213
213
  "publicCreateOptions",
214
214
  "publicUpdateOptions"
215
215
  ]) {
216
- const options = record[bucket];
216
+ const options = record2[bucket];
217
217
  if (!options || typeof options !== "object" && typeof options !== "function") continue;
218
218
  for (const key of ["lean", "hydration"]) {
219
219
  if (!(key in options)) continue;
@@ -260,11 +260,28 @@ function normalizeHydrationUpdate(current, key, value) {
260
260
 
261
261
  // src/runtime.ts
262
262
  var import_mongoose_schema_jsonschema = __toESM(require("mongoose-schema-jsonschema"));
263
- var import_utils10 = require("@web-ts-toolkit/utils");
263
+ var import_utils12 = require("@web-ts-toolkit/utils");
264
264
 
265
265
  // src/helpers/query.ts
266
266
  var import_utils2 = require("@web-ts-toolkit/utils");
267
267
  var DEFAULT_LIST_HARD_LIMIT = 1e3;
268
+ function normalizeSelect(select) {
269
+ if (Array.isArray(select)) return (0, import_utils2.flattenDeep)(select.map(normalizeSelect));
270
+ if ((0, import_utils2.isPlainObject)(select)) {
271
+ return (0, import_utils2.reduce)(
272
+ select,
273
+ (ret, val, key) => {
274
+ if (val === 1) ret.push(key);
275
+ else if (val === -1) ret.push(`-${key}`);
276
+ return ret;
277
+ },
278
+ []
279
+ );
280
+ }
281
+ if ((0, import_utils2.isString)(select))
282
+ return String(select).split(/[\s,]+/).map((v) => v.trim()).filter(Boolean);
283
+ return [];
284
+ }
268
285
 
269
286
  // src/helpers/sort-policy.ts
270
287
  var fieldPathPattern = /^[A-Za-z_][A-Za-z0-9_$]*(\.[A-Za-z_][A-Za-z0-9_$]*)*$/;
@@ -1180,14 +1197,492 @@ function validateRequestComplexity(value, options, scope = "request") {
1180
1197
  return errors;
1181
1198
  }
1182
1199
 
1200
+ // src/acl/virtual-descriptor.ts
1201
+ var import_utils10 = require("@web-ts-toolkit/utils");
1202
+ var isVirtualContainerValue = (value) => (0, import_utils10.isPlainObject)(value) && "sub" in value;
1203
+ function getScopeVirtualsObject(root, scopePath = []) {
1204
+ let current = root;
1205
+ for (let i = 0; i < scopePath.length; i += 2) {
1206
+ if (!current || scopePath[i + 1] !== "sub") return null;
1207
+ const container = current[scopePath[i]];
1208
+ if (!isVirtualContainerValue(container)) return null;
1209
+ current = container.sub;
1210
+ }
1211
+ return (0, import_utils10.isPlainObject)(current) ? current : null;
1212
+ }
1213
+ function toDescriptor(leaf, shared = {}) {
1214
+ const record2 = (0, import_utils10.isFunction)(leaf) ? { get: leaf } : (0, import_utils10.isPlainObject)(leaf) ? leaf : null;
1215
+ if (!record2 || !(0, import_utils10.isFunction)(record2.get)) return void 0;
1216
+ const dependsOn = record2.dependsOn ?? shared.dependsOn ?? [];
1217
+ const populated = record2.dependsOnPopulate === void 0 ? shared.dependsOnPopulate : record2.dependsOnPopulate;
1218
+ return {
1219
+ get: record2.get,
1220
+ dependsOn: [...dependsOn],
1221
+ ...populated === void 0 ? {} : {
1222
+ dependsOnPopulate: populated.map(({ path, select }) => ({
1223
+ path,
1224
+ ...select === void 0 ? {} : { select: Array.isArray(select) ? [...select] : typeof select === "object" ? { ...select } : select }
1225
+ }))
1226
+ }
1227
+ };
1228
+ }
1229
+ function resolveSnapshotDescriptor(scopeVirtuals, virtualName, access) {
1230
+ const entry = scopeVirtuals?.[virtualName];
1231
+ if (entry === void 0 || isVirtualContainerValue(entry)) return void 0;
1232
+ if ((0, import_utils10.isFunction)(entry)) return toDescriptor(entry);
1233
+ if (!(0, import_utils10.isPlainObject)(entry)) return void 0;
1234
+ const record2 = entry;
1235
+ if ("get" in record2) return toDescriptor(record2);
1236
+ return toDescriptor(record2[access], record2) ?? toDescriptor(record2.default, record2);
1237
+ }
1238
+
1239
+ // src/acl/virtual-populate-dependencies.ts
1240
+ var import_utils11 = require("@web-ts-toolkit/utils");
1241
+
1242
+ // src/acl/authorization-snapshot.ts
1243
+ var import_node_util3 = require("util");
1244
+ var import_mongoose2 = require("mongoose");
1245
+ var import_express_json_router2 = __toESM(require("@web-ts-toolkit/express-json-router"));
1246
+ var ServiceAuthorizationError = class extends import_express_json_router2.default.clientErrors.BadRequestError {
1247
+ constructor(detail) {
1248
+ const errors = [{ detail: `Service authorization: ${detail}` }];
1249
+ super("Bad Request", { errors });
1250
+ this.result = { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors };
1251
+ }
1252
+ };
1253
+ function authorizationError(detail) {
1254
+ throw new ServiceAuthorizationError(detail);
1255
+ }
1256
+ var unsafeKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
1257
+ function authorizationRecord(value, label) {
1258
+ if (!value || typeof value !== "object" || Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
1259
+ authorizationError(`${label} must be a plain object`);
1260
+ }
1261
+ return value;
1262
+ }
1263
+ function copyAuthorizationValue(value, configuration = false) {
1264
+ const active = /* @__PURE__ */ new WeakSet();
1265
+ let nodes = 0;
1266
+ function copy(input, depth) {
1267
+ if (++nodes > 2e4 || depth > 100) authorizationError("snapshot exceeds structural limits");
1268
+ if (typeof input === "function") {
1269
+ if (configuration === true) return input;
1270
+ authorizationError("functions are not policy values");
1271
+ }
1272
+ if (typeof input === "symbol") authorizationError("symbols are not policy values");
1273
+ if (input === null || typeof input !== "object") return input;
1274
+ if (active.has(input)) authorizationError("cyclic input");
1275
+ active.add(input);
1276
+ try {
1277
+ if (input instanceof Date) return new Date(input.getTime());
1278
+ if (Buffer.isBuffer(input)) return Buffer.from(input);
1279
+ if (input instanceof RegExp) {
1280
+ const result2 = new RegExp(input.source, input.flags);
1281
+ result2.lastIndex = input.lastIndex;
1282
+ return result2;
1283
+ }
1284
+ if (input instanceof import_mongoose2.mongo.BSON.BSONValue) {
1285
+ try {
1286
+ return import_mongoose2.mongo.BSON.deserialize(import_mongoose2.mongo.BSON.serialize({ value: input }), {
1287
+ promoteValues: false,
1288
+ bsonRegExp: true
1289
+ }).value;
1290
+ } catch {
1291
+ authorizationError("unsupported BSON snapshot");
1292
+ }
1293
+ }
1294
+ if (configuration && input instanceof Map) {
1295
+ return new Map([...input].map(([key, entry]) => [copy(key, depth + 1), copy(entry, depth + 1)]));
1296
+ }
1297
+ if (configuration && input instanceof Set) return new Set([...input].map((entry) => copy(entry, depth + 1)));
1298
+ const array = Array.isArray(input);
1299
+ if (array && input.length > 2e4) authorizationError("snapshot array exceeds structural limits");
1300
+ if (!array) authorizationRecord(input, "snapshot");
1301
+ const result = array ? [] : {};
1302
+ for (const key of Reflect.ownKeys(input)) {
1303
+ if (array && key === "length") continue;
1304
+ if (typeof key !== "string" || unsafeKeys.has(key)) authorizationError("unsafe snapshot key");
1305
+ if (array && !/^(0|[1-9]\d*)$/.test(key)) authorizationError("invalid array property");
1306
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
1307
+ if (!("value" in descriptor) || !descriptor.enumerable && configuration !== "document")
1308
+ authorizationError("accessor/non-enumerable input");
1309
+ Object.defineProperty(result, key, {
1310
+ value: copy(descriptor.value, depth + 1),
1311
+ enumerable: true,
1312
+ writable: true,
1313
+ configurable: true
1314
+ });
1315
+ }
1316
+ if (array) result.length = input.length;
1317
+ return Object.freeze(result);
1318
+ } finally {
1319
+ active.delete(input);
1320
+ }
1321
+ }
1322
+ return copy(value, 0);
1323
+ }
1324
+
1325
+ // src/acl/field-catalog.ts
1326
+ var safeSegment = (part) => !!part && part !== "sub" && !["__proto__", "constructor", "prototype", "_doc", "__v"].includes(part) && !/^[+$-]|[\s*]/.test(part) && !part.includes("[") && !part.includes("]") && !/^\d+$/.test(part) && ![...part].some((character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127);
1327
+ var isSafeOutputPath = (path) => path.split(".").every(safeSegment);
1328
+ var inputControlSegments = /* @__PURE__ */ new Set([
1329
+ "_permissions",
1330
+ "_view",
1331
+ "_edit",
1332
+ "documentAuthorization",
1333
+ "documentAuthorizationStage",
1334
+ "resolvedAuthorization",
1335
+ "execution",
1336
+ "executionContext",
1337
+ "serviceExecutionContext",
1338
+ "preparedQuery",
1339
+ "preparedFilter",
1340
+ "preparedModelQuery",
1341
+ "resolvedIdentifier",
1342
+ "skipParsing",
1343
+ "skipAuthorization",
1344
+ "alreadyAuthorized"
1345
+ ]);
1346
+ function isSafeInputPath(path, requestIdentity = false) {
1347
+ return isSafeOutputPath(path) && path.split(".").every((part) => !inputControlSegments.has(part) && (requestIdentity || part !== "_id"));
1348
+ }
1349
+ function matchesCatalogPattern(pattern, path, descendants = false) {
1350
+ const expected = pattern.split(".");
1351
+ const actual = path.split(".");
1352
+ return (descendants ? actual.length >= expected.length : actual.length === expected.length) && expected.every((part, index) => part === "$*" || part === actual[index]);
1353
+ }
1354
+ function captureAuthorizationFieldCatalog(schema, virtuals, documentPermissionField = "_permissions") {
1355
+ const paths = /* @__PURE__ */ new Set();
1356
+ const containers = /* @__PURE__ */ new Set();
1357
+ const opaque = /* @__PURE__ */ new Set();
1358
+ const references = /* @__PURE__ */ new Set();
1359
+ const virtualPaths = /* @__PURE__ */ new Set();
1360
+ const virtualScopes = /* @__PURE__ */ new Set();
1361
+ const schemaVirtualPaths = /* @__PURE__ */ new Set();
1362
+ const arrays = /* @__PURE__ */ new Set();
1363
+ const protectedPaths = /* @__PURE__ */ new Set([documentPermissionField, "_doc", "$__", "__v"]);
1364
+ const add = (path) => {
1365
+ if (path.split(".").every((part) => part === "$*" || safeSegment(part))) paths.add(path);
1366
+ };
1367
+ const ancestors = (path) => {
1368
+ const parts = path.split(".");
1369
+ for (let n = 1; n < parts.length; n++) {
1370
+ const parent = parts.slice(0, n).join(".");
1371
+ add(parent);
1372
+ containers.add(parent);
1373
+ }
1374
+ };
1375
+ const visitType = (type, path, active) => {
1376
+ add(path);
1377
+ ancestors(path);
1378
+ const element = type.$embeddedSchemaType ?? type.embeddedSchemaType ?? type.caster;
1379
+ if (type.instance === "Array" || type.$isMongooseDocumentArray) arrays.add(path);
1380
+ if (type.options?.ref || type.options?.refPath || element?.options?.ref || element?.options?.refPath) {
1381
+ references.add(path);
1382
+ return;
1383
+ }
1384
+ if (type.$isSchemaMap || type.instance === "Map") {
1385
+ const value = type.$__schemaType;
1386
+ if (value) visitType(value, `${path}.$*`, active);
1387
+ else opaque.add(path);
1388
+ containers.delete(path);
1389
+ return;
1390
+ }
1391
+ const child = type.schema ?? element?.schema;
1392
+ if (child) {
1393
+ containers.add(path);
1394
+ if (!active.has(child)) visitSchema(child, path, /* @__PURE__ */ new Set([...active, child]));
1395
+ return;
1396
+ }
1397
+ if (type.instance === "Mixed" || element?.instance === "Mixed") opaque.add(path);
1398
+ };
1399
+ const visitSchema = (current, prefix, active) => {
1400
+ const version = current.options.versionKey;
1401
+ if (typeof version === "string") protectedPaths.add(prefix ? `${prefix}.${version}` : version);
1402
+ for (const name of Object.keys(current.virtuals)) {
1403
+ schemaVirtualPaths.add(prefix ? `${prefix}.${name}` : name);
1404
+ }
1405
+ for (const [name, raw] of Object.entries(current.paths)) {
1406
+ if (name.includes("$*")) continue;
1407
+ visitType(raw, prefix ? `${prefix}.${name}` : name, active);
1408
+ }
1409
+ };
1410
+ visitSchema(schema, "", /* @__PURE__ */ new Set([schema]));
1411
+ const persistedPaths = [...paths];
1412
+ const visitVirtuals = (record2, prefix) => {
1413
+ for (const [name, value] of Object.entries(record2 ?? {})) {
1414
+ if (value === void 0) continue;
1415
+ const path = prefix ? `${prefix}.${name}` : name;
1416
+ if (!isSafeOutputPath(path)) continue;
1417
+ if (value && typeof value === "object" && "sub" in value) {
1418
+ if (references.has(path)) continue;
1419
+ virtualScopes.add(path);
1420
+ add(path);
1421
+ containers.add(path);
1422
+ visitVirtuals(value.sub, path);
1423
+ } else {
1424
+ add(path);
1425
+ ancestors(path);
1426
+ virtualPaths.add(path);
1427
+ }
1428
+ }
1429
+ };
1430
+ visitVirtuals(virtuals, "");
1431
+ const eligible = [...paths].filter((p) => ![...protectedPaths].some((v) => matchesCatalogPattern(v, p, true)));
1432
+ return Object.freeze({
1433
+ paths: Object.freeze(eligible.filter((p) => !p.includes("$*"))),
1434
+ persistedPaths: Object.freeze(persistedPaths),
1435
+ arrayPaths: Object.freeze([...arrays]),
1436
+ schemaVirtualPaths: Object.freeze([...schemaVirtualPaths]),
1437
+ metadataPaths: Object.freeze([documentPermissionField]),
1438
+ dynamicPaths: Object.freeze(eligible.filter((p) => p.includes("$*"))),
1439
+ containerPaths: Object.freeze([...containers]),
1440
+ opaquePaths: Object.freeze([...opaque]),
1441
+ referencePaths: Object.freeze([...references]),
1442
+ virtualPaths: Object.freeze([...virtualPaths]),
1443
+ virtualScopePaths: Object.freeze([...virtualScopes]),
1444
+ protectedPaths: Object.freeze([...protectedPaths])
1445
+ });
1446
+ }
1447
+
1448
+ // src/acl/virtual-populate-dependencies.ts
1449
+ var elementType = (type) => type.$embeddedSchemaType ?? type.embeddedSchemaType ?? type.caster;
1450
+ var join = (prefix, path) => prefix ? `${prefix}.${path}` : path;
1451
+ var within = (path, parent) => path === parent || path.startsWith(`${parent}.`);
1452
+ var accesses = ["default", "list", "create", "read", "update"];
1453
+ var fail = (label, message) => {
1454
+ throw new Error(`Virtual ${label}: dependsOnPopulate ${message}`);
1455
+ };
1456
+ var varyingSchema = (schema) => Object.keys(schema.discriminators ?? {}).length > 0 || schema.discriminatorMapping?.isRoot === false;
1457
+ var varyingModel = (model) => !!model.baseModelName || Object.keys(model.discriminators ?? {}).length > 0 || varyingSchema(model.schema);
1458
+ function record(value, label) {
1459
+ if (!(0, import_utils11.isPlainObject)(value)) return fail(label, "entries must be plain { path, select? } objects");
1460
+ for (const key of Reflect.ownKeys(value)) {
1461
+ const property = Object.getOwnPropertyDescriptor(value, key);
1462
+ if (typeof key !== "string" || !property.enumerable || !("value" in property))
1463
+ fail(label, "requires enumerable data properties");
1464
+ }
1465
+ return value;
1466
+ }
1467
+ function targetSelectionCatalog(schema, options) {
1468
+ const leaves = /* @__PURE__ */ new Set();
1469
+ const containers = /* @__PURE__ */ new Set();
1470
+ const forbidden = /* @__PURE__ */ new Set([options.documentPermissionField ?? "_permissions"]);
1471
+ const visit = (current, prefix, active) => {
1472
+ const version = current.options.versionKey;
1473
+ if (typeof version === "string") forbidden.add(join(prefix, version));
1474
+ for (const name of Object.keys(current.virtuals)) forbidden.add(join(prefix, name));
1475
+ for (const name of Object.keys(current.aliases ?? {})) forbidden.add(join(prefix, name));
1476
+ for (const [name, raw] of Object.entries(current.paths)) {
1477
+ const path = join(prefix, name);
1478
+ if (!isSafeInputPath(path, true)) continue;
1479
+ const parts = path.split(".");
1480
+ for (let n = 1; n < parts.length; n++) containers.add(parts.slice(0, n).join("."));
1481
+ let type = raw;
1482
+ while (type.instance === "Array" && elementType(type)) type = elementType(type);
1483
+ if (type.instance === "Mixed" || type.instance === "Map") {
1484
+ forbidden.add(path);
1485
+ continue;
1486
+ }
1487
+ const child = type.schema ?? raw.schema;
1488
+ if (raw.options?.ref !== void 0 || raw.options?.refPath !== void 0 || type.options?.ref !== void 0 || type.options?.refPath !== void 0) {
1489
+ if (child) forbidden.add(path);
1490
+ else leaves.add(path);
1491
+ continue;
1492
+ }
1493
+ if (child) {
1494
+ if (active.has(child) || varyingSchema(child)) forbidden.add(path);
1495
+ else {
1496
+ containers.add(path);
1497
+ visit(child, path, /* @__PURE__ */ new Set([...active, child]));
1498
+ }
1499
+ } else leaves.add(path);
1500
+ }
1501
+ };
1502
+ visit(schema, "", /* @__PURE__ */ new Set([schema]));
1503
+ const visitVirtuals = (virtuals, prefix) => {
1504
+ for (const [name, entry] of Object.entries(virtuals)) {
1505
+ if (entry === void 0) continue;
1506
+ const path = join(prefix, name);
1507
+ if (isVirtualContainerValue(entry)) visitVirtuals(entry.sub, path);
1508
+ else forbidden.add(path);
1509
+ }
1510
+ };
1511
+ visitVirtuals(options.virtuals ?? {}, "");
1512
+ const allowed = (path) => ![...forbidden].some((blocked) => within(path, blocked));
1513
+ return {
1514
+ leaves: [...leaves].filter(allowed).sort(),
1515
+ paths: new Set([...leaves, ...containers].filter(allowed))
1516
+ };
1517
+ }
1518
+ function normalizeSelection(select, catalog, label) {
1519
+ if (select !== void 0 && typeof select !== "string") {
1520
+ if (Array.isArray(select)) {
1521
+ if (Array.from(select).some((token) => typeof token !== "string")) fail(label, "select arrays require strings");
1522
+ } else {
1523
+ const projection = record(select, label);
1524
+ for (const [path, value] of Object.entries(projection)) {
1525
+ if (!isSafeInputPath(path, true) || value !== 1 && value !== -1)
1526
+ fail(label, "select objects require safe persisted paths with 1/-1 values");
1527
+ }
1528
+ }
1529
+ }
1530
+ const tokens = normalizeSelect(select);
1531
+ for (const token of tokens) {
1532
+ const path = token.startsWith("-") ? token.slice(1) : token;
1533
+ if (!isSafeInputPath(path, true) || !catalog.paths.has(path))
1534
+ fail(label, `select path "${path}" is not an eligible static persisted target path`);
1535
+ }
1536
+ const positive = tokens.filter((token) => !token.startsWith("-"));
1537
+ const negative = tokens.filter((token) => token.startsWith("-")).map((token) => token.slice(1));
1538
+ const selection = catalog.leaves.filter(
1539
+ (path) => (path === "_id" || positive.length === 0 || positive.some((included) => within(path, included))) && !negative.some((excluded) => within(path, excluded))
1540
+ );
1541
+ return {
1542
+ selection: Object.freeze(selection),
1543
+ fetchSelection: Object.freeze([.../* @__PURE__ */ new Set(["_id", ...selection])].sort()),
1544
+ includeId: selection.includes("_id")
1545
+ };
1546
+ }
1547
+ function captureVirtualPopulateDependencies(runtime, modelName, options, globalOptions = runtime.getGlobalOptions()) {
1548
+ const requireReadOperationAccessForPopulateDependencies = globalOptions.requireReadOperationAccessForPopulateDependencies !== false;
1549
+ const model = runtime.getModelInstance(modelName);
1550
+ const targets = /* @__PURE__ */ new Map();
1551
+ const scopes = [];
1552
+ const visit = (virtuals, schema, schemaPrefix, scopePath, unsupportedScope) => {
1553
+ const sourcePrefix = scopePath.filter((_, index) => index % 2 === 0).join(".");
1554
+ const captureList = (value, label) => {
1555
+ if (value === void 0) return Object.freeze([]);
1556
+ if (!Array.isArray(value)) return fail(label, "must be an array");
1557
+ const seen = /* @__PURE__ */ new Set();
1558
+ return Object.freeze(
1559
+ Array.from(value, (entry) => {
1560
+ const dependency = record(entry, label);
1561
+ if (Object.keys(dependency).some((key) => key !== "path" && key !== "select"))
1562
+ fail(label, "accepts only path/select");
1563
+ const path = dependency.path;
1564
+ if (typeof path !== "string" || path.includes(".") || !isSafeInputPath(path, true))
1565
+ return fail(label, "path must be a safe scope-local persisted reference key");
1566
+ if (seen.has(path)) fail(label, `duplicate path "${path}"`);
1567
+ seen.add(path);
1568
+ if (within(join(sourcePrefix, path), options.documentPermissionField ?? "_permissions") || path === schema?.options.versionKey)
1569
+ fail(label, "source permission metadata/version paths are not reference inputs");
1570
+ if (!model || !schema || unsupportedScope)
1571
+ return fail(label, "requires a static embedded, non-discriminator source scope");
1572
+ const type = schema.path(join(schemaPrefix, path));
1573
+ const isArray6 = type?.instance === "Array";
1574
+ const scalar = type && (isArray6 ? elementType(type) : type);
1575
+ const ref = type?.options?.ref ?? scalar?.options?.ref;
1576
+ if (!scalar || scalar.instance !== "ObjectId" || typeof ref !== "string" || !ref || type?.options?.refPath !== void 0 || scalar.options?.refPath !== void 0)
1577
+ return fail(label, `path "${path}" requires a static string ref on an ObjectId scalar or 1D array`);
1578
+ let captured = targets.get(ref);
1579
+ if (!captured) {
1580
+ if (ref !== modelName && !runtime.hasModel(ref))
1581
+ return fail(label, `target "${ref}" must be configured first in this runtime`);
1582
+ const targetModel = runtime.getModelInstance(ref);
1583
+ if (!targetModel || targetModel.db !== model.db || model.db.models[ref] !== targetModel || varyingModel(targetModel) || targetModel.schema.path("_id")?.instance !== "ObjectId")
1584
+ return fail(
1585
+ label,
1586
+ `target "${ref}" requires a registered same-connection non-discriminator ObjectId model bound to the source ref`
1587
+ );
1588
+ const targetOptions = ref === modelName ? options : runtime.getModelOptions(ref);
1589
+ const defaults = runtime.getDefaultModelOptions();
1590
+ const readOption = (key) => resolveNestedOption((path2, fallback) => (0, import_utils11.get)(targetOptions, path2, fallback), key, (0, import_utils11.get)(defaults, key));
1591
+ const documentPermissionField = targetOptions.documentPermissionField ?? defaults.documentPermissionField;
1592
+ const catalog = captureAuthorizationFieldCatalog(targetModel.schema, void 0, documentPermissionField);
1593
+ const configuration = copyAuthorizationValue(
1594
+ {
1595
+ catalog,
1596
+ documentPermissionField,
1597
+ requireReadOperationAccessForPopulateDependencies,
1598
+ operationAccess: { read: readOption("operationAccess.read") },
1599
+ baseFilter: { read: readOption("baseFilter.read") },
1600
+ overrideFilter: { read: readOption("overrideFilter.read") },
1601
+ hydration: targetOptions.hydration
1602
+ },
1603
+ true
1604
+ );
1605
+ captured = {
1606
+ target: Object.freeze({
1607
+ identity: Object.freeze({}),
1608
+ runtime,
1609
+ modelName: ref,
1610
+ model: targetModel,
1611
+ schema: targetModel.schema,
1612
+ configuration
1613
+ }),
1614
+ catalog: targetSelectionCatalog(targetModel.schema, { ...targetOptions, documentPermissionField })
1615
+ };
1616
+ targets.set(ref, captured);
1617
+ }
1618
+ return Object.freeze({
1619
+ path,
1620
+ sourcePath: join(sourcePrefix, path),
1621
+ cardinality: isArray6 ? "array" : "scalar",
1622
+ target: captured.target,
1623
+ ...normalizeSelection(dependency.select, captured.catalog, label)
1624
+ });
1625
+ })
1626
+ );
1627
+ };
1628
+ for (const [name, raw] of Object.entries(virtuals)) {
1629
+ if (isVirtualContainerValue(raw)) {
1630
+ const path = join(schemaPrefix, name);
1631
+ const type = schema?.path(path);
1632
+ const element = type && elementType(type);
1633
+ const child = type?.schema ?? element?.schema;
1634
+ const nonEmbedded = [type, element].some(
1635
+ (entry2) => entry2 && (entry2.options?.ref !== void 0 || entry2.options?.refPath !== void 0 || entry2.instance === "Map" || entry2.instance === "Mixed")
1636
+ );
1637
+ visit(
1638
+ raw.sub,
1639
+ child ?? schema,
1640
+ child ? "" : path,
1641
+ [...scopePath, name, "sub"],
1642
+ unsupportedScope || nonEmbedded || !!(child && varyingSchema(child))
1643
+ );
1644
+ continue;
1645
+ }
1646
+ if (!(0, import_utils11.isPlainObject)(raw)) continue;
1647
+ const entry = raw;
1648
+ const label = join(sourcePrefix, name);
1649
+ captureList(entry.dependsOnPopulate, label);
1650
+ if (!("get" in entry))
1651
+ for (const access of accesses) {
1652
+ if ((0, import_utils11.isPlainObject)(entry[access]))
1653
+ captureList(entry[access].dependsOnPopulate, `${label}.${access}`);
1654
+ }
1655
+ const byAccess = {};
1656
+ let declared = false;
1657
+ for (const access of accesses) {
1658
+ const descriptor = resolveSnapshotDescriptor(virtuals, name, access);
1659
+ if (descriptor) {
1660
+ byAccess[access] = captureList(descriptor.dependsOnPopulate, `${label}.${access}`);
1661
+ declared ||= descriptor.dependsOnPopulate !== void 0;
1662
+ }
1663
+ }
1664
+ if (declared)
1665
+ scopes.push(
1666
+ Object.freeze({
1667
+ scopePath: Object.freeze([...scopePath]),
1668
+ virtualName: name,
1669
+ byAccess: Object.freeze(byAccess)
1670
+ })
1671
+ );
1672
+ }
1673
+ };
1674
+ visit(options.virtuals ?? {}, model?.schema, "", [], !!model && varyingModel(model));
1675
+ return Object.freeze({ scopes: Object.freeze(scopes) });
1676
+ }
1677
+
1183
1678
  // src/runtime.ts
1184
1679
  var mongooseJsonSchemaInitialized = false;
1185
1680
  var ensureMongooseJsonSchemaInitialized = () => {
1186
1681
  if (mongooseJsonSchemaInitialized) return;
1187
- (0, import_mongoose_schema_jsonschema.default)(import_mongoose2.default);
1682
+ (0, import_mongoose_schema_jsonschema.default)(import_mongoose3.default);
1188
1683
  mongooseJsonSchemaInitialized = true;
1189
1684
  };
1190
- var pluralize = import_mongoose2.default.pluralize();
1685
+ var pluralize = import_mongoose3.default.pluralize();
1191
1686
  var FIELD_ACCESS_KEYS = ["list", "create", "read", "update"];
1192
1687
  var defaultModelOptions = {
1193
1688
  basePath: null,
@@ -1200,44 +1695,44 @@ var defaultDataOptions = {
1200
1695
  listHardLimit: DEFAULT_LIST_HARD_LIMIT
1201
1696
  };
1202
1697
  var normalizeBasePath = (name, value) => {
1203
- if ((0, import_utils10.isNil)(value)) {
1698
+ if ((0, import_utils12.isNil)(value)) {
1204
1699
  return `/${pluralize(name)}`;
1205
1700
  }
1206
- return (0, import_utils10.isString)(value) ? (0, import_utils10.addLeadingSlash)(value) : "";
1701
+ return (0, import_utils12.isString)(value) ? (0, import_utils12.addLeadingSlash)(value) : "";
1207
1702
  };
1208
1703
  var hasModelPermission = (value, modelPermissionPrefix) => {
1209
1704
  if (!modelPermissionPrefix) {
1210
1705
  return true;
1211
1706
  }
1212
- if ((0, import_utils10.isString)(value)) {
1707
+ if ((0, import_utils12.isString)(value)) {
1213
1708
  return value.trim().split(" ").some((item) => item.startsWith(modelPermissionPrefix));
1214
1709
  }
1215
- if ((0, import_utils10.isArray)(value)) {
1710
+ if ((0, import_utils12.isArray)(value)) {
1216
1711
  return value.some((item) => {
1217
- if ((0, import_utils10.isString)(item) || (0, import_utils10.isArray)(item)) {
1712
+ if ((0, import_utils12.isString)(item) || (0, import_utils12.isArray)(item)) {
1218
1713
  return hasModelPermission(item, modelPermissionPrefix);
1219
1714
  }
1220
1715
  return true;
1221
1716
  });
1222
1717
  }
1223
- return (0, import_utils10.isFunction)(value);
1718
+ return (0, import_utils12.isFunction)(value);
1224
1719
  };
1225
1720
  var classifyPermissionSchema = (permissionSchema, modelPermissionPrefix) => {
1226
1721
  const schemaKeys = Object.keys(permissionSchema);
1227
1722
  const globalPermissionKeys = {};
1228
1723
  const modelPermissionKeys = {};
1229
- (0, import_utils10.forEach)(schemaKeys, (schemaKey) => {
1724
+ (0, import_utils12.forEach)(schemaKeys, (schemaKey) => {
1230
1725
  const schemaRule = permissionSchema[schemaKey];
1231
- const ruleEntries = (0, import_utils10.isPlainObject)(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
1726
+ const ruleEntries = (0, import_utils12.isPlainObject)(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
1232
1727
  for (let x = 0; x < ruleEntries.length; x++) {
1233
1728
  const [accessKey, value] = ruleEntries[x];
1234
- if (!(0, import_utils10.isArray)(globalPermissionKeys[accessKey])) {
1729
+ if (!(0, import_utils12.isArray)(globalPermissionKeys[accessKey])) {
1235
1730
  globalPermissionKeys[accessKey] = [];
1236
1731
  }
1237
- if (!(0, import_utils10.isArray)(modelPermissionKeys[accessKey])) {
1732
+ if (!(0, import_utils12.isArray)(modelPermissionKeys[accessKey])) {
1238
1733
  modelPermissionKeys[accessKey] = [];
1239
1734
  }
1240
- if ((0, import_utils10.isBoolean)(value)) {
1735
+ if ((0, import_utils12.isBoolean)(value)) {
1241
1736
  globalPermissionKeys[accessKey].push(schemaKey);
1242
1737
  continue;
1243
1738
  }
@@ -1269,13 +1764,13 @@ var VIRTUAL_UNSUPPORTED_ACCESSES = ["delete", "distinct", "count"];
1269
1764
  var VIRTUAL_RESERVED_NAMES = /* @__PURE__ */ new Set(["_id", "__v", "id"]);
1270
1765
  var VIRTUAL_DANGEROUS_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
1271
1766
  var VIRTUAL_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
1272
- var isVirtualContainerValue = (value) => (0, import_utils10.isPlainObject)(value) && "sub" in value;
1767
+ var isVirtualContainerValue2 = (value) => (0, import_utils12.isPlainObject)(value) && "sub" in value;
1273
1768
  var virtualFullPath = (prefix, name) => prefix ? `${prefix}.${name}` : name;
1274
1769
  var virtualPathsOverlap = (virtualPath, permissionField) => {
1275
1770
  if (!virtualPath || !permissionField) return false;
1276
1771
  try {
1277
- if ((0, import_utils10.get)((0, import_utils10.set)({}, virtualPath, true), permissionField) !== void 0) return true;
1278
- if ((0, import_utils10.get)((0, import_utils10.set)({}, permissionField, true), virtualPath) !== void 0) return true;
1772
+ if ((0, import_utils12.get)((0, import_utils12.set)({}, virtualPath, true), permissionField) !== void 0) return true;
1773
+ if ((0, import_utils12.get)((0, import_utils12.set)({}, permissionField, true), virtualPath) !== void 0) return true;
1279
1774
  } catch {
1280
1775
  return false;
1281
1776
  }
@@ -1336,12 +1831,12 @@ var cloneVirtualsForValidation = (value) => {
1336
1831
  };
1337
1832
  var validateVirtualDependsOn = (dependsOn, entryLabel, storedFields, siblingVirtualNames) => {
1338
1833
  if (dependsOn === void 0) return [];
1339
- if (!(0, import_utils10.isArray)(dependsOn)) {
1834
+ if (!(0, import_utils12.isArray)(dependsOn)) {
1340
1835
  throw new Error(`Virtual ${entryLabel}: dependsOn must be an array of top-level persisted field names`);
1341
1836
  }
1342
1837
  const list = dependsOn;
1343
1838
  for (const dep of list) {
1344
- if (!(0, import_utils10.isString)(dep) || dep.length === 0) {
1839
+ if (!(0, import_utils12.isString)(dep) || dep.length === 0) {
1345
1840
  throw new Error(`Virtual ${entryLabel}: dependsOn entries must be non-empty strings`);
1346
1841
  }
1347
1842
  if (dep.includes(".")) {
@@ -1363,18 +1858,20 @@ var validateVirtualDependsOn = (dependsOn, entryLabel, storedFields, siblingVirt
1363
1858
  return list;
1364
1859
  };
1365
1860
  var validateVirtualLeafValue = (value, entryLabel, storedFields, siblingVirtualNames, sharedDependsOn) => {
1366
- if ((0, import_utils10.isFunction)(value)) return;
1367
- if (!(0, import_utils10.isPlainObject)(value)) {
1861
+ if ((0, import_utils12.isFunction)(value)) return;
1862
+ if (!(0, import_utils12.isPlainObject)(value)) {
1368
1863
  throw new Error(`Virtual ${entryLabel}: descriptor must be a getter function or { get, dependsOn }`);
1369
1864
  }
1370
- const record = value;
1371
- if (!(0, import_utils10.isFunction)(record.get)) {
1865
+ const record2 = value;
1866
+ if (!(0, import_utils12.isFunction)(record2.get)) {
1372
1867
  throw new Error(`Virtual ${entryLabel}: descriptor.get must be a callable getter function`);
1373
1868
  }
1374
- validateVirtualDependsOn(record.dependsOn ?? sharedDependsOn, entryLabel, storedFields, siblingVirtualNames);
1375
- for (const k of Object.keys(record)) {
1376
- if (k !== "get" && k !== "dependsOn") {
1377
- throw new Error(`Virtual ${entryLabel}: unsupported descriptor key "${k}" (expected only get/dependsOn)`);
1869
+ validateVirtualDependsOn(record2.dependsOn ?? sharedDependsOn, entryLabel, storedFields, siblingVirtualNames);
1870
+ for (const k of Object.keys(record2)) {
1871
+ if (k !== "get" && k !== "dependsOn" && k !== "dependsOnPopulate") {
1872
+ throw new Error(
1873
+ `Virtual ${entryLabel}: unsupported descriptor key "${k}" (expected get/dependsOn/dependsOnPopulate)`
1874
+ );
1378
1875
  }
1379
1876
  }
1380
1877
  };
@@ -1383,7 +1880,7 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1383
1880
  const leafNames = /* @__PURE__ */ new Set();
1384
1881
  for (const [name, raw] of Object.entries(scopeVirtuals)) {
1385
1882
  if (raw === void 0) continue;
1386
- if (isVirtualContainerValue(raw)) continue;
1883
+ if (isVirtualContainerValue2(raw)) continue;
1387
1884
  leafNames.add(name);
1388
1885
  }
1389
1886
  for (const [name, raw] of Object.entries(scopeVirtuals)) {
@@ -1400,15 +1897,15 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1400
1897
  `Virtual ${scopeLabel}${name}: overlaps document permission field "${documentPermissionField}" (equal/ancestor/descendant rejected)`
1401
1898
  );
1402
1899
  }
1403
- if (isVirtualContainerValue(raw)) {
1404
- const record2 = raw;
1405
- const extra = Object.keys(record2).filter((k) => k !== "sub");
1900
+ if (isVirtualContainerValue2(raw)) {
1901
+ const record3 = raw;
1902
+ const extra = Object.keys(record3).filter((k) => k !== "sub");
1406
1903
  if (extra.length > 0) {
1407
1904
  throw new Error(
1408
1905
  `Virtual ${scopeLabel}${name}: scope-container must only hold "sub" (embedded container "${name}" is not a virtual-leaf collision)`
1409
1906
  );
1410
1907
  }
1411
- if (!(0, import_utils10.isPlainObject)(record2.sub)) {
1908
+ if (!(0, import_utils12.isPlainObject)(record3.sub)) {
1412
1909
  throw new Error(`Virtual ${scopeLabel}${name}: scope-container "sub" must be a plain object`);
1413
1910
  }
1414
1911
  continue;
@@ -1418,19 +1915,19 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1418
1915
  `Virtual ${scopeLabel}${name}: collides with a stored path (inspected actual Mongoose schema/child scope; getModelAtt alone is insufficient)`
1419
1916
  );
1420
1917
  }
1421
- if ((0, import_utils10.isFunction)(raw)) continue;
1422
- if (!(0, import_utils10.isPlainObject)(raw)) {
1918
+ if ((0, import_utils12.isFunction)(raw)) continue;
1919
+ if (!(0, import_utils12.isPlainObject)(raw)) {
1423
1920
  throw new Error(
1424
1921
  `Virtual ${scopeLabel}${name}: malformed descriptor (expected getter, { get, dependsOn }, or per-access record)`
1425
1922
  );
1426
1923
  }
1427
- const record = raw;
1428
- const hasGet = "get" in record;
1429
- const accessKeys = Object.keys(record).filter((k) => VIRTUAL_SUPPORTED_ACCESSES.includes(k));
1430
- const unsupported2 = Object.keys(record).filter(
1431
- (k) => k !== "get" && k !== "dependsOn" && k !== "sub" && !VIRTUAL_SUPPORTED_ACCESSES.includes(k)
1924
+ const record2 = raw;
1925
+ const hasGet = "get" in record2;
1926
+ const accessKeys = Object.keys(record2).filter((k) => VIRTUAL_SUPPORTED_ACCESSES.includes(k));
1927
+ const unsupported2 = Object.keys(record2).filter(
1928
+ (k) => k !== "get" && k !== "dependsOn" && k !== "dependsOnPopulate" && k !== "sub" && !VIRTUAL_SUPPORTED_ACCESSES.includes(k)
1432
1929
  );
1433
- for (const key of Object.keys(record)) {
1930
+ for (const key of Object.keys(record2)) {
1434
1931
  if (VIRTUAL_UNSUPPORTED_ACCESSES.includes(key)) {
1435
1932
  throw new Error(
1436
1933
  `Virtual ${scopeLabel}${name}: unsupported access "${key}" (supported: default + list/create/read/update; NOT delete/distinct/count)`
@@ -1448,21 +1945,21 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1448
1945
  `Virtual ${scopeLabel}${name}: cannot mix "get" with per-access keys (use either bare { get, dependsOn } or a per-access record)`
1449
1946
  );
1450
1947
  }
1451
- if ("sub" in record) {
1948
+ if ("sub" in record2) {
1452
1949
  throw new Error(`Virtual ${scopeLabel}${name}: cannot mix "get" with "sub" (leaf vs embedded container)`);
1453
1950
  }
1454
1951
  validateVirtualLeafValue(raw, `${scopeLabel}${name}`, storedFields, leafNames, void 0);
1455
1952
  continue;
1456
1953
  }
1457
1954
  if (accessKeys.length > 0) {
1458
- if ("sub" in record) {
1955
+ if ("sub" in record2) {
1459
1956
  throw new Error(`Virtual ${scopeLabel}${name}: cannot mix per-access keys with "sub"`);
1460
1957
  }
1461
- validateVirtualDependsOn(record.dependsOn, `${scopeLabel}${name}`, storedFields, leafNames);
1958
+ validateVirtualDependsOn(record2.dependsOn, `${scopeLabel}${name}`, storedFields, leafNames);
1462
1959
  for (const access of accessKeys) {
1463
- const leaf = record[access];
1960
+ const leaf = record2[access];
1464
1961
  if (leaf === void 0) continue;
1465
- validateVirtualLeafValue(leaf, `${scopeLabel}${name}.${access}`, storedFields, leafNames, record.dependsOn);
1962
+ validateVirtualLeafValue(leaf, `${scopeLabel}${name}.${access}`, storedFields, leafNames, record2.dependsOn);
1466
1963
  }
1467
1964
  continue;
1468
1965
  }
@@ -1473,7 +1970,7 @@ var validateVirtualsScope = (scope, documentPermissionField) => {
1473
1970
  };
1474
1971
  var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName) => {
1475
1972
  if (virtuals === void 0 || virtuals === null) return;
1476
- if (!(0, import_utils10.isPlainObject)(virtuals)) {
1973
+ if (!(0, import_utils12.isPlainObject)(virtuals)) {
1477
1974
  throw new Error(`Virtuals for model "${modelName}": virtuals must be a plain object mapping names to descriptors`);
1478
1975
  }
1479
1976
  const rootSchema = model?.schema ?? null;
@@ -1483,13 +1980,14 @@ var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName)
1483
1980
  { scopeVirtuals: rootVirtuals, storedFields: rootStored, scopePrefix: "", scopeLabel: "" },
1484
1981
  documentPermissionField
1485
1982
  );
1486
- const visitContainers = (currentVirtuals, currentSchema, currentPrefix) => {
1983
+ const visitContainers = (currentVirtuals, currentSchema, currentPrefix, schemaPrefix = "") => {
1487
1984
  for (const [containerName, raw] of Object.entries(currentVirtuals)) {
1488
- if (raw === void 0 || !isVirtualContainerValue(raw)) continue;
1489
- const record = raw;
1490
- const childSchema = getChildSchemaForField(currentSchema, containerName);
1491
- const nestedFields = getNestedChildFields(currentSchema, containerName);
1492
- const currentStored = collectStoredTopLevel(currentSchema);
1985
+ if (raw === void 0 || !isVirtualContainerValue2(raw)) continue;
1986
+ const record2 = raw;
1987
+ const schemaPath = virtualFullPath(schemaPrefix, containerName);
1988
+ const childSchema = getChildSchemaForField(currentSchema, schemaPath);
1989
+ const nestedFields = getNestedChildFields(currentSchema, schemaPath);
1990
+ const currentStored = schemaPrefix ? getNestedChildFields(currentSchema, schemaPrefix) : collectStoredTopLevel(currentSchema);
1493
1991
  if (!currentStored.has(containerName)) {
1494
1992
  throw new Error(
1495
1993
  `Virtual ${containerName}: scope-container "${containerName}" is not a persisted field in its scope`
@@ -1503,7 +2001,7 @@ var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName)
1503
2001
  }
1504
2002
  const subStored = childSchema ? collectStoredTopLevel(childSchema) : nestedFields;
1505
2003
  const subPrefix = currentPrefix ? `${currentPrefix}.${containerName}` : containerName;
1506
- const subVirtuals = record.sub ?? {};
2004
+ const subVirtuals = record2.sub ?? {};
1507
2005
  validateVirtualsScope(
1508
2006
  {
1509
2007
  scopeVirtuals: subVirtuals,
@@ -1513,37 +2011,11 @@ var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName)
1513
2011
  },
1514
2012
  documentPermissionField
1515
2013
  );
1516
- const nextSchema = childSchema;
1517
- visitContainers(subVirtuals, nextSchema, subPrefix);
2014
+ visitContainers(subVirtuals, childSchema ?? currentSchema, subPrefix, childSchema ? "" : schemaPath);
1518
2015
  }
1519
2016
  };
1520
2017
  visitContainers(rootVirtuals, rootSchema, "");
1521
2018
  };
1522
- var getScopeVirtualsObject = (rootVirtuals, scopePath) => {
1523
- if (!rootVirtuals || !(0, import_utils10.isPlainObject)(rootVirtuals)) return null;
1524
- if (!scopePath || scopePath.length === 0) return rootVirtuals;
1525
- let current = rootVirtuals;
1526
- for (let i = 0; i < scopePath.length; i += 2) {
1527
- const field = scopePath[i];
1528
- const subMarker = scopePath[i + 1];
1529
- if (!field || subMarker !== "sub") return null;
1530
- if (!(0, import_utils10.isPlainObject)(current)) return null;
1531
- const container = current[field];
1532
- if (!isVirtualContainerValue(container)) return null;
1533
- current = container.sub;
1534
- if (!(0, import_utils10.isPlainObject)(current)) return null;
1535
- }
1536
- return current;
1537
- };
1538
- var toVirtualDescriptor = (leaf, sharedDependsOn) => {
1539
- if ((0, import_utils10.isFunction)(leaf))
1540
- return { get: leaf, dependsOn: sharedDependsOn ?? [] };
1541
- if (!(0, import_utils10.isPlainObject)(leaf)) return null;
1542
- const record = leaf;
1543
- if (!(0, import_utils10.isFunction)(record.get)) return null;
1544
- const dependsOn = record.dependsOn ?? sharedDependsOn ?? [];
1545
- return { get: record.get, dependsOn };
1546
- };
1547
2019
  var AccessRuntime = class {
1548
2020
  constructor(options = {}) {
1549
2021
  this.globalOptions = new OptionsManager(
@@ -1551,6 +2023,7 @@ var AccessRuntime = class {
1551
2023
  requestPermissionField: "_permissions",
1552
2024
  globalPermissions: () => ({}),
1553
2025
  requireRegisteredPopulateModels: true,
2026
+ requireReadOperationAccessForPopulateDependencies: true,
1554
2027
  logger: defaultLogger,
1555
2028
  requestComplexity: defaultRequestComplexity
1556
2029
  },
@@ -1592,20 +2065,20 @@ var AccessRuntime = class {
1592
2065
  this.modelInstances[modelName] = model;
1593
2066
  }
1594
2067
  hasModelInstance(modelName) {
1595
- return modelName in this.modelInstances || this.allowGlobalModelLookup && modelName in import_mongoose2.default.models;
2068
+ return modelName in this.modelInstances || this.allowGlobalModelLookup && modelName in import_mongoose3.default.models;
1596
2069
  }
1597
2070
  getModelInstance(modelName) {
1598
2071
  const registered = this.modelInstances[modelName];
1599
2072
  if (registered) return registered;
1600
2073
  if (!this.allowGlobalModelLookup) return null;
1601
- const global = import_mongoose2.default.models[modelName];
2074
+ const global = import_mongoose3.default.models[modelName];
1602
2075
  if (!global) return null;
1603
2076
  this.registerModelInstance(modelName, global);
1604
2077
  return global;
1605
2078
  }
1606
2079
  registerOpenApiRoute(route) {
1607
2080
  this.openApiRegistry.register(
1608
- this.openApiPathPrefix ? { ...route, path: (0, import_utils10.normalizeUrlPath)(`${this.openApiPathPrefix}/${route.path}`) } : route
2081
+ this.openApiPathPrefix ? { ...route, path: (0, import_utils12.normalizeUrlPath)(`${this.openApiPathPrefix}/${route.path}`) } : route
1609
2082
  );
1610
2083
  }
1611
2084
  /**
@@ -1616,7 +2089,7 @@ var AccessRuntime = class {
1616
2089
  */
1617
2090
  withOpenApiPathPrefix(prefix, build) {
1618
2091
  const previous = this.openApiPathPrefix;
1619
- this.openApiPathPrefix = (0, import_utils10.normalizeUrlPath)(`${previous}/${prefix}`);
2092
+ this.openApiPathPrefix = (0, import_utils12.normalizeUrlPath)(`${previous}/${prefix}`);
1620
2093
  try {
1621
2094
  return build();
1622
2095
  } finally {
@@ -1723,9 +2196,16 @@ var AccessRuntime = class {
1723
2196
  }
1724
2197
  /** Shallowly replace supplied global values; nested objects such as requestComplexity are not deep-merged. */
1725
2198
  setGlobalOptions(options) {
1726
- this.globalOptions.assign(options);
2199
+ const next = { ...options };
2200
+ if ("requireReadOperationAccessForPopulateDependencies" in next)
2201
+ next.requireReadOperationAccessForPopulateDependencies = next.requireReadOperationAccessForPopulateDependencies !== false;
2202
+ this.globalOptions.assign(next);
1727
2203
  }
1728
2204
  setGlobalOption(key, value) {
2205
+ if (key === "requireReadOperationAccessForPopulateDependencies") {
2206
+ this.globalOptions.set("requireReadOperationAccessForPopulateDependencies", value !== false);
2207
+ return;
2208
+ }
1729
2209
  this.globalOptions.set(key, value);
1730
2210
  }
1731
2211
  getGlobalOptions() {
@@ -1752,7 +2232,7 @@ var AccessRuntime = class {
1752
2232
  if (keyStr === "defaults") assertPublicDefaults(value);
1753
2233
  else if (keyStr.startsWith("defaults.")) {
1754
2234
  const proposed = {};
1755
- (0, import_utils10.set)(proposed, keyStr.slice("defaults.".length), value);
2235
+ (0, import_utils12.set)(proposed, keyStr.slice("defaults.".length), value);
1756
2236
  assertPublicDefaults(proposed);
1757
2237
  }
1758
2238
  this.defaultModelOptions.set(key, value);
@@ -1781,7 +2261,7 @@ var AccessRuntime = class {
1781
2261
  }).onchange("basePath", function(newval, key, target) {
1782
2262
  target[key] = normalizeBasePath(
1783
2263
  modelName,
1784
- (0, import_utils10.isString)(newval) || (0, import_utils10.isNil)(newval) ? newval : void 0
2264
+ (0, import_utils12.isString)(newval) || (0, import_utils12.isNil)(newval) ? newval : void 0
1785
2265
  );
1786
2266
  }).build();
1787
2267
  this.modelJsonSchemas[modelName] = model.jsonSchema();
@@ -1805,13 +2285,14 @@ var AccessRuntime = class {
1805
2285
  setModelOptions(modelName, options) {
1806
2286
  assertPublicDefaults(options.defaults);
1807
2287
  if ("hydration" in options) options = { ...options, hydration: normalizeHydration(options.hydration) };
1808
- const manager = this.getOrCreateModelOptions(modelName);
1809
2288
  const defaultOptions = this.getDefaultModelOptions();
1810
- const currentModelOptions = manager.fetch();
2289
+ const currentModelOptions = this.modelOptions[modelName]?.fetch() ?? { ...defaultModelOptions, modelName };
1811
2290
  const merged = { ...defaultOptions, ...currentModelOptions, ...options };
1812
2291
  const model = this.getModelInstance(modelName);
1813
2292
  const permissionField = merged.documentPermissionField ?? currentModelOptions.documentPermissionField ?? this.getDefaultModelOption("documentPermissionField") ?? "_permissions";
1814
2293
  validateVirtualsTree(model, merged.virtuals, permissionField, modelName);
2294
+ captureVirtualPopulateDependencies(this, modelName, merged);
2295
+ const manager = this.getOrCreateModelOptions(modelName);
1815
2296
  manager.assign({ ...defaultOptions, ...currentModelOptions, ...options });
1816
2297
  }
1817
2298
  setModelOption(modelName, key, value) {
@@ -1824,14 +2305,14 @@ var AccessRuntime = class {
1824
2305
  if (keyStr === "defaults") assertPublicDefaults(value);
1825
2306
  else if (keyStr.startsWith("defaults.")) {
1826
2307
  const proposed = {};
1827
- (0, import_utils10.set)(proposed, keyStr.slice("defaults.".length), value);
2308
+ (0, import_utils12.set)(proposed, keyStr.slice("defaults.".length), value);
1828
2309
  assertPublicDefaults(proposed);
1829
2310
  }
1830
- const manager = this.getOrCreateModelOptions(modelName);
2311
+ const manager = this.modelOptions[modelName];
1831
2312
  if (keyStr === "virtuals" || keyStr.startsWith("virtuals.") || keyStr === "documentPermissionField") {
1832
2313
  const model = this.getModelInstance(modelName);
1833
- const currentVirtuals = manager.get("virtuals");
1834
- const currentPermissionField = manager.get("documentPermissionField") ?? this.getDefaultModelOption("documentPermissionField") ?? "_permissions";
2314
+ const currentVirtuals = manager?.get("virtuals");
2315
+ const currentPermissionField = manager?.get("documentPermissionField") ?? this.getDefaultModelOption("documentPermissionField") ?? "_permissions";
1835
2316
  let proposedVirtuals = currentVirtuals;
1836
2317
  let proposedPermissionField = currentPermissionField;
1837
2318
  if (keyStr === "documentPermissionField") {
@@ -1845,21 +2326,27 @@ var AccessRuntime = class {
1845
2326
  const segments = nestedPath.split(".");
1846
2327
  let cursor = cloned;
1847
2328
  for (let i = 0; i < segments.length - 1; i++) {
1848
- if (!(0, import_utils10.isPlainObject)(cursor)) break;
2329
+ if (!(0, import_utils12.isPlainObject)(cursor)) break;
1849
2330
  cursor = cursor[segments[i]];
1850
2331
  }
1851
- if ((0, import_utils10.isPlainObject)(cursor)) {
2332
+ if ((0, import_utils12.isPlainObject)(cursor)) {
1852
2333
  delete cursor[segments[segments.length - 1]];
1853
2334
  }
1854
2335
  proposedVirtuals = cloned;
1855
2336
  } else {
1856
- (0, import_utils10.set)(cloned, nestedPath, value);
2337
+ (0, import_utils12.set)(cloned, nestedPath, value);
1857
2338
  proposedVirtuals = cloned;
1858
2339
  }
1859
2340
  }
1860
2341
  validateVirtualsTree(model, proposedVirtuals, proposedPermissionField, modelName);
2342
+ captureVirtualPopulateDependencies(this, modelName, {
2343
+ ...this.getDefaultModelOptions(),
2344
+ ...manager?.fetch(),
2345
+ virtuals: proposedVirtuals,
2346
+ documentPermissionField: proposedPermissionField
2347
+ });
1861
2348
  }
1862
- manager.set(key, value);
2349
+ this.getOrCreateModelOptions(modelName).set(key, value);
1863
2350
  }
1864
2351
  /** Frozen stored snapshot, not fully resolved per-path defaults. Read again for current configuration. */
1865
2352
  getModelOptions(modelName) {
@@ -1898,7 +2385,7 @@ var AccessRuntime = class {
1898
2385
  const rootVirtuals = manager.get("virtuals");
1899
2386
  const scopeVirtuals = getScopeVirtualsObject(rootVirtuals, scopePath);
1900
2387
  if (!scopeVirtuals) return [];
1901
- return Object.entries(scopeVirtuals).filter(([, v]) => v !== void 0 && !isVirtualContainerValue(v)).map(([k]) => k);
2388
+ return Object.entries(scopeVirtuals).filter(([, v]) => v !== void 0 && !isVirtualContainerValue2(v)).map(([k]) => k);
1902
2389
  }
1903
2390
  /**
1904
2391
  * Whether a field is a registered virtual leaf in a scope (VIRT-01).
@@ -1912,7 +2399,7 @@ var AccessRuntime = class {
1912
2399
  const scopeVirtuals = getScopeVirtualsObject(rootVirtuals, scopePath);
1913
2400
  if (!scopeVirtuals || !(fieldName in scopeVirtuals)) return false;
1914
2401
  const entry = scopeVirtuals[fieldName];
1915
- if (entry === void 0 || isVirtualContainerValue(entry)) return false;
2402
+ if (entry === void 0 || isVirtualContainerValue2(entry)) return false;
1916
2403
  return true;
1917
2404
  }
1918
2405
  /**
@@ -1922,34 +2409,14 @@ var AccessRuntime = class {
1922
2409
  * interpreted as a getter descriptor when the access is absent: an
1923
2410
  * inapplicable registered name stays virtual (excluded from persisted
1924
2411
  * projections, write admission, and DB sort/filter/distinct).
1925
- * Shared record-level `dependsOn` is inherited when a leaf lacks its own.
2412
+ * Shared `dependsOn` and `dependsOnPopulate` lists inherit independently;
2413
+ * each defined leaf list replaces its shared list wholesale.
1926
2414
  */
1927
2415
  resolveVirtualDescriptor(modelName, virtualName, access, scopePath) {
1928
2416
  const manager = this.getOrCreateModelOptions(modelName);
1929
2417
  const rootVirtuals = manager.get("virtuals");
1930
2418
  const scopeVirtuals = getScopeVirtualsObject(rootVirtuals, scopePath);
1931
- if (!scopeVirtuals || !(virtualName in scopeVirtuals)) return void 0;
1932
- const entry = scopeVirtuals[virtualName];
1933
- if (entry === void 0 || isVirtualContainerValue(entry)) return void 0;
1934
- if ((0, import_utils10.isFunction)(entry)) return { get: entry, dependsOn: [] };
1935
- if (!(0, import_utils10.isPlainObject)(entry)) return void 0;
1936
- const record = entry;
1937
- if ("get" in record) {
1938
- const descriptor = toVirtualDescriptor(entry, void 0);
1939
- return descriptor ?? void 0;
1940
- }
1941
- const sharedDependsOn = record.dependsOn;
1942
- const exact = record[access];
1943
- if (exact !== void 0) {
1944
- const descriptor = toVirtualDescriptor(exact, sharedDependsOn);
1945
- if (descriptor) return descriptor;
1946
- }
1947
- const fallback = record.default;
1948
- if (fallback !== void 0) {
1949
- const descriptor = toVirtualDescriptor(fallback, sharedDependsOn);
1950
- if (descriptor) return descriptor;
1951
- }
1952
- return void 0;
2419
+ return resolveSnapshotDescriptor(scopeVirtuals, virtualName, access);
1953
2420
  }
1954
2421
  getModelNames() {
1955
2422
  return Object.keys(this.modelOptions);
@@ -1968,7 +2435,7 @@ var AccessRuntime = class {
1968
2435
  manager.onchange("basePath", function(newval, key, target) {
1969
2436
  target[key] = normalizeBasePath(
1970
2437
  dataName,
1971
- (0, import_utils10.isString)(newval) || (0, import_utils10.isNil)(newval) ? newval : void 0
2438
+ (0, import_utils12.isString)(newval) || (0, import_utils12.isNil)(newval) ? newval : void 0
1972
2439
  );
1973
2440
  }).build();
1974
2441
  return manager;
@@ -2028,20 +2495,20 @@ var AccessRuntime = class {
2028
2495
  const schema = model.schema;
2029
2496
  this.modelRefs[modelName] = buildRefs(schema.tree);
2030
2497
  this.modelSubs[modelName] = buildSubPaths(schema.tree);
2031
- this.modelAtts[modelName] = (0, import_utils10.keys)(schema.obj);
2498
+ this.modelAtts[modelName] = (0, import_utils12.keys)(schema.obj);
2032
2499
  }
2033
2500
  getModelRef(modelName, refPath) {
2034
2501
  this.ensureModelMeta(modelName);
2035
- const value = (0, import_utils10.get)(this.modelRefs, `${modelName}.${refPath}`, null);
2036
- return (0, import_utils10.isString)(value) ? value : null;
2502
+ const value = (0, import_utils12.get)(this.modelRefs, `${modelName}.${refPath}`, null);
2503
+ return (0, import_utils12.isString)(value) ? value : null;
2037
2504
  }
2038
2505
  getModelSub(modelName) {
2039
2506
  this.ensureModelMeta(modelName);
2040
- return (0, import_utils10.get)(this.modelSubs, modelName, []);
2507
+ return (0, import_utils12.get)(this.modelSubs, modelName, []);
2041
2508
  }
2042
2509
  getModelAtt(modelName) {
2043
2510
  this.ensureModelMeta(modelName);
2044
- return (0, import_utils10.get)(this.modelAtts, modelName, []);
2511
+ return (0, import_utils12.get)(this.modelAtts, modelName, []);
2045
2512
  }
2046
2513
  };
2047
2514
  var defaultRuntime = new AccessRuntime({ allowGlobalModelLookup: true });
@@ -2061,7 +2528,7 @@ var getGlobalOption = (key, defaultValue) => {
2061
2528
 
2062
2529
  // src/validation/common.ts
2063
2530
  var import_zod2 = require("zod");
2064
- var import_utils12 = require("@web-ts-toolkit/utils");
2531
+ var import_utils14 = require("@web-ts-toolkit/utils");
2065
2532
 
2066
2533
  // src/validation/public-admission-schema.ts
2067
2534
  var admissions = /* @__PURE__ */ new WeakMap();
@@ -2083,7 +2550,7 @@ function assertTransformedPublicAdmission(schema, value) {
2083
2550
  }
2084
2551
 
2085
2552
  // src/correlated-includes.ts
2086
- var import_utils11 = require("@web-ts-toolkit/utils");
2553
+ var import_utils13 = require("@web-ts-toolkit/utils");
2087
2554
  var PARENT_MARKER_KEY = "$parent";
2088
2555
  var ESCAPE_WRAPPER_KEY = "$escape";
2089
2556
  var SUBQUERY_PAYLOAD_KEYS = /* @__PURE__ */ new Set(["$$sq", "$$date"]);
@@ -2094,10 +2561,10 @@ var FIELD_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
2094
2561
  var ARRAY_INDEX_SEGMENT_PATTERN = /^(0|[1-9]\d*)$/;
2095
2562
  var ownKeys = (value) => Object.keys(value);
2096
2563
  function isParentRefMarker(value) {
2097
- return (0, import_utils11.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
2564
+ return (0, import_utils13.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
2098
2565
  }
2099
2566
  function isEscapedParentRef(value) {
2100
- return (0, import_utils11.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
2567
+ return (0, import_utils13.isPlainObject)(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
2101
2568
  }
2102
2569
  function hasMarkerKey(value) {
2103
2570
  return ownKeys(value).includes(PARENT_MARKER_KEY) || ownKeys(value).includes(ESCAPE_WRAPPER_KEY);
@@ -2116,12 +2583,12 @@ function containsParentMarkerShape(value) {
2116
2583
  const seen = /* @__PURE__ */ new Set();
2117
2584
  const visit = (current) => {
2118
2585
  if (isParentRefMarker(current) || isEscapedParentRef(current)) return true;
2119
- if ((0, import_utils11.isArray)(current)) {
2586
+ if ((0, import_utils13.isArray)(current)) {
2120
2587
  if (seen.has(current)) return false;
2121
2588
  seen.add(current);
2122
2589
  return current.some(visit);
2123
2590
  }
2124
- if ((0, import_utils11.isPlainObject)(current)) {
2591
+ if ((0, import_utils13.isPlainObject)(current)) {
2125
2592
  if (seen.has(current)) return false;
2126
2593
  seen.add(current);
2127
2594
  if (hasMarkerKey(current)) return true;
@@ -2151,7 +2618,7 @@ function scanTemplateValueNode(value, path, issues) {
2151
2618
  }
2152
2619
  return;
2153
2620
  }
2154
- if ((0, import_utils11.isPlainObject)(value)) {
2621
+ if ((0, import_utils13.isPlainObject)(value)) {
2155
2622
  if (hasMarkerKey(value)) {
2156
2623
  issues.push({
2157
2624
  message: 'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }',
@@ -2162,7 +2629,7 @@ function scanTemplateValueNode(value, path, issues) {
2162
2629
  scanTemplateObjectEntries(value, path, issues);
2163
2630
  return;
2164
2631
  }
2165
- if ((0, import_utils11.isArray)(value)) {
2632
+ if ((0, import_utils13.isArray)(value)) {
2166
2633
  value.forEach((item, index) => scanTemplateValueNode(item, [...path, index], issues));
2167
2634
  }
2168
2635
  }
@@ -2203,7 +2670,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
2203
2670
  continue;
2204
2671
  }
2205
2672
  if (LOGICAL_CLAUSE_KEYS.has(key)) {
2206
- if (!(0, import_utils11.isArray)(child)) {
2673
+ if (!(0, import_utils13.isArray)(child)) {
2207
2674
  scanTemplateValueNode(child, childPath, issues);
2208
2675
  continue;
2209
2676
  }
@@ -2216,7 +2683,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
2216
2683
  });
2217
2684
  return;
2218
2685
  }
2219
- if ((0, import_utils11.isPlainObject)(clause)) {
2686
+ if ((0, import_utils13.isPlainObject)(clause)) {
2220
2687
  scanTemplateObjectEntries(clause, clausePath, issues);
2221
2688
  }
2222
2689
  });
@@ -2227,7 +2694,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
2227
2694
  }
2228
2695
  function validateCorrelatedFilterTemplate(filter) {
2229
2696
  const issues = [];
2230
- if (!(0, import_utils11.isPlainObject)(filter)) {
2697
+ if (!(0, import_utils13.isPlainObject)(filter)) {
2231
2698
  issues.push({ message: "Correlated include filter must be an object", path: [] });
2232
2699
  return issues;
2233
2700
  }
@@ -2355,7 +2822,7 @@ var correlatedFilterSchema = import_zod2.z.record(import_zod2.z.string(), import
2355
2822
  }
2356
2823
  });
2357
2824
  var correlatedEmptyOptionsSchema = import_zod2.z.unknown().refine(
2358
- (value) => value === void 0 || (0, import_utils12.isPlainObject)(value) && Object.keys(value).length === 0,
2825
+ (value) => value === void 0 || (0, import_utils14.isPlainObject)(value) && Object.keys(value).length === 0,
2359
2826
  "Correlated include options must be absent or empty"
2360
2827
  ).optional();
2361
2828
  var correlatedPathSchema = import_zod2.z.string().min(1).superRefine((path, ctx) => {
@@ -2392,7 +2859,7 @@ var correlatedListArgsSchema = import_zod2.z.object({
2392
2859
  include: import_zod2.z.lazy(() => correlatedNestedIncludeSchema).optional()
2393
2860
  }).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
2394
2861
  var correlatedCountArgsSchema = import_zod2.z.unknown().refine(
2395
- (value) => value === void 0 || (0, import_utils12.isPlainObject)(value) && Object.keys(value).length === 0,
2862
+ (value) => value === void 0 || (0, import_utils14.isPlainObject)(value) && Object.keys(value).length === 0,
2396
2863
  "Count includes accept no args"
2397
2864
  ).optional();
2398
2865
  var correlatedReadByIdSchema = import_zod2.z.object({
@@ -2445,7 +2912,7 @@ var correlatedNestedIncludeSchema = import_zod2.z.union([includeItemSchema, impo
2445
2912
  var rejectDuplicateCorrelatedPaths = (items, ctx) => {
2446
2913
  const seen = /* @__PURE__ */ new Set();
2447
2914
  items.forEach((item, index) => {
2448
- if ((0, import_utils12.isPlainObject)(item) && item.mode === "correlated" && typeof item.path === "string") {
2915
+ if ((0, import_utils14.isPlainObject)(item) && item.mode === "correlated" && typeof item.path === "string") {
2449
2916
  if (seen.has(item.path)) {
2450
2917
  ctx.addIssue({
2451
2918
  code: import_zod2.z.ZodIssueCode.custom,
@@ -2483,7 +2950,7 @@ function rejectKeys(body, ctx, keys2) {
2483
2950
  }
2484
2951
 
2485
2952
  // src/validation/parsers.ts
2486
- var clientErrors = import_express_json_router2.default.clientErrors;
2953
+ var clientErrors = import_express_json_router3.default.clientErrors;
2487
2954
  function parsePathParam(value, parameter) {
2488
2955
  const result = stringOrStringArray.safeParse(value);
2489
2956
  if (!result.success) {
@@ -2915,8 +3382,8 @@ function isArkTypeErrors(value) {
2915
3382
  if (typeof value !== "object" || value === null) {
2916
3383
  return false;
2917
3384
  }
2918
- const record = value;
2919
- return record.arkKind === "errors" || record[" arkKind"] === "errors";
3385
+ const record2 = value;
3386
+ return record2.arkKind === "errors" || record2[" arkKind"] === "errors";
2920
3387
  }
2921
3388
  function isThenable(value) {
2922
3389
  return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";