@web-ts-toolkit/access-router 0.47.1 → 0.49.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 +529 -1
- package/advanced.d.mts +110 -13
- package/advanced.d.ts +110 -13
- package/advanced.js +422 -20
- package/advanced.mjs +424 -21
- package/index.d.mts +134 -45
- package/index.d.ts +134 -45
- package/index.js +8837 -4773
- package/index.mjs +8786 -4712
- package/llms.txt +138 -2
- package/package.json +3 -3
- package/{parsers-BidvJUu7.d.mts → parsers-DhUuvj9B.d.mts} +941 -55
- package/{parsers-BidvJUu7.d.ts → parsers-DhUuvj9B.d.ts} +941 -55
package/advanced.js
CHANGED
|
@@ -888,11 +888,11 @@ var classifyPermissionSchema = (permissionSchema, modelPermissionPrefix) => {
|
|
|
888
888
|
}
|
|
889
889
|
if ((0, import_utils8.isBoolean)(value)) {
|
|
890
890
|
globalPermissionKeys[accessKey].push(schemaKey);
|
|
891
|
-
|
|
891
|
+
continue;
|
|
892
892
|
}
|
|
893
893
|
if (hasModelPermission(value, modelPermissionPrefix)) {
|
|
894
894
|
modelPermissionKeys[accessKey].push(schemaKey);
|
|
895
|
-
|
|
895
|
+
continue;
|
|
896
896
|
}
|
|
897
897
|
globalPermissionKeys[accessKey].push(schemaKey);
|
|
898
898
|
}
|
|
@@ -913,6 +913,286 @@ var refreshPermissionMetadata = (target) => {
|
|
|
913
913
|
target._globalPermissionKeys = globalPermissionKeys;
|
|
914
914
|
target._modelPermissionKeys = modelPermissionKeys;
|
|
915
915
|
};
|
|
916
|
+
var VIRTUAL_SUPPORTED_ACCESSES = ["default", "list", "create", "read", "update"];
|
|
917
|
+
var VIRTUAL_UNSUPPORTED_ACCESSES = ["delete", "distinct", "count"];
|
|
918
|
+
var VIRTUAL_RESERVED_NAMES = /* @__PURE__ */ new Set(["_id", "__v", "id"]);
|
|
919
|
+
var VIRTUAL_DANGEROUS_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
920
|
+
var VIRTUAL_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
921
|
+
var isVirtualContainerValue = (value) => (0, import_utils8.isPlainObject)(value) && "sub" in value;
|
|
922
|
+
var virtualFullPath = (prefix, name) => prefix ? `${prefix}.${name}` : name;
|
|
923
|
+
var virtualPathsOverlap = (virtualPath, permissionField) => {
|
|
924
|
+
if (!virtualPath || !permissionField) return false;
|
|
925
|
+
try {
|
|
926
|
+
if ((0, import_utils8.get)((0, import_utils8.set)({}, virtualPath, true), permissionField) !== void 0) return true;
|
|
927
|
+
if ((0, import_utils8.get)((0, import_utils8.set)({}, permissionField, true), virtualPath) !== void 0) return true;
|
|
928
|
+
} catch {
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
return false;
|
|
932
|
+
};
|
|
933
|
+
var collectStoredTopLevel = (schema) => {
|
|
934
|
+
const fields = /* @__PURE__ */ new Set();
|
|
935
|
+
if (!schema) return fields;
|
|
936
|
+
const paths = schema.paths;
|
|
937
|
+
if (paths) {
|
|
938
|
+
for (const p of Object.keys(paths)) {
|
|
939
|
+
const top = p.split(".")[0];
|
|
940
|
+
if (top) fields.add(top);
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
const obj = schema.obj;
|
|
944
|
+
if (obj) {
|
|
945
|
+
for (const k of Object.keys(obj)) fields.add(k);
|
|
946
|
+
}
|
|
947
|
+
return fields;
|
|
948
|
+
};
|
|
949
|
+
var getChildSchemaForField = (parentSchema, fieldName) => {
|
|
950
|
+
if (!parentSchema) return null;
|
|
951
|
+
try {
|
|
952
|
+
const pathType = parentSchema.path?.(fieldName);
|
|
953
|
+
if (pathType && typeof pathType === "object") {
|
|
954
|
+
if (pathType.schema) return pathType.schema;
|
|
955
|
+
if (pathType.caster?.schema) return pathType.caster.schema;
|
|
956
|
+
}
|
|
957
|
+
} catch {
|
|
958
|
+
return null;
|
|
959
|
+
}
|
|
960
|
+
return null;
|
|
961
|
+
};
|
|
962
|
+
var getNestedChildFields = (parentSchema, fieldName) => {
|
|
963
|
+
const fields = /* @__PURE__ */ new Set();
|
|
964
|
+
if (!parentSchema) return fields;
|
|
965
|
+
const paths = parentSchema.paths;
|
|
966
|
+
if (paths) {
|
|
967
|
+
const prefix = `${fieldName}.`;
|
|
968
|
+
for (const p of Object.keys(paths)) {
|
|
969
|
+
if (p.startsWith(prefix)) {
|
|
970
|
+
const rest = p.slice(prefix.length);
|
|
971
|
+
const top = rest.split(".")[0];
|
|
972
|
+
if (top) fields.add(top);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
return fields;
|
|
977
|
+
};
|
|
978
|
+
var cloneVirtualsForValidation = (value) => {
|
|
979
|
+
if (Array.isArray(value)) return value.map((item) => cloneVirtualsForValidation(item));
|
|
980
|
+
if (!value || typeof value !== "object") return value;
|
|
981
|
+
if (Object.getPrototypeOf(value) !== Object.prototype) return value;
|
|
982
|
+
return Object.fromEntries(
|
|
983
|
+
Object.entries(value).map(([k, v]) => [k, cloneVirtualsForValidation(v)])
|
|
984
|
+
);
|
|
985
|
+
};
|
|
986
|
+
var validateVirtualDependsOn = (dependsOn, entryLabel, storedFields, siblingVirtualNames) => {
|
|
987
|
+
if (dependsOn === void 0) return [];
|
|
988
|
+
if (!(0, import_utils8.isArray)(dependsOn)) {
|
|
989
|
+
throw new Error(`Virtual ${entryLabel}: dependsOn must be an array of top-level persisted field names`);
|
|
990
|
+
}
|
|
991
|
+
const list = dependsOn;
|
|
992
|
+
for (const dep of list) {
|
|
993
|
+
if (!(0, import_utils8.isString)(dep) || dep.length === 0) {
|
|
994
|
+
throw new Error(`Virtual ${entryLabel}: dependsOn entries must be non-empty strings`);
|
|
995
|
+
}
|
|
996
|
+
if (dep.includes(".")) {
|
|
997
|
+
throw new Error(
|
|
998
|
+
`Virtual ${entryLabel}: dependsOn "${dep}" must be a top-level persisted name relative to its scope (dotted paths rejected)`
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
if (siblingVirtualNames.has(dep)) {
|
|
1002
|
+
throw new Error(
|
|
1003
|
+
`Virtual ${entryLabel}: dependsOn "${dep}" must not reference another virtual (virtual-to-virtual rejected)`
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
if (!storedFields.has(dep)) {
|
|
1007
|
+
throw new Error(
|
|
1008
|
+
`Virtual ${entryLabel}: dependsOn "${dep}" is not a persisted field in its scope (validated against the receiving Mongoose schema/child scope)`
|
|
1009
|
+
);
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
return list;
|
|
1013
|
+
};
|
|
1014
|
+
var validateVirtualLeafValue = (value, entryLabel, storedFields, siblingVirtualNames, sharedDependsOn) => {
|
|
1015
|
+
if ((0, import_utils8.isFunction)(value)) return;
|
|
1016
|
+
if (!(0, import_utils8.isPlainObject)(value)) {
|
|
1017
|
+
throw new Error(`Virtual ${entryLabel}: descriptor must be a getter function or { get, dependsOn }`);
|
|
1018
|
+
}
|
|
1019
|
+
const record = value;
|
|
1020
|
+
if (!(0, import_utils8.isFunction)(record.get)) {
|
|
1021
|
+
throw new Error(`Virtual ${entryLabel}: descriptor.get must be a callable getter function`);
|
|
1022
|
+
}
|
|
1023
|
+
validateVirtualDependsOn(record.dependsOn ?? sharedDependsOn, entryLabel, storedFields, siblingVirtualNames);
|
|
1024
|
+
for (const k of Object.keys(record)) {
|
|
1025
|
+
if (k !== "get" && k !== "dependsOn") {
|
|
1026
|
+
throw new Error(`Virtual ${entryLabel}: unsupported descriptor key "${k}" (expected only get/dependsOn)`);
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
var validateVirtualsScope = (scope, documentPermissionField) => {
|
|
1031
|
+
const { scopeVirtuals, storedFields, scopePrefix, scopeLabel } = scope;
|
|
1032
|
+
const leafNames = /* @__PURE__ */ new Set();
|
|
1033
|
+
for (const [name, raw] of Object.entries(scopeVirtuals)) {
|
|
1034
|
+
if (raw === void 0) continue;
|
|
1035
|
+
if (isVirtualContainerValue(raw)) continue;
|
|
1036
|
+
leafNames.add(name);
|
|
1037
|
+
}
|
|
1038
|
+
for (const [name, raw] of Object.entries(scopeVirtuals)) {
|
|
1039
|
+
if (raw === void 0) continue;
|
|
1040
|
+
if (name.includes(".")) {
|
|
1041
|
+
throw new Error(`Virtual ${scopeLabel}${name}: dotted definition names are rejected (use sub scopes)`);
|
|
1042
|
+
}
|
|
1043
|
+
if (VIRTUAL_DANGEROUS_SEGMENTS.has(name) || VIRTUAL_RESERVED_NAMES.has(name) || name.startsWith("$") || !VIRTUAL_NAME_PATTERN.test(name)) {
|
|
1044
|
+
throw new Error(`Virtual ${scopeLabel}${name}: "_id"/reserved internal paths are rejected`);
|
|
1045
|
+
}
|
|
1046
|
+
const fullPath = virtualFullPath(scopePrefix, name);
|
|
1047
|
+
if (virtualPathsOverlap(fullPath, documentPermissionField)) {
|
|
1048
|
+
throw new Error(
|
|
1049
|
+
`Virtual ${scopeLabel}${name}: overlaps document permission field "${documentPermissionField}" (equal/ancestor/descendant rejected)`
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
if (isVirtualContainerValue(raw)) {
|
|
1053
|
+
const record2 = raw;
|
|
1054
|
+
const extra = Object.keys(record2).filter((k) => k !== "sub");
|
|
1055
|
+
if (extra.length > 0) {
|
|
1056
|
+
throw new Error(
|
|
1057
|
+
`Virtual ${scopeLabel}${name}: scope-container must only hold "sub" (embedded container "${name}" is not a virtual-leaf collision)`
|
|
1058
|
+
);
|
|
1059
|
+
}
|
|
1060
|
+
if (!(0, import_utils8.isPlainObject)(record2.sub)) {
|
|
1061
|
+
throw new Error(`Virtual ${scopeLabel}${name}: scope-container "sub" must be a plain object`);
|
|
1062
|
+
}
|
|
1063
|
+
continue;
|
|
1064
|
+
}
|
|
1065
|
+
if (storedFields.has(name)) {
|
|
1066
|
+
throw new Error(
|
|
1067
|
+
`Virtual ${scopeLabel}${name}: collides with a stored path (inspected actual Mongoose schema/child scope; getModelAtt alone is insufficient)`
|
|
1068
|
+
);
|
|
1069
|
+
}
|
|
1070
|
+
if ((0, import_utils8.isFunction)(raw)) continue;
|
|
1071
|
+
if (!(0, import_utils8.isPlainObject)(raw)) {
|
|
1072
|
+
throw new Error(
|
|
1073
|
+
`Virtual ${scopeLabel}${name}: malformed descriptor (expected getter, { get, dependsOn }, or per-access record)`
|
|
1074
|
+
);
|
|
1075
|
+
}
|
|
1076
|
+
const record = raw;
|
|
1077
|
+
const hasGet = "get" in record;
|
|
1078
|
+
const accessKeys = Object.keys(record).filter((k) => VIRTUAL_SUPPORTED_ACCESSES.includes(k));
|
|
1079
|
+
const unsupported = Object.keys(record).filter(
|
|
1080
|
+
(k) => k !== "get" && k !== "dependsOn" && k !== "sub" && !VIRTUAL_SUPPORTED_ACCESSES.includes(k)
|
|
1081
|
+
);
|
|
1082
|
+
for (const key of Object.keys(record)) {
|
|
1083
|
+
if (VIRTUAL_UNSUPPORTED_ACCESSES.includes(key)) {
|
|
1084
|
+
throw new Error(
|
|
1085
|
+
`Virtual ${scopeLabel}${name}: unsupported access "${key}" (supported: default + list/create/read/update; NOT delete/distinct/count)`
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
if (unsupported.length > 0) {
|
|
1090
|
+
throw new Error(
|
|
1091
|
+
`Virtual ${scopeLabel}${name}: unsupported access/key "${unsupported[0]}" (supported: default + list/create/read/update)`
|
|
1092
|
+
);
|
|
1093
|
+
}
|
|
1094
|
+
if (hasGet) {
|
|
1095
|
+
if (accessKeys.length > 0) {
|
|
1096
|
+
throw new Error(
|
|
1097
|
+
`Virtual ${scopeLabel}${name}: cannot mix "get" with per-access keys (use either bare { get, dependsOn } or a per-access record)`
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
if ("sub" in record) {
|
|
1101
|
+
throw new Error(`Virtual ${scopeLabel}${name}: cannot mix "get" with "sub" (leaf vs embedded container)`);
|
|
1102
|
+
}
|
|
1103
|
+
validateVirtualLeafValue(raw, `${scopeLabel}${name}`, storedFields, leafNames, void 0);
|
|
1104
|
+
continue;
|
|
1105
|
+
}
|
|
1106
|
+
if (accessKeys.length > 0) {
|
|
1107
|
+
if ("sub" in record) {
|
|
1108
|
+
throw new Error(`Virtual ${scopeLabel}${name}: cannot mix per-access keys with "sub"`);
|
|
1109
|
+
}
|
|
1110
|
+
validateVirtualDependsOn(record.dependsOn, `${scopeLabel}${name}`, storedFields, leafNames);
|
|
1111
|
+
for (const access of accessKeys) {
|
|
1112
|
+
const leaf = record[access];
|
|
1113
|
+
if (leaf === void 0) continue;
|
|
1114
|
+
validateVirtualLeafValue(leaf, `${scopeLabel}${name}.${access}`, storedFields, leafNames, record.dependsOn);
|
|
1115
|
+
}
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
throw new Error(
|
|
1119
|
+
`Virtual ${scopeLabel}${name}: malformed descriptor (expected getter, { get, dependsOn }, or per-access record with default/list/create/read/update)`
|
|
1120
|
+
);
|
|
1121
|
+
}
|
|
1122
|
+
};
|
|
1123
|
+
var validateVirtualsTree = (model, virtuals, documentPermissionField, modelName) => {
|
|
1124
|
+
if (virtuals === void 0 || virtuals === null) return;
|
|
1125
|
+
if (!(0, import_utils8.isPlainObject)(virtuals)) {
|
|
1126
|
+
throw new Error(`Virtuals for model "${modelName}": virtuals must be a plain object mapping names to descriptors`);
|
|
1127
|
+
}
|
|
1128
|
+
const rootSchema = model?.schema ?? null;
|
|
1129
|
+
const rootStored = collectStoredTopLevel(rootSchema);
|
|
1130
|
+
const rootVirtuals = virtuals;
|
|
1131
|
+
validateVirtualsScope(
|
|
1132
|
+
{ scopeVirtuals: rootVirtuals, storedFields: rootStored, scopePrefix: "", scopeLabel: "" },
|
|
1133
|
+
documentPermissionField
|
|
1134
|
+
);
|
|
1135
|
+
const visitContainers = (currentVirtuals, currentSchema, currentPrefix) => {
|
|
1136
|
+
for (const [containerName, raw] of Object.entries(currentVirtuals)) {
|
|
1137
|
+
if (raw === void 0 || !isVirtualContainerValue(raw)) continue;
|
|
1138
|
+
const record = raw;
|
|
1139
|
+
const childSchema = getChildSchemaForField(currentSchema, containerName);
|
|
1140
|
+
const nestedFields = getNestedChildFields(currentSchema, containerName);
|
|
1141
|
+
const currentStored = collectStoredTopLevel(currentSchema);
|
|
1142
|
+
if (!currentStored.has(containerName)) {
|
|
1143
|
+
throw new Error(
|
|
1144
|
+
`Virtual ${containerName}: scope-container "${containerName}" is not a persisted field in its scope`
|
|
1145
|
+
);
|
|
1146
|
+
}
|
|
1147
|
+
const isEmbedded = childSchema !== null || nestedFields.size > 0;
|
|
1148
|
+
if (!isEmbedded) {
|
|
1149
|
+
throw new Error(
|
|
1150
|
+
`Virtual ${containerName}: scope-container "${containerName}" must be an embedded field with a child scope`
|
|
1151
|
+
);
|
|
1152
|
+
}
|
|
1153
|
+
const subStored = childSchema ? collectStoredTopLevel(childSchema) : nestedFields;
|
|
1154
|
+
const subPrefix = currentPrefix ? `${currentPrefix}.${containerName}` : containerName;
|
|
1155
|
+
const subVirtuals = record.sub ?? {};
|
|
1156
|
+
validateVirtualsScope(
|
|
1157
|
+
{
|
|
1158
|
+
scopeVirtuals: subVirtuals,
|
|
1159
|
+
storedFields: subStored,
|
|
1160
|
+
scopePrefix: subPrefix,
|
|
1161
|
+
scopeLabel: `${subPrefix}.sub.`
|
|
1162
|
+
},
|
|
1163
|
+
documentPermissionField
|
|
1164
|
+
);
|
|
1165
|
+
const nextSchema = childSchema;
|
|
1166
|
+
visitContainers(subVirtuals, nextSchema, subPrefix);
|
|
1167
|
+
}
|
|
1168
|
+
};
|
|
1169
|
+
visitContainers(rootVirtuals, rootSchema, "");
|
|
1170
|
+
};
|
|
1171
|
+
var getScopeVirtualsObject = (rootVirtuals, scopePath) => {
|
|
1172
|
+
if (!rootVirtuals || !(0, import_utils8.isPlainObject)(rootVirtuals)) return null;
|
|
1173
|
+
if (!scopePath || scopePath.length === 0) return rootVirtuals;
|
|
1174
|
+
let current = rootVirtuals;
|
|
1175
|
+
for (let i = 0; i < scopePath.length; i += 2) {
|
|
1176
|
+
const field = scopePath[i];
|
|
1177
|
+
const subMarker = scopePath[i + 1];
|
|
1178
|
+
if (!field || subMarker !== "sub") return null;
|
|
1179
|
+
if (!(0, import_utils8.isPlainObject)(current)) return null;
|
|
1180
|
+
const container = current[field];
|
|
1181
|
+
if (!isVirtualContainerValue(container)) return null;
|
|
1182
|
+
current = container.sub;
|
|
1183
|
+
if (!(0, import_utils8.isPlainObject)(current)) return null;
|
|
1184
|
+
}
|
|
1185
|
+
return current;
|
|
1186
|
+
};
|
|
1187
|
+
var toVirtualDescriptor = (leaf, sharedDependsOn) => {
|
|
1188
|
+
if ((0, import_utils8.isFunction)(leaf))
|
|
1189
|
+
return { get: leaf, dependsOn: sharedDependsOn ?? [] };
|
|
1190
|
+
if (!(0, import_utils8.isPlainObject)(leaf)) return null;
|
|
1191
|
+
const record = leaf;
|
|
1192
|
+
if (!(0, import_utils8.isFunction)(record.get)) return null;
|
|
1193
|
+
const dependsOn = record.dependsOn ?? sharedDependsOn ?? [];
|
|
1194
|
+
return { get: record.get, dependsOn };
|
|
1195
|
+
};
|
|
916
1196
|
var AccessRuntime = class {
|
|
917
1197
|
constructor(options = {}) {
|
|
918
1198
|
this.globalOptions = new OptionsManager(
|
|
@@ -1150,10 +1430,46 @@ var AccessRuntime = class {
|
|
|
1150
1430
|
const manager = this.getOrCreateModelOptions(modelName);
|
|
1151
1431
|
const defaultOptions = this.getDefaultModelOptions();
|
|
1152
1432
|
const currentModelOptions = manager.fetch();
|
|
1433
|
+
const merged = { ...defaultOptions, ...currentModelOptions, ...options };
|
|
1434
|
+
const model = this.getModelInstance(modelName);
|
|
1435
|
+
const permissionField = merged.documentPermissionField ?? currentModelOptions.documentPermissionField ?? this.getDefaultModelOption("documentPermissionField") ?? "_permissions";
|
|
1436
|
+
validateVirtualsTree(model, merged.virtuals, permissionField, modelName);
|
|
1153
1437
|
manager.assign({ ...defaultOptions, ...currentModelOptions, ...options });
|
|
1154
1438
|
}
|
|
1155
1439
|
setModelOption(modelName, key, value) {
|
|
1156
1440
|
const manager = this.getOrCreateModelOptions(modelName);
|
|
1441
|
+
const keyStr = String(key);
|
|
1442
|
+
if (keyStr === "virtuals" || keyStr.startsWith("virtuals.") || keyStr === "documentPermissionField") {
|
|
1443
|
+
const model = this.getModelInstance(modelName);
|
|
1444
|
+
const currentVirtuals = manager.get("virtuals");
|
|
1445
|
+
const currentPermissionField = manager.get("documentPermissionField") ?? this.getDefaultModelOption("documentPermissionField") ?? "_permissions";
|
|
1446
|
+
let proposedVirtuals = currentVirtuals;
|
|
1447
|
+
let proposedPermissionField = currentPermissionField;
|
|
1448
|
+
if (keyStr === "documentPermissionField") {
|
|
1449
|
+
proposedPermissionField = value;
|
|
1450
|
+
} else if (keyStr === "virtuals") {
|
|
1451
|
+
proposedVirtuals = value;
|
|
1452
|
+
} else {
|
|
1453
|
+
const cloned = cloneVirtualsForValidation(currentVirtuals ?? {});
|
|
1454
|
+
const nestedPath = keyStr.slice("virtuals.".length);
|
|
1455
|
+
if (value === void 0) {
|
|
1456
|
+
const segments = nestedPath.split(".");
|
|
1457
|
+
let cursor = cloned;
|
|
1458
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1459
|
+
if (!(0, import_utils8.isPlainObject)(cursor)) break;
|
|
1460
|
+
cursor = cursor[segments[i]];
|
|
1461
|
+
}
|
|
1462
|
+
if ((0, import_utils8.isPlainObject)(cursor)) {
|
|
1463
|
+
delete cursor[segments[segments.length - 1]];
|
|
1464
|
+
}
|
|
1465
|
+
proposedVirtuals = cloned;
|
|
1466
|
+
} else {
|
|
1467
|
+
(0, import_utils8.set)(cloned, nestedPath, value);
|
|
1468
|
+
proposedVirtuals = cloned;
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
validateVirtualsTree(model, proposedVirtuals, proposedPermissionField, modelName);
|
|
1472
|
+
}
|
|
1157
1473
|
manager.set(key, value);
|
|
1158
1474
|
}
|
|
1159
1475
|
getModelOptions(modelName) {
|
|
@@ -1173,6 +1489,71 @@ var AccessRuntime = class {
|
|
|
1173
1489
|
const defaultModelValue = this.getDefaultModelOption(key);
|
|
1174
1490
|
return manager.get(key, defaultModelValue);
|
|
1175
1491
|
}
|
|
1492
|
+
/**
|
|
1493
|
+
* List registered virtual leaf names for a scope (VIRT-01).
|
|
1494
|
+
* Scope containers (`{ sub }`) are not leaves. Inapplicable names are
|
|
1495
|
+
* still listed here; applicability is decided per-access by
|
|
1496
|
+
* {@link resolveVirtualDescriptor}. Request-controlled include collisions
|
|
1497
|
+
* are validated by VIRT-05, not guessed here.
|
|
1498
|
+
*/
|
|
1499
|
+
getVirtualNames(modelName, scopePath) {
|
|
1500
|
+
const manager = this.getOrCreateModelOptions(modelName);
|
|
1501
|
+
const rootVirtuals = manager.get("virtuals");
|
|
1502
|
+
const scopeVirtuals = getScopeVirtualsObject(rootVirtuals, scopePath);
|
|
1503
|
+
if (!scopeVirtuals) return [];
|
|
1504
|
+
return Object.entries(scopeVirtuals).filter(([, v]) => v !== void 0 && !isVirtualContainerValue(v)).map(([k]) => k);
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* Whether a field is a registered virtual leaf in a scope (VIRT-01).
|
|
1508
|
+
* Inapplicable registered names stay virtual (never persisted), even when
|
|
1509
|
+
* no getter applies for the current access. Containers and persisted
|
|
1510
|
+
* fields return false.
|
|
1511
|
+
*/
|
|
1512
|
+
isVirtualField(modelName, fieldName, scopePath) {
|
|
1513
|
+
const manager = this.getOrCreateModelOptions(modelName);
|
|
1514
|
+
const rootVirtuals = manager.get("virtuals");
|
|
1515
|
+
const scopeVirtuals = getScopeVirtualsObject(rootVirtuals, scopePath);
|
|
1516
|
+
if (!scopeVirtuals || !(fieldName in scopeVirtuals)) return false;
|
|
1517
|
+
const entry = scopeVirtuals[fieldName];
|
|
1518
|
+
if (entry === void 0 || isVirtualContainerValue(entry)) return false;
|
|
1519
|
+
return true;
|
|
1520
|
+
}
|
|
1521
|
+
/**
|
|
1522
|
+
* Resolve an applicable virtual descriptor with exact → `.default` → bare
|
|
1523
|
+
* semantics (VIRT-01, VIRT-00A D1/D5). Returns `undefined` when no getter
|
|
1524
|
+
* applies for `access`. Crucially, an access-record object is NEVER
|
|
1525
|
+
* interpreted as a getter descriptor when the access is absent: an
|
|
1526
|
+
* inapplicable registered name stays virtual (excluded from persisted
|
|
1527
|
+
* projections, write admission, and DB sort/filter/distinct).
|
|
1528
|
+
* Shared record-level `dependsOn` is inherited when a leaf lacks its own.
|
|
1529
|
+
*/
|
|
1530
|
+
resolveVirtualDescriptor(modelName, virtualName, access, scopePath) {
|
|
1531
|
+
const manager = this.getOrCreateModelOptions(modelName);
|
|
1532
|
+
const rootVirtuals = manager.get("virtuals");
|
|
1533
|
+
const scopeVirtuals = getScopeVirtualsObject(rootVirtuals, scopePath);
|
|
1534
|
+
if (!scopeVirtuals || !(virtualName in scopeVirtuals)) return void 0;
|
|
1535
|
+
const entry = scopeVirtuals[virtualName];
|
|
1536
|
+
if (entry === void 0 || isVirtualContainerValue(entry)) return void 0;
|
|
1537
|
+
if ((0, import_utils8.isFunction)(entry)) return { get: entry, dependsOn: [] };
|
|
1538
|
+
if (!(0, import_utils8.isPlainObject)(entry)) return void 0;
|
|
1539
|
+
const record = entry;
|
|
1540
|
+
if ("get" in record) {
|
|
1541
|
+
const descriptor = toVirtualDescriptor(entry, void 0);
|
|
1542
|
+
return descriptor ?? void 0;
|
|
1543
|
+
}
|
|
1544
|
+
const sharedDependsOn = record.dependsOn;
|
|
1545
|
+
const exact = record[access];
|
|
1546
|
+
if (exact !== void 0) {
|
|
1547
|
+
const descriptor = toVirtualDescriptor(exact, sharedDependsOn);
|
|
1548
|
+
if (descriptor) return descriptor;
|
|
1549
|
+
}
|
|
1550
|
+
const fallback = record.default;
|
|
1551
|
+
if (fallback !== void 0) {
|
|
1552
|
+
const descriptor = toVirtualDescriptor(fallback, sharedDependsOn);
|
|
1553
|
+
if (descriptor) return descriptor;
|
|
1554
|
+
}
|
|
1555
|
+
return void 0;
|
|
1556
|
+
}
|
|
1176
1557
|
getModelNames() {
|
|
1177
1558
|
return Object.keys(this.modelOptions);
|
|
1178
1559
|
}
|
|
@@ -1471,6 +1852,7 @@ var sortSchema = import_zod2.z.union([
|
|
|
1471
1852
|
import_zod2.z.array(import_zod2.z.tuple([import_zod2.z.string(), sortOrderSchema])),
|
|
1472
1853
|
import_zod2.z.null()
|
|
1473
1854
|
]);
|
|
1855
|
+
var populateAccessSchema = import_zod2.z.enum(["list", "read"]);
|
|
1474
1856
|
var populateSchema = import_zod2.z.union([
|
|
1475
1857
|
import_zod2.z.string(),
|
|
1476
1858
|
import_zod2.z.array(
|
|
@@ -1480,7 +1862,7 @@ var populateSchema = import_zod2.z.union([
|
|
|
1480
1862
|
path: import_zod2.z.string().min(1),
|
|
1481
1863
|
select: projectionSchema.optional(),
|
|
1482
1864
|
match: import_zod2.z.unknown().optional(),
|
|
1483
|
-
access:
|
|
1865
|
+
access: populateAccessSchema.optional()
|
|
1484
1866
|
}).passthrough()
|
|
1485
1867
|
])
|
|
1486
1868
|
),
|
|
@@ -1488,7 +1870,7 @@ var populateSchema = import_zod2.z.union([
|
|
|
1488
1870
|
path: import_zod2.z.string().min(1),
|
|
1489
1871
|
select: projectionSchema.optional(),
|
|
1490
1872
|
match: import_zod2.z.unknown().optional(),
|
|
1491
|
-
access:
|
|
1873
|
+
access: populateAccessSchema.optional()
|
|
1492
1874
|
}).passthrough()
|
|
1493
1875
|
]);
|
|
1494
1876
|
var subPopulateSchema = import_zod2.z.union([
|
|
@@ -2152,23 +2534,32 @@ var listQuerySchema = import_zod3.z.object({
|
|
|
2152
2534
|
page_size: positiveIntegerString.optional(),
|
|
2153
2535
|
skim: queryBooleanString.optional(),
|
|
2154
2536
|
include_permissions: queryBooleanString.optional(),
|
|
2537
|
+
include_field_permissions: queryBooleanString.optional(),
|
|
2155
2538
|
include_count: queryBooleanString.optional(),
|
|
2156
|
-
include_extra_headers: queryBooleanString.optional()
|
|
2539
|
+
include_extra_headers: queryBooleanString.optional(),
|
|
2540
|
+
select: stringOrStringArray.optional(),
|
|
2541
|
+
sort: import_zod3.z.string().optional().describe("Space-separated sort fields; prefix a field with - for descending order.")
|
|
2157
2542
|
}).passthrough();
|
|
2158
2543
|
var createQuerySchema = import_zod3.z.object({
|
|
2159
|
-
include_permissions: queryBooleanString.optional()
|
|
2544
|
+
include_permissions: queryBooleanString.optional(),
|
|
2545
|
+
include_field_permissions: queryBooleanString.optional()
|
|
2160
2546
|
}).passthrough();
|
|
2161
2547
|
var readQuerySchema = import_zod3.z.object({
|
|
2162
2548
|
include_permissions: queryBooleanString.optional(),
|
|
2163
|
-
|
|
2549
|
+
include_field_permissions: queryBooleanString.optional(),
|
|
2550
|
+
try_list: queryBooleanString.optional(),
|
|
2551
|
+
select: stringOrStringArray.optional()
|
|
2164
2552
|
}).passthrough();
|
|
2165
2553
|
var updateQuerySchema = import_zod3.z.object({
|
|
2166
2554
|
returning_all: queryBooleanString.optional(),
|
|
2167
|
-
include_permissions: queryBooleanString.optional()
|
|
2555
|
+
include_permissions: queryBooleanString.optional(),
|
|
2556
|
+
include_field_permissions: queryBooleanString.optional(),
|
|
2557
|
+
select: stringOrStringArray.optional()
|
|
2168
2558
|
}).passthrough();
|
|
2169
2559
|
var upsertQuerySchema = import_zod3.z.object({
|
|
2170
2560
|
returning_all: queryBooleanString.optional(),
|
|
2171
|
-
include_permissions: queryBooleanString.optional()
|
|
2561
|
+
include_permissions: queryBooleanString.optional(),
|
|
2562
|
+
include_field_permissions: queryBooleanString.optional()
|
|
2172
2563
|
}).passthrough();
|
|
2173
2564
|
var listBodySchema = import_zod3.z.object({
|
|
2174
2565
|
filter: objectOrArraySchema.optional(),
|
|
@@ -2184,9 +2575,10 @@ var listBodySchema = import_zod3.z.object({
|
|
|
2184
2575
|
options: import_zod3.z.object({
|
|
2185
2576
|
skim: import_zod3.z.boolean().optional(),
|
|
2186
2577
|
includePermissions: import_zod3.z.boolean().optional(),
|
|
2578
|
+
includeFieldPermissions: import_zod3.z.boolean().optional(),
|
|
2187
2579
|
includeCount: import_zod3.z.boolean().optional(),
|
|
2188
2580
|
includeExtraHeaders: import_zod3.z.boolean().optional(),
|
|
2189
|
-
populateAccess:
|
|
2581
|
+
populateAccess: populateAccessSchema.optional()
|
|
2190
2582
|
}).passthrough().optional()
|
|
2191
2583
|
}).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]));
|
|
2192
2584
|
var countBodySchema = import_zod3.z.object({
|
|
@@ -2202,8 +2594,9 @@ var readFilterBodySchema = import_zod3.z.object({
|
|
|
2202
2594
|
options: import_zod3.z.object({
|
|
2203
2595
|
skim: import_zod3.z.boolean().optional(),
|
|
2204
2596
|
includePermissions: import_zod3.z.boolean().optional(),
|
|
2597
|
+
includeFieldPermissions: import_zod3.z.boolean().optional(),
|
|
2205
2598
|
tryList: import_zod3.z.boolean().optional(),
|
|
2206
|
-
populateAccess:
|
|
2599
|
+
populateAccess: populateAccessSchema.optional()
|
|
2207
2600
|
}).passthrough().optional()
|
|
2208
2601
|
}).passthrough();
|
|
2209
2602
|
var readByIdBodySchema = import_zod3.z.object({
|
|
@@ -2214,8 +2607,9 @@ var readByIdBodySchema = import_zod3.z.object({
|
|
|
2214
2607
|
options: import_zod3.z.object({
|
|
2215
2608
|
skim: import_zod3.z.boolean().optional(),
|
|
2216
2609
|
includePermissions: import_zod3.z.boolean().optional(),
|
|
2610
|
+
includeFieldPermissions: import_zod3.z.boolean().optional(),
|
|
2217
2611
|
tryList: import_zod3.z.boolean().optional(),
|
|
2218
|
-
populateAccess:
|
|
2612
|
+
populateAccess: populateAccessSchema.optional()
|
|
2219
2613
|
}).passthrough().optional()
|
|
2220
2614
|
}).passthrough();
|
|
2221
2615
|
var advancedCreateBodySchema = import_zod3.z.object({
|
|
@@ -2225,7 +2619,8 @@ var advancedCreateBodySchema = import_zod3.z.object({
|
|
|
2225
2619
|
tasks: tasksSchema.optional(),
|
|
2226
2620
|
options: import_zod3.z.object({
|
|
2227
2621
|
includePermissions: import_zod3.z.boolean().optional(),
|
|
2228
|
-
|
|
2622
|
+
includeFieldPermissions: import_zod3.z.boolean().optional(),
|
|
2623
|
+
populateAccess: populateAccessSchema.optional()
|
|
2229
2624
|
}).passthrough().optional()
|
|
2230
2625
|
}).passthrough();
|
|
2231
2626
|
var createBodySchema = import_zod3.z.union([
|
|
@@ -2241,7 +2636,8 @@ var advancedUpdateBodySchema = import_zod3.z.object({
|
|
|
2241
2636
|
options: import_zod3.z.object({
|
|
2242
2637
|
returningAll: import_zod3.z.boolean().optional(),
|
|
2243
2638
|
includePermissions: import_zod3.z.boolean().optional(),
|
|
2244
|
-
|
|
2639
|
+
includeFieldPermissions: import_zod3.z.boolean().optional(),
|
|
2640
|
+
populateAccess: populateAccessSchema.optional()
|
|
2245
2641
|
}).passthrough().optional()
|
|
2246
2642
|
}).passthrough();
|
|
2247
2643
|
var upsertBodySchema = import_zod3.z.record(import_zod3.z.string(), import_zod3.z.unknown());
|
|
@@ -2253,7 +2649,8 @@ var advancedUpsertBodySchema = import_zod3.z.object({
|
|
|
2253
2649
|
options: import_zod3.z.object({
|
|
2254
2650
|
returningAll: import_zod3.z.boolean().optional(),
|
|
2255
2651
|
includePermissions: import_zod3.z.boolean().optional(),
|
|
2256
|
-
|
|
2652
|
+
includeFieldPermissions: import_zod3.z.boolean().optional(),
|
|
2653
|
+
populateAccess: populateAccessSchema.optional()
|
|
2257
2654
|
}).passthrough().optional()
|
|
2258
2655
|
}).passthrough();
|
|
2259
2656
|
var distinctBodySchema = import_zod3.z.object({
|
|
@@ -2323,8 +2720,9 @@ var rootModelListArgsSchema = import_zod5.z.object({
|
|
|
2323
2720
|
var rootModelListOptionsSchema = import_zod5.z.object({
|
|
2324
2721
|
skim: import_zod5.z.boolean().optional(),
|
|
2325
2722
|
includePermissions: import_zod5.z.boolean().optional(),
|
|
2723
|
+
includeFieldPermissions: import_zod5.z.boolean().optional(),
|
|
2326
2724
|
includeCount: import_zod5.z.boolean().optional(),
|
|
2327
|
-
populateAccess:
|
|
2725
|
+
populateAccess: populateAccessSchema.optional(),
|
|
2328
2726
|
lean: import_zod5.z.boolean().optional()
|
|
2329
2727
|
}).passthrough();
|
|
2330
2728
|
var rootModelReadArgsSchema = import_zod5.z.object({
|
|
@@ -2339,8 +2737,9 @@ var rootModelReadFilterArgsSchema = rootModelReadArgsSchema.extend({
|
|
|
2339
2737
|
var rootModelReadOptionsSchema = import_zod5.z.object({
|
|
2340
2738
|
skim: import_zod5.z.boolean().optional(),
|
|
2341
2739
|
includePermissions: import_zod5.z.boolean().optional(),
|
|
2740
|
+
includeFieldPermissions: import_zod5.z.boolean().optional(),
|
|
2342
2741
|
tryList: import_zod5.z.boolean().optional(),
|
|
2343
|
-
populateAccess:
|
|
2742
|
+
populateAccess: populateAccessSchema.optional(),
|
|
2344
2743
|
lean: import_zod5.z.boolean().optional()
|
|
2345
2744
|
}).passthrough();
|
|
2346
2745
|
var rootModelCreateArgsSchema = import_zod5.z.object({
|
|
@@ -2351,7 +2750,8 @@ var rootModelCreateArgsSchema = import_zod5.z.object({
|
|
|
2351
2750
|
var rootModelCreateOptionsSchema = import_zod5.z.object({
|
|
2352
2751
|
skim: import_zod5.z.boolean().optional(),
|
|
2353
2752
|
includePermissions: import_zod5.z.boolean().optional(),
|
|
2354
|
-
|
|
2753
|
+
includeFieldPermissions: import_zod5.z.boolean().optional(),
|
|
2754
|
+
populateAccess: populateAccessSchema.optional()
|
|
2355
2755
|
}).passthrough();
|
|
2356
2756
|
var rootModelUpdateArgsSchema = import_zod5.z.object({
|
|
2357
2757
|
select: projectionSchema.optional(),
|
|
@@ -2362,7 +2762,8 @@ var rootModelUpdateOptionsSchema = import_zod5.z.object({
|
|
|
2362
2762
|
skim: import_zod5.z.boolean().optional(),
|
|
2363
2763
|
returningAll: import_zod5.z.boolean().optional(),
|
|
2364
2764
|
includePermissions: import_zod5.z.boolean().optional(),
|
|
2365
|
-
|
|
2765
|
+
includeFieldPermissions: import_zod5.z.boolean().optional(),
|
|
2766
|
+
populateAccess: populateAccessSchema.optional()
|
|
2366
2767
|
}).passthrough();
|
|
2367
2768
|
var rootModelUpsertArgsSchema = rootModelUpdateArgsSchema;
|
|
2368
2769
|
var rootModelUpsertOptionsSchema = rootModelUpdateOptionsSchema;
|
|
@@ -2393,7 +2794,8 @@ var rootModelNewArgsSchema = import_zod5.z.object({
|
|
|
2393
2794
|
}).passthrough();
|
|
2394
2795
|
var rootModelNewOptionsSchema = import_zod5.z.object({
|
|
2395
2796
|
skim: import_zod5.z.boolean().optional(),
|
|
2396
|
-
includePermissions: import_zod5.z.boolean().optional()
|
|
2797
|
+
includePermissions: import_zod5.z.boolean().optional(),
|
|
2798
|
+
includeFieldPermissions: import_zod5.z.boolean().optional()
|
|
2397
2799
|
}).passthrough();
|
|
2398
2800
|
var rootModelQueryEntrySchema = import_zod5.z.union([
|
|
2399
2801
|
import_zod5.z.object({
|