@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/README.md +218 -56
- package/advanced.d.mts +1 -1
- package/advanced.d.ts +1 -1
- package/advanced.js +100 -61
- package/advanced.mjs +67 -28
- package/index.d.mts +2 -2
- package/index.d.ts +2 -2
- package/index.js +624 -533
- package/index.mjs +361 -270
- package/llms.txt +3 -2
- package/package.json +3 -3
- package/{parsers-BrVRL2fg.d.mts → parsers-CngKnVjW.d.mts} +93 -14
- package/{parsers-BrVRL2fg.d.ts → parsers-CngKnVjW.d.ts} +93 -14
package/index.mjs
CHANGED
|
@@ -2140,10 +2140,34 @@ var init_field_catalog = __esm({
|
|
|
2140
2140
|
}
|
|
2141
2141
|
});
|
|
2142
2142
|
|
|
2143
|
+
// src/acl/populate-target-configuration.ts
|
|
2144
|
+
import { isPlainObject as isPlainObject12 } from "@web-ts-toolkit/utils";
|
|
2145
|
+
function capturePopulateTargetConfiguration(runtime, modelName, source, proposedOptions) {
|
|
2146
|
+
const label = `Populate target "${modelName}" for ${source}`;
|
|
2147
|
+
if (!proposedOptions && !runtime.hasModel(modelName))
|
|
2148
|
+
authorizationError(
|
|
2149
|
+
`${label} must be configured first in this runtime; register its Mongoose model and setModelOptions with an object permissionSchema`
|
|
2150
|
+
);
|
|
2151
|
+
const model = runtime.getModelInstance(modelName);
|
|
2152
|
+
if (!model) authorizationError(`${label} requires an actual registered Mongoose model in this runtime`);
|
|
2153
|
+
const options = proposedOptions ?? runtime.getModelOptions(modelName);
|
|
2154
|
+
const permissionSchema = options.permissionSchema === void 0 ? runtime.getDefaultModelOption("permissionSchema") : options.permissionSchema;
|
|
2155
|
+
if (!isPlainObject12(permissionSchema))
|
|
2156
|
+
authorizationError(
|
|
2157
|
+
`${label} requires an effective object permissionSchema; configure the model or runtime model defaults ({} explicitly closes business fields)`
|
|
2158
|
+
);
|
|
2159
|
+
return { model, options: { ...options, permissionSchema } };
|
|
2160
|
+
}
|
|
2161
|
+
var init_populate_target_configuration = __esm({
|
|
2162
|
+
"src/acl/populate-target-configuration.ts"() {
|
|
2163
|
+
init_authorization_snapshot();
|
|
2164
|
+
}
|
|
2165
|
+
});
|
|
2166
|
+
|
|
2143
2167
|
// src/acl/virtual-populate-dependencies.ts
|
|
2144
|
-
import { get as get4, isPlainObject as
|
|
2168
|
+
import { get as get4, isPlainObject as isPlainObject13 } from "@web-ts-toolkit/utils";
|
|
2145
2169
|
function record(value, label) {
|
|
2146
|
-
if (!
|
|
2170
|
+
if (!isPlainObject13(value)) return fail(label, "entries must be plain { path, select? } objects");
|
|
2147
2171
|
for (const key of Reflect.ownKeys(value)) {
|
|
2148
2172
|
const property = Object.getOwnPropertyDescriptor(value, key);
|
|
2149
2173
|
if (typeof key !== "string" || !property.enumerable || !("value" in property))
|
|
@@ -2231,7 +2255,9 @@ function normalizeSelection(select, catalog, label) {
|
|
|
2231
2255
|
includeId: selection.includes("_id")
|
|
2232
2256
|
};
|
|
2233
2257
|
}
|
|
2234
|
-
function captureVirtualPopulateDependencies(runtime, modelName, options) {
|
|
2258
|
+
function captureVirtualPopulateDependencies(runtime, modelName, options, globalOptions = runtime.getGlobalOptions()) {
|
|
2259
|
+
const requireOperationAccessForPopulateDependencies = globalOptions.requireOperationAccessForPopulateDependencies !== false;
|
|
2260
|
+
const requireOperationAccessForPopulateQueries = globalOptions.requireOperationAccessForPopulateQueries !== false;
|
|
2235
2261
|
const model = runtime.getModelInstance(modelName);
|
|
2236
2262
|
const targets = /* @__PURE__ */ new Map();
|
|
2237
2263
|
const scopes = [];
|
|
@@ -2271,7 +2297,12 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
|
|
|
2271
2297
|
label,
|
|
2272
2298
|
`target "${ref}" requires a registered same-connection non-discriminator ObjectId model bound to the source ref`
|
|
2273
2299
|
);
|
|
2274
|
-
const
|
|
2300
|
+
const { options: targetOptions } = capturePopulateTargetConfiguration(
|
|
2301
|
+
runtime,
|
|
2302
|
+
ref,
|
|
2303
|
+
`dependsOnPopulate virtual "${label}"`,
|
|
2304
|
+
ref === modelName ? options : void 0
|
|
2305
|
+
);
|
|
2275
2306
|
const defaults = runtime.getDefaultModelOptions();
|
|
2276
2307
|
const readOption = (key) => resolveNestedOption((path2, fallback) => get4(targetOptions, path2, fallback), key, get4(defaults, key));
|
|
2277
2308
|
const documentPermissionField = targetOptions.documentPermissionField ?? defaults.documentPermissionField;
|
|
@@ -2280,6 +2311,9 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
|
|
|
2280
2311
|
{
|
|
2281
2312
|
catalog,
|
|
2282
2313
|
documentPermissionField,
|
|
2314
|
+
requireOperationAccessForPopulateDependencies,
|
|
2315
|
+
requireOperationAccessForPopulateQueries,
|
|
2316
|
+
permissionSchema: targetOptions.permissionSchema,
|
|
2283
2317
|
operationAccess: { read: readOption("operationAccess.read") },
|
|
2284
2318
|
baseFilter: { read: readOption("baseFilter.read") },
|
|
2285
2319
|
overrideFilter: { read: readOption("overrideFilter.read") },
|
|
@@ -2328,13 +2362,13 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
|
|
|
2328
2362
|
);
|
|
2329
2363
|
continue;
|
|
2330
2364
|
}
|
|
2331
|
-
if (!
|
|
2365
|
+
if (!isPlainObject13(raw)) continue;
|
|
2332
2366
|
const entry = raw;
|
|
2333
2367
|
const label = join(sourcePrefix, name);
|
|
2334
2368
|
captureList(entry.dependsOnPopulate, label);
|
|
2335
2369
|
if (!("get" in entry))
|
|
2336
2370
|
for (const access of accesses) {
|
|
2337
|
-
if (
|
|
2371
|
+
if (isPlainObject13(entry[access]))
|
|
2338
2372
|
captureList(entry[access].dependsOnPopulate, `${label}.${access}`);
|
|
2339
2373
|
}
|
|
2340
2374
|
const byAccess = {};
|
|
@@ -2359,8 +2393,8 @@ function captureVirtualPopulateDependencies(runtime, modelName, options) {
|
|
|
2359
2393
|
visit(options.virtuals ?? {}, model?.schema, "", [], !!model && varyingModel(model));
|
|
2360
2394
|
return Object.freeze({ scopes: Object.freeze(scopes) });
|
|
2361
2395
|
}
|
|
2362
|
-
function captureVirtualPopulateSnapshot(runtime, modelName, options) {
|
|
2363
|
-
const snapshot = captureVirtualPopulateDependencies(runtime, modelName, options);
|
|
2396
|
+
function captureVirtualPopulateSnapshot(runtime, modelName, options, globalOptions = runtime.getGlobalOptions()) {
|
|
2397
|
+
const snapshot = captureVirtualPopulateDependencies(runtime, modelName, options, globalOptions);
|
|
2364
2398
|
const token = () => {
|
|
2365
2399
|
};
|
|
2366
2400
|
snapshots.set(token, snapshot);
|
|
@@ -2392,6 +2426,7 @@ var init_virtual_populate_dependencies = __esm({
|
|
|
2392
2426
|
init_authorization_snapshot();
|
|
2393
2427
|
init_field_catalog();
|
|
2394
2428
|
init_virtual_descriptor();
|
|
2429
|
+
init_populate_target_configuration();
|
|
2395
2430
|
elementType = (type) => type.$embeddedSchemaType ?? type.embeddedSchemaType ?? type.caster;
|
|
2396
2431
|
join = (prefix, path) => prefix ? `${prefix}.${path}` : path;
|
|
2397
2432
|
within = (path, parent) => path === parent || path.startsWith(`${parent}.`);
|
|
@@ -2416,7 +2451,7 @@ import {
|
|
|
2416
2451
|
isBoolean,
|
|
2417
2452
|
isFunction as isFunction2,
|
|
2418
2453
|
isNil as isNil2,
|
|
2419
|
-
isPlainObject as
|
|
2454
|
+
isPlainObject as isPlainObject14,
|
|
2420
2455
|
isString as isString4,
|
|
2421
2456
|
keys,
|
|
2422
2457
|
normalizeUrlPath,
|
|
@@ -2483,7 +2518,7 @@ var init_runtime = __esm({
|
|
|
2483
2518
|
const modelPermissionKeys = {};
|
|
2484
2519
|
forEach2(schemaKeys, (schemaKey) => {
|
|
2485
2520
|
const schemaRule = permissionSchema[schemaKey];
|
|
2486
|
-
const ruleEntries =
|
|
2521
|
+
const ruleEntries = isPlainObject14(schemaRule) ? Object.entries(schemaRule) : FIELD_ACCESS_KEYS.map((accessKey) => [accessKey, schemaRule]);
|
|
2487
2522
|
for (let x = 0; x < ruleEntries.length; x++) {
|
|
2488
2523
|
const [accessKey, value] = ruleEntries[x];
|
|
2489
2524
|
if (!isArray5(globalPermissionKeys[accessKey])) {
|
|
@@ -2524,7 +2559,7 @@ var init_runtime = __esm({
|
|
|
2524
2559
|
VIRTUAL_RESERVED_NAMES = /* @__PURE__ */ new Set(["_id", "__v", "id"]);
|
|
2525
2560
|
VIRTUAL_DANGEROUS_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
2526
2561
|
VIRTUAL_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
2527
|
-
isVirtualContainerValue2 = (value) =>
|
|
2562
|
+
isVirtualContainerValue2 = (value) => isPlainObject14(value) && "sub" in value;
|
|
2528
2563
|
virtualFullPath = (prefix, name) => prefix ? `${prefix}.${name}` : name;
|
|
2529
2564
|
virtualPathsOverlap = (virtualPath, permissionField) => {
|
|
2530
2565
|
if (!virtualPath || !permissionField) return false;
|
|
@@ -2619,7 +2654,7 @@ var init_runtime = __esm({
|
|
|
2619
2654
|
};
|
|
2620
2655
|
validateVirtualLeafValue = (value, entryLabel, storedFields, siblingVirtualNames, sharedDependsOn) => {
|
|
2621
2656
|
if (isFunction2(value)) return;
|
|
2622
|
-
if (!
|
|
2657
|
+
if (!isPlainObject14(value)) {
|
|
2623
2658
|
throw new Error(`Virtual ${entryLabel}: descriptor must be a getter function or { get, dependsOn }`);
|
|
2624
2659
|
}
|
|
2625
2660
|
const record3 = value;
|
|
@@ -2665,7 +2700,7 @@ var init_runtime = __esm({
|
|
|
2665
2700
|
`Virtual ${scopeLabel}${name}: scope-container must only hold "sub" (embedded container "${name}" is not a virtual-leaf collision)`
|
|
2666
2701
|
);
|
|
2667
2702
|
}
|
|
2668
|
-
if (!
|
|
2703
|
+
if (!isPlainObject14(record4.sub)) {
|
|
2669
2704
|
throw new Error(`Virtual ${scopeLabel}${name}: scope-container "sub" must be a plain object`);
|
|
2670
2705
|
}
|
|
2671
2706
|
continue;
|
|
@@ -2676,7 +2711,7 @@ var init_runtime = __esm({
|
|
|
2676
2711
|
);
|
|
2677
2712
|
}
|
|
2678
2713
|
if (isFunction2(raw)) continue;
|
|
2679
|
-
if (!
|
|
2714
|
+
if (!isPlainObject14(raw)) {
|
|
2680
2715
|
throw new Error(
|
|
2681
2716
|
`Virtual ${scopeLabel}${name}: malformed descriptor (expected getter, { get, dependsOn }, or per-access record)`
|
|
2682
2717
|
);
|
|
@@ -2730,7 +2765,7 @@ var init_runtime = __esm({
|
|
|
2730
2765
|
};
|
|
2731
2766
|
validateVirtualsTree = (model, virtuals, documentPermissionField, modelName) => {
|
|
2732
2767
|
if (virtuals === void 0 || virtuals === null) return;
|
|
2733
|
-
if (!
|
|
2768
|
+
if (!isPlainObject14(virtuals)) {
|
|
2734
2769
|
throw new Error(`Virtuals for model "${modelName}": virtuals must be a plain object mapping names to descriptors`);
|
|
2735
2770
|
}
|
|
2736
2771
|
const rootSchema = model?.schema ?? null;
|
|
@@ -2782,7 +2817,8 @@ var init_runtime = __esm({
|
|
|
2782
2817
|
{
|
|
2783
2818
|
requestPermissionField: "_permissions",
|
|
2784
2819
|
globalPermissions: () => ({}),
|
|
2785
|
-
|
|
2820
|
+
requireOperationAccessForPopulateQueries: true,
|
|
2821
|
+
requireOperationAccessForPopulateDependencies: true,
|
|
2786
2822
|
logger: defaultLogger,
|
|
2787
2823
|
requestComplexity: defaultRequestComplexity
|
|
2788
2824
|
},
|
|
@@ -2955,9 +2991,18 @@ var init_runtime = __esm({
|
|
|
2955
2991
|
}
|
|
2956
2992
|
/** Shallowly replace supplied global values; nested objects such as requestComplexity are not deep-merged. */
|
|
2957
2993
|
setGlobalOptions(options) {
|
|
2958
|
-
|
|
2994
|
+
const next = { ...options };
|
|
2995
|
+
if ("requireOperationAccessForPopulateQueries" in next)
|
|
2996
|
+
next.requireOperationAccessForPopulateQueries = next.requireOperationAccessForPopulateQueries !== false;
|
|
2997
|
+
if ("requireOperationAccessForPopulateDependencies" in next)
|
|
2998
|
+
next.requireOperationAccessForPopulateDependencies = next.requireOperationAccessForPopulateDependencies !== false;
|
|
2999
|
+
this.globalOptions.assign(next);
|
|
2959
3000
|
}
|
|
2960
3001
|
setGlobalOption(key, value) {
|
|
3002
|
+
if (key === "requireOperationAccessForPopulateQueries" || key === "requireOperationAccessForPopulateDependencies") {
|
|
3003
|
+
this.globalOptions.set(key, value !== false);
|
|
3004
|
+
return;
|
|
3005
|
+
}
|
|
2961
3006
|
this.globalOptions.set(key, value);
|
|
2962
3007
|
}
|
|
2963
3008
|
getGlobalOptions() {
|
|
@@ -3078,10 +3123,10 @@ var init_runtime = __esm({
|
|
|
3078
3123
|
const segments = nestedPath.split(".");
|
|
3079
3124
|
let cursor = cloned;
|
|
3080
3125
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
3081
|
-
if (!
|
|
3126
|
+
if (!isPlainObject14(cursor)) break;
|
|
3082
3127
|
cursor = cursor[segments[i]];
|
|
3083
3128
|
}
|
|
3084
|
-
if (
|
|
3129
|
+
if (isPlainObject14(cursor)) {
|
|
3085
3130
|
delete cursor[segments[segments.length - 1]];
|
|
3086
3131
|
}
|
|
3087
3132
|
proposedVirtuals = cloned;
|
|
@@ -3573,7 +3618,6 @@ function normalizePolicy(value, applicability, configuration, targets) {
|
|
|
3573
3618
|
const matches = targets.filter((target2) => target2.path === path);
|
|
3574
3619
|
if (matches.length !== 1) authorizationError(`unused or ambiguous related path: ${path}`);
|
|
3575
3620
|
const target = matches[0];
|
|
3576
|
-
if (target.kind === "passthrough") authorizationError(`related policy requires a registered target: ${path}`);
|
|
3577
3621
|
const child = authorizationRecord(entry, `related.${path}`);
|
|
3578
3622
|
assertAuthorizationKeys(
|
|
3579
3623
|
child,
|
|
@@ -4083,7 +4127,7 @@ var init_field_authorization = __esm({
|
|
|
4083
4127
|
});
|
|
4084
4128
|
|
|
4085
4129
|
// src/acl/virtual-projection.ts
|
|
4086
|
-
import { get as get6, isArray as isArray7, isPlainObject as
|
|
4130
|
+
import { get as get6, isArray as isArray7, isPlainObject as isPlainObject16 } from "@web-ts-toolkit/utils";
|
|
4087
4131
|
function planVirtualProjection(args) {
|
|
4088
4132
|
if (args.snapshot.catalog) return planCatalogProjection(args);
|
|
4089
4133
|
const {
|
|
@@ -4317,15 +4361,15 @@ var init_virtual_projection = __esm({
|
|
|
4317
4361
|
init_virtual_populate_dependencies();
|
|
4318
4362
|
init_virtual_descriptor();
|
|
4319
4363
|
getScopedPermissionSchema = (root, scopePath) => {
|
|
4320
|
-
if (!root || !
|
|
4364
|
+
if (!root || !isPlainObject16(root)) return null;
|
|
4321
4365
|
if (scopePath.length === 0) return root;
|
|
4322
4366
|
const scoped = get6(root, scopePath.join("."));
|
|
4323
|
-
return
|
|
4367
|
+
return isPlainObject16(scoped) ? scoped : null;
|
|
4324
4368
|
};
|
|
4325
4369
|
resolveAlwaysSelectForAccess = (raw, access) => {
|
|
4326
4370
|
if (!raw) return [];
|
|
4327
4371
|
if (isArray7(raw)) return [...raw];
|
|
4328
|
-
if (
|
|
4372
|
+
if (isPlainObject16(raw)) {
|
|
4329
4373
|
const record3 = raw;
|
|
4330
4374
|
const exact = record3[access];
|
|
4331
4375
|
if (isArray7(exact)) return [...exact];
|
|
@@ -4599,15 +4643,22 @@ function getCapturedAuthorizationOption(configuration, key) {
|
|
|
4599
4643
|
const defaultValue = key.startsWith("operationAccess.") ? get7(configuration.operationAccessDefaults, key.slice("operationAccess.".length)) : void 0;
|
|
4600
4644
|
return resolveNestedOption((path, fallback) => get7(configuration, path, fallback), key, defaultValue);
|
|
4601
4645
|
}
|
|
4602
|
-
function captureModelAuthorizationConfiguration(runtime, modelName, options = runtime.getModelOptions(modelName)) {
|
|
4646
|
+
function captureModelAuthorizationConfiguration(runtime, modelName, options = runtime.getModelOptions(modelName), globalOptions = runtime.getGlobalOptions()) {
|
|
4603
4647
|
const model = runtime.getModelInstance(modelName);
|
|
4604
4648
|
if (!model) return authorizationError(`unknown receiving model: ${modelName}`);
|
|
4605
4649
|
const virtuals = options.virtuals;
|
|
4606
4650
|
return copyAuthorizationValue(
|
|
4607
4651
|
{
|
|
4608
4652
|
catalog: captureAuthorizationFieldCatalog(model.schema, virtuals, options.documentPermissionField),
|
|
4609
|
-
virtualPopulateSnapshot: captureVirtualPopulateSnapshot(
|
|
4610
|
-
|
|
4653
|
+
virtualPopulateSnapshot: captureVirtualPopulateSnapshot(
|
|
4654
|
+
runtime,
|
|
4655
|
+
modelName,
|
|
4656
|
+
options,
|
|
4657
|
+
globalOptions
|
|
4658
|
+
),
|
|
4659
|
+
requireOperationAccessForPopulateDependencies: globalOptions.requireOperationAccessForPopulateDependencies !== false,
|
|
4660
|
+
requireOperationAccessForPopulateQueries: globalOptions.requireOperationAccessForPopulateQueries !== false,
|
|
4661
|
+
permissionSchema: options.permissionSchema === void 0 ? runtime.getDefaultModelOption("permissionSchema") : options.permissionSchema,
|
|
4611
4662
|
virtuals,
|
|
4612
4663
|
alwaysSelectFields: options.alwaysSelectFields,
|
|
4613
4664
|
modelPermissionPrefix: options.modelPermissionPrefix,
|
|
@@ -4673,15 +4724,15 @@ import {
|
|
|
4673
4724
|
isBoolean as isBoolean2,
|
|
4674
4725
|
isEmpty as isEmpty2,
|
|
4675
4726
|
isFunction as isFunction3,
|
|
4676
|
-
isPlainObject as
|
|
4727
|
+
isPlainObject as isPlainObject17,
|
|
4677
4728
|
isString as isString5
|
|
4678
4729
|
} from "@web-ts-toolkit/utils";
|
|
4679
4730
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
4680
4731
|
function isAndFilter(filter2) {
|
|
4681
|
-
return !!filter2 &&
|
|
4732
|
+
return !!filter2 && isPlainObject17(filter2) && Object.keys(filter2).length === 1 && isArray8(filter2.$and);
|
|
4682
4733
|
}
|
|
4683
4734
|
function isMergeableClause(filter2) {
|
|
4684
|
-
return !!filter2 &&
|
|
4735
|
+
return !!filter2 && isPlainObject17(filter2) && Object.keys(filter2).every((key) => !key.startsWith("$"));
|
|
4685
4736
|
}
|
|
4686
4737
|
function optimizeAndFilter(clausesInput) {
|
|
4687
4738
|
const clauses = [];
|
|
@@ -4702,7 +4753,7 @@ function optimizeAndFilter(clausesInput) {
|
|
|
4702
4753
|
const entries = Array.from(value, dedupeKey);
|
|
4703
4754
|
return entries.every((entry) => entry !== void 0) ? `array:${JSON.stringify(entries)}` : void 0;
|
|
4704
4755
|
}
|
|
4705
|
-
if (
|
|
4756
|
+
if (isPlainObject17(value)) {
|
|
4706
4757
|
const entries = Object.keys(value).sort().map((key) => [key, dedupeKey(value[key])]);
|
|
4707
4758
|
return entries.every(([, entry]) => entry !== void 0) ? `object:${JSON.stringify(entries)}` : void 0;
|
|
4708
4759
|
}
|
|
@@ -4750,7 +4801,7 @@ function optimizeAndFilter(clausesInput) {
|
|
|
4750
4801
|
}
|
|
4751
4802
|
function normalizeFilter(filter2) {
|
|
4752
4803
|
if (filter2 === false) return false;
|
|
4753
|
-
if (!filter2 || !
|
|
4804
|
+
if (!filter2 || !isPlainObject17(filter2) || isEmpty2(filter2)) return null;
|
|
4754
4805
|
if (!isAndFilter(filter2)) {
|
|
4755
4806
|
return filter2;
|
|
4756
4807
|
}
|
|
@@ -4828,7 +4879,7 @@ async function setRequestPermissions(req) {
|
|
|
4828
4879
|
if (hasFieldValue && owner === void 0) return;
|
|
4829
4880
|
const globalPermissions = getGlobalOption("globalPermissions");
|
|
4830
4881
|
const permissions = isFunction3(globalPermissions) ? await globalPermissions.call(req, req) : void 0;
|
|
4831
|
-
if (
|
|
4882
|
+
if (isPlainObject17(permissions)) req[requestPermissionField] = permissions;
|
|
4832
4883
|
else if (isArray8(permissions)) req[requestPermissionField] = arrayToRecord(permissions);
|
|
4833
4884
|
else if (isString5(permissions)) req[requestPermissionField] = { [permissions]: true };
|
|
4834
4885
|
else req[requestPermissionField] = {};
|
|
@@ -5227,7 +5278,7 @@ var init_filter_resolution = __esm({
|
|
|
5227
5278
|
// src/acl/virtual-populate-execution.ts
|
|
5228
5279
|
import { Document as Document4, mongo as mongo4 } from "mongoose";
|
|
5229
5280
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
5230
|
-
import { isPlainObject as
|
|
5281
|
+
import { isPlainObject as isPlainObject20 } from "@web-ts-toolkit/utils";
|
|
5231
5282
|
function projectVirtualPopulateView(source, selection, structurePaths = []) {
|
|
5232
5283
|
const root = { children: /* @__PURE__ */ new Map() };
|
|
5233
5284
|
for (const path of compactPersistedProjection(selection)) {
|
|
@@ -5259,8 +5310,8 @@ function equivalentVirtualPopulatePredicate(left, right) {
|
|
|
5259
5310
|
}
|
|
5260
5311
|
if (Array.isArray(left) || Array.isArray(right))
|
|
5261
5312
|
return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((entry, index) => equivalentVirtualPopulatePredicate(entry, right[index]));
|
|
5262
|
-
if (
|
|
5263
|
-
if (!
|
|
5313
|
+
if (isPlainObject20(left) || isPlainObject20(right)) {
|
|
5314
|
+
if (!isPlainObject20(left) || !isPlainObject20(right)) return false;
|
|
5264
5315
|
const a = Object.keys(left), b = Object.keys(right);
|
|
5265
5316
|
return a.length === b.length && a.every(
|
|
5266
5317
|
(key, index) => key === b[index] && equivalentVirtualPopulatePredicate(
|
|
@@ -5277,7 +5328,8 @@ function createVirtualPopulateBatch(owner) {
|
|
|
5277
5328
|
owner: { ...owner },
|
|
5278
5329
|
rows: [],
|
|
5279
5330
|
requests: [],
|
|
5280
|
-
rowCache: owner.core && getRequestRowCache(owner.core) || new Cache()
|
|
5331
|
+
rowCache: owner.core && getRequestRowCache(owner.core) || new Cache(),
|
|
5332
|
+
readGuards: /* @__PURE__ */ new Map()
|
|
5281
5333
|
});
|
|
5282
5334
|
return batch;
|
|
5283
5335
|
}
|
|
@@ -5326,7 +5378,12 @@ function captureVirtualPopulateRows(batch, inputs, plan, publicPopulate = [], so
|
|
|
5326
5378
|
}
|
|
5327
5379
|
const record3 = storage(value);
|
|
5328
5380
|
if (!record3) return;
|
|
5329
|
-
const occurrence = {
|
|
5381
|
+
const occurrence = {
|
|
5382
|
+
address,
|
|
5383
|
+
plan: currentPlan,
|
|
5384
|
+
refs: /* @__PURE__ */ new Map(),
|
|
5385
|
+
dependencies: /* @__PURE__ */ new Map()
|
|
5386
|
+
};
|
|
5330
5387
|
row.occurrences.set(addressKey(address), occurrence);
|
|
5331
5388
|
for (const candidate of currentPlan.candidates) {
|
|
5332
5389
|
const dependencies = (candidate.populateDependencies ?? []).map((dependency) => {
|
|
@@ -5392,6 +5449,27 @@ function referenceIds(original) {
|
|
|
5392
5449
|
if (!original.present || original.value == null) return [];
|
|
5393
5450
|
return (Array.isArray(original.value) ? original.value : [original.value]).filter((id) => id != null);
|
|
5394
5451
|
}
|
|
5452
|
+
function targetReadAllowed(state, target) {
|
|
5453
|
+
let pending = state.readGuards.get(target.identity);
|
|
5454
|
+
if (!pending) {
|
|
5455
|
+
const { owner } = state;
|
|
5456
|
+
pending = getRequestWorkState(owner.request, owner.runtime).hookGate.run(
|
|
5457
|
+
() => evaluateRouteGuard(
|
|
5458
|
+
owner.request,
|
|
5459
|
+
owner.permissions,
|
|
5460
|
+
getCapturedAuthorizationOption(target.configuration, "operationAccess.read")
|
|
5461
|
+
)
|
|
5462
|
+
).then(
|
|
5463
|
+
(allowed) => !!allowed,
|
|
5464
|
+
() => {
|
|
5465
|
+
warn("Virtual populated dependency unavailable", { modelName: target.modelName, category: "policy" });
|
|
5466
|
+
return false;
|
|
5467
|
+
}
|
|
5468
|
+
);
|
|
5469
|
+
state.readGuards.set(target.identity, pending);
|
|
5470
|
+
}
|
|
5471
|
+
return pending;
|
|
5472
|
+
}
|
|
5395
5473
|
function executeVirtualPopulateBatch(batch) {
|
|
5396
5474
|
const state = batches.get(batch);
|
|
5397
5475
|
if (!state) throw new Error("Unknown private populate batch");
|
|
@@ -5408,14 +5486,8 @@ async function execute(state) {
|
|
|
5408
5486
|
if (!pending) {
|
|
5409
5487
|
pending = (async () => {
|
|
5410
5488
|
try {
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
owner.request,
|
|
5414
|
-
owner.permissions,
|
|
5415
|
-
getCapturedAuthorizationOption(target.configuration, "operationAccess.read")
|
|
5416
|
-
)
|
|
5417
|
-
);
|
|
5418
|
-
if (!allowed) return void 0;
|
|
5489
|
+
if (target.configuration.requireOperationAccessForPopulateDependencies !== false && !await targetReadAllowed(state, target))
|
|
5490
|
+
return void 0;
|
|
5419
5491
|
const parts = await work.hookGate.run(
|
|
5420
5492
|
() => resolveAccessFilterParts({
|
|
5421
5493
|
req: owner.request,
|
|
@@ -5642,7 +5714,7 @@ var init_virtual_populate_execution = __esm({
|
|
|
5642
5714
|
publicViewIdentities = /* @__PURE__ */ new WeakMap();
|
|
5643
5715
|
familyRawFetches = /* @__PURE__ */ new WeakMap();
|
|
5644
5716
|
addressKey = (address) => JSON.stringify(address);
|
|
5645
|
-
storage = (value) => value instanceof Document4 ? value._doc :
|
|
5717
|
+
storage = (value) => value instanceof Document4 ? value._doc : isPlainObject20(value) ? value : void 0;
|
|
5646
5718
|
originalRef = (source, key) => {
|
|
5647
5719
|
const record3 = storage(source);
|
|
5648
5720
|
return {
|
|
@@ -5655,7 +5727,7 @@ var init_virtual_populate_execution = __esm({
|
|
|
5655
5727
|
const option = getCapturedAuthorizationOption(configuration, `${key}.${access}`);
|
|
5656
5728
|
return key === "operationAccess" || typeof option === "function" ? option : void 0;
|
|
5657
5729
|
});
|
|
5658
|
-
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.
|
|
5659
5731
|
equivalentVirtualPopulatePredicate(
|
|
5660
5732
|
a.binding.configuration.catalog.persistedPaths,
|
|
5661
5733
|
b.binding.configuration.catalog.persistedPaths
|
|
@@ -5669,7 +5741,7 @@ var init_virtual_populate_execution = __esm({
|
|
|
5669
5741
|
});
|
|
5670
5742
|
|
|
5671
5743
|
// src/acl/output-field-filter.ts
|
|
5672
|
-
import { isPlainObject as
|
|
5744
|
+
import { isPlainObject as isPlainObject21 } from "@web-ts-toolkit/utils";
|
|
5673
5745
|
async function resolveOutputDocumentAuthorization(args) {
|
|
5674
5746
|
const { authorization, binding } = args;
|
|
5675
5747
|
const { configuration, access } = readServiceAuthorization(authorization, binding);
|
|
@@ -5683,7 +5755,7 @@ async function resolveOutputDocumentAuthorization(args) {
|
|
|
5683
5755
|
try {
|
|
5684
5756
|
const run = () => hook.call(this, doc, permissions, args.context);
|
|
5685
5757
|
const grants = await getRequestWorkState(binding.request, binding.runtime).hookGate.run(run);
|
|
5686
|
-
return
|
|
5758
|
+
return isPlainObject21(grants) ? grants : {};
|
|
5687
5759
|
} catch (error2) {
|
|
5688
5760
|
warn("docPermissions hook failed; applying empty document permissions", {
|
|
5689
5761
|
modelName: binding.modelName,
|
|
@@ -5798,7 +5870,7 @@ function copyOutputValue(value, plan, path) {
|
|
|
5798
5870
|
const visit = (input, current) => {
|
|
5799
5871
|
if (Array.isArray(input)) return input.map((entry) => visit(entry, current));
|
|
5800
5872
|
if (input instanceof Map) return visit(Object.fromEntries(input), current);
|
|
5801
|
-
if (!
|
|
5873
|
+
if (!isPlainObject21(input)) return deepIsolateValue(input);
|
|
5802
5874
|
const output = {};
|
|
5803
5875
|
for (const [key, entry] of Object.entries(input)) {
|
|
5804
5876
|
const child = `${current}.${key}`;
|
|
@@ -5814,25 +5886,21 @@ function copyOutputValue(value, plan, path) {
|
|
|
5814
5886
|
}
|
|
5815
5887
|
function copyAuthorizedReference(value, plan, path) {
|
|
5816
5888
|
if (Array.isArray(value)) return value.map((entry) => copyAuthorizedReference(entry, plan, path));
|
|
5817
|
-
if (!
|
|
5889
|
+
if (!isPlainObject21(value)) return deepIsolateValue(value);
|
|
5818
5890
|
const handle = getAssociatedDocumentAuthorization(value, plan.authorization);
|
|
5819
5891
|
if (handle) {
|
|
5820
5892
|
const copy = deepIsolateValue(value);
|
|
5821
5893
|
transferDocumentAuthorizationGraph(value, copy);
|
|
5822
5894
|
return copy;
|
|
5823
5895
|
}
|
|
5824
|
-
const { relatedTargets } = readServiceAuthorization(plan.authorization, plan.authorizationBinding);
|
|
5825
|
-
if (relatedTargets.some((target) => target.path === path && target.kind === "passthrough")) {
|
|
5826
|
-
return deepIsolateValue(value);
|
|
5827
|
-
}
|
|
5828
5896
|
return Object.prototype.hasOwnProperty.call(value, "_id") ? deepIsolateValue(value._id) : void 0;
|
|
5829
5897
|
}
|
|
5830
5898
|
function retainOutputMetadata(output, source, configuration, scope2) {
|
|
5831
5899
|
if (scope2.length || configuration.stripPermissionsField) return;
|
|
5832
5900
|
const parts = (configuration.documentPermissionField ?? "_permissions").split(".");
|
|
5833
5901
|
let value = source;
|
|
5834
|
-
for (const part of parts) value =
|
|
5835
|
-
if (!
|
|
5902
|
+
for (const part of parts) value = isPlainObject21(value) ? value[part] : void 0;
|
|
5903
|
+
if (!isPlainObject21(value)) return;
|
|
5836
5904
|
const keys2 = configuration.exposedDocPermissionKeys;
|
|
5837
5905
|
const metadata = Object.fromEntries(
|
|
5838
5906
|
Object.entries(value).filter(
|
|
@@ -5842,7 +5910,7 @@ function retainOutputMetadata(output, source, configuration, scope2) {
|
|
|
5842
5910
|
const copy = { ...output };
|
|
5843
5911
|
let target = copy;
|
|
5844
5912
|
for (const part of parts.slice(0, -1)) {
|
|
5845
|
-
target[part] =
|
|
5913
|
+
target[part] = isPlainObject21(target[part]) ? { ...target[part] } : {};
|
|
5846
5914
|
target = target[part];
|
|
5847
5915
|
}
|
|
5848
5916
|
target[parts[parts.length - 1]] = deepIsolateValue(metadata);
|
|
@@ -5884,7 +5952,7 @@ async function filterExistingOutput(source, plan, handle, associated) {
|
|
|
5884
5952
|
for (const entry of value2) values.push(await one(entry) ?? null);
|
|
5885
5953
|
return values;
|
|
5886
5954
|
}
|
|
5887
|
-
if (!
|
|
5955
|
+
if (!isPlainObject21(value2)) return value2 === null ? null : void 0;
|
|
5888
5956
|
const childHandle = associated ? getAssociatedDocumentAuthorization(value2) : void 0;
|
|
5889
5957
|
let child = scoped;
|
|
5890
5958
|
if (childHandle) {
|
|
@@ -5964,7 +6032,7 @@ async function filterModelOutputForHelper(args) {
|
|
|
5964
6032
|
const plan = helperPlan(normalized.authorization, binding);
|
|
5965
6033
|
if (args.doc == null) return { output: args.doc, fields: [] };
|
|
5966
6034
|
const source = isolateDocForOutput(args.doc);
|
|
5967
|
-
if (!
|
|
6035
|
+
if (!isPlainObject21(source)) return authorizationError("output helper requires one plain or hydrated document");
|
|
5968
6036
|
const knownOutput = !!args.doc && typeof args.doc === "object" && isKnownAuthorizationOutput(args.doc);
|
|
5969
6037
|
const handle = await resolveOutputDocumentAuthorization({
|
|
5970
6038
|
authorization: normalized.authorization,
|
|
@@ -6059,7 +6127,7 @@ __export(finalize_model_output_exports, {
|
|
|
6059
6127
|
finalizeModelOutput: () => finalizeModelOutput,
|
|
6060
6128
|
finalizeModelOutputs: () => finalizeModelOutputs
|
|
6061
6129
|
});
|
|
6062
|
-
import { get as get9, isPlainObject as
|
|
6130
|
+
import { get as get9, isPlainObject as isPlainObject22, set as set7 } from "@web-ts-toolkit/utils";
|
|
6063
6131
|
async function finalizeSingleDoc(args, input) {
|
|
6064
6132
|
const scopePath = args.scopePath;
|
|
6065
6133
|
const plan = args.plan;
|
|
@@ -6075,8 +6143,8 @@ async function finalizeSingleDoc(args, input) {
|
|
|
6075
6143
|
const privateRow = args.virtualPopulateRow ?? (original && typeof original === "object" ? getVirtualPopulateRow(original) : void 0);
|
|
6076
6144
|
const privateAddress = args.virtualPopulateAddress ?? [];
|
|
6077
6145
|
const isolated = isolateDocForOutput(input);
|
|
6078
|
-
const output =
|
|
6079
|
-
if (captured &&
|
|
6146
|
+
const output = isPlainObject22(isolated) ? isolated : {};
|
|
6147
|
+
if (captured && isPlainObject22(input))
|
|
6080
6148
|
for (const key of Object.keys(output)) {
|
|
6081
6149
|
transferDocumentAuthorizationGraph(input[key], output[key]);
|
|
6082
6150
|
}
|
|
@@ -6131,7 +6199,7 @@ async function finalizeSingleDoc(args, input) {
|
|
|
6131
6199
|
);
|
|
6132
6200
|
continue;
|
|
6133
6201
|
}
|
|
6134
|
-
if (captured && !
|
|
6202
|
+
if (captured && !isPlainObject22(rawContainer) && !Array.isArray(rawContainer)) {
|
|
6135
6203
|
delete output[containerName];
|
|
6136
6204
|
continue;
|
|
6137
6205
|
}
|
|
@@ -6155,7 +6223,7 @@ async function finalizeSingleDoc(args, input) {
|
|
|
6155
6223
|
const finalizeOneChild = async (rawChild, address) => {
|
|
6156
6224
|
if (captured && Array.isArray(rawChild))
|
|
6157
6225
|
return mapWithConcurrencyLimit(rawChild, limit, (entry, index) => finalizeOneChild(entry, [...address, index]));
|
|
6158
|
-
if (!
|
|
6226
|
+
if (!isPlainObject22(rawChild) && !Array.isArray(rawChild)) return captured ? null : deepIsolateValue(rawChild);
|
|
6159
6227
|
if (args.traversal?.finalizeEmbeddedChildren) {
|
|
6160
6228
|
return args.traversal.finalizeEmbeddedChildren({
|
|
6161
6229
|
containerName,
|
|
@@ -6181,7 +6249,7 @@ async function finalizeSingleDoc(args, input) {
|
|
|
6181
6249
|
(entry, index) => finalizeOneChild(entry, [...privateAddress, containerName, index])
|
|
6182
6250
|
);
|
|
6183
6251
|
output[containerName] = finalized;
|
|
6184
|
-
} else if (
|
|
6252
|
+
} else if (isPlainObject22(rawContainer)) {
|
|
6185
6253
|
output[containerName] = await finalizeOneChild(rawContainer, [
|
|
6186
6254
|
...privateAddress,
|
|
6187
6255
|
containerName
|
|
@@ -6225,7 +6293,7 @@ async function finalizeSingleDoc(args, input) {
|
|
|
6225
6293
|
related: target.plan.relatedPlans?.length ? (args.related ?? []).filter((entry) => entry.path.startsWith(`${target.path}.`)) : []
|
|
6226
6294
|
};
|
|
6227
6295
|
const finalizeOneRelated = async (rawChild, originalChild = rawChild) => {
|
|
6228
|
-
if (!
|
|
6296
|
+
if (!isPlainObject22(rawChild) && !Array.isArray(rawChild)) return rawChild;
|
|
6229
6297
|
if (typeof rawChild?._bsontype === "string") return rawChild;
|
|
6230
6298
|
const childOriginal = getIncludeOriginal(originalChild);
|
|
6231
6299
|
const childRow = childOriginal && typeof childOriginal === "object" ? getVirtualPopulateRow(childOriginal) : void 0;
|
|
@@ -6246,7 +6314,7 @@ async function finalizeSingleDoc(args, input) {
|
|
|
6246
6314
|
limit,
|
|
6247
6315
|
(entry, index) => finalizeOneRelated(entry, Array.isArray(originalRelated) ? originalRelated[index] : void 0)
|
|
6248
6316
|
);
|
|
6249
|
-
} else if (
|
|
6317
|
+
} else if (isPlainObject22(rawRelated)) {
|
|
6250
6318
|
finalized = await finalizeOneRelated(rawRelated, originalRelated);
|
|
6251
6319
|
} else {
|
|
6252
6320
|
continue;
|
|
@@ -6447,20 +6515,20 @@ var init_finalize_model_output = __esm({
|
|
|
6447
6515
|
init_field_catalog();
|
|
6448
6516
|
init_virtual_populate_execution();
|
|
6449
6517
|
init_include_output();
|
|
6450
|
-
isVirtualContainerValue3 = (value) =>
|
|
6518
|
+
isVirtualContainerValue3 = (value) => isPlainObject22(value) && "sub" in value;
|
|
6451
6519
|
getScopeVirtualsObject2 = (rootVirtuals, scopePath) => {
|
|
6452
|
-
if (!rootVirtuals || !
|
|
6520
|
+
if (!rootVirtuals || !isPlainObject22(rootVirtuals)) return null;
|
|
6453
6521
|
if (scopePath.length === 0) return rootVirtuals;
|
|
6454
6522
|
let current = rootVirtuals;
|
|
6455
6523
|
for (let i = 0; i < scopePath.length; i += 2) {
|
|
6456
6524
|
const field = scopePath[i];
|
|
6457
6525
|
const subMarker = scopePath[i + 1];
|
|
6458
6526
|
if (!field || subMarker !== "sub") return null;
|
|
6459
|
-
if (!
|
|
6527
|
+
if (!isPlainObject22(current)) return null;
|
|
6460
6528
|
const container = current[field];
|
|
6461
6529
|
if (!isVirtualContainerValue3(container)) return null;
|
|
6462
6530
|
current = container.sub;
|
|
6463
|
-
if (!
|
|
6531
|
+
if (!isPlainObject22(current)) return null;
|
|
6464
6532
|
}
|
|
6465
6533
|
return current;
|
|
6466
6534
|
};
|
|
@@ -6473,11 +6541,11 @@ var init_finalize_model_output = __esm({
|
|
|
6473
6541
|
return Object.entries(scopeVirtuals).filter(([, v]) => v !== void 0 && !isVirtualContainerValue3(v)).map(([k]) => k);
|
|
6474
6542
|
};
|
|
6475
6543
|
getScopedPermissionSchema2 = (root, scopePath) => {
|
|
6476
|
-
if (!root || !
|
|
6544
|
+
if (!root || !isPlainObject22(root)) return null;
|
|
6477
6545
|
if (scopePath.length === 0) return root;
|
|
6478
6546
|
try {
|
|
6479
6547
|
const scoped = get9(root, scopePath.join("."));
|
|
6480
|
-
return
|
|
6548
|
+
return isPlainObject22(scoped) ? scoped : null;
|
|
6481
6549
|
} catch {
|
|
6482
6550
|
return null;
|
|
6483
6551
|
}
|
|
@@ -6536,7 +6604,7 @@ var init_finalize_model_output = __esm({
|
|
|
6536
6604
|
const grants = await args.sharedGate.run(
|
|
6537
6605
|
() => hook.call(args.request, isolatedForHook, globalPerms, scopeContext)
|
|
6538
6606
|
);
|
|
6539
|
-
const normalized =
|
|
6607
|
+
const normalized = isPlainObject22(grants) ? grants : {};
|
|
6540
6608
|
scopeContext.docPermissions = normalized;
|
|
6541
6609
|
return normalized;
|
|
6542
6610
|
}
|
|
@@ -6558,19 +6626,21 @@ var init_finalize_model_output = __esm({
|
|
|
6558
6626
|
});
|
|
6559
6627
|
|
|
6560
6628
|
// src/index.ts
|
|
6561
|
-
import { isPlainObject as
|
|
6629
|
+
import { isPlainObject as isPlainObject31, isString as isString10, isUndefined as isUndefined4 } from "@web-ts-toolkit/utils";
|
|
6562
6630
|
|
|
6563
6631
|
// src/middleware.ts
|
|
6564
6632
|
import JsonRouter5 from "@web-ts-toolkit/express-json-router";
|
|
6565
|
-
import { isArray as isArray13, isFunction as isFunction7, isPlainObject as
|
|
6633
|
+
import { isArray as isArray13, isFunction as isFunction7, isPlainObject as isPlainObject27, isString as isString7 } from "@web-ts-toolkit/utils";
|
|
6566
6634
|
|
|
6567
6635
|
// src/core.ts
|
|
6568
6636
|
init_public_admission();
|
|
6569
6637
|
init_options();
|
|
6638
|
+
init_permission();
|
|
6570
6639
|
import {
|
|
6571
6640
|
castArray as castArray4,
|
|
6572
6641
|
compact as compact3,
|
|
6573
6642
|
forEach as forEach6,
|
|
6643
|
+
get as get15,
|
|
6574
6644
|
isArray as isArray12,
|
|
6575
6645
|
isBoolean as isBoolean5,
|
|
6576
6646
|
isFunction as isFunction6,
|
|
@@ -6580,27 +6650,6 @@ import {
|
|
|
6580
6650
|
uniq as uniq3
|
|
6581
6651
|
} from "@web-ts-toolkit/utils";
|
|
6582
6652
|
|
|
6583
|
-
// src/meta.ts
|
|
6584
|
-
init_runtime();
|
|
6585
|
-
init_runtime_context();
|
|
6586
|
-
var getRuntime5 = () => getActiveRuntime() ?? defaultRuntime;
|
|
6587
|
-
var getModelRef = (modelName, refPath) => {
|
|
6588
|
-
const direct = getRuntime5().getModelRef(modelName, refPath);
|
|
6589
|
-
if (direct) return direct;
|
|
6590
|
-
if (!refPath.includes(".")) return null;
|
|
6591
|
-
try {
|
|
6592
|
-
const runtime = getRuntime5();
|
|
6593
|
-
const instance = runtime.getModelInstance?.(
|
|
6594
|
-
modelName
|
|
6595
|
-
);
|
|
6596
|
-
const schemaPath = instance?.schema?.path?.(refPath);
|
|
6597
|
-
const ref = schemaPath?.options?.ref ?? schemaPath?.caster?.options?.ref ?? null;
|
|
6598
|
-
return typeof ref === "string" && ref.length > 0 ? ref : null;
|
|
6599
|
-
} catch {
|
|
6600
|
-
return null;
|
|
6601
|
-
}
|
|
6602
|
-
};
|
|
6603
|
-
|
|
6604
6653
|
// src/services/base.ts
|
|
6605
6654
|
init_options();
|
|
6606
6655
|
init_helpers();
|
|
@@ -6616,7 +6665,7 @@ import {
|
|
|
6616
6665
|
forEach as forEach3,
|
|
6617
6666
|
get as get8,
|
|
6618
6667
|
isArray as isArray9,
|
|
6619
|
-
isPlainObject as
|
|
6668
|
+
isPlainObject as isPlainObject18,
|
|
6620
6669
|
set as set6,
|
|
6621
6670
|
uniq
|
|
6622
6671
|
} from "@web-ts-toolkit/utils";
|
|
@@ -6741,7 +6790,7 @@ init_public_admission();
|
|
|
6741
6790
|
// src/correlated-includes.ts
|
|
6742
6791
|
init_request_complexity();
|
|
6743
6792
|
init_sort_policy();
|
|
6744
|
-
import { cloneDeep, isArray as isArray6, isPlainObject as
|
|
6793
|
+
import { cloneDeep, isArray as isArray6, isPlainObject as isPlainObject15 } from "@web-ts-toolkit/utils";
|
|
6745
6794
|
var PARENT_MARKER_KEY = "$parent";
|
|
6746
6795
|
var ESCAPE_WRAPPER_KEY = "$escape";
|
|
6747
6796
|
var SUBQUERY_PAYLOAD_KEYS = /* @__PURE__ */ new Set(["$$sq", "$$date"]);
|
|
@@ -6752,10 +6801,10 @@ var FIELD_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
|
6752
6801
|
var ARRAY_INDEX_SEGMENT_PATTERN = /^(0|[1-9]\d*)$/;
|
|
6753
6802
|
var ownKeys = (value) => Object.keys(value);
|
|
6754
6803
|
function isParentRefMarker(value) {
|
|
6755
|
-
return
|
|
6804
|
+
return isPlainObject15(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
|
|
6756
6805
|
}
|
|
6757
6806
|
function isEscapedParentRef(value) {
|
|
6758
|
-
return
|
|
6807
|
+
return isPlainObject15(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
|
|
6759
6808
|
}
|
|
6760
6809
|
function hasMarkerKey(value) {
|
|
6761
6810
|
return ownKeys(value).includes(PARENT_MARKER_KEY) || ownKeys(value).includes(ESCAPE_WRAPPER_KEY);
|
|
@@ -6779,7 +6828,7 @@ function containsParentMarkerShape(value) {
|
|
|
6779
6828
|
seen.add(current);
|
|
6780
6829
|
return current.some(visit);
|
|
6781
6830
|
}
|
|
6782
|
-
if (
|
|
6831
|
+
if (isPlainObject15(current)) {
|
|
6783
6832
|
if (seen.has(current)) return false;
|
|
6784
6833
|
seen.add(current);
|
|
6785
6834
|
if (hasMarkerKey(current)) return true;
|
|
@@ -6809,7 +6858,7 @@ function scanTemplateValueNode(value, path, issues) {
|
|
|
6809
6858
|
}
|
|
6810
6859
|
return;
|
|
6811
6860
|
}
|
|
6812
|
-
if (
|
|
6861
|
+
if (isPlainObject15(value)) {
|
|
6813
6862
|
if (hasMarkerKey(value)) {
|
|
6814
6863
|
issues.push({
|
|
6815
6864
|
message: 'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }',
|
|
@@ -6874,7 +6923,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
|
|
|
6874
6923
|
});
|
|
6875
6924
|
return;
|
|
6876
6925
|
}
|
|
6877
|
-
if (
|
|
6926
|
+
if (isPlainObject15(clause)) {
|
|
6878
6927
|
scanTemplateObjectEntries(clause, clausePath, issues);
|
|
6879
6928
|
}
|
|
6880
6929
|
});
|
|
@@ -6885,7 +6934,7 @@ function scanTemplateObjectEntries(obj, basePath, issues) {
|
|
|
6885
6934
|
}
|
|
6886
6935
|
function validateCorrelatedFilterTemplate(filter2) {
|
|
6887
6936
|
const issues = [];
|
|
6888
|
-
if (!
|
|
6937
|
+
if (!isPlainObject15(filter2)) {
|
|
6889
6938
|
issues.push({ message: "Correlated include filter must be an object", path: [] });
|
|
6890
6939
|
return issues;
|
|
6891
6940
|
}
|
|
@@ -6934,7 +6983,7 @@ function collectFilterReferencePaths(filter2) {
|
|
|
6934
6983
|
value.forEach(visitValue);
|
|
6935
6984
|
return;
|
|
6936
6985
|
}
|
|
6937
|
-
if (
|
|
6986
|
+
if (isPlainObject15(value)) {
|
|
6938
6987
|
if (seen.has(value)) return;
|
|
6939
6988
|
seen.add(value);
|
|
6940
6989
|
for (const [key, child] of Object.entries(value)) {
|
|
@@ -6980,7 +7029,7 @@ function getOwnPathValue(parent, path) {
|
|
|
6980
7029
|
return current;
|
|
6981
7030
|
}
|
|
6982
7031
|
function cloneSubstitutedValue(value) {
|
|
6983
|
-
if (
|
|
7032
|
+
if (isPlainObject15(value) || isArray6(value)) return cloneDeep(value);
|
|
6984
7033
|
return value;
|
|
6985
7034
|
}
|
|
6986
7035
|
function literalParentRefObject(path) {
|
|
@@ -7029,7 +7078,7 @@ function resolveObjectEntries(obj, parent) {
|
|
|
7029
7078
|
if (isParentRefMarker(clause) || isEscapedParentRef(clause)) {
|
|
7030
7079
|
throw new CorrelatedReferenceError(`Unsupported $parent reference as a direct ${key} clause`);
|
|
7031
7080
|
}
|
|
7032
|
-
if (!
|
|
7081
|
+
if (!isPlainObject15(clause)) return cloneSubstitutedValue(clause);
|
|
7033
7082
|
return resolveObjectEntries(clause, parent);
|
|
7034
7083
|
});
|
|
7035
7084
|
continue;
|
|
@@ -7058,10 +7107,10 @@ function resolveValueNode(template, parent, bare) {
|
|
|
7058
7107
|
}
|
|
7059
7108
|
const value = getOwnPathValue(parent, path);
|
|
7060
7109
|
if (value === void 0 || value === null) throw UNRESOLVABLE;
|
|
7061
|
-
if (bare &&
|
|
7110
|
+
if (bare && isPlainObject15(value)) return { $eq: cloneDeep(value) };
|
|
7062
7111
|
return cloneSubstitutedValue(value);
|
|
7063
7112
|
}
|
|
7064
|
-
if (
|
|
7113
|
+
if (isPlainObject15(template)) {
|
|
7065
7114
|
if (hasMarkerKey(template)) {
|
|
7066
7115
|
throw new CorrelatedReferenceError(
|
|
7067
7116
|
'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }'
|
|
@@ -7103,7 +7152,7 @@ function resolveCorrelatedIdTemplate(id, parent) {
|
|
|
7103
7152
|
}
|
|
7104
7153
|
function resolveCorrelatedFilterTemplate(filter2, parent) {
|
|
7105
7154
|
try {
|
|
7106
|
-
if (!
|
|
7155
|
+
if (!isPlainObject15(filter2) || isParentRefMarker(filter2) || isEscapedParentRef(filter2)) {
|
|
7107
7156
|
throw new CorrelatedReferenceError("Correlated include filter must be an object");
|
|
7108
7157
|
}
|
|
7109
7158
|
return { status: "resolved", filter: resolveObjectEntries(filter2, parent) };
|
|
@@ -7118,7 +7167,7 @@ function validateExpandedCorrelatedOperands(expanded, limits) {
|
|
|
7118
7167
|
var MAX_NESTED_INCLUDE_DEPTH = 10;
|
|
7119
7168
|
function validateCorrelatedArgsShape(args, op, depth) {
|
|
7120
7169
|
if (args === void 0) return [];
|
|
7121
|
-
if (!
|
|
7170
|
+
if (!isPlainObject15(args)) return ["Correlated include args must be an object"];
|
|
7122
7171
|
const record3 = args;
|
|
7123
7172
|
const allowed = op === "list" ? /* @__PURE__ */ new Set(["select", "sort", "skip", "limit", "page", "pageSize", "include"]) : /* @__PURE__ */ new Set(["select", "sort", "include"]);
|
|
7124
7173
|
for (const key of Object.keys(record3)) {
|
|
@@ -7140,7 +7189,7 @@ function validateCorrelatedArgsShape(args, op, depth) {
|
|
|
7140
7189
|
return [];
|
|
7141
7190
|
}
|
|
7142
7191
|
function validateCorrelatedIncludeShape(entry, depth = 0) {
|
|
7143
|
-
if (!
|
|
7192
|
+
if (!isPlainObject15(entry)) return ["Correlated include must be an object"];
|
|
7144
7193
|
const record3 = entry;
|
|
7145
7194
|
if (record3.mode !== "correlated") return ['Correlated include mode must be "correlated"'];
|
|
7146
7195
|
if (typeof record3.model !== "string" || record3.model.length === 0)
|
|
@@ -7153,7 +7202,7 @@ function validateCorrelatedIncludeShape(entry, depth = 0) {
|
|
|
7153
7202
|
if ("localField" in record3 || "foreignField" in record3) {
|
|
7154
7203
|
return ["Correlated includes must not carry localField or foreignField"];
|
|
7155
7204
|
}
|
|
7156
|
-
if (record3.options !== void 0 && !(
|
|
7205
|
+
if (record3.options !== void 0 && !(isPlainObject15(record3.options) && Object.keys(record3.options).length === 0)) {
|
|
7157
7206
|
return ["Correlated include options must be absent or empty"];
|
|
7158
7207
|
}
|
|
7159
7208
|
const hasId = record3.id !== void 0;
|
|
@@ -7175,7 +7224,7 @@ function validateCorrelatedIncludeShape(entry, depth = 0) {
|
|
|
7175
7224
|
return validateCorrelatedArgsShape(record3.args, record3.op, depth);
|
|
7176
7225
|
}
|
|
7177
7226
|
function isCorrelatedInclude(value) {
|
|
7178
|
-
return
|
|
7227
|
+
return isPlainObject15(value) && value.mode === "correlated";
|
|
7179
7228
|
}
|
|
7180
7229
|
|
|
7181
7230
|
// src/services/base.ts
|
|
@@ -7242,6 +7291,11 @@ function modelServiceOptions(receiver, read) {
|
|
|
7242
7291
|
if (call?.receiver !== receiver) return read();
|
|
7243
7292
|
return call.options ??= read();
|
|
7244
7293
|
}
|
|
7294
|
+
function modelServiceGlobalOptions(receiver, runtime) {
|
|
7295
|
+
const call = dispatch.getStore();
|
|
7296
|
+
if (call?.receiver !== receiver) return runtime.getGlobalOptions();
|
|
7297
|
+
return call.globalOptions ??= runtime.getGlobalOptions();
|
|
7298
|
+
}
|
|
7245
7299
|
|
|
7246
7300
|
// src/services/base.ts
|
|
7247
7301
|
init_request_work();
|
|
@@ -7394,9 +7448,31 @@ function castCountGroups(input, values) {
|
|
|
7394
7448
|
// src/services/base.ts
|
|
7395
7449
|
init_service_authorization();
|
|
7396
7450
|
|
|
7451
|
+
// src/meta.ts
|
|
7452
|
+
init_runtime();
|
|
7453
|
+
init_runtime_context();
|
|
7454
|
+
var getRuntime5 = () => getActiveRuntime() ?? defaultRuntime;
|
|
7455
|
+
var getModelRef = (modelName, refPath, runtime = getRuntime5()) => {
|
|
7456
|
+
const direct = runtime.getModelRef(modelName, refPath);
|
|
7457
|
+
if (direct) return direct;
|
|
7458
|
+
if (!refPath.includes(".")) return null;
|
|
7459
|
+
try {
|
|
7460
|
+
const instance = runtime.getModelInstance?.(
|
|
7461
|
+
modelName
|
|
7462
|
+
);
|
|
7463
|
+
const schemaPath = instance?.schema?.path?.(refPath);
|
|
7464
|
+
const element = schemaPath?.$embeddedSchemaType ?? schemaPath?.embeddedSchemaType ?? schemaPath?.caster;
|
|
7465
|
+
const ref = schemaPath?.options?.ref ?? element?.options?.ref ?? null;
|
|
7466
|
+
return typeof ref === "string" && ref.length > 0 ? ref : null;
|
|
7467
|
+
} catch {
|
|
7468
|
+
return null;
|
|
7469
|
+
}
|
|
7470
|
+
};
|
|
7471
|
+
|
|
7397
7472
|
// src/acl/related-execution.ts
|
|
7398
7473
|
init_public_admission();
|
|
7399
7474
|
init_model_output_planning();
|
|
7475
|
+
init_populate_target_configuration();
|
|
7400
7476
|
init_authorization_snapshot();
|
|
7401
7477
|
|
|
7402
7478
|
// src/acl/service-execution.ts
|
|
@@ -7682,7 +7758,7 @@ function staticObjectIdReference(runtime, source, path, target) {
|
|
|
7682
7758
|
const scalar = type?.instance === "Array" ? type.$embeddedSchemaType ?? type.embeddedSchemaType ?? type.caster : type;
|
|
7683
7759
|
return scalar?.instance === "ObjectId" && (type?.options?.ref ?? scalar.options?.ref) === target && type?.options?.refPath === void 0 && scalar.options?.refPath === void 0;
|
|
7684
7760
|
}
|
|
7685
|
-
function captureRelatedTargets(runtime, modelName, args = {}, depth = 0) {
|
|
7761
|
+
function captureRelatedTargets(runtime, modelName, args = {}, depth = 0, globalOptions = runtime.getGlobalOptions()) {
|
|
7686
7762
|
if (depth > 32) authorizationError("related descriptor depth exceeded");
|
|
7687
7763
|
assertPublicAdmission(args.populate, "populate");
|
|
7688
7764
|
assertPublicAdmission(args.include, "include");
|
|
@@ -7691,21 +7767,20 @@ function captureRelatedTargets(runtime, modelName, args = {}, depth = 0) {
|
|
|
7691
7767
|
for (const entry of entries(args.populate)) {
|
|
7692
7768
|
const path = typeof entry === "string" ? entry : entry.path;
|
|
7693
7769
|
if (typeof entry !== "string") assertPopulateAccess(entry.access);
|
|
7694
|
-
const model = getModelRef(modelName, path);
|
|
7695
|
-
if (model
|
|
7770
|
+
const model = getModelRef(modelName, path, runtime);
|
|
7771
|
+
if (model) {
|
|
7772
|
+
const target = capturePopulateTargetConfiguration(runtime, model, `${modelName}.${path}`);
|
|
7696
7773
|
targets.push({
|
|
7697
7774
|
path,
|
|
7698
7775
|
modelName: model,
|
|
7699
|
-
configuration: captureModelAuthorizationConfiguration(runtime, model),
|
|
7776
|
+
configuration: captureModelAuthorizationConfiguration(runtime, model, target.options, globalOptions),
|
|
7700
7777
|
staticObjectIdReference: staticObjectIdReference(runtime, modelName, path, model)
|
|
7701
7778
|
});
|
|
7702
|
-
else if (model && !runtime.getGlobalOption("requireRegisteredPopulateModels", true)) {
|
|
7703
|
-
targets.push({ path, modelName: model, kind: "passthrough", configuration: { catalog: { paths: [] } } });
|
|
7704
7779
|
}
|
|
7705
7780
|
}
|
|
7706
7781
|
for (const entry of entries(args.include)) {
|
|
7707
7782
|
if (!runtime.hasModel(entry.model)) authorizationError(`Model ${entry.model} not found`);
|
|
7708
|
-
const configuration = captureModelAuthorizationConfiguration(runtime, entry.model);
|
|
7783
|
+
const configuration = captureModelAuthorizationConfiguration(runtime, entry.model, void 0, globalOptions);
|
|
7709
7784
|
const queryIntent = entry.op === "count" ? void 0 : captureModelServiceIntent(
|
|
7710
7785
|
{
|
|
7711
7786
|
defaults: configuration.defaults ?? {},
|
|
@@ -7731,7 +7806,13 @@ function captureRelatedTargets(runtime, modelName, args = {}, depth = 0) {
|
|
|
7731
7806
|
configuration,
|
|
7732
7807
|
queryIntent,
|
|
7733
7808
|
operationGuard: runtime.getModelOption(entry.model, `operationAccess.${entry.op}`),
|
|
7734
|
-
relatedTargets: captureRelatedTargets(
|
|
7809
|
+
relatedTargets: captureRelatedTargets(
|
|
7810
|
+
runtime,
|
|
7811
|
+
entry.model,
|
|
7812
|
+
queryIntent?.args ?? entry.args ?? {},
|
|
7813
|
+
depth + 1,
|
|
7814
|
+
globalOptions
|
|
7815
|
+
)
|
|
7735
7816
|
});
|
|
7736
7817
|
}
|
|
7737
7818
|
if (new Set(targets.map((target) => target.path)).size !== targets.length)
|
|
@@ -7880,20 +7961,20 @@ var copyAuthorizedOutput = (value) => {
|
|
|
7880
7961
|
transferDocumentAuthorizationGraph(value, copy);
|
|
7881
7962
|
return copy;
|
|
7882
7963
|
};
|
|
7883
|
-
var isVirtualContainerValueForGuard = (value) =>
|
|
7964
|
+
var isVirtualContainerValueForGuard = (value) => isPlainObject18(value) && "sub" in value;
|
|
7884
7965
|
var getScopeVirtualsForGuard = (rootVirtuals, scopePath) => {
|
|
7885
|
-
if (!rootVirtuals || !
|
|
7966
|
+
if (!rootVirtuals || !isPlainObject18(rootVirtuals)) return null;
|
|
7886
7967
|
if (scopePath.length === 0) return rootVirtuals;
|
|
7887
7968
|
let current = rootVirtuals;
|
|
7888
7969
|
for (let i = 0; i < scopePath.length; i += 2) {
|
|
7889
7970
|
const field = scopePath[i];
|
|
7890
7971
|
const subMarker = scopePath[i + 1];
|
|
7891
7972
|
if (!field || subMarker !== "sub") return null;
|
|
7892
|
-
if (!
|
|
7973
|
+
if (!isPlainObject18(current)) return null;
|
|
7893
7974
|
const container = current[field];
|
|
7894
7975
|
if (!isVirtualContainerValueForGuard(container)) return null;
|
|
7895
7976
|
current = container.sub;
|
|
7896
|
-
if (!
|
|
7977
|
+
if (!isPlainObject18(current)) return null;
|
|
7897
7978
|
}
|
|
7898
7979
|
return current;
|
|
7899
7980
|
};
|
|
@@ -7959,7 +8040,7 @@ var sanitizeSubScopeVirtualKeys = (data, snapshot, sub) => {
|
|
|
7959
8040
|
for (const entry of value) stripScope(entry, currentScope);
|
|
7960
8041
|
return;
|
|
7961
8042
|
}
|
|
7962
|
-
if (!
|
|
8043
|
+
if (!isPlainObject18(value)) return;
|
|
7963
8044
|
const record3 = value;
|
|
7964
8045
|
const leaves = getScopeVirtualLeafNames(snapshot, currentScope);
|
|
7965
8046
|
for (const leaf of leaves) {
|
|
@@ -7972,7 +8053,7 @@ var sanitizeSubScopeVirtualKeys = (data, snapshot, sub) => {
|
|
|
7972
8053
|
for (const key of Object.keys(record3)) {
|
|
7973
8054
|
if (leaves.has(key) || containers.has(key)) continue;
|
|
7974
8055
|
const child = record3[key];
|
|
7975
|
-
if (Array.isArray(child) ||
|
|
8056
|
+
if (Array.isArray(child) || isPlainObject18(child)) {
|
|
7976
8057
|
stripScope(child, currentScope);
|
|
7977
8058
|
}
|
|
7978
8059
|
}
|
|
@@ -7984,7 +8065,7 @@ var LOGICAL_FILTER_KEYS = /* @__PURE__ */ new Set(["$and", "$or", "$nor"]);
|
|
|
7984
8065
|
var isOperatorKey = (key) => key.startsWith("$");
|
|
7985
8066
|
var REMOVED_VIRTUAL_FILTER = /* @__PURE__ */ Symbol("removed virtual filter clause");
|
|
7986
8067
|
var rewriteFilterObject = (value, visit) => {
|
|
7987
|
-
if (!
|
|
8068
|
+
if (!isPlainObject18(value)) return value;
|
|
7988
8069
|
let changed = false;
|
|
7989
8070
|
const entries = [];
|
|
7990
8071
|
for (const [key, child] of Object.entries(value)) {
|
|
@@ -8015,7 +8096,7 @@ var resolveVirtualFilterField = (path, scope2) => {
|
|
|
8015
8096
|
if (!Object.hasOwn(scope2, segment) || scope2[segment] === void 0) return null;
|
|
8016
8097
|
const definition = scope2[segment];
|
|
8017
8098
|
if (!isVirtualContainerValueForGuard(definition)) return REMOVED_VIRTUAL_FILTER;
|
|
8018
|
-
scope2 =
|
|
8099
|
+
scope2 = isPlainObject18(definition.sub) ? definition.sub : null;
|
|
8019
8100
|
inContainer = true;
|
|
8020
8101
|
}
|
|
8021
8102
|
return scope2;
|
|
@@ -8027,7 +8108,7 @@ var stripVirtualFilterOperator = (key, value, scope2) => {
|
|
|
8027
8108
|
}
|
|
8028
8109
|
if (key === "$all") {
|
|
8029
8110
|
return rewriteFilterClauses(value, (entry) => {
|
|
8030
|
-
if (!
|
|
8111
|
+
if (!isPlainObject18(entry) || Object.keys(entry).length !== 1 || !Object.hasOwn(entry, "$elemMatch")) return entry;
|
|
8031
8112
|
return rewriteFilterObject(entry, (operator, operand) => stripVirtualFilterOperator(operator, operand, scope2));
|
|
8032
8113
|
});
|
|
8033
8114
|
}
|
|
@@ -8042,7 +8123,7 @@ var stripVirtualFilterQuery = (value, scope2, element = false) => {
|
|
|
8042
8123
|
if (isOperatorKey(key)) return element ? stripVirtualFilterOperator(key, child, scope2) : child;
|
|
8043
8124
|
const fieldScope = resolveVirtualFilterField(key, scope2);
|
|
8044
8125
|
if (fieldScope === REMOVED_VIRTUAL_FILTER) return REMOVED_VIRTUAL_FILTER;
|
|
8045
|
-
if (!fieldScope || !
|
|
8126
|
+
if (!fieldScope || !isPlainObject18(child)) return child;
|
|
8046
8127
|
if (Object.keys(child).some(isOperatorKey)) {
|
|
8047
8128
|
return rewriteFilterObject(
|
|
8048
8129
|
child,
|
|
@@ -8066,7 +8147,7 @@ function getCorrelatedTemplateDepth(includes) {
|
|
|
8066
8147
|
const visit = (entries, depth) => {
|
|
8067
8148
|
const list = castArray2(entries).filter(Boolean);
|
|
8068
8149
|
for (const entry of list) {
|
|
8069
|
-
if (!
|
|
8150
|
+
if (!isPlainObject18(entry)) continue;
|
|
8070
8151
|
max = Math.max(max, depth);
|
|
8071
8152
|
const nested = entry.args?.include;
|
|
8072
8153
|
if (nested !== void 0) {
|
|
@@ -8095,7 +8176,7 @@ function validateClientFilter(filter2) {
|
|
|
8095
8176
|
value.forEach((item, index) => visit(item, `${path}[${index}]`));
|
|
8096
8177
|
return;
|
|
8097
8178
|
}
|
|
8098
|
-
if (!
|
|
8179
|
+
if (!isPlainObject18(value)) return;
|
|
8099
8180
|
Object.entries(value).forEach(([key, child]) => {
|
|
8100
8181
|
const nextPath = path ? `${path}.${key}` : key;
|
|
8101
8182
|
if (blockedOperators.has(key)) {
|
|
@@ -8377,9 +8458,9 @@ var Base = class {
|
|
|
8377
8458
|
const walk = (node, prefix) => {
|
|
8378
8459
|
for (const [key, value] of Object.entries(node)) {
|
|
8379
8460
|
if (value === void 0) continue;
|
|
8380
|
-
if (
|
|
8461
|
+
if (isPlainObject18(value) && "sub" in value) {
|
|
8381
8462
|
const sub = value.sub;
|
|
8382
|
-
if (
|
|
8463
|
+
if (isPlainObject18(sub)) walk(sub, prefix ? `${prefix}.${key}` : key);
|
|
8383
8464
|
continue;
|
|
8384
8465
|
}
|
|
8385
8466
|
out.push(prefix ? `${prefix}.${key}` : key);
|
|
@@ -8432,7 +8513,7 @@ var Base = class {
|
|
|
8432
8513
|
this.throwClientRequestError("bad_request" /* BadRequest */, `Model ${modelName} not found`);
|
|
8433
8514
|
}
|
|
8434
8515
|
for (const entry of entries) {
|
|
8435
|
-
if (!
|
|
8516
|
+
if (!isPlainObject18(entry)) continue;
|
|
8436
8517
|
const models = visited.get(entry) ?? /* @__PURE__ */ new Set();
|
|
8437
8518
|
if (models.has(modelName)) continue;
|
|
8438
8519
|
models.add(modelName);
|
|
@@ -9051,7 +9132,7 @@ import {
|
|
|
9051
9132
|
get as get13,
|
|
9052
9133
|
isArray as isArray10,
|
|
9053
9134
|
isBoolean as isBoolean4,
|
|
9054
|
-
isPlainObject as
|
|
9135
|
+
isPlainObject as isPlainObject25,
|
|
9055
9136
|
omit,
|
|
9056
9137
|
set as set10,
|
|
9057
9138
|
uniq as uniq2,
|
|
@@ -9152,7 +9233,7 @@ var model_default = Model;
|
|
|
9152
9233
|
// src/acl/distinct-field-authorization.ts
|
|
9153
9234
|
init_field_authorization();
|
|
9154
9235
|
init_field_catalog();
|
|
9155
|
-
import { isPlainObject as
|
|
9236
|
+
import { isPlainObject as isPlainObject19 } from "@web-ts-toolkit/utils";
|
|
9156
9237
|
var schemaVariants = (schema) => Object.values(schema.discriminators ?? {});
|
|
9157
9238
|
var scalarTypes = /* @__PURE__ */ new Set([
|
|
9158
9239
|
"String",
|
|
@@ -9232,8 +9313,8 @@ function isDistinctFieldAuthorized(args) {
|
|
|
9232
9313
|
if (path !== field && !path.startsWith(`${field}.`) && !field.startsWith(`${path}.`)) continue;
|
|
9233
9314
|
if (path.startsWith(`${field}.`) && (!eligible(path) || !schemaShape(schema, path) || !granted(path)))
|
|
9234
9315
|
return false;
|
|
9235
|
-
if (
|
|
9236
|
-
if (!
|
|
9316
|
+
if (isPlainObject19(raw) && raw.sub !== void 0) {
|
|
9317
|
+
if (!isPlainObject19(raw.sub) || !declaredRulesSafe(raw.sub, path, next)) return false;
|
|
9237
9318
|
}
|
|
9238
9319
|
}
|
|
9239
9320
|
return true;
|
|
@@ -9315,7 +9396,9 @@ function prepareSubdocumentOutput(service, sub, operation, virtualAccess, output
|
|
|
9315
9396
|
captureRelatedTargets(
|
|
9316
9397
|
getServiceExecutors(service).binding().runtime,
|
|
9317
9398
|
service.getServiceModelName(),
|
|
9318
|
-
{ populate }
|
|
9399
|
+
{ populate },
|
|
9400
|
+
0,
|
|
9401
|
+
configuration
|
|
9319
9402
|
),
|
|
9320
9403
|
void 0,
|
|
9321
9404
|
configuration,
|
|
@@ -9409,7 +9492,7 @@ init_populate_target();
|
|
|
9409
9492
|
|
|
9410
9493
|
// src/helpers/apply-update.ts
|
|
9411
9494
|
init_lib();
|
|
9412
|
-
import { isPlainObject as
|
|
9495
|
+
import { isPlainObject as isPlainObject23, set as set8 } from "@web-ts-toolkit/utils";
|
|
9413
9496
|
function applyUpdate(target, data, allowedFields) {
|
|
9414
9497
|
const wholeFields = /* @__PURE__ */ new Set();
|
|
9415
9498
|
const partialContainers = /* @__PURE__ */ new Set();
|
|
@@ -9429,7 +9512,7 @@ function applyUpdate(target, data, allowedFields) {
|
|
|
9429
9512
|
const apply = (values, prefix = "") => {
|
|
9430
9513
|
for (const [key, value] of Object.entries(values)) {
|
|
9431
9514
|
const path = prefix ? `${prefix}.${key}` : key;
|
|
9432
|
-
if (partialContainers.has(path) && !wholeFields.has(path) && (
|
|
9515
|
+
if (partialContainers.has(path) && !wholeFields.has(path) && (isPlainObject23(value) || Array.isArray(value))) {
|
|
9433
9516
|
apply(value, path);
|
|
9434
9517
|
} else if (isDocument2(target)) {
|
|
9435
9518
|
target.set(path, value);
|
|
@@ -9446,7 +9529,7 @@ init_document();
|
|
|
9446
9529
|
init_request_work();
|
|
9447
9530
|
init_logger_helpers();
|
|
9448
9531
|
init_request_complexity();
|
|
9449
|
-
import { get as get10, isPlainObject as
|
|
9532
|
+
import { get as get10, isPlainObject as isPlainObject24, set as set9 } from "@web-ts-toolkit/utils";
|
|
9450
9533
|
import { mongo as mongo5 } from "mongoose";
|
|
9451
9534
|
|
|
9452
9535
|
// src/acl/select-resolution.ts
|
|
@@ -9563,7 +9646,7 @@ init_field_catalog();
|
|
|
9563
9646
|
init_service_authorization();
|
|
9564
9647
|
var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
|
|
9565
9648
|
var inside = (path, root) => path === root || path.startsWith(`${root}.`);
|
|
9566
|
-
var record2 = (value) =>
|
|
9649
|
+
var record2 = (value) => isPlainObject24(value);
|
|
9567
9650
|
function inputValue(value) {
|
|
9568
9651
|
if (typeof value === "function" || typeof value === "symbol") {
|
|
9569
9652
|
authorizationError("input values must be persisted data, not functions or symbols");
|
|
@@ -10354,10 +10437,12 @@ var Service = class extends Base {
|
|
|
10354
10437
|
model: this.model.mongooseModel,
|
|
10355
10438
|
modelName: this.modelName
|
|
10356
10439
|
}),
|
|
10357
|
-
configuration: () => this.requestRuntime.getModelInstance(this.modelName) ? captureModelAuthorizationConfiguration(
|
|
10358
|
-
|
|
10359
|
-
|
|
10360
|
-
|
|
10440
|
+
configuration: () => this.requestRuntime.getModelInstance(this.modelName) ? captureModelAuthorizationConfiguration(
|
|
10441
|
+
this.requestRuntime,
|
|
10442
|
+
this.modelName,
|
|
10443
|
+
{ ...this.options, defaults: this.defaults },
|
|
10444
|
+
modelServiceGlobalOptions(this, this.requestRuntime)
|
|
10445
|
+
) : { catalog: { paths: [] }, ...this.options },
|
|
10361
10446
|
permissions: () => this.requestCore.getPermissions?.() ?? new permission_default({}),
|
|
10362
10447
|
parse: (filter2) => this.parseClientData(filter2, this.getCorrelatedExecState().scheduler),
|
|
10363
10448
|
validate: (filter2, expanded) => {
|
|
@@ -10886,12 +10971,13 @@ var Service = class extends Base {
|
|
|
10886
10971
|
});
|
|
10887
10972
|
}
|
|
10888
10973
|
captureRelated(args, defaults) {
|
|
10974
|
+
const globalOptions = modelServiceGlobalOptions(this, this.requestRuntime);
|
|
10889
10975
|
const effective = { populate: args?.populate ?? defaults?.populate, include: args?.include ?? defaults?.include };
|
|
10890
10976
|
if (effective.include) {
|
|
10891
10977
|
const processed = this.processInclude(effective.include);
|
|
10892
10978
|
effective.include = [...processed.includes, ...processed.correlatedIncludes];
|
|
10893
10979
|
}
|
|
10894
|
-
return captureRelatedTargets(this.requestRuntime, this.modelName, effective);
|
|
10980
|
+
return captureRelatedTargets(this.requestRuntime, this.modelName, effective, 0, globalOptions);
|
|
10895
10981
|
}
|
|
10896
10982
|
/** Canonical population uses the target's retained policy for both fetch and output. */
|
|
10897
10983
|
async genExecutionPopulate(execution, access, populate) {
|
|
@@ -10913,14 +10999,9 @@ var Service = class extends Base {
|
|
|
10913
10999
|
modelPermissionPrefix: captured.configuration.modelPermissionPrefix
|
|
10914
11000
|
});
|
|
10915
11001
|
if (sourceState === "denied") continue;
|
|
10916
|
-
const
|
|
11002
|
+
const target = captured.relatedTargets.find((target2) => target2.path === descriptor.path);
|
|
11003
|
+
const modelName = target?.modelName;
|
|
10917
11004
|
if (!modelName) continue;
|
|
10918
|
-
if (!this.requestRuntime.hasModel(modelName)) {
|
|
10919
|
-
if (captured.relatedTargets.some((target) => target.path === descriptor.path && target.kind === "passthrough")) {
|
|
10920
|
-
result2.push({ path: descriptor.path, select: descriptor.select });
|
|
10921
|
-
}
|
|
10922
|
-
continue;
|
|
10923
|
-
}
|
|
10924
11005
|
const policy = relatedPolicy(state.authorization, state.binding, descriptor.path);
|
|
10925
11006
|
const svc = this.requestCore.getPublicService(modelName);
|
|
10926
11007
|
const child = createRelatedExecution(
|
|
@@ -10939,7 +11020,7 @@ var Service = class extends Base {
|
|
|
10939
11020
|
if (isExecutionRowDenied(svc, child)) continue;
|
|
10940
11021
|
const childState = readServiceExecution(svc, child);
|
|
10941
11022
|
const targetConfiguration = readServiceAuthorization(childState.authorization, childState.binding).configuration;
|
|
10942
|
-
if (policy?.operation.mode !== "grant" && !await this.hookGate.run(
|
|
11023
|
+
if (targetConfiguration.requireOperationAccessForPopulateQueries !== false && policy?.operation.mode !== "grant" && !await this.hookGate.run(
|
|
10943
11024
|
() => evaluateRouteGuard(
|
|
10944
11025
|
this.req,
|
|
10945
11026
|
getAuthorizationPermissions(childState.authorization, childState.binding),
|
|
@@ -10971,7 +11052,7 @@ var Service = class extends Base {
|
|
|
10971
11052
|
schema: childState.binding.model.schema,
|
|
10972
11053
|
configuration: targetConfiguration,
|
|
10973
11054
|
requestRead: targetAccess === "read" && policy?.operation.mode !== "grant" && readServiceAuthorization(childState.authorization, childState.binding).authorization.rows.mode === "request",
|
|
10974
|
-
staticObjectIdReference: captured.relatedTargets.find((
|
|
11055
|
+
staticObjectIdReference: captured.relatedTargets.find((target2) => target2.path === descriptor.path)?.staticObjectIdReference
|
|
10975
11056
|
}
|
|
10976
11057
|
});
|
|
10977
11058
|
result2.push(ret);
|
|
@@ -10991,7 +11072,7 @@ var Service = class extends Base {
|
|
|
10991
11072
|
if (this.isScalarPopulateValue(rawTarget)) return rawTarget;
|
|
10992
11073
|
const isDoc = (() => {
|
|
10993
11074
|
try {
|
|
10994
|
-
if (
|
|
11075
|
+
if (isPlainObject25(rawTarget)) return true;
|
|
10995
11076
|
const maybe = rawTarget;
|
|
10996
11077
|
if (maybe && typeof maybe === "object" && "_doc" in maybe) return true;
|
|
10997
11078
|
if (maybe && typeof maybe.toObject === "function") return true;
|
|
@@ -11015,15 +11096,13 @@ var Service = class extends Base {
|
|
|
11015
11096
|
transferDocumentAuthorizationGraph(source, copy2);
|
|
11016
11097
|
return copy2;
|
|
11017
11098
|
}
|
|
11018
|
-
let targetMongooseModel;
|
|
11019
|
-
|
|
11020
|
-
|
|
11021
|
-
meta.targetModelName
|
|
11022
|
-
|
|
11023
|
-
|
|
11024
|
-
|
|
11025
|
-
} catch {
|
|
11026
|
-
targetMongooseModel = parentContext.mongooseModel;
|
|
11099
|
+
let targetMongooseModel = meta.fetchBinding?.model;
|
|
11100
|
+
if (!targetMongooseModel) {
|
|
11101
|
+
try {
|
|
11102
|
+
targetMongooseModel = this.requestRuntime.getModelInstance(meta.targetModelName);
|
|
11103
|
+
} catch {
|
|
11104
|
+
targetMongooseModel = parentContext.mongooseModel;
|
|
11105
|
+
}
|
|
11027
11106
|
}
|
|
11028
11107
|
const targetContext = {
|
|
11029
11108
|
mongooseModel: targetMongooseModel ?? parentContext.mongooseModel,
|
|
@@ -13396,7 +13475,7 @@ init_helpers();
|
|
|
13396
13475
|
|
|
13397
13476
|
// src/processors.ts
|
|
13398
13477
|
init_permissions_alias();
|
|
13399
|
-
import { cloneDeep as cloneDeep5, forEach as forEach5, get as get14, hasOwn as hasOwn3, isArray as isArray11, isPlainObject as
|
|
13478
|
+
import { cloneDeep as cloneDeep5, forEach as forEach5, get as get14, hasOwn as hasOwn3, isArray as isArray11, isPlainObject as isPlainObject26, map, set as set11 } from "@web-ts-toolkit/utils";
|
|
13400
13479
|
function cloneProcessorValue(value) {
|
|
13401
13480
|
const copy = cloneDeep5(value);
|
|
13402
13481
|
copyPermissionsAliasGraph(value, copy);
|
|
@@ -13436,7 +13515,7 @@ function resolveLeafParents(obj, src) {
|
|
|
13436
13515
|
for (let ind = 0; ind < segs.length - 1; ind += 1) {
|
|
13437
13516
|
const seg = segs[ind];
|
|
13438
13517
|
targets = targets.reduce((ret, target) => {
|
|
13439
|
-
if (!
|
|
13518
|
+
if (!isPlainObject26(target)) return ret;
|
|
13440
13519
|
const targetObject = target;
|
|
13441
13520
|
const next = targetObject[seg];
|
|
13442
13521
|
if (isArray11(next)) {
|
|
@@ -13450,7 +13529,7 @@ function resolveLeafParents(obj, src) {
|
|
|
13450
13529
|
const leaf = segs[segs.length - 1];
|
|
13451
13530
|
const pairs = [];
|
|
13452
13531
|
forEach5(targets, (target) => {
|
|
13453
|
-
if (!
|
|
13532
|
+
if (!isPlainObject26(target)) return;
|
|
13454
13533
|
pairs.push({ parent: target, leaf });
|
|
13455
13534
|
});
|
|
13456
13535
|
return pairs;
|
|
@@ -13471,7 +13550,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
13471
13550
|
forEach5(segs, (seg, ind) => {
|
|
13472
13551
|
if (segs.length === ind + 1) {
|
|
13473
13552
|
forEach5(targets, (target) => {
|
|
13474
|
-
if (!
|
|
13553
|
+
if (!isPlainObject26(target)) return;
|
|
13475
13554
|
const targetObject = target;
|
|
13476
13555
|
const leaf = targetObject[seg];
|
|
13477
13556
|
const sourceForDest = leaf;
|
|
@@ -13479,7 +13558,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
13479
13558
|
if (isArray11(leaf)) {
|
|
13480
13559
|
if (leaf.length === 0) {
|
|
13481
13560
|
depopulated = [];
|
|
13482
|
-
} else if (leaf.every((item) =>
|
|
13561
|
+
} else if (leaf.every((item) => isPlainObject26(item))) {
|
|
13483
13562
|
depopulated = map(leaf, idField).map((id, i) => {
|
|
13484
13563
|
if (id === void 0) {
|
|
13485
13564
|
failMissingId(`${src}[${i}]`);
|
|
@@ -13489,7 +13568,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
13489
13568
|
} else {
|
|
13490
13569
|
return;
|
|
13491
13570
|
}
|
|
13492
|
-
} else if (
|
|
13571
|
+
} else if (isPlainObject26(leaf)) {
|
|
13493
13572
|
const id = get14(leaf, idField);
|
|
13494
13573
|
if (id === void 0) {
|
|
13495
13574
|
failMissingId(src);
|
|
@@ -13503,7 +13582,7 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
13503
13582
|
});
|
|
13504
13583
|
} else {
|
|
13505
13584
|
targets = targets.reduce((ret, target) => {
|
|
13506
|
-
if (!
|
|
13585
|
+
if (!isPlainObject26(target)) return ret;
|
|
13507
13586
|
const targetObject = target;
|
|
13508
13587
|
const next = targetObject[seg];
|
|
13509
13588
|
if (isArray11(next)) {
|
|
@@ -13609,7 +13688,7 @@ var countPaths = (docObject, operations, options = { mutable: true }) => {
|
|
|
13609
13688
|
let count;
|
|
13610
13689
|
if (isArray11(leafValue)) {
|
|
13611
13690
|
count = leafValue.length;
|
|
13612
|
-
} else if (
|
|
13691
|
+
} else if (isPlainObject26(leafValue)) {
|
|
13613
13692
|
count = Object.keys(leafValue).length;
|
|
13614
13693
|
} else if (leafValue === null || typeof leafValue === "undefined") {
|
|
13615
13694
|
count = 0;
|
|
@@ -13687,6 +13766,8 @@ init_core_shared();
|
|
|
13687
13766
|
init_virtual_projection();
|
|
13688
13767
|
init_populate_target();
|
|
13689
13768
|
init_model_output_planning();
|
|
13769
|
+
init_authorization_snapshot();
|
|
13770
|
+
init_document();
|
|
13690
13771
|
init_output_field_filter();
|
|
13691
13772
|
init_request_work();
|
|
13692
13773
|
var emptyPermissionLeaf = () => ({ $: "_" });
|
|
@@ -13797,17 +13878,11 @@ var Core = class {
|
|
|
13797
13878
|
return this.genSelect(modelName, access, targetFields, options);
|
|
13798
13879
|
}
|
|
13799
13880
|
/** Persisted request-only populate admission; fetch planning is not field authority. */
|
|
13800
|
-
async requestPopulateSelect(
|
|
13881
|
+
async requestPopulateSelect(configuration, permissions, access, targetFields = null, scopePath = []) {
|
|
13801
13882
|
const subPaths = scopePath.flatMap((part) => [part, "sub"]);
|
|
13802
|
-
const permissionSchema =
|
|
13803
|
-
const
|
|
13804
|
-
|
|
13805
|
-
try {
|
|
13806
|
-
const runtime = getActiveRuntime() ?? defaultRuntime;
|
|
13807
|
-
virtualNames = runtime.getVirtualNames(modelName, subPaths);
|
|
13808
|
-
} catch {
|
|
13809
|
-
virtualNames = [];
|
|
13810
|
-
}
|
|
13883
|
+
const permissionSchema = get15(configuration, ["permissionSchema", ...subPaths]);
|
|
13884
|
+
const prefix = scopePath.length ? `${scopePath.join(".")}.` : "";
|
|
13885
|
+
const virtualNames = (configuration.catalog.virtualPaths ?? []).filter((path) => path.startsWith(prefix)).map((path) => path.slice(prefix.length)).filter((path) => !path.includes("."));
|
|
13811
13886
|
return resolveSelectForRequest({
|
|
13812
13887
|
req: this.req,
|
|
13813
13888
|
permissionSchema,
|
|
@@ -13826,13 +13901,21 @@ var Core = class {
|
|
|
13826
13901
|
assertPublicAdmission(_populate, "populate");
|
|
13827
13902
|
assertPopulateAccess(access);
|
|
13828
13903
|
if (!_populate) return [];
|
|
13829
|
-
|
|
13830
|
-
for (const p of
|
|
13904
|
+
const descriptors = copyAuthorizationValue(Array.isArray(_populate) ? _populate : [_populate], true);
|
|
13905
|
+
for (const p of descriptors) {
|
|
13831
13906
|
if (!isString6(p)) assertPopulateAccess(p.access);
|
|
13832
13907
|
}
|
|
13833
|
-
|
|
13908
|
+
const runtime = this.requestRuntime;
|
|
13909
|
+
const globalOptions = modelServiceGlobalOptions(this, runtime);
|
|
13910
|
+
const relatedTargets = captureRelatedTargets(runtime, modelName, { populate: descriptors }, 0, globalOptions);
|
|
13911
|
+
const sourceConfiguration = captureModelAuthorizationConfiguration(runtime, modelName, void 0, globalOptions);
|
|
13912
|
+
const originalPermissions = this.getGlobalPermissions();
|
|
13913
|
+
const permissions = new permission_default(
|
|
13914
|
+
Object.fromEntries(originalPermissions.keys.map((key) => [key, originalPermissions.has(key)]))
|
|
13915
|
+
);
|
|
13916
|
+
const populate = compact3(
|
|
13834
13917
|
await Promise.all(
|
|
13835
|
-
|
|
13918
|
+
descriptors.map(async (p) => {
|
|
13836
13919
|
const populateAccess = !isString6(p) && p.access ? p.access : access;
|
|
13837
13920
|
assertPopulateAccess(populateAccess);
|
|
13838
13921
|
const originalSelect = isString6(p) ? void 0 : p.select;
|
|
@@ -13844,78 +13927,86 @@ var Core = class {
|
|
|
13844
13927
|
const pathForSourcePermission = scopePrefix && ret.path.startsWith(`${scopePrefix}.`) ? ret.path.slice(scopePrefix.length + 1) : ret.path;
|
|
13845
13928
|
const parentPath = pathForSourcePermission.includes(".") ? pathForSourcePermission.split(".")[0] : pathForSourcePermission;
|
|
13846
13929
|
const allowedParentPaths = await this.requestPopulateSelect(
|
|
13847
|
-
|
|
13930
|
+
sourceConfiguration,
|
|
13931
|
+
permissions,
|
|
13848
13932
|
populateAccess,
|
|
13849
13933
|
[parentPath],
|
|
13850
13934
|
scopePath
|
|
13851
13935
|
);
|
|
13852
13936
|
if (!allowedParentPaths.includes(parentPath)) return null;
|
|
13853
|
-
const
|
|
13854
|
-
if (!
|
|
13855
|
-
const
|
|
13856
|
-
|
|
13857
|
-
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13937
|
+
const target = relatedTargets.find((entry) => entry.path === ret.path);
|
|
13938
|
+
if (!target) return null;
|
|
13939
|
+
const refModelName = target.modelName;
|
|
13940
|
+
const targetConfiguration = target.configuration;
|
|
13941
|
+
if (targetConfiguration.requireOperationAccessForPopulateQueries !== false && !await withCapturedModelOperationGuard(
|
|
13942
|
+
this,
|
|
13943
|
+
refModelName,
|
|
13944
|
+
populateAccess,
|
|
13945
|
+
getCapturedAuthorizationOption(targetConfiguration, `operationAccess.${populateAccess}`),
|
|
13946
|
+
permissions,
|
|
13947
|
+
() => this.isAllowed(refModelName, populateAccess)
|
|
13948
|
+
)) {
|
|
13863
13949
|
return null;
|
|
13864
13950
|
}
|
|
13865
|
-
ret.select = await this.requestPopulateSelect(
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13951
|
+
ret.select = await this.requestPopulateSelect(
|
|
13952
|
+
targetConfiguration,
|
|
13953
|
+
permissions,
|
|
13954
|
+
populateAccess,
|
|
13955
|
+
ret.select
|
|
13956
|
+
);
|
|
13957
|
+
const hookInputs = resolveAlwaysSelectForAccess(
|
|
13958
|
+
targetConfiguration.alwaysSelectFields,
|
|
13959
|
+
populateAccess
|
|
13960
|
+
);
|
|
13961
|
+
ret.select = uniq3([
|
|
13962
|
+
...ret.select,
|
|
13963
|
+
...stripVirtuals(hookInputs, [...targetConfiguration.catalog.virtualPaths ?? []])
|
|
13964
|
+
]);
|
|
13965
|
+
const match = isString6(p) ? {} : p.match ?? {};
|
|
13966
|
+
const filter2 = await resolveAccessFilterForRequest({
|
|
13967
|
+
req: this.req,
|
|
13968
|
+
permissions,
|
|
13969
|
+
cache: this.caches.baseFilter,
|
|
13970
|
+
cacheKey: `${refModelName}_baseFilter_${populateAccess}`,
|
|
13971
|
+
access: populateAccess,
|
|
13972
|
+
filter: deepIsolateValue(match),
|
|
13973
|
+
getOption: (key) => getCapturedAuthorizationOption(targetConfiguration, key)
|
|
13974
|
+
});
|
|
13869
13975
|
if (filter2 === false) return null;
|
|
13870
|
-
ret.match = filter2;
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
13874
|
-
|
|
13875
|
-
|
|
13876
|
-
|
|
13877
|
-
|
|
13878
|
-
|
|
13879
|
-
|
|
13880
|
-
|
|
13881
|
-
|
|
13882
|
-
|
|
13883
|
-
|
|
13884
|
-
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13894
|
-
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
|
|
13899
|
-
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
|
|
13903
|
-
|
|
13904
|
-
(t) => t !== "-_id" && !t.includes(".sub.")
|
|
13905
|
-
);
|
|
13906
|
-
if (!merged.includes("_id")) merged.push("_id");
|
|
13907
|
-
ret.select = merged;
|
|
13908
|
-
setPopulateTargetMeta(ret, {
|
|
13909
|
-
targetModelName: refModelName,
|
|
13910
|
-
virtualAccess: planAccess,
|
|
13911
|
-
outputAccess: planAccess,
|
|
13912
|
-
docPermissionsAccess: planAccess,
|
|
13913
|
-
requestedSelect: originalSelect,
|
|
13914
|
-
plan: targetPlan,
|
|
13915
|
-
snapshot: targetSnapshot
|
|
13916
|
-
});
|
|
13917
|
-
} catch {
|
|
13918
|
-
}
|
|
13976
|
+
ret.match = deepIsolateValue(intersectFilters(match, filter2));
|
|
13977
|
+
const planAccess = populateAccess;
|
|
13978
|
+
const targetSnapshot = targetConfiguration;
|
|
13979
|
+
const targetPlan = planVirtualProjection({
|
|
13980
|
+
receivingModelName: refModelName,
|
|
13981
|
+
snapshot: {
|
|
13982
|
+
permissionSchema: targetSnapshot.permissionSchema,
|
|
13983
|
+
virtuals: targetSnapshot.virtuals,
|
|
13984
|
+
alwaysSelectFields: targetSnapshot.alwaysSelectFields,
|
|
13985
|
+
modelPermissionPrefix: targetSnapshot.modelPermissionPrefix,
|
|
13986
|
+
requireExplicitSelect: targetSnapshot.requireExplicitSelect,
|
|
13987
|
+
documentPermissionField: targetSnapshot.documentPermissionField
|
|
13988
|
+
},
|
|
13989
|
+
virtualAccess: planAccess,
|
|
13990
|
+
outputAccess: planAccess,
|
|
13991
|
+
docPermissionsAccess: planAccess,
|
|
13992
|
+
requestedSelect: originalSelect,
|
|
13993
|
+
internalFetch: { baseFields: ["_id"] },
|
|
13994
|
+
globalPermissions: permissions
|
|
13995
|
+
});
|
|
13996
|
+
const merged = uniq3([...normalizeSelect(ret.select), ...targetPlan.virtualOnlyDeps ?? []]).filter(
|
|
13997
|
+
(t) => t !== "-_id" && !t.includes(".sub.")
|
|
13998
|
+
);
|
|
13999
|
+
if (!merged.includes("_id")) merged.push("_id");
|
|
14000
|
+
ret.select = merged;
|
|
14001
|
+
setPopulateTargetMeta(ret, {
|
|
14002
|
+
targetModelName: refModelName,
|
|
14003
|
+
virtualAccess: planAccess,
|
|
14004
|
+
outputAccess: planAccess,
|
|
14005
|
+
docPermissionsAccess: planAccess,
|
|
14006
|
+
requestedSelect: originalSelect,
|
|
14007
|
+
plan: targetPlan,
|
|
14008
|
+
snapshot: targetSnapshot
|
|
14009
|
+
});
|
|
13919
14010
|
return ret;
|
|
13920
14011
|
})
|
|
13921
14012
|
)
|
|
@@ -14239,12 +14330,12 @@ function guard(condition) {
|
|
|
14239
14330
|
const permissions = req[PERMISSIONS];
|
|
14240
14331
|
let cond = condition;
|
|
14241
14332
|
let phas = (key) => permissions.has(key);
|
|
14242
|
-
if (
|
|
14333
|
+
if (isPlainObject27(condition)) {
|
|
14243
14334
|
const { modelName, id, condition: _cond } = condition;
|
|
14244
14335
|
const svc = req.macl.getPublicService(modelName);
|
|
14245
14336
|
const select = getModelOption(modelName, `alwaysSelectFields.read`, void 0);
|
|
14246
14337
|
let _id = isString7(id) ? id : null;
|
|
14247
|
-
if (
|
|
14338
|
+
if (isPlainObject27(id)) {
|
|
14248
14339
|
const { type = "param", key } = id;
|
|
14249
14340
|
if (type === "param") {
|
|
14250
14341
|
const paramValue = req.params[key];
|
|
@@ -14286,7 +14377,7 @@ import express2 from "express";
|
|
|
14286
14377
|
|
|
14287
14378
|
// src/routers/model-router.ts
|
|
14288
14379
|
import JsonRouter8 from "@web-ts-toolkit/express-json-router";
|
|
14289
|
-
import { forEach as forEach7, isPlainObject as
|
|
14380
|
+
import { forEach as forEach7, isPlainObject as isPlainObject29, isString as isString8, isUndefined as isUndefined2, normalizeUrlPath as normalizeUrlPath3, padEnd } from "@web-ts-toolkit/utils";
|
|
14290
14381
|
init_logger_helpers();
|
|
14291
14382
|
init_runtime();
|
|
14292
14383
|
init_runtime_context();
|
|
@@ -14420,7 +14511,7 @@ import JsonRouter7 from "@web-ts-toolkit/express-json-router";
|
|
|
14420
14511
|
|
|
14421
14512
|
// src/validation/common.ts
|
|
14422
14513
|
import { z as z2 } from "zod";
|
|
14423
|
-
import { isPlainObject as
|
|
14514
|
+
import { isPlainObject as isPlainObject28 } from "@web-ts-toolkit/utils";
|
|
14424
14515
|
|
|
14425
14516
|
// src/validation/public-admission-schema.ts
|
|
14426
14517
|
init_public_admission();
|
|
@@ -14549,7 +14640,7 @@ var correlatedFilterSchema = z2.record(z2.string(), z2.unknown()).superRefine((f
|
|
|
14549
14640
|
}
|
|
14550
14641
|
});
|
|
14551
14642
|
var correlatedEmptyOptionsSchema = z2.unknown().refine(
|
|
14552
|
-
(value) => value === void 0 ||
|
|
14643
|
+
(value) => value === void 0 || isPlainObject28(value) && Object.keys(value).length === 0,
|
|
14553
14644
|
"Correlated include options must be absent or empty"
|
|
14554
14645
|
).optional();
|
|
14555
14646
|
var correlatedPathSchema = z2.string().min(1).superRefine((path, ctx) => {
|
|
@@ -14586,7 +14677,7 @@ var correlatedListArgsSchema = z2.object({
|
|
|
14586
14677
|
include: z2.lazy(() => correlatedNestedIncludeSchema).optional()
|
|
14587
14678
|
}).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
|
|
14588
14679
|
var correlatedCountArgsSchema = z2.unknown().refine(
|
|
14589
|
-
(value) => value === void 0 ||
|
|
14680
|
+
(value) => value === void 0 || isPlainObject28(value) && Object.keys(value).length === 0,
|
|
14590
14681
|
"Count includes accept no args"
|
|
14591
14682
|
).optional();
|
|
14592
14683
|
var correlatedReadByIdSchema = z2.object({
|
|
@@ -14639,7 +14730,7 @@ var correlatedNestedIncludeSchema = z2.union([includeItemSchema, z2.array(includ
|
|
|
14639
14730
|
var rejectDuplicateCorrelatedPaths = (items, ctx) => {
|
|
14640
14731
|
const seen = /* @__PURE__ */ new Set();
|
|
14641
14732
|
items.forEach((item, index) => {
|
|
14642
|
-
if (
|
|
14733
|
+
if (isPlainObject28(item) && item.mode === "correlated" && typeof item.path === "string") {
|
|
14643
14734
|
if (seen.has(item.path)) {
|
|
14644
14735
|
ctx.addIssue({
|
|
14645
14736
|
code: z2.ZodIssueCode.custom,
|
|
@@ -16640,7 +16731,7 @@ var ModelRouter = class _ModelRouter {
|
|
|
16640
16731
|
value
|
|
16641
16732
|
);
|
|
16642
16733
|
}
|
|
16643
|
-
if (arguments.length === 1 &&
|
|
16734
|
+
if (arguments.length === 1 && isPlainObject29(keyOrOptions)) {
|
|
16644
16735
|
assertMutableRouterOptions("model", keyOrOptions);
|
|
16645
16736
|
this.runtime.setModelOptions(
|
|
16646
16737
|
this.modelName,
|
|
@@ -17174,7 +17265,7 @@ var RootRouter = class {
|
|
|
17174
17265
|
|
|
17175
17266
|
// src/routers/data-router.ts
|
|
17176
17267
|
import JsonRouter10 from "@web-ts-toolkit/express-json-router";
|
|
17177
|
-
import { isPlainObject as
|
|
17268
|
+
import { isPlainObject as isPlainObject30, isString as isString9, isUndefined as isUndefined3, normalizeUrlPath as normalizeUrlPath5 } from "@web-ts-toolkit/utils";
|
|
17178
17269
|
init_runtime();
|
|
17179
17270
|
init_helpers();
|
|
17180
17271
|
init_schemas();
|
|
@@ -17390,7 +17481,7 @@ var DataRouter = class {
|
|
|
17390
17481
|
value
|
|
17391
17482
|
);
|
|
17392
17483
|
}
|
|
17393
|
-
if (arguments.length === 1 &&
|
|
17484
|
+
if (arguments.length === 1 && isPlainObject30(keyOrOptions)) {
|
|
17394
17485
|
assertMutableRouterOptions("data", keyOrOptions);
|
|
17395
17486
|
this.runtime.setDataOptions(this.dataName, keyOrOptions);
|
|
17396
17487
|
}
|
|
@@ -17549,7 +17640,7 @@ function createRuntimeApi(runtime) {
|
|
|
17549
17640
|
if (arguments.length === 2 && isString10(keyOrOptions)) {
|
|
17550
17641
|
return runtime.setGlobalOption(keyOrOptions, value);
|
|
17551
17642
|
}
|
|
17552
|
-
if (arguments.length === 1 &&
|
|
17643
|
+
if (arguments.length === 1 && isPlainObject31(keyOrOptions)) {
|
|
17553
17644
|
return runtime.setGlobalOptions(keyOrOptions);
|
|
17554
17645
|
}
|
|
17555
17646
|
};
|