@web-ts-toolkit/access-router 0.45.0 → 0.46.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 +255 -9
- package/advanced.d.mts +1 -1
- package/advanced.d.ts +1 -1
- package/advanced.js +40 -17
- package/advanced.mjs +42 -18
- package/index.d.mts +5 -186
- package/index.d.ts +5 -186
- package/index.js +545 -276
- package/index.mjs +408 -137
- package/llms.txt +68 -3
- package/package.json +3 -3
- package/{parsers-DppKW-Fd.d.mts → parsers-BKF7VX2-.d.mts} +339 -9
- package/{parsers-DppKW-Fd.d.ts → parsers-BKF7VX2-.d.ts} +339 -9
package/index.js
CHANGED
|
@@ -77,14 +77,14 @@ __export(index_exports, {
|
|
|
77
77
|
setModelOptions: () => setModelOptions
|
|
78
78
|
});
|
|
79
79
|
module.exports = __toCommonJS(index_exports);
|
|
80
|
-
var
|
|
80
|
+
var import_utils32 = require("@web-ts-toolkit/utils");
|
|
81
81
|
|
|
82
82
|
// src/middleware.ts
|
|
83
83
|
var import_express_json_router2 = __toESM(require("@web-ts-toolkit/express-json-router"));
|
|
84
|
-
var
|
|
84
|
+
var import_utils25 = require("@web-ts-toolkit/utils");
|
|
85
85
|
|
|
86
86
|
// src/core.ts
|
|
87
|
-
var
|
|
87
|
+
var import_utils24 = require("@web-ts-toolkit/utils");
|
|
88
88
|
|
|
89
89
|
// src/runtime.ts
|
|
90
90
|
var import_mongoose3 = __toESM(require("mongoose"));
|
|
@@ -122,8 +122,12 @@ var mapWithConcurrencyLimit = async (items, limit, iteratee) => {
|
|
|
122
122
|
};
|
|
123
123
|
var RequestConcurrencyScheduler = class {
|
|
124
124
|
constructor(limit) {
|
|
125
|
+
this.activeWork = 0;
|
|
126
|
+
this.waiters = [];
|
|
125
127
|
this.limit = Math.max(1, limit);
|
|
126
128
|
}
|
|
129
|
+
// Each map bounds its own orchestration workers. Recursive maps never hold
|
|
130
|
+
// shared work permits while awaiting descendants (including at limit 1).
|
|
127
131
|
async map(items, iteratee) {
|
|
128
132
|
return mapWithConcurrencyLimit(items, this.limit, (item, index) => iteratee(item, index, true));
|
|
129
133
|
}
|
|
@@ -131,6 +135,23 @@ var RequestConcurrencyScheduler = class {
|
|
|
131
135
|
const [result] = await this.map([void 0], () => iteratee(true));
|
|
132
136
|
return result;
|
|
133
137
|
}
|
|
138
|
+
// Only leaf persistence operations belong here, not service/hook callbacks.
|
|
139
|
+
// All work calls on this scheduler share a FIFO admission ceiling.
|
|
140
|
+
async work(operation) {
|
|
141
|
+
if (this.activeWork >= this.limit) {
|
|
142
|
+
await new Promise((resolve) => this.waiters.push(resolve));
|
|
143
|
+
} else {
|
|
144
|
+
this.activeWork += 1;
|
|
145
|
+
}
|
|
146
|
+
try {
|
|
147
|
+
return await operation();
|
|
148
|
+
} finally {
|
|
149
|
+
const next = this.waiters.shift();
|
|
150
|
+
if (next)
|
|
151
|
+
next();
|
|
152
|
+
else this.activeWork -= 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
134
155
|
};
|
|
135
156
|
|
|
136
157
|
// src/helpers/document.ts
|
|
@@ -1222,6 +1243,7 @@ var AccessRuntime = class {
|
|
|
1222
1243
|
this.modelAtts = {};
|
|
1223
1244
|
this.modelInstances = {};
|
|
1224
1245
|
this.openApiRegistry = new OpenApiRegistry();
|
|
1246
|
+
this.openApiPathPrefix = "";
|
|
1225
1247
|
this.allowGlobalModelLookup = options.allowGlobalModelLookup ?? false;
|
|
1226
1248
|
ensureMongooseJsonSchemaInitialized();
|
|
1227
1249
|
}
|
|
@@ -1250,7 +1272,24 @@ var AccessRuntime = class {
|
|
|
1250
1272
|
return global;
|
|
1251
1273
|
}
|
|
1252
1274
|
registerOpenApiRoute(route) {
|
|
1253
|
-
this.openApiRegistry.register(
|
|
1275
|
+
this.openApiRegistry.register(
|
|
1276
|
+
this.openApiPathPrefix ? { ...route, path: (0, import_utils11.normalizeUrlPath)(`${this.openApiPathPrefix}/${route.path}`) } : route
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
/**
|
|
1280
|
+
* Compose OpenAPI paths while synchronously constructing mounted routers.
|
|
1281
|
+
* Prefixes apply before collision checks; prior descriptors and Express paths
|
|
1282
|
+
* are unchanged. Nested calls compose and the prior scope is restored even on
|
|
1283
|
+
* failure. The callback must finish registration synchronously (no async work).
|
|
1284
|
+
*/
|
|
1285
|
+
withOpenApiPathPrefix(prefix, build) {
|
|
1286
|
+
const previous = this.openApiPathPrefix;
|
|
1287
|
+
this.openApiPathPrefix = (0, import_utils11.normalizeUrlPath)(`${previous}/${prefix}`);
|
|
1288
|
+
try {
|
|
1289
|
+
return build();
|
|
1290
|
+
} finally {
|
|
1291
|
+
this.openApiPathPrefix = previous;
|
|
1292
|
+
}
|
|
1254
1293
|
}
|
|
1255
1294
|
/**
|
|
1256
1295
|
* Enable strict OpenAPI collision detection for the remainder of this
|
|
@@ -1925,7 +1964,8 @@ function resolveValueNode(template, parent, bare) {
|
|
|
1925
1964
|
if (!isParentRefMarker(inner) || typeof inner.$parent !== "string" || (inner.$parent?.length ?? 0) === 0) {
|
|
1926
1965
|
throw new CorrelatedReferenceError('Invalid $escape payload: expected { "$escape": { "$parent": "<field>" } }');
|
|
1927
1966
|
}
|
|
1928
|
-
|
|
1967
|
+
const literal = literalParentRefObject(inner.$parent);
|
|
1968
|
+
return bare ? { $eq: literal } : literal;
|
|
1929
1969
|
}
|
|
1930
1970
|
if (isParentRefMarker(template)) {
|
|
1931
1971
|
const path = template.$parent;
|
|
@@ -2054,8 +2094,28 @@ function isCorrelatedInclude(value) {
|
|
|
2054
2094
|
return (0, import_utils12.isPlainObject)(value) && value.mode === "correlated";
|
|
2055
2095
|
}
|
|
2056
2096
|
|
|
2097
|
+
// src/helpers/request-work.ts
|
|
2098
|
+
var states = /* @__PURE__ */ new WeakMap();
|
|
2099
|
+
function getRequestWorkState(req, runtime) {
|
|
2100
|
+
let owners = states.get(req);
|
|
2101
|
+
if (!owners) {
|
|
2102
|
+
owners = /* @__PURE__ */ new WeakMap();
|
|
2103
|
+
states.set(req, owners);
|
|
2104
|
+
}
|
|
2105
|
+
let state = owners.get(runtime);
|
|
2106
|
+
if (!state) {
|
|
2107
|
+
state = {
|
|
2108
|
+
totalQueries: 0,
|
|
2109
|
+
scheduler: new RequestConcurrencyScheduler(
|
|
2110
|
+
resolveRequestComplexity(runtime.getGlobalOption("requestComplexity")).maxBulkConcurrency
|
|
2111
|
+
)
|
|
2112
|
+
};
|
|
2113
|
+
owners.set(runtime, state);
|
|
2114
|
+
}
|
|
2115
|
+
return state;
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2057
2118
|
// src/services/base.ts
|
|
2058
|
-
var correlatedExecStates = /* @__PURE__ */ new WeakMap();
|
|
2059
2119
|
function getCorrelatedTemplateDepth(includes) {
|
|
2060
2120
|
let max = 0;
|
|
2061
2121
|
const visit = (entries, depth) => {
|
|
@@ -2105,6 +2165,7 @@ function validateClientFilter(filter2) {
|
|
|
2105
2165
|
}
|
|
2106
2166
|
var Base = class {
|
|
2107
2167
|
constructor(req, modelName) {
|
|
2168
|
+
this.requestRuntime = getActiveRuntime() ?? defaultRuntime;
|
|
2108
2169
|
this.req = req;
|
|
2109
2170
|
this.modelName = modelName;
|
|
2110
2171
|
}
|
|
@@ -2242,6 +2303,7 @@ var Base = class {
|
|
|
2242
2303
|
}
|
|
2243
2304
|
seenCorrelatedPaths.add(entry.path);
|
|
2244
2305
|
}
|
|
2306
|
+
this.assertIncludeOutputPaths([...legacy, ...correlated]);
|
|
2245
2307
|
let includeLocalFields = [];
|
|
2246
2308
|
let includePaths = [];
|
|
2247
2309
|
(0, import_utils13.forEach)(legacy, (inc) => {
|
|
@@ -2258,6 +2320,39 @@ var Base = class {
|
|
|
2258
2320
|
correlatedReferenceFields: (0, import_utils13.uniq)((0, import_utils13.compact)(correlatedReferenceFields))
|
|
2259
2321
|
};
|
|
2260
2322
|
}
|
|
2323
|
+
validateIncludeOutputPath(path, modelName) {
|
|
2324
|
+
const permissionField = getModelOption(modelName, "documentPermissionField");
|
|
2325
|
+
if ((0, import_utils13.get)((0, import_utils13.set)({}, path, true), permissionField) !== void 0 || (0, import_utils13.get)((0, import_utils13.set)({}, permissionField, true), path) !== void 0) {
|
|
2326
|
+
this.throwClientRequestError(
|
|
2327
|
+
"bad_request" /* BadRequest */,
|
|
2328
|
+
`Include output path ${path} overlaps document permission field ${permissionField} on model ${modelName}`
|
|
2329
|
+
);
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
assertIncludeOutputPaths(include) {
|
|
2333
|
+
const pending = [{ entries: include, modelName: this.modelName }];
|
|
2334
|
+
const visited = /* @__PURE__ */ new WeakMap();
|
|
2335
|
+
while (pending.length > 0) {
|
|
2336
|
+
const { entries, modelName } = pending.pop();
|
|
2337
|
+
if (modelName !== this.modelName && !getModelNames().includes(modelName)) {
|
|
2338
|
+
this.throwClientRequestError("bad_request" /* BadRequest */, `Model ${modelName} not found`);
|
|
2339
|
+
}
|
|
2340
|
+
for (const entry of entries) {
|
|
2341
|
+
if (!(0, import_utils13.isPlainObject)(entry)) continue;
|
|
2342
|
+
const models = visited.get(entry) ?? /* @__PURE__ */ new Set();
|
|
2343
|
+
if (models.has(modelName)) continue;
|
|
2344
|
+
models.add(modelName);
|
|
2345
|
+
visited.set(entry, models);
|
|
2346
|
+
if (typeof entry.path === "string" && entry.path) {
|
|
2347
|
+
this.validateIncludeOutputPath(entry.path, modelName);
|
|
2348
|
+
}
|
|
2349
|
+
if ((entry.op === "read" || entry.op === "list") && typeof entry.model === "string") {
|
|
2350
|
+
const nested = entry.args?.include;
|
|
2351
|
+
if (nested) pending.push({ entries: (0, import_utils13.compact)((0, import_utils13.castArray)(nested)), modelName: entry.model });
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2261
2356
|
getForeignKeyValues(value) {
|
|
2262
2357
|
return (0, import_utils13.flatten)((0, import_utils13.castArray)(value));
|
|
2263
2358
|
}
|
|
@@ -2392,6 +2487,7 @@ var Base = class {
|
|
|
2392
2487
|
const svc = await this.getAuthorizedTargetService(model, "count");
|
|
2393
2488
|
const localValues = docs.flatMap((doc) => this.getForeignKeyValues((0, import_utils13.get)(doc, localField)));
|
|
2394
2489
|
const result = await svc.countByFieldValues(foreignField, localValues, _filters ?? {}, "count");
|
|
2490
|
+
if (!result.success && result.code === "bad_request" /* BadRequest */) throw new ClientRequestError(result);
|
|
2395
2491
|
if (!result.success) return docs;
|
|
2396
2492
|
for (let y = 0; y < docs.length; y++) {
|
|
2397
2493
|
const doc = docs[y];
|
|
@@ -2400,16 +2496,7 @@ var Base = class {
|
|
|
2400
2496
|
return docs;
|
|
2401
2497
|
}
|
|
2402
2498
|
getCorrelatedExecState() {
|
|
2403
|
-
|
|
2404
|
-
let state = correlatedExecStates.get(key);
|
|
2405
|
-
if (!state) {
|
|
2406
|
-
state = {
|
|
2407
|
-
totalQueries: 0,
|
|
2408
|
-
scheduler: new RequestConcurrencyScheduler(this.getRequestComplexity().maxBulkConcurrency)
|
|
2409
|
-
};
|
|
2410
|
-
correlatedExecStates.set(key, state);
|
|
2411
|
-
}
|
|
2412
|
-
return state;
|
|
2499
|
+
return getRequestWorkState(this.req, this.requestRuntime);
|
|
2413
2500
|
}
|
|
2414
2501
|
claimCorrelatedQuerySlot() {
|
|
2415
2502
|
const limits = this.getRequestComplexity();
|
|
@@ -2806,10 +2893,30 @@ var Base = class {
|
|
|
2806
2893
|
};
|
|
2807
2894
|
|
|
2808
2895
|
// src/services/service.ts
|
|
2809
|
-
var
|
|
2896
|
+
var import_utils17 = require("@web-ts-toolkit/utils");
|
|
2810
2897
|
var import_just_diff = require("just-diff");
|
|
2811
2898
|
|
|
2812
2899
|
// src/model.ts
|
|
2900
|
+
var import_utils14 = require("@web-ts-toolkit/utils");
|
|
2901
|
+
function admitModelPersistence(adapter, scheduler) {
|
|
2902
|
+
return {
|
|
2903
|
+
modelName: adapter.modelName,
|
|
2904
|
+
mongooseModel: adapter.mongooseModel,
|
|
2905
|
+
new: () => adapter.new(),
|
|
2906
|
+
// Mongoose create(array) otherwise starts all document saves at once. Keep
|
|
2907
|
+
// the adapter's array input/output contract, with one permit per item; all
|
|
2908
|
+
// items are submitted even if one rejects, as with unordered create(array).
|
|
2909
|
+
create: (data) => Array.isArray(data) ? Promise.all(data.map((item) => scheduler.work(async () => (await adapter.create([item]))[0]))) : scheduler.work(() => adapter.create(data)),
|
|
2910
|
+
find: (props) => scheduler.work(() => adapter.find(props)),
|
|
2911
|
+
findOne: (props) => scheduler.work(() => adapter.findOne(props)),
|
|
2912
|
+
exists: (filter2) => scheduler.work(() => adapter.exists(filter2)),
|
|
2913
|
+
countDocuments: (filter2) => scheduler.work(() => adapter.countDocuments(filter2)),
|
|
2914
|
+
distinct: (field, conditions) => scheduler.work(() => adapter.distinct(field, conditions)),
|
|
2915
|
+
aggregate: (pipeline) => scheduler.work(() => adapter.aggregate(pipeline)),
|
|
2916
|
+
// Casting builds no persistence work and must not acquire a recursive permit.
|
|
2917
|
+
...adapter.castFilter ? { castFilter: (filter2) => adapter.castFilter(filter2) } : {}
|
|
2918
|
+
};
|
|
2919
|
+
}
|
|
2813
2920
|
var Model = class {
|
|
2814
2921
|
constructor(modelName, runtime) {
|
|
2815
2922
|
this.modelName = modelName;
|
|
@@ -2862,6 +2969,11 @@ var Model = class {
|
|
|
2862
2969
|
countDocuments(filter2 = {}) {
|
|
2863
2970
|
return this.mongooseModel.countDocuments(filter2);
|
|
2864
2971
|
}
|
|
2972
|
+
/** Cast a copy using this model's query schema/setters, without executing query middleware or persistence. */
|
|
2973
|
+
castFilter(filter2) {
|
|
2974
|
+
const query = this.mongooseModel.countDocuments((0, import_utils14.cloneDeep)(filter2));
|
|
2975
|
+
return query.cast(this.mongooseModel);
|
|
2976
|
+
}
|
|
2865
2977
|
// see https://mongoosejs.com/docs/api.html#model_Model.distinct
|
|
2866
2978
|
distinct(field, conditions = {}) {
|
|
2867
2979
|
return this.mongooseModel.distinct(field, conditions);
|
|
@@ -2872,6 +2984,39 @@ var Model = class {
|
|
|
2872
2984
|
};
|
|
2873
2985
|
var model_default = Model;
|
|
2874
2986
|
|
|
2987
|
+
// src/helpers/apply-update.ts
|
|
2988
|
+
var import_utils15 = require("@web-ts-toolkit/utils");
|
|
2989
|
+
function applyUpdate(target, data, allowedFields) {
|
|
2990
|
+
const wholeFields = /* @__PURE__ */ new Set();
|
|
2991
|
+
const partialContainers = /* @__PURE__ */ new Set();
|
|
2992
|
+
const collectBoundary = (shape, prefix = "") => {
|
|
2993
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
2994
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
2995
|
+
if (value === true) wholeFields.add(path);
|
|
2996
|
+
else {
|
|
2997
|
+
partialContainers.add(path);
|
|
2998
|
+
collectBoundary(value, path);
|
|
2999
|
+
}
|
|
3000
|
+
}
|
|
3001
|
+
};
|
|
3002
|
+
for (const field of allowedFields) {
|
|
3003
|
+
collectBoundary((0, import_utils15.set)({}, field, true));
|
|
3004
|
+
}
|
|
3005
|
+
const apply = (values, prefix = "") => {
|
|
3006
|
+
for (const [key, value] of Object.entries(values)) {
|
|
3007
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
3008
|
+
if (partialContainers.has(path) && !wholeFields.has(path) && ((0, import_utils15.isPlainObject)(value) || Array.isArray(value))) {
|
|
3009
|
+
apply(value, path);
|
|
3010
|
+
} else if (isDocument2(target)) {
|
|
3011
|
+
target.set(path, value);
|
|
3012
|
+
} else {
|
|
3013
|
+
(0, import_utils15.set)(target, path, value);
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
};
|
|
3017
|
+
apply(data ?? {});
|
|
3018
|
+
}
|
|
3019
|
+
|
|
2875
3020
|
// src/logger-helpers.ts
|
|
2876
3021
|
var SENSITIVE_FILTER_KEYS = /* @__PURE__ */ new Set([
|
|
2877
3022
|
"password",
|
|
@@ -3050,28 +3195,52 @@ var error = (error2) => {
|
|
|
3050
3195
|
};
|
|
3051
3196
|
|
|
3052
3197
|
// src/services/model-subdocument-service.ts
|
|
3053
|
-
var
|
|
3198
|
+
var import_utils16 = require("@web-ts-toolkit/utils");
|
|
3199
|
+
async function visibleMutationRows(service, isAllowed, parentId, sub, rows, response) {
|
|
3200
|
+
const accesses = ["read", `subs.${sub}.read`];
|
|
3201
|
+
if (response === "create") accesses.push(`subs.${sub}.list`);
|
|
3202
|
+
const allowed = await Promise.all(accesses.map(isAllowed));
|
|
3203
|
+
if (allowed.some((value) => !value)) return [];
|
|
3204
|
+
const parentFilter = await service.genFilter("read", { _id: parentId });
|
|
3205
|
+
if (parentFilter === false) return [];
|
|
3206
|
+
const parent = await service.findRawParentDoc({
|
|
3207
|
+
filter: { $and: [{ _id: parentId }, parentFilter] },
|
|
3208
|
+
select: "_id",
|
|
3209
|
+
populate: [],
|
|
3210
|
+
lean: true
|
|
3211
|
+
});
|
|
3212
|
+
if (!parent) return [];
|
|
3213
|
+
const targetFilter = response === "create" ? {} : response === "single" ? { _id: rows[0]?._id } : { _id: { $in: rows.map((row) => row._id) } };
|
|
3214
|
+
const [readFilter, listFilter, select] = await Promise.all([
|
|
3215
|
+
service.genFilter(`subs.${sub}.read`, targetFilter),
|
|
3216
|
+
response === "create" ? service.genFilter(`subs.${sub}.list`) : Promise.resolve({}),
|
|
3217
|
+
service.genQuerySelect("read", null, false, [sub, "sub"])
|
|
3218
|
+
]);
|
|
3219
|
+
if (readFilter === false || listFilter === false) return [];
|
|
3220
|
+
const visible = filterCollection(filterCollection(rows, listFilter), readFilter);
|
|
3221
|
+
return select ? visible.map((row) => (0, import_utils16.pick)(toObject(row), select.concat("_id"))) : visible;
|
|
3222
|
+
}
|
|
3054
3223
|
async function listSub(service, id, sub, options) {
|
|
3055
3224
|
const { filter: ft, select } = options ?? {};
|
|
3056
3225
|
const filterErrors = validateClientFilter(ft);
|
|
3057
3226
|
if (filterErrors.length > 0) return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: filterErrors };
|
|
3058
3227
|
const parentDoc = await getParentDoc(service, id, sub, null, { access: "read" });
|
|
3059
3228
|
if (!parentDoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3060
|
-
let result = (0,
|
|
3229
|
+
let result = (0, import_utils16.get)(parentDoc, sub);
|
|
3061
3230
|
const [subFilter, subSelect] = await Promise.all([
|
|
3062
3231
|
service.genFilter(`subs.${sub}.list`, ft),
|
|
3063
3232
|
service.genQuerySelect("list", select, false, [sub, "sub"])
|
|
3064
3233
|
]);
|
|
3065
3234
|
if (subFilter === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */ };
|
|
3066
3235
|
result = filterCollection(result, subFilter);
|
|
3067
|
-
if (subSelect) result = result.map((v) => (0,
|
|
3236
|
+
if (subSelect) result = result.map((v) => (0, import_utils16.pick)(toObject(v), subSelect.concat("_id")));
|
|
3068
3237
|
return { success: true, kind: "list", code: "success" /* Success */, data: result, count: result.length };
|
|
3069
3238
|
}
|
|
3070
3239
|
async function readSub(service, id, sub, subId, options) {
|
|
3071
3240
|
const { select, populate } = options ?? {};
|
|
3072
3241
|
const parentDoc = await getParentDoc(service, id, sub, { populate }, { access: "read" });
|
|
3073
3242
|
if (!parentDoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3074
|
-
const result = (0,
|
|
3243
|
+
const result = (0, import_utils16.get)(parentDoc, sub);
|
|
3075
3244
|
const [subFilter, subSelect] = await Promise.all([
|
|
3076
3245
|
service.genFilter(`subs.${sub}.read`, { _id: subId }),
|
|
3077
3246
|
service.genQuerySelect("read", select, false, [sub, "sub"])
|
|
@@ -3079,28 +3248,27 @@ async function readSub(service, id, sub, subId, options) {
|
|
|
3079
3248
|
if (subFilter === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */ };
|
|
3080
3249
|
let subdoc = findElement(result, subFilter);
|
|
3081
3250
|
if (!subdoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3082
|
-
if (subSelect) subdoc = (0,
|
|
3251
|
+
if (subSelect) subdoc = (0, import_utils16.pick)(toObject(subdoc), subSelect.concat(["_id"]));
|
|
3083
3252
|
return { success: true, kind: "single", code: "success" /* Success */, data: subdoc };
|
|
3084
3253
|
}
|
|
3085
|
-
async function updateSub(service, id, sub, subId, data) {
|
|
3254
|
+
async function updateSub(service, persist, isAllowed, id, sub, subId, data) {
|
|
3086
3255
|
const parentDoc = await getParentDoc(service, id, sub, null, { access: "update" });
|
|
3087
3256
|
if (!parentDoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3088
|
-
const result = (0,
|
|
3089
|
-
const [subFilter,
|
|
3257
|
+
const result = (0, import_utils16.get)(parentDoc, sub);
|
|
3258
|
+
const [subFilter, subUpdateSelect] = await Promise.all([
|
|
3090
3259
|
service.genFilter(`subs.${sub}.update`, { _id: subId }),
|
|
3091
|
-
service.genQuerySelect("read", null, false, [sub, "sub"]),
|
|
3092
3260
|
service.genQuerySelect("update", null, false, [sub, "sub"])
|
|
3093
3261
|
]);
|
|
3094
3262
|
if (subFilter === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */ };
|
|
3095
|
-
|
|
3263
|
+
const subdoc = findElement(result, subFilter);
|
|
3096
3264
|
if (!subdoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3097
|
-
const allowedData = (0,
|
|
3098
|
-
|
|
3099
|
-
await parentDoc.save();
|
|
3100
|
-
|
|
3101
|
-
return { success: true, kind: "single", code: "success" /* Success */, data:
|
|
3265
|
+
const allowedData = (0, import_utils16.pick)(data, subUpdateSelect);
|
|
3266
|
+
applyUpdate(subdoc, allowedData, subUpdateSelect);
|
|
3267
|
+
await persist(() => parentDoc.save());
|
|
3268
|
+
const visible = await visibleMutationRows(service, isAllowed, parentDoc._id, sub, [subdoc], "single");
|
|
3269
|
+
return { success: true, kind: "single", code: "success" /* Success */, data: visible[0] ?? null };
|
|
3102
3270
|
}
|
|
3103
|
-
async function bulkUpdateSub(service, id, sub, data) {
|
|
3271
|
+
async function bulkUpdateSub(service, persist, isAllowed, id, sub, data) {
|
|
3104
3272
|
const { maxBulkItems } = service.getRequestComplexity();
|
|
3105
3273
|
if (data.length > maxBulkItems) {
|
|
3106
3274
|
return {
|
|
@@ -3112,25 +3280,24 @@ async function bulkUpdateSub(service, id, sub, data) {
|
|
|
3112
3280
|
}
|
|
3113
3281
|
const parentDoc = await getParentDoc(service, id, sub, null, { access: "update" });
|
|
3114
3282
|
if (!parentDoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3115
|
-
let result = (0,
|
|
3116
|
-
const [subFilter,
|
|
3283
|
+
let result = (0, import_utils16.get)(parentDoc, sub);
|
|
3284
|
+
const [subFilter, subUpdateSelect] = await Promise.all([
|
|
3117
3285
|
service.genFilter(`subs.${sub}.update`, { _id: { $in: data.map((v) => v._id) } }),
|
|
3118
|
-
service.genQuerySelect("read", null, false, [sub, "sub"]),
|
|
3119
3286
|
service.genQuerySelect("update", null, false, [sub, "sub"])
|
|
3120
3287
|
]);
|
|
3121
3288
|
if (subFilter === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */ };
|
|
3122
|
-
result = filterCollection(result, subFilter);
|
|
3123
|
-
(0,
|
|
3289
|
+
result = filterCollection(result, subFilter).filter((subdoc) => findElementById(data, subdoc._id));
|
|
3290
|
+
(0, import_utils16.forEach)(result, (subdoc) => {
|
|
3124
3291
|
const tdata = findElementById(data, subdoc._id);
|
|
3125
3292
|
if (!tdata) return;
|
|
3126
|
-
const allowedData = (0,
|
|
3127
|
-
|
|
3293
|
+
const allowedData = (0, import_utils16.pick)(tdata, subUpdateSelect);
|
|
3294
|
+
applyUpdate(subdoc, allowedData, subUpdateSelect);
|
|
3128
3295
|
});
|
|
3129
|
-
await parentDoc.save();
|
|
3130
|
-
|
|
3296
|
+
await persist(() => parentDoc.save());
|
|
3297
|
+
result = await visibleMutationRows(service, isAllowed, parentDoc._id, sub, result, "bulk");
|
|
3131
3298
|
return { success: true, kind: "list", code: "success" /* Success */, data: result, count: result.length };
|
|
3132
3299
|
}
|
|
3133
|
-
async function createSub(service, id, sub, data, options) {
|
|
3300
|
+
async function createSub(service, persist, isAllowed, id, sub, data, options) {
|
|
3134
3301
|
const { addFirst } = options ?? {};
|
|
3135
3302
|
const { maxBulkItems } = service.getRequestComplexity();
|
|
3136
3303
|
if (Array.isArray(data) && data.length > maxBulkItems) {
|
|
@@ -3143,31 +3310,28 @@ async function createSub(service, id, sub, data, options) {
|
|
|
3143
3310
|
}
|
|
3144
3311
|
const parentDoc = await getParentDoc(service, id, sub, null, { access: "update" });
|
|
3145
3312
|
if (!parentDoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3146
|
-
let result = (0,
|
|
3147
|
-
const
|
|
3148
|
-
|
|
3149
|
-
service.genQuerySelect("read", null, false, [sub, "sub"])
|
|
3150
|
-
]);
|
|
3151
|
-
const allowedData = Array.isArray(data) ? data.map((row) => (0, import_utils14.pick)(row, subCreateSelect)) : (0, import_utils14.pick)(data, subCreateSelect);
|
|
3313
|
+
let result = (0, import_utils16.get)(parentDoc, sub);
|
|
3314
|
+
const subCreateSelect = await service.genQuerySelect("create", null, false, [sub, "sub"]);
|
|
3315
|
+
const allowedData = Array.isArray(data) ? data.map((row) => (0, import_utils16.pick)(row, subCreateSelect)) : (0, import_utils16.pick)(data, subCreateSelect);
|
|
3152
3316
|
if (Array.isArray(allowedData)) {
|
|
3153
3317
|
addFirst === true ? result.unshift(...allowedData) : result.push(...allowedData);
|
|
3154
3318
|
} else {
|
|
3155
3319
|
addFirst === true ? result.unshift(allowedData) : result.push(allowedData);
|
|
3156
3320
|
}
|
|
3157
|
-
await parentDoc.save();
|
|
3158
|
-
|
|
3321
|
+
await persist(() => parentDoc.save());
|
|
3322
|
+
result = await visibleMutationRows(service, isAllowed, parentDoc._id, sub, result, "create");
|
|
3159
3323
|
return { success: true, kind: "list", code: "created" /* Created */, data: result, count: result.length };
|
|
3160
3324
|
}
|
|
3161
|
-
async function deleteSub(service, id, sub, subId) {
|
|
3325
|
+
async function deleteSub(service, persist, id, sub, subId) {
|
|
3162
3326
|
const parentDoc = await getParentDoc(service, id, sub, null, { access: "update" });
|
|
3163
3327
|
if (!parentDoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3164
|
-
const result = (0,
|
|
3328
|
+
const result = (0, import_utils16.get)(parentDoc, sub);
|
|
3165
3329
|
const subFilter = await service.genFilter(`subs.${sub}.delete`, { _id: subId });
|
|
3166
3330
|
if (subFilter === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */ };
|
|
3167
3331
|
const subdoc = findElement(result, subFilter);
|
|
3168
3332
|
if (!subdoc) return { success: false, kind: "error", code: "not_found" /* NotFound */ };
|
|
3169
3333
|
await ("deleteOne" in subdoc ? subdoc.deleteOne?.() : subdoc.remove?.());
|
|
3170
|
-
await parentDoc.save();
|
|
3334
|
+
await persist(() => parentDoc.save());
|
|
3171
3335
|
return { success: true, kind: "single", code: "success" /* Success */, data: subdoc._id };
|
|
3172
3336
|
}
|
|
3173
3337
|
async function getParentDoc(service, id, sub, args, options) {
|
|
@@ -3326,6 +3490,15 @@ var shouldKeepCorrelatedRef = (ref, keep) => {
|
|
|
3326
3490
|
return false;
|
|
3327
3491
|
};
|
|
3328
3492
|
var Service = class extends Base {
|
|
3493
|
+
constructor(req, modelName) {
|
|
3494
|
+
super(req, modelName);
|
|
3495
|
+
this.persist = (operation) => this.getCorrelatedExecState().scheduler.work(operation);
|
|
3496
|
+
this.model = admitModelPersistence(this.createModelAdapter(modelName), this.getCorrelatedExecState().scheduler);
|
|
3497
|
+
this.options = this.getModelRouterOptions(modelName);
|
|
3498
|
+
this.defaults = this.options.defaults || {};
|
|
3499
|
+
this.baseFields = ["_id"];
|
|
3500
|
+
this.baseFieldsExt = this.baseFields.concat(this.options.documentPermissionField);
|
|
3501
|
+
}
|
|
3329
3502
|
findRawParentDoc(args) {
|
|
3330
3503
|
return this.model.findOne({
|
|
3331
3504
|
...args,
|
|
@@ -3363,14 +3536,6 @@ var Service = class extends Base {
|
|
|
3363
3536
|
...extra ?? {}
|
|
3364
3537
|
});
|
|
3365
3538
|
}
|
|
3366
|
-
constructor(req, modelName) {
|
|
3367
|
-
super(req, modelName);
|
|
3368
|
-
this.model = this.createModelAdapter(modelName);
|
|
3369
|
-
this.options = this.getModelRouterOptions(modelName);
|
|
3370
|
-
this.defaults = this.options.defaults || {};
|
|
3371
|
-
this.baseFields = ["_id"];
|
|
3372
|
-
this.baseFieldsExt = this.baseFields.concat(this.options.documentPermissionField);
|
|
3373
|
-
}
|
|
3374
3539
|
async findOne(filter2, args, options) {
|
|
3375
3540
|
const filterErrors = this.validateClientFilter(filter2);
|
|
3376
3541
|
if (filterErrors.length > 0) return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: filterErrors };
|
|
@@ -3378,20 +3543,22 @@ var Service = class extends Base {
|
|
|
3378
3543
|
const { skim, includePermissions, access, populateAccess, lean } = this.resolveFindOneOptions(options);
|
|
3379
3544
|
const { filter: overrideFilter, select: overrideSelect, populate: overridePopulate } = overrides ?? {};
|
|
3380
3545
|
let parsedFilter;
|
|
3546
|
+
let processedInclude;
|
|
3381
3547
|
try {
|
|
3382
|
-
|
|
3548
|
+
processedInclude = this.processInclude(include);
|
|
3549
|
+
parsedFilter = overrideFilter === false ? false : await this.parseClientData(filter2);
|
|
3383
3550
|
} catch (error2) {
|
|
3384
3551
|
const result = this.getClientRequestErrorResult(error2);
|
|
3385
3552
|
if (result) return result;
|
|
3386
3553
|
throw error2;
|
|
3387
3554
|
}
|
|
3388
3555
|
let [_filter, _select, _populate, allowedSortFields] = await Promise.all([
|
|
3389
|
-
overrideFilter
|
|
3556
|
+
overrideFilter ?? this.genFilter(access, parsedFilter),
|
|
3390
3557
|
overrideSelect || this.genQuerySelect(access, select),
|
|
3391
3558
|
overridePopulate || this.genPopulate(populateAccess || access, populate),
|
|
3392
3559
|
this.genAllowedFields({}, access, this.baseFieldsExt)
|
|
3393
3560
|
]);
|
|
3394
|
-
const { includes, correlatedIncludes, includeLocalFields, includePaths, correlatedReferenceFields } =
|
|
3561
|
+
const { includes, correlatedIncludes, includeLocalFields, includePaths, correlatedReferenceFields } = processedInclude;
|
|
3395
3562
|
const correlatedOutputPaths = correlatedIncludes.map((entry) => entry.path);
|
|
3396
3563
|
const finalSelect = normalizeSelect(_select).concat(includeLocalFields, correlatedReferenceFields);
|
|
3397
3564
|
const query = {
|
|
@@ -3426,7 +3593,7 @@ var Service = class extends Base {
|
|
|
3426
3593
|
originalDocumentSnapshot: toObject(doc),
|
|
3427
3594
|
resolvedQuery: query
|
|
3428
3595
|
};
|
|
3429
|
-
const correlatedSnapshots = [(0,
|
|
3596
|
+
const correlatedSnapshots = [(0, import_utils17.cloneDeep)(toObject(doc))];
|
|
3430
3597
|
try {
|
|
3431
3598
|
doc = await this.includeDocs(doc, includes);
|
|
3432
3599
|
if (correlatedIncludes.length > 0) {
|
|
@@ -3473,7 +3640,8 @@ var Service = class extends Base {
|
|
|
3473
3640
|
const { select, populate, include, overrides } = this.resolveFindByIdArgs(args);
|
|
3474
3641
|
const { skim, includePermissions, access, populateAccess, lean } = this.resolveFindByIdOptions(options);
|
|
3475
3642
|
const { select: overrideSelect, populate: overridePopulate, idFilter: overrideIdFilter } = overrides ?? {};
|
|
3476
|
-
const filter2 = overrideIdFilter
|
|
3643
|
+
const filter2 = overrideIdFilter ?? await this.genIDFilter(id);
|
|
3644
|
+
if (filter2 === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */, query: { filter: filter2 } };
|
|
3477
3645
|
return this.findOne(
|
|
3478
3646
|
filter2,
|
|
3479
3647
|
{
|
|
@@ -3495,23 +3663,25 @@ var Service = class extends Base {
|
|
|
3495
3663
|
const { skim, includePermissions, includeCount, populateAccess, lean } = this.resolveFindOptions(options);
|
|
3496
3664
|
const { filter: overrideFilter, select: overrideSelect, populate: overridePopulate } = overrides ?? {};
|
|
3497
3665
|
let parsedFilter;
|
|
3666
|
+
let processedInclude;
|
|
3498
3667
|
try {
|
|
3499
|
-
|
|
3668
|
+
processedInclude = this.processInclude(include);
|
|
3669
|
+
parsedFilter = overrideFilter === false ? false : await this.parseClientData(filter2);
|
|
3500
3670
|
} catch (error2) {
|
|
3501
3671
|
const result = this.getClientRequestErrorResult(error2);
|
|
3502
3672
|
if (result) return result;
|
|
3503
3673
|
throw error2;
|
|
3504
3674
|
}
|
|
3505
3675
|
const [_filter, _select, _populate, pagination, allowedSortFields] = await Promise.all([
|
|
3506
|
-
overrideFilter
|
|
3676
|
+
overrideFilter ?? this.genFilter("list", parsedFilter),
|
|
3507
3677
|
overrideSelect || this.genQuerySelect("list", select),
|
|
3508
3678
|
overridePopulate || this.genPopulate(populateAccess, populate),
|
|
3509
3679
|
genPagination({ skip, limit, page, pageSize }, this.options.listHardLimit),
|
|
3510
3680
|
this.genAllowedFields({}, "list", this.baseFieldsExt)
|
|
3511
3681
|
]);
|
|
3512
3682
|
const finalSelect = normalizeSelect(_select);
|
|
3513
|
-
const filteredPopulate = (0,
|
|
3514
|
-
const { includes, correlatedIncludes, includeLocalFields, includePaths, correlatedReferenceFields } =
|
|
3683
|
+
const filteredPopulate = (0, import_utils17.isArray)(finalSelect) && (0, import_utils17.isArray)(_populate) ? _populate.filter((p) => finalSelect.includes(p.path.split(".")[0])) : _populate;
|
|
3684
|
+
const { includes, correlatedIncludes, includeLocalFields, includePaths, correlatedReferenceFields } = processedInclude;
|
|
3515
3685
|
const correlatedOutputPaths = correlatedIncludes.map((entry) => entry.path);
|
|
3516
3686
|
const query = {
|
|
3517
3687
|
filter: _filter,
|
|
@@ -3548,8 +3718,8 @@ var Service = class extends Base {
|
|
|
3548
3718
|
originalDocumentSnapshot: toObject(doc),
|
|
3549
3719
|
resolvedQuery: query
|
|
3550
3720
|
}));
|
|
3551
|
-
const _decorate = (0,
|
|
3552
|
-
const correlatedSnapshots = docs.map((doc) => (0,
|
|
3721
|
+
const _decorate = (0, import_utils17.isFunction)(decorate) ? decorate : (v) => v;
|
|
3722
|
+
const correlatedSnapshots = docs.map((doc) => (0, import_utils17.cloneDeep)(toObject(doc)));
|
|
3553
3723
|
try {
|
|
3554
3724
|
docs = await this.includeDocs(docs, includes);
|
|
3555
3725
|
if (correlatedIncludes.length > 0) {
|
|
@@ -3665,16 +3835,16 @@ var Service = class extends Base {
|
|
|
3665
3835
|
resolvedQuery: resolvedPopulate.length > 0 ? { populate: resolvedPopulate } : {}
|
|
3666
3836
|
};
|
|
3667
3837
|
const allowedFields = await this.genAllowedFields(item, "create");
|
|
3668
|
-
const allowedData = (0,
|
|
3838
|
+
const allowedData = (0, import_utils17.pick)(item, allowedFields);
|
|
3669
3839
|
context.allowedFields = allowedFields;
|
|
3670
3840
|
context.allowedData = allowedData;
|
|
3671
3841
|
const validated = await this.validate(allowedData, "create", context);
|
|
3672
|
-
if ((0,
|
|
3842
|
+
if ((0, import_utils17.isBoolean)(validated)) {
|
|
3673
3843
|
if (!validated) {
|
|
3674
3844
|
validationErrors.push({ index, errors: [] });
|
|
3675
3845
|
return void 0;
|
|
3676
3846
|
}
|
|
3677
|
-
} else if ((0,
|
|
3847
|
+
} else if ((0, import_utils17.isArray)(validated)) {
|
|
3678
3848
|
if (validated.length > 0) {
|
|
3679
3849
|
validationErrors.push({
|
|
3680
3850
|
index,
|
|
@@ -3704,7 +3874,7 @@ var Service = class extends Base {
|
|
|
3704
3874
|
contexts[index].preparedData = preparedData;
|
|
3705
3875
|
return preparedData;
|
|
3706
3876
|
});
|
|
3707
|
-
const _decorate = (0,
|
|
3877
|
+
const _decorate = (0, import_utils17.isFunction)(decorate) ? decorate : (v) => v;
|
|
3708
3878
|
const createdDocs = await this.model.create(items);
|
|
3709
3879
|
const docs = await mapWithConcurrencyLimit(createdDocs, maxBulkConcurrency, async (doc, index) => {
|
|
3710
3880
|
contexts[index].currentDocument = doc;
|
|
@@ -3721,7 +3891,7 @@ var Service = class extends Base {
|
|
|
3721
3891
|
}
|
|
3722
3892
|
if (includeDocPermissions) doc = await this.addDocPermissions(doc, "create", contexts[index]);
|
|
3723
3893
|
if (includePermissions) doc = await this.addFieldPermissions(doc, "read", contexts[index]);
|
|
3724
|
-
if (resolvedPopulate.length > 0) await populateDoc(doc, resolvedPopulate);
|
|
3894
|
+
if (resolvedPopulate.length > 0) await this.persist(() => populateDoc(doc, resolvedPopulate));
|
|
3725
3895
|
doc = await this.trimOutputFields(doc, "read", this.baseFieldsExt);
|
|
3726
3896
|
let outputDoc = await _decorate(doc, contexts[index]);
|
|
3727
3897
|
if (!includePermissions) outputDoc = this.addEmptyPermissions(outputDoc);
|
|
@@ -3777,6 +3947,13 @@ var Service = class extends Base {
|
|
|
3777
3947
|
data: doc
|
|
3778
3948
|
};
|
|
3779
3949
|
}
|
|
3950
|
+
/**
|
|
3951
|
+
* Update at authorized policy paths: admitted leaves preserve omitted siblings;
|
|
3952
|
+
* whole-authorized objects/arrays replace. Shared by updateById and existing-row
|
|
3953
|
+
* upsert. Validation precedes trusted prepare output (not re-filtered); partial
|
|
3954
|
+
* prepare containers preserve omissions. Transform retains explicit document-setter
|
|
3955
|
+
* replacement authority. Send nested client JSON, not literal dotted update keys.
|
|
3956
|
+
*/
|
|
3780
3957
|
async updateOne(filter2, data, args, options, decorate) {
|
|
3781
3958
|
const filterErrors = this.validateClientFilter(filter2);
|
|
3782
3959
|
if (filterErrors.length > 0) return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: filterErrors };
|
|
@@ -3784,7 +3961,7 @@ var Service = class extends Base {
|
|
|
3784
3961
|
const { skim, includePermissions, populateAccess } = this.resolveUpdateOneOptions(options);
|
|
3785
3962
|
const { filter: overrideFilter, populate: overridePopulate } = overrides ?? {};
|
|
3786
3963
|
const [_filter, _populate] = await Promise.all([
|
|
3787
|
-
overrideFilter
|
|
3964
|
+
overrideFilter ?? this.genFilter("update", filter2),
|
|
3788
3965
|
overridePopulate || this.genPopulate(populateAccess, populate)
|
|
3789
3966
|
]);
|
|
3790
3967
|
const query = { filter: _filter, populate: _populate };
|
|
@@ -3822,16 +3999,16 @@ var Service = class extends Base {
|
|
|
3822
3999
|
context.docPermissions = this.getDocPermissions(doc);
|
|
3823
4000
|
context.currentDocument = doc;
|
|
3824
4001
|
const allowedFields = await this.genAllowedFields(doc, "update");
|
|
3825
|
-
const allowedData = (0,
|
|
4002
|
+
const allowedData = (0, import_utils17.pick)(data, allowedFields);
|
|
3826
4003
|
context.allowedFields = allowedFields;
|
|
3827
4004
|
context.allowedData = allowedData;
|
|
3828
4005
|
const validated = await this.validate(allowedData, "update", context);
|
|
3829
|
-
if ((0,
|
|
4006
|
+
if ((0, import_utils17.isBoolean)(validated)) {
|
|
3830
4007
|
if (!validated) {
|
|
3831
4008
|
this.completeOp("updateOne", startedAt, "bad_request" /* BadRequest */, _filter);
|
|
3832
4009
|
return { success: false, kind: "error", code: "bad_request" /* BadRequest */ };
|
|
3833
4010
|
}
|
|
3834
|
-
} else if ((0,
|
|
4011
|
+
} else if ((0, import_utils17.isArray)(validated)) {
|
|
3835
4012
|
if (validated.length > 0) {
|
|
3836
4013
|
this.completeOp("updateOne", startedAt, "bad_request" /* BadRequest */, _filter);
|
|
3837
4014
|
return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: validated };
|
|
@@ -3839,18 +4016,18 @@ var Service = class extends Base {
|
|
|
3839
4016
|
}
|
|
3840
4017
|
const prepared = await this.prepare(allowedData, "update", context);
|
|
3841
4018
|
context.preparedData = prepared;
|
|
3842
|
-
|
|
4019
|
+
applyUpdate(doc, prepared, allowedFields);
|
|
3843
4020
|
context.modifiedPaths = doc.modifiedPaths();
|
|
3844
4021
|
doc = assertModelDocument(await this.transform(doc, "update", context), this.modelName, "transform");
|
|
3845
4022
|
context.currentDocument = doc;
|
|
3846
|
-
doc = await doc.save();
|
|
4023
|
+
doc = await this.persist(() => doc.save());
|
|
3847
4024
|
const diffExcludeFields = [this.options.documentPermissionField, "__v"];
|
|
3848
4025
|
this.asServiceHookContext(context).diff = (d) => {
|
|
3849
4026
|
context.changes = (0, import_just_diff.diff)(
|
|
3850
|
-
(0,
|
|
3851
|
-
(0,
|
|
4027
|
+
(0, import_utils17.omit)(context.originalDocumentSnapshot, diffExcludeFields),
|
|
4028
|
+
(0, import_utils17.omit)(d.toObject({ virtuals: false }), diffExcludeFields)
|
|
3852
4029
|
) || [];
|
|
3853
|
-
context.modifiedPaths = (0,
|
|
4030
|
+
context.modifiedPaths = (0, import_utils17.uniq)(context.changes.map((di) => di.path.length > 0 ? String(di.path[0]) : ""));
|
|
3854
4031
|
};
|
|
3855
4032
|
doc = assertModelDocument(await this.afterPersist(doc, "update", context), this.modelName, "afterPersist");
|
|
3856
4033
|
context.currentDocument = doc;
|
|
@@ -3863,10 +4040,10 @@ var Service = class extends Base {
|
|
|
3863
4040
|
}
|
|
3864
4041
|
if (includeDocPermissions) doc = await this.addDocPermissions(doc, "update", context);
|
|
3865
4042
|
if (includePermissions) doc = await this.addFieldPermissions(doc, "update", context);
|
|
3866
|
-
if (_populate) await populateDoc(doc, _populate);
|
|
4043
|
+
if (_populate) await this.persist(() => populateDoc(doc, _populate));
|
|
3867
4044
|
doc = await this.trimOutputFields(doc, "read", this.baseFieldsExt);
|
|
3868
4045
|
let outputDoc = doc;
|
|
3869
|
-
if ((0,
|
|
4046
|
+
if ((0, import_utils17.isFunction)(decorate)) outputDoc = await decorate(outputDoc, context);
|
|
3870
4047
|
if (!includePermissions) outputDoc = this.addEmptyPermissions(outputDoc);
|
|
3871
4048
|
this.completeOp("updateOne", startedAt, "success" /* Success */, _filter);
|
|
3872
4049
|
return { success: true, kind: "single", code: "success" /* Success */, data: outputDoc, input: prepared };
|
|
@@ -3875,7 +4052,8 @@ var Service = class extends Base {
|
|
|
3875
4052
|
const { populate, overrides } = this.resolveUpdateByIdArgs(args);
|
|
3876
4053
|
const { skim, includePermissions, populateAccess } = this.resolveUpdateByIdOptions(options);
|
|
3877
4054
|
const { populate: overridePopulate, idFilter: overrideIdFilter } = overrides;
|
|
3878
|
-
const filter2 = overrideIdFilter
|
|
4055
|
+
const filter2 = overrideIdFilter ?? await this.genIDFilter(id);
|
|
4056
|
+
if (filter2 === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */, query: { filter: filter2 } };
|
|
3879
4057
|
return this.updateOne(
|
|
3880
4058
|
filter2,
|
|
3881
4059
|
data,
|
|
@@ -3895,7 +4073,7 @@ var Service = class extends Base {
|
|
|
3895
4073
|
const { populate, overrides } = this.resolveUpsertArgs(args);
|
|
3896
4074
|
const { skim, includePermissions, populateAccess } = this.resolveUpsertOptions(options);
|
|
3897
4075
|
const { filter: overrideFilter, populate: overridePopulate } = overrides ?? {};
|
|
3898
|
-
const _filter = await (overrideFilter
|
|
4076
|
+
const _filter = await (overrideFilter ?? this.genFilter("update", filter2));
|
|
3899
4077
|
const query = { filter: _filter };
|
|
3900
4078
|
const startedAt = this.beginOp("upsert", _filter);
|
|
3901
4079
|
if (_filter === false) {
|
|
@@ -3955,7 +4133,9 @@ var Service = class extends Base {
|
|
|
3955
4133
|
resolvedQuery: query
|
|
3956
4134
|
};
|
|
3957
4135
|
await this.beforeDelete(doc, context);
|
|
3958
|
-
await
|
|
4136
|
+
await this.persist(
|
|
4137
|
+
() => "deleteOne" in doc ? doc.deleteOne() : doc.remove()
|
|
4138
|
+
);
|
|
3959
4139
|
context.finalDocumentSnapshot = toObject(doc);
|
|
3960
4140
|
await this.afterDelete(doc, context);
|
|
3961
4141
|
this.completeOp("delete", startedAt, "success" /* Success */, filter2);
|
|
@@ -3966,6 +4146,7 @@ var Service = class extends Base {
|
|
|
3966
4146
|
if (filterErrors.length > 0) return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: filterErrors };
|
|
3967
4147
|
const { access, includeId } = this.resolveExistsOptions(options);
|
|
3968
4148
|
filter2 = await this.genFilter(access, filter2);
|
|
4149
|
+
if (filter2 === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */, query: { filter: filter2 } };
|
|
3969
4150
|
const result = await this.model.exists(filter2);
|
|
3970
4151
|
return {
|
|
3971
4152
|
success: true,
|
|
@@ -4035,6 +4216,13 @@ var Service = class extends Base {
|
|
|
4035
4216
|
query
|
|
4036
4217
|
};
|
|
4037
4218
|
}
|
|
4219
|
+
/**
|
|
4220
|
+
* Group target document IDs by original parent-key aliases using one aggregate.
|
|
4221
|
+
* Resolves the requested row policy (legacy count includes pass `count`), casts
|
|
4222
|
+
* authorized filters/foreign operands with the target schema, and deduplicates IDs
|
|
4223
|
+
* independently of pagination. Cast failures return BadRequest; false policy returns
|
|
4224
|
+
* Forbidden. Casting does not execute countDocuments middleware/plugins.
|
|
4225
|
+
*/
|
|
4038
4226
|
async countByFieldValues(foreignField, values, filter2 = {}, access = "list") {
|
|
4039
4227
|
if (!isValidFieldPath(foreignField)) {
|
|
4040
4228
|
return {
|
|
@@ -4046,14 +4234,32 @@ var Service = class extends Base {
|
|
|
4046
4234
|
}
|
|
4047
4235
|
const filterErrors = this.validateClientFilter(filter2);
|
|
4048
4236
|
if (filterErrors.length > 0) return { success: false, kind: "error", code: "bad_request" /* BadRequest */, errors: filterErrors };
|
|
4049
|
-
const uniqueValues = (0,
|
|
4237
|
+
const uniqueValues = (0, import_utils17.uniqBy)(values, (value) => String(value));
|
|
4050
4238
|
filter2 = await this.genFilter(access, {
|
|
4051
4239
|
...filter2,
|
|
4052
4240
|
[foreignField]: { $in: uniqueValues }
|
|
4053
4241
|
});
|
|
4054
4242
|
const query = { filter: filter2 };
|
|
4055
4243
|
if (filter2 === false) return { success: false, kind: "error", code: "forbidden" /* Forbidden */, query };
|
|
4056
|
-
|
|
4244
|
+
let matchFilter = filter2;
|
|
4245
|
+
let castValues = uniqueValues;
|
|
4246
|
+
try {
|
|
4247
|
+
if (this.model.castFilter) {
|
|
4248
|
+
matchFilter = this.model.castFilter(matchFilter);
|
|
4249
|
+
const foreignFilter = this.model.castFilter({ [foreignField]: { $in: uniqueValues } });
|
|
4250
|
+
castValues = foreignFilter[foreignField]?.$in;
|
|
4251
|
+
if (!Array.isArray(castValues) || castValues.length !== uniqueValues.length) {
|
|
4252
|
+
throw new Error("Foreign field query casting must retain the join operands");
|
|
4253
|
+
}
|
|
4254
|
+
}
|
|
4255
|
+
} catch {
|
|
4256
|
+
return {
|
|
4257
|
+
success: false,
|
|
4258
|
+
kind: "error",
|
|
4259
|
+
code: "bad_request" /* BadRequest */,
|
|
4260
|
+
errors: [{ detail: "Invalid grouped include count filter or foreign-key value" }]
|
|
4261
|
+
};
|
|
4262
|
+
}
|
|
4057
4263
|
const rows = await this.model.aggregate([
|
|
4058
4264
|
{ $match: matchFilter },
|
|
4059
4265
|
{
|
|
@@ -4064,12 +4270,20 @@ var Service = class extends Base {
|
|
|
4064
4270
|
}
|
|
4065
4271
|
},
|
|
4066
4272
|
{ $unwind: "$foreignValues" },
|
|
4067
|
-
{ $match: { foreignValues: { $in:
|
|
4273
|
+
{ $match: { foreignValues: { $in: castValues } } },
|
|
4068
4274
|
{ $group: { _id: "$foreignValues", documentIds: { $addToSet: "$_id" } } }
|
|
4069
4275
|
]);
|
|
4070
|
-
const
|
|
4276
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
4071
4277
|
for (const row of rows) {
|
|
4072
|
-
|
|
4278
|
+
const key = String(row._id);
|
|
4279
|
+
const ids = grouped.get(key) ?? /* @__PURE__ */ new Set();
|
|
4280
|
+
for (const id of row.documentIds) ids.add(String(id));
|
|
4281
|
+
grouped.set(key, ids);
|
|
4282
|
+
}
|
|
4283
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4284
|
+
for (let i = 0; i < uniqueValues.length; i++) {
|
|
4285
|
+
const ids = grouped.get(String(castValues[i]));
|
|
4286
|
+
if (ids) counts.set(String(uniqueValues[i]), ids);
|
|
4073
4287
|
}
|
|
4074
4288
|
return { success: true, kind: "single", code: "success" /* Success */, data: counts, query };
|
|
4075
4289
|
}
|
|
@@ -4122,7 +4336,7 @@ var Service = class extends Base {
|
|
|
4122
4336
|
return resolveExistsOptions(this, options);
|
|
4123
4337
|
}
|
|
4124
4338
|
async getFieldPermissionAccess(ids) {
|
|
4125
|
-
const uniqueIds = (0,
|
|
4339
|
+
const uniqueIds = (0, import_utils17.compact)((0, import_utils17.uniqBy)(ids, (id) => String(id)).map((id) => String(id)));
|
|
4126
4340
|
if (uniqueIds.length === 0) {
|
|
4127
4341
|
return {
|
|
4128
4342
|
readIds: /* @__PURE__ */ new Set(),
|
|
@@ -4148,17 +4362,60 @@ var Service = class extends Base {
|
|
|
4148
4362
|
async readSub(id, sub, subId, options) {
|
|
4149
4363
|
return readSub(this, id, sub, subId, options);
|
|
4150
4364
|
}
|
|
4365
|
+
/**
|
|
4366
|
+
* Apply authorized policy-path updates, preserving protected siblings, then save.
|
|
4367
|
+
* Output requires post-save parent read and subdocument read operation/row access;
|
|
4368
|
+
* hidden output is successful `data: null` (direct/root-entry 200), not a failed write.
|
|
4369
|
+
* Visible output uses read fields plus `_id`. Do not retry solely for null output.
|
|
4370
|
+
*/
|
|
4151
4371
|
async updateSub(id, sub, subId, data) {
|
|
4152
|
-
return updateSub(
|
|
4372
|
+
return updateSub(
|
|
4373
|
+
this,
|
|
4374
|
+
this.persist,
|
|
4375
|
+
(access) => this.req.macl.isAllowed(this.modelName, access),
|
|
4376
|
+
id,
|
|
4377
|
+
sub,
|
|
4378
|
+
subId,
|
|
4379
|
+
data
|
|
4380
|
+
);
|
|
4153
4381
|
}
|
|
4382
|
+
/**
|
|
4383
|
+
* Save authorized targeted updates, then return readable targets in stored order.
|
|
4384
|
+
* Requires parent/subdocument read access for output, not subdocument list access;
|
|
4385
|
+
* uses read fields plus `_id`. Hidden output succeeds with `data: [], count: 0`
|
|
4386
|
+
* (direct/root-entry 200); count measures visible rows, not all updated rows.
|
|
4387
|
+
*/
|
|
4154
4388
|
async bulkUpdateSub(id, sub, data) {
|
|
4155
|
-
return bulkUpdateSub(
|
|
4389
|
+
return bulkUpdateSub(
|
|
4390
|
+
this,
|
|
4391
|
+
this.persist,
|
|
4392
|
+
(access) => this.req.macl.isAllowed(this.modelName, access),
|
|
4393
|
+
id,
|
|
4394
|
+
sub,
|
|
4395
|
+
(0, import_utils17.castArray)(data)
|
|
4396
|
+
);
|
|
4156
4397
|
}
|
|
4398
|
+
/**
|
|
4399
|
+
* Append/prepend admitted rows, then return the visible full array (including when
|
|
4400
|
+
* input is empty). Output requires post-save parent read and subdocument list AND
|
|
4401
|
+
* read guards/row filters; fields use read projection plus `_id`.
|
|
4402
|
+
* Hidden output succeeds with code `created`, `data: [], count: 0`
|
|
4403
|
+
* (direct/root-entry 201). Visible count/order follow filtered stored rows.
|
|
4404
|
+
* Empty output does not mean the write failed; addFirst is a service option.
|
|
4405
|
+
*/
|
|
4157
4406
|
async createSub(id, sub, data, options) {
|
|
4158
|
-
return createSub(
|
|
4407
|
+
return createSub(
|
|
4408
|
+
this,
|
|
4409
|
+
this.persist,
|
|
4410
|
+
(access) => this.req.macl.isAllowed(this.modelName, access),
|
|
4411
|
+
id,
|
|
4412
|
+
sub,
|
|
4413
|
+
data,
|
|
4414
|
+
options
|
|
4415
|
+
);
|
|
4159
4416
|
}
|
|
4160
4417
|
async deleteSub(id, sub, subId) {
|
|
4161
|
-
return deleteSub(this, id, sub, subId);
|
|
4418
|
+
return deleteSub(this, this.persist, id, sub, subId);
|
|
4162
4419
|
}
|
|
4163
4420
|
async getParentDoc(id, sub, args, options) {
|
|
4164
4421
|
return getParentDoc(this, id, sub, args, options);
|
|
@@ -4166,7 +4423,7 @@ var Service = class extends Base {
|
|
|
4166
4423
|
};
|
|
4167
4424
|
|
|
4168
4425
|
// src/services/public-service.ts
|
|
4169
|
-
var
|
|
4426
|
+
var import_utils18 = require("@web-ts-toolkit/utils");
|
|
4170
4427
|
var PublicService = class extends Service {
|
|
4171
4428
|
async _list(filter2, args, options) {
|
|
4172
4429
|
const { select, populate, include, sort, skip, limit, page, pageSize, tasks } = this.resolvePublicListArgs(args);
|
|
@@ -4205,7 +4462,7 @@ var PublicService = class extends Service {
|
|
|
4205
4462
|
let d = toObject(doc);
|
|
4206
4463
|
d = await this.decorate(d, "create", context);
|
|
4207
4464
|
d = this.runTasks(d, tasks);
|
|
4208
|
-
if (select) d = (0,
|
|
4465
|
+
if (select) d = (0, import_utils18.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]);
|
|
4209
4466
|
return d;
|
|
4210
4467
|
}
|
|
4211
4468
|
);
|
|
@@ -4232,6 +4489,7 @@ var PublicService = class extends Service {
|
|
|
4232
4489
|
},
|
|
4233
4490
|
{ skim, includePermissions, access, populateAccess, lean }
|
|
4234
4491
|
);
|
|
4492
|
+
if (!result.success && (result.code === "bad_request" /* BadRequest */ || result.code === "forbidden" /* Forbidden */)) return result;
|
|
4235
4493
|
if (tryList && (!result.success || !result.data)) {
|
|
4236
4494
|
const listAllowed = await this.req.macl.isAllowed(this.modelName, "list");
|
|
4237
4495
|
if (!listAllowed) {
|
|
@@ -4272,6 +4530,7 @@ var PublicService = class extends Service {
|
|
|
4272
4530
|
},
|
|
4273
4531
|
{ skim, includePermissions, access, populateAccess, lean }
|
|
4274
4532
|
);
|
|
4533
|
+
if (!result.success && (result.code === "bad_request" /* BadRequest */ || result.code === "forbidden" /* Forbidden */)) return result;
|
|
4275
4534
|
if (tryList && (!result.success || !result.data)) {
|
|
4276
4535
|
const listAllowed = await this.req.macl.isAllowed(this.modelName, "list");
|
|
4277
4536
|
if (!listAllowed) {
|
|
@@ -4310,8 +4569,8 @@ var PublicService = class extends Service {
|
|
|
4310
4569
|
let d = toObject(doc);
|
|
4311
4570
|
d = await this.decorate(d, "update", context);
|
|
4312
4571
|
d = this.runTasks(d, tasks);
|
|
4313
|
-
if (select) d = (0,
|
|
4314
|
-
else if (!returningAll) d = (0,
|
|
4572
|
+
if (select) d = (0, import_utils18.pick)(d, [...normalizeSelect(select), ...this.baseFieldsExt]);
|
|
4573
|
+
else if (!returningAll) d = (0, import_utils18.pick)(d, [...Object.keys(data), "_id"]);
|
|
4315
4574
|
return d;
|
|
4316
4575
|
}
|
|
4317
4576
|
);
|
|
@@ -4320,6 +4579,11 @@ var PublicService = class extends Service {
|
|
|
4320
4579
|
}
|
|
4321
4580
|
return result;
|
|
4322
4581
|
}
|
|
4582
|
+
/**
|
|
4583
|
+
* With an _id, check update-policy existence then update: terminal denial returns
|
|
4584
|
+
* Forbidden, an allowed miss remains Unauthorized, and neither creates a row.
|
|
4585
|
+
* Without an _id, use the create path.
|
|
4586
|
+
*/
|
|
4323
4587
|
async _upsert(data, args, options) {
|
|
4324
4588
|
const idKey = this.getIdentifier();
|
|
4325
4589
|
if (idKey !== "_id") {
|
|
@@ -4433,7 +4697,7 @@ var PublicService = class extends Service {
|
|
|
4433
4697
|
};
|
|
4434
4698
|
|
|
4435
4699
|
// src/services/data-service.ts
|
|
4436
|
-
var
|
|
4700
|
+
var import_utils19 = require("@web-ts-toolkit/utils");
|
|
4437
4701
|
var DataService = class {
|
|
4438
4702
|
constructor(req, dataName) {
|
|
4439
4703
|
this.req = req;
|
|
@@ -4455,7 +4719,7 @@ var DataService = class {
|
|
|
4455
4719
|
let doc = await findElement(this.data, _filter);
|
|
4456
4720
|
if (!doc) return { success: false, kind: "error", code: "not_found" /* NotFound */, query };
|
|
4457
4721
|
doc = await this.trimOutputFields(doc, access);
|
|
4458
|
-
if (_select.length > 0) doc = (0,
|
|
4722
|
+
if (_select.length > 0) doc = (0, import_utils19.pick)(doc, _select);
|
|
4459
4723
|
return { success: true, kind: "single", code: "success" /* Success */, data: doc, query };
|
|
4460
4724
|
}
|
|
4461
4725
|
async findById(id, args, options) {
|
|
@@ -4495,13 +4759,13 @@ var DataService = class {
|
|
|
4495
4759
|
const totalCount = docs.length;
|
|
4496
4760
|
if (sort) {
|
|
4497
4761
|
const normalizedSort = normalizeSortForOrderBy(sort);
|
|
4498
|
-
docs = (0,
|
|
4762
|
+
docs = (0, import_utils19.orderBy)(docs, normalizedSort.fields, normalizedSort.orders);
|
|
4499
4763
|
}
|
|
4500
4764
|
const pagedDocs = docs.slice(query.skip, query.limit && query.skip + query.limit);
|
|
4501
4765
|
const { maxHookConcurrency } = this.getRequestComplexity();
|
|
4502
4766
|
const trimmed = await mapWithConcurrencyLimit(pagedDocs, maxHookConcurrency, async (doc) => {
|
|
4503
4767
|
doc = await this.trimOutputFields(doc, "list");
|
|
4504
|
-
if (_select.length > 0) doc = (0,
|
|
4768
|
+
if (_select.length > 0) doc = (0, import_utils19.pick)(doc, _select);
|
|
4505
4769
|
return doc;
|
|
4506
4770
|
});
|
|
4507
4771
|
if (!hasExplicitLimit && trimmed.length === totalCount) {
|
|
@@ -4550,7 +4814,7 @@ var DataService = class {
|
|
|
4550
4814
|
};
|
|
4551
4815
|
|
|
4552
4816
|
// src/processors.ts
|
|
4553
|
-
var
|
|
4817
|
+
var import_utils20 = require("@web-ts-toolkit/utils");
|
|
4554
4818
|
var UNSAFE_PATH_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
4555
4819
|
var DEFAULT_MAX_SLICE = 1e3;
|
|
4556
4820
|
var DEFAULT_MASK_REPLACEMENT = "***";
|
|
@@ -4585,10 +4849,10 @@ function resolveLeafParents(obj, src) {
|
|
|
4585
4849
|
for (let ind = 0; ind < segs.length - 1; ind += 1) {
|
|
4586
4850
|
const seg = segs[ind];
|
|
4587
4851
|
targets = targets.reduce((ret, target) => {
|
|
4588
|
-
if (!(0,
|
|
4852
|
+
if (!(0, import_utils20.isPlainObject)(target)) return ret;
|
|
4589
4853
|
const targetObject = target;
|
|
4590
4854
|
const next = targetObject[seg];
|
|
4591
|
-
if ((0,
|
|
4855
|
+
if ((0, import_utils20.isArray)(next)) {
|
|
4592
4856
|
for (const item of next) {
|
|
4593
4857
|
ret.push(item);
|
|
4594
4858
|
}
|
|
@@ -4598,8 +4862,8 @@ function resolveLeafParents(obj, src) {
|
|
|
4598
4862
|
}
|
|
4599
4863
|
const leaf = segs[segs.length - 1];
|
|
4600
4864
|
const pairs = [];
|
|
4601
|
-
(0,
|
|
4602
|
-
if (!(0,
|
|
4865
|
+
(0, import_utils20.forEach)(targets, (target) => {
|
|
4866
|
+
if (!(0, import_utils20.isPlainObject)(target)) return;
|
|
4603
4867
|
pairs.push({ parent: target, leaf });
|
|
4604
4868
|
});
|
|
4605
4869
|
return pairs;
|
|
@@ -4607,8 +4871,8 @@ function resolveLeafParents(obj, src) {
|
|
|
4607
4871
|
var copyAndDepopulate = (docObject, operations, options = { mutable: true, idField: "_id" }) => {
|
|
4608
4872
|
const mutable = options.mutable !== false;
|
|
4609
4873
|
const idField = options.idField ?? "_id";
|
|
4610
|
-
const obj = mutable ? docObject : (0,
|
|
4611
|
-
(0,
|
|
4874
|
+
const obj = mutable ? docObject : (0, import_utils20.cloneDeep)(docObject);
|
|
4875
|
+
(0, import_utils20.forEach)(Array.isArray(operations) ? operations : [], (op) => {
|
|
4612
4876
|
if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
|
|
4613
4877
|
const src = op.src;
|
|
4614
4878
|
const dest = op.dest;
|
|
@@ -4617,19 +4881,19 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
4617
4881
|
assertSafePath(dest);
|
|
4618
4882
|
let targets = [obj];
|
|
4619
4883
|
const segs = src.split(".");
|
|
4620
|
-
(0,
|
|
4884
|
+
(0, import_utils20.forEach)(segs, (seg, ind) => {
|
|
4621
4885
|
if (segs.length === ind + 1) {
|
|
4622
|
-
(0,
|
|
4623
|
-
if (!(0,
|
|
4886
|
+
(0, import_utils20.forEach)(targets, (target) => {
|
|
4887
|
+
if (!(0, import_utils20.isPlainObject)(target)) return;
|
|
4624
4888
|
const targetObject = target;
|
|
4625
4889
|
const leaf = targetObject[seg];
|
|
4626
4890
|
const sourceForDest = leaf;
|
|
4627
4891
|
let depopulated;
|
|
4628
|
-
if ((0,
|
|
4892
|
+
if ((0, import_utils20.isArray)(leaf)) {
|
|
4629
4893
|
if (leaf.length === 0) {
|
|
4630
4894
|
depopulated = [];
|
|
4631
|
-
} else if (leaf.every((item) => (0,
|
|
4632
|
-
depopulated = (0,
|
|
4895
|
+
} else if (leaf.every((item) => (0, import_utils20.isPlainObject)(item))) {
|
|
4896
|
+
depopulated = (0, import_utils20.map)(leaf, idField).map((id, i) => {
|
|
4633
4897
|
if (id === void 0) {
|
|
4634
4898
|
failMissingId(`${src}[${i}]`);
|
|
4635
4899
|
}
|
|
@@ -4638,8 +4902,8 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
4638
4902
|
} else {
|
|
4639
4903
|
return;
|
|
4640
4904
|
}
|
|
4641
|
-
} else if ((0,
|
|
4642
|
-
const id = (0,
|
|
4905
|
+
} else if ((0, import_utils20.isPlainObject)(leaf)) {
|
|
4906
|
+
const id = (0, import_utils20.get)(leaf, idField);
|
|
4643
4907
|
if (id === void 0) {
|
|
4644
4908
|
failMissingId(src);
|
|
4645
4909
|
}
|
|
@@ -4647,15 +4911,15 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
4647
4911
|
} else {
|
|
4648
4912
|
return;
|
|
4649
4913
|
}
|
|
4650
|
-
(0,
|
|
4651
|
-
(0,
|
|
4914
|
+
(0, import_utils20.set)(targetObject, dest, sourceForDest);
|
|
4915
|
+
(0, import_utils20.set)(targetObject, seg, depopulated);
|
|
4652
4916
|
});
|
|
4653
4917
|
} else {
|
|
4654
4918
|
targets = targets.reduce((ret, target) => {
|
|
4655
|
-
if (!(0,
|
|
4919
|
+
if (!(0, import_utils20.isPlainObject)(target)) return ret;
|
|
4656
4920
|
const targetObject = target;
|
|
4657
4921
|
const next = targetObject[seg];
|
|
4658
|
-
if ((0,
|
|
4922
|
+
if ((0, import_utils20.isArray)(next)) {
|
|
4659
4923
|
for (const item of next) {
|
|
4660
4924
|
ret.push(item);
|
|
4661
4925
|
}
|
|
@@ -4669,8 +4933,8 @@ var copyAndDepopulate = (docObject, operations, options = { mutable: true, idFie
|
|
|
4669
4933
|
};
|
|
4670
4934
|
var copyPaths = (docObject, operations, options = { mutable: true }) => {
|
|
4671
4935
|
const mutable = options.mutable !== false;
|
|
4672
|
-
const obj = mutable ? docObject : (0,
|
|
4673
|
-
(0,
|
|
4936
|
+
const obj = mutable ? docObject : (0, import_utils20.cloneDeep)(docObject);
|
|
4937
|
+
(0, import_utils20.forEach)(Array.isArray(operations) ? operations : [], (op) => {
|
|
4674
4938
|
if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
|
|
4675
4939
|
const src = op.src;
|
|
4676
4940
|
const dest = op.dest;
|
|
@@ -4678,17 +4942,17 @@ var copyPaths = (docObject, operations, options = { mutable: true }) => {
|
|
|
4678
4942
|
assertSafePath(src, "copyPaths");
|
|
4679
4943
|
assertSafePath(dest, "copyPaths");
|
|
4680
4944
|
if (src === dest) return;
|
|
4681
|
-
(0,
|
|
4682
|
-
if (!(0,
|
|
4683
|
-
(0,
|
|
4945
|
+
(0, import_utils20.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
|
|
4946
|
+
if (!(0, import_utils20.hasOwn)(parent, leaf)) return;
|
|
4947
|
+
(0, import_utils20.set)(parent, dest, (0, import_utils20.cloneDeep)(parent[leaf]));
|
|
4684
4948
|
});
|
|
4685
4949
|
});
|
|
4686
4950
|
return obj;
|
|
4687
4951
|
};
|
|
4688
4952
|
var movePaths = (docObject, operations, options = { mutable: true }) => {
|
|
4689
4953
|
const mutable = options.mutable !== false;
|
|
4690
|
-
const obj = mutable ? docObject : (0,
|
|
4691
|
-
(0,
|
|
4954
|
+
const obj = mutable ? docObject : (0, import_utils20.cloneDeep)(docObject);
|
|
4955
|
+
(0, import_utils20.forEach)(Array.isArray(operations) ? operations : [], (op) => {
|
|
4692
4956
|
if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
|
|
4693
4957
|
const src = op.src;
|
|
4694
4958
|
const dest = op.dest;
|
|
@@ -4696,10 +4960,10 @@ var movePaths = (docObject, operations, options = { mutable: true }) => {
|
|
|
4696
4960
|
assertSafePath(src, "movePaths");
|
|
4697
4961
|
assertSafePath(dest, "movePaths");
|
|
4698
4962
|
if (src === dest) return;
|
|
4699
|
-
(0,
|
|
4700
|
-
if (!(0,
|
|
4701
|
-
const value = (0,
|
|
4702
|
-
(0,
|
|
4963
|
+
(0, import_utils20.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
|
|
4964
|
+
if (!(0, import_utils20.hasOwn)(parent, leaf)) return;
|
|
4965
|
+
const value = (0, import_utils20.cloneDeep)(parent[leaf]);
|
|
4966
|
+
(0, import_utils20.set)(parent, dest, value);
|
|
4703
4967
|
if (dest === leaf || dest.startsWith(`${leaf}.`)) return;
|
|
4704
4968
|
delete parent[leaf];
|
|
4705
4969
|
});
|
|
@@ -4710,8 +4974,8 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
|
|
|
4710
4974
|
const mutable = options.mutable !== false;
|
|
4711
4975
|
const maxSlice = options.maxSlice ?? DEFAULT_MAX_SLICE;
|
|
4712
4976
|
assertNonNegativeSafeInteger(maxSlice, "maxSlice", "sliceArrays");
|
|
4713
|
-
const obj = mutable ? docObject : (0,
|
|
4714
|
-
(0,
|
|
4977
|
+
const obj = mutable ? docObject : (0, import_utils20.cloneDeep)(docObject);
|
|
4978
|
+
(0, import_utils20.forEach)(Array.isArray(operations) ? operations : [], (op) => {
|
|
4715
4979
|
if (!op || typeof op.src !== "string") return;
|
|
4716
4980
|
const src = op.src;
|
|
4717
4981
|
if (src.length === 0) return;
|
|
@@ -4728,15 +4992,15 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
|
|
|
4728
4992
|
assertNonNegativeSafeInteger(op.limit, "limit", "sliceArrays");
|
|
4729
4993
|
limit = Math.min(op.limit, maxSlice);
|
|
4730
4994
|
}
|
|
4731
|
-
(0,
|
|
4995
|
+
(0, import_utils20.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
|
|
4732
4996
|
const leafValue = parent[leaf];
|
|
4733
|
-
if (!(0,
|
|
4997
|
+
if (!(0, import_utils20.isArray)(leafValue)) return;
|
|
4734
4998
|
const end = typeof limit === "undefined" ? void 0 : skip + limit;
|
|
4735
4999
|
const window = leafValue.slice(skip, end);
|
|
4736
5000
|
if (typeof rawDest === "undefined") {
|
|
4737
|
-
(0,
|
|
5001
|
+
(0, import_utils20.set)(parent, leaf, window);
|
|
4738
5002
|
} else {
|
|
4739
|
-
(0,
|
|
5003
|
+
(0, import_utils20.set)(parent, rawDest, window);
|
|
4740
5004
|
}
|
|
4741
5005
|
});
|
|
4742
5006
|
});
|
|
@@ -4744,44 +5008,44 @@ var sliceArrays = (docObject, operations, options = { mutable: true, maxSlice: D
|
|
|
4744
5008
|
};
|
|
4745
5009
|
var countPaths = (docObject, operations, options = { mutable: true }) => {
|
|
4746
5010
|
const mutable = options.mutable !== false;
|
|
4747
|
-
const obj = mutable ? docObject : (0,
|
|
4748
|
-
(0,
|
|
5011
|
+
const obj = mutable ? docObject : (0, import_utils20.cloneDeep)(docObject);
|
|
5012
|
+
(0, import_utils20.forEach)(Array.isArray(operations) ? operations : [], (op) => {
|
|
4749
5013
|
if (!op || typeof op.src !== "string" || typeof op.dest !== "string") return;
|
|
4750
5014
|
const src = op.src;
|
|
4751
5015
|
const dest = op.dest;
|
|
4752
5016
|
if (src.length === 0 || dest.length === 0) return;
|
|
4753
5017
|
assertSafePath(src, "countPaths");
|
|
4754
5018
|
assertSafePath(dest, "countPaths");
|
|
4755
|
-
(0,
|
|
4756
|
-
if (!(0,
|
|
5019
|
+
(0, import_utils20.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
|
|
5020
|
+
if (!(0, import_utils20.hasOwn)(parent, leaf)) return;
|
|
4757
5021
|
const leafValue = parent[leaf];
|
|
4758
5022
|
let count;
|
|
4759
|
-
if ((0,
|
|
5023
|
+
if ((0, import_utils20.isArray)(leafValue)) {
|
|
4760
5024
|
count = leafValue.length;
|
|
4761
|
-
} else if ((0,
|
|
5025
|
+
} else if ((0, import_utils20.isPlainObject)(leafValue)) {
|
|
4762
5026
|
count = Object.keys(leafValue).length;
|
|
4763
5027
|
} else if (leafValue === null || typeof leafValue === "undefined") {
|
|
4764
5028
|
count = 0;
|
|
4765
5029
|
} else {
|
|
4766
5030
|
count = 1;
|
|
4767
5031
|
}
|
|
4768
|
-
(0,
|
|
5032
|
+
(0, import_utils20.set)(parent, dest, count);
|
|
4769
5033
|
});
|
|
4770
5034
|
});
|
|
4771
5035
|
return obj;
|
|
4772
5036
|
};
|
|
4773
5037
|
var maskPaths = (docObject, operations, options = { mutable: true }) => {
|
|
4774
5038
|
const mutable = options.mutable !== false;
|
|
4775
|
-
const obj = mutable ? docObject : (0,
|
|
4776
|
-
(0,
|
|
5039
|
+
const obj = mutable ? docObject : (0, import_utils20.cloneDeep)(docObject);
|
|
5040
|
+
(0, import_utils20.forEach)(Array.isArray(operations) ? operations : [], (op) => {
|
|
4777
5041
|
if (!op || typeof op.src !== "string") return;
|
|
4778
5042
|
const src = op.src;
|
|
4779
5043
|
if (src.length === 0) return;
|
|
4780
5044
|
assertSafePath(src, "maskPaths");
|
|
4781
5045
|
const replacement = Object.prototype.hasOwnProperty.call(op, "replacement") ? op.replacement : DEFAULT_MASK_REPLACEMENT;
|
|
4782
|
-
(0,
|
|
4783
|
-
if (!(0,
|
|
4784
|
-
(0,
|
|
5046
|
+
(0, import_utils20.forEach)(resolveLeafParents(obj, src), ({ parent, leaf }) => {
|
|
5047
|
+
if (!(0, import_utils20.hasOwn)(parent, leaf)) return;
|
|
5048
|
+
(0, import_utils20.set)(parent, leaf, replacement);
|
|
4785
5049
|
});
|
|
4786
5050
|
});
|
|
4787
5051
|
return obj;
|
|
@@ -4825,10 +5089,10 @@ var Cache = class {
|
|
|
4825
5089
|
};
|
|
4826
5090
|
|
|
4827
5091
|
// src/core-shared.ts
|
|
4828
|
-
var
|
|
5092
|
+
var import_utils22 = require("@web-ts-toolkit/utils");
|
|
4829
5093
|
|
|
4830
5094
|
// src/permission.ts
|
|
4831
|
-
var
|
|
5095
|
+
var import_utils21 = require("@web-ts-toolkit/utils");
|
|
4832
5096
|
var Permission = class {
|
|
4833
5097
|
constructor(permissions) {
|
|
4834
5098
|
this.permissions = { ...permissions };
|
|
@@ -4844,7 +5108,7 @@ var Permission = class {
|
|
|
4844
5108
|
return [permissionOrPermissions].concat(permissions);
|
|
4845
5109
|
}
|
|
4846
5110
|
hasKey(permission) {
|
|
4847
|
-
return (0,
|
|
5111
|
+
return (0, import_utils21.hasOwn)(this.permissions, permission);
|
|
4848
5112
|
}
|
|
4849
5113
|
has(permission) {
|
|
4850
5114
|
return this.permissions[permission] === true;
|
|
@@ -4864,10 +5128,10 @@ var permission_default = Permission;
|
|
|
4864
5128
|
|
|
4865
5129
|
// src/core-shared.ts
|
|
4866
5130
|
function isAndFilter(filter2) {
|
|
4867
|
-
return !!filter2 && (0,
|
|
5131
|
+
return !!filter2 && (0, import_utils22.isPlainObject)(filter2) && Object.keys(filter2).length === 1 && (0, import_utils22.isArray)(filter2.$and);
|
|
4868
5132
|
}
|
|
4869
5133
|
function isMergeableClause(filter2) {
|
|
4870
|
-
return !!filter2 && (0,
|
|
5134
|
+
return !!filter2 && (0, import_utils22.isPlainObject)(filter2) && Object.keys(filter2).every((key) => !key.startsWith("$"));
|
|
4871
5135
|
}
|
|
4872
5136
|
function optimizeAndFilter(clausesInput) {
|
|
4873
5137
|
const clauses = [];
|
|
@@ -4882,10 +5146,10 @@ function optimizeAndFilter(clausesInput) {
|
|
|
4882
5146
|
}
|
|
4883
5147
|
}
|
|
4884
5148
|
const dedupeKey = (value) => {
|
|
4885
|
-
if ((0,
|
|
5149
|
+
if ((0, import_utils22.isArray)(value)) {
|
|
4886
5150
|
return `[${value.map(dedupeKey).join(",")}]`;
|
|
4887
5151
|
}
|
|
4888
|
-
if ((0,
|
|
5152
|
+
if ((0, import_utils22.isPlainObject)(value)) {
|
|
4889
5153
|
return `{${Object.keys(value).sort().map((key) => `${key}:${dedupeKey(value[key])}`).join(",")}}`;
|
|
4890
5154
|
}
|
|
4891
5155
|
return JSON.stringify(value);
|
|
@@ -4909,7 +5173,7 @@ function optimizeAndFilter(clausesInput) {
|
|
|
4909
5173
|
}
|
|
4910
5174
|
let canMerge = true;
|
|
4911
5175
|
for (const [key, value] of Object.entries(clause)) {
|
|
4912
|
-
if ((0,
|
|
5176
|
+
if ((0, import_utils22.hasOwn)(mergedClause, key) && !(0, import_utils22.isEqual)(mergedClause[key], value)) {
|
|
4913
5177
|
canMerge = false;
|
|
4914
5178
|
break;
|
|
4915
5179
|
}
|
|
@@ -4920,24 +5184,24 @@ function optimizeAndFilter(clausesInput) {
|
|
|
4920
5184
|
}
|
|
4921
5185
|
Object.assign(mergedClause, clause);
|
|
4922
5186
|
}
|
|
4923
|
-
const finalClauses = (0,
|
|
5187
|
+
const finalClauses = (0, import_utils22.isEmpty)(mergedClause) ? remainingClauses : [mergedClause, ...remainingClauses];
|
|
4924
5188
|
if (finalClauses.length === 0) return null;
|
|
4925
5189
|
if (finalClauses.length === 1) return finalClauses[0];
|
|
4926
5190
|
return { $and: finalClauses };
|
|
4927
5191
|
}
|
|
4928
5192
|
function normalizeFilter(filter2) {
|
|
4929
5193
|
if (filter2 === false) return false;
|
|
4930
|
-
if (!filter2 || !(0,
|
|
5194
|
+
if (!filter2 || !(0, import_utils22.isPlainObject)(filter2) || (0, import_utils22.isEmpty)(filter2)) return null;
|
|
4931
5195
|
if (!isAndFilter(filter2)) {
|
|
4932
5196
|
return filter2;
|
|
4933
5197
|
}
|
|
4934
5198
|
return optimizeAndFilter(filter2.$and);
|
|
4935
5199
|
}
|
|
4936
5200
|
async function resolveIdentifierFilter(req, idField, resolveIdFilter, id) {
|
|
4937
|
-
if ((0,
|
|
5201
|
+
if ((0, import_utils22.isFunction)(resolveIdFilter)) {
|
|
4938
5202
|
return await resolveIdFilter.call(req, id);
|
|
4939
5203
|
}
|
|
4940
|
-
if ((0,
|
|
5204
|
+
if ((0, import_utils22.isString)(idField)) {
|
|
4941
5205
|
return { [idField]: id };
|
|
4942
5206
|
}
|
|
4943
5207
|
return { _id: id };
|
|
@@ -4953,12 +5217,12 @@ async function resolveAccessFilter({
|
|
|
4953
5217
|
}) {
|
|
4954
5218
|
let nextFilter = normalizeFilter(filter2);
|
|
4955
5219
|
const overrideFilterFn = getOption(`overrideFilter.${access}`, null);
|
|
4956
|
-
if (nextFilter !== false && (0,
|
|
5220
|
+
if (nextFilter !== false && (0, import_utils22.isFunction)(overrideFilterFn)) {
|
|
4957
5221
|
nextFilter = normalizeFilter(await overrideFilterFn.call(req, nextFilter, permissions));
|
|
4958
5222
|
}
|
|
4959
5223
|
if (nextFilter === false) return false;
|
|
4960
5224
|
const baseFilterFn = getOption(`baseFilter.${access}`, null);
|
|
4961
|
-
if (!(0,
|
|
5225
|
+
if (!(0, import_utils22.isFunction)(baseFilterFn)) return nextFilter ?? {};
|
|
4962
5226
|
const baseFilter = normalizeFilter(
|
|
4963
5227
|
cache.has(cacheKey) ? cache.get(cacheKey) : await baseFilterFn.call(req, permissions)
|
|
4964
5228
|
);
|
|
@@ -4992,34 +5256,34 @@ async function setRequestPermissions(req) {
|
|
|
4992
5256
|
if (owner === activeRuntime) return;
|
|
4993
5257
|
if (hasFieldValue && owner === void 0) return;
|
|
4994
5258
|
const globalPermissions = getGlobalOption("globalPermissions");
|
|
4995
|
-
if (!(0,
|
|
5259
|
+
if (!(0, import_utils22.isFunction)(globalPermissions)) return;
|
|
4996
5260
|
const permissions = await globalPermissions.call(req, req);
|
|
4997
|
-
if ((0,
|
|
4998
|
-
else if ((0,
|
|
4999
|
-
else if ((0,
|
|
5261
|
+
if ((0, import_utils22.isPlainObject)(permissions)) req[requestPermissionField] = permissions;
|
|
5262
|
+
else if ((0, import_utils22.isArray)(permissions)) req[requestPermissionField] = (0, import_utils22.arrayToRecord)(permissions);
|
|
5263
|
+
else if ((0, import_utils22.isString)(permissions)) req[requestPermissionField] = { [permissions]: true };
|
|
5000
5264
|
owners.set(requestPermissionField, activeRuntime);
|
|
5001
5265
|
}
|
|
5002
5266
|
async function evaluateRouteGuard(req, permissions, routeGuard) {
|
|
5003
5267
|
const phas = (key) => permissions.has(key);
|
|
5004
5268
|
const { stringHandler, arrayHandler } = createValidator(phas);
|
|
5005
|
-
if ((0,
|
|
5269
|
+
if ((0, import_utils22.isBoolean)(routeGuard)) {
|
|
5006
5270
|
return routeGuard === true;
|
|
5007
5271
|
}
|
|
5008
|
-
if ((0,
|
|
5272
|
+
if ((0, import_utils22.isString)(routeGuard)) {
|
|
5009
5273
|
return stringHandler(routeGuard);
|
|
5010
5274
|
}
|
|
5011
|
-
if ((0,
|
|
5275
|
+
if ((0, import_utils22.isArray)(routeGuard)) {
|
|
5012
5276
|
return arrayHandler(routeGuard);
|
|
5013
5277
|
}
|
|
5014
|
-
if ((0,
|
|
5278
|
+
if ((0, import_utils22.isFunction)(routeGuard)) {
|
|
5015
5279
|
return routeGuard.call(req, permissions);
|
|
5016
5280
|
}
|
|
5017
5281
|
return false;
|
|
5018
5282
|
}
|
|
5019
5283
|
async function callHookChain(req, hook, doc, permissions, context) {
|
|
5020
|
-
const hooks = (0,
|
|
5284
|
+
const hooks = (0, import_utils22.castArray)(hook);
|
|
5021
5285
|
for (let x = 0; x < hooks.length; x++) {
|
|
5022
|
-
if ((0,
|
|
5286
|
+
if ((0, import_utils22.isFunction)(hooks[x])) {
|
|
5023
5287
|
doc = await hooks[x].call(req, doc, permissions, context);
|
|
5024
5288
|
}
|
|
5025
5289
|
}
|
|
@@ -5042,13 +5306,13 @@ async function collectSchemaFields({
|
|
|
5042
5306
|
if (baseFields.includes(key)) continue;
|
|
5043
5307
|
const val = permissionSchema[key];
|
|
5044
5308
|
const value = val && val[access] || val;
|
|
5045
|
-
if ((0,
|
|
5309
|
+
if ((0, import_utils22.isBoolean)(value)) {
|
|
5046
5310
|
if (value) fields.push(key);
|
|
5047
|
-
} else if ((0,
|
|
5311
|
+
} else if ((0, import_utils22.isString)(value)) {
|
|
5048
5312
|
if (stringHandler(value)) fields.push(key);
|
|
5049
|
-
} else if ((0,
|
|
5313
|
+
} else if ((0, import_utils22.isArray)(value)) {
|
|
5050
5314
|
if (arrayHandler(value)) fields.push(key);
|
|
5051
|
-
} else if ((0,
|
|
5315
|
+
} else if ((0, import_utils22.isFunction)(value)) {
|
|
5052
5316
|
if (await value.call(req, ...functionArgs)) fields.push(key);
|
|
5053
5317
|
}
|
|
5054
5318
|
}
|
|
@@ -5134,7 +5398,7 @@ async function runDecorateAllHook({
|
|
|
5134
5398
|
}
|
|
5135
5399
|
|
|
5136
5400
|
// src/acl/select-resolution.ts
|
|
5137
|
-
var
|
|
5401
|
+
var import_utils23 = require("@web-ts-toolkit/utils");
|
|
5138
5402
|
async function collectAllowedFieldsForRequest({
|
|
5139
5403
|
req,
|
|
5140
5404
|
permissionSchema,
|
|
@@ -5202,15 +5466,15 @@ async function resolveSelectForRequest({
|
|
|
5202
5466
|
const excludeall = normalizedSelect.every((v) => v.startsWith("-"));
|
|
5203
5467
|
if (excludeall) {
|
|
5204
5468
|
normalizedSelect = normalizedSelect.map((v) => v.substring(1));
|
|
5205
|
-
fields = (0,
|
|
5469
|
+
fields = (0, import_utils23.difference)(fields, normalizedSelect);
|
|
5206
5470
|
if (excludeid) fields.push("-_id");
|
|
5207
5471
|
} else {
|
|
5208
|
-
fields = (0,
|
|
5472
|
+
fields = (0, import_utils23.intersection)(normalizedSelect, fields.concat(excludeid ? "-_id" : "_id"));
|
|
5209
5473
|
}
|
|
5210
5474
|
}
|
|
5211
5475
|
return fields.concat(alwaysSelectFields);
|
|
5212
5476
|
}
|
|
5213
|
-
return (0,
|
|
5477
|
+
return (0, import_utils23.intersection)(normalizedSelect, fields);
|
|
5214
5478
|
}
|
|
5215
5479
|
|
|
5216
5480
|
// src/core.ts
|
|
@@ -5225,10 +5489,10 @@ var Core = class {
|
|
|
5225
5489
|
getIdentifier(modelName) {
|
|
5226
5490
|
const resolveIdFilter = getModelOption(modelName, "resolveIdFilter");
|
|
5227
5491
|
const idField = getModelOption(modelName, "idField");
|
|
5228
|
-
if ((0,
|
|
5492
|
+
if ((0, import_utils24.isFunction)(resolveIdFilter)) {
|
|
5229
5493
|
return null;
|
|
5230
5494
|
}
|
|
5231
|
-
if ((0,
|
|
5495
|
+
if ((0, import_utils24.isString)(idField)) {
|
|
5232
5496
|
return idField;
|
|
5233
5497
|
}
|
|
5234
5498
|
return "_id";
|
|
@@ -5306,11 +5570,11 @@ var Core = class {
|
|
|
5306
5570
|
async genPopulate(modelName, access = "read", _populate = null, subPaths = []) {
|
|
5307
5571
|
if (!_populate) return [];
|
|
5308
5572
|
let populate = Array.isArray(_populate) ? _populate : [_populate];
|
|
5309
|
-
populate = (0,
|
|
5573
|
+
populate = (0, import_utils24.compact)(
|
|
5310
5574
|
await Promise.all(
|
|
5311
5575
|
populate.map(async (p) => {
|
|
5312
|
-
const populateAccess = !(0,
|
|
5313
|
-
const ret = (0,
|
|
5576
|
+
const populateAccess = !(0, import_utils24.isString)(p) && p.access ? p.access : access;
|
|
5577
|
+
const ret = (0, import_utils24.isString)(p) ? { path: p } : {
|
|
5314
5578
|
path: p.path,
|
|
5315
5579
|
select: normalizeSelect(p.select)
|
|
5316
5580
|
};
|
|
@@ -5348,10 +5612,10 @@ var Core = class {
|
|
|
5348
5612
|
}
|
|
5349
5613
|
async validate(modelName, allowedData, access, context) {
|
|
5350
5614
|
const validate = getModelOption(modelName, `validate.${access}`, null);
|
|
5351
|
-
if ((0,
|
|
5615
|
+
if ((0, import_utils24.isFunction)(validate)) {
|
|
5352
5616
|
const permissions = this.getGlobalPermissions();
|
|
5353
5617
|
return validate.call(this.req, allowedData, permissions, context);
|
|
5354
|
-
} else if ((0,
|
|
5618
|
+
} else if ((0, import_utils24.isBoolean)(validate) || (0, import_utils24.isArray)(validate)) {
|
|
5355
5619
|
return validate;
|
|
5356
5620
|
} else {
|
|
5357
5621
|
return true;
|
|
@@ -5376,7 +5640,7 @@ var Core = class {
|
|
|
5376
5640
|
const changeOptions = getModelOption(modelName, `onChange`, {});
|
|
5377
5641
|
for (let x = 0; x < context.modifiedPaths.length; x++) {
|
|
5378
5642
|
const mpath = context.modifiedPaths[x];
|
|
5379
|
-
if ((0,
|
|
5643
|
+
if ((0, import_utils24.isFunction)(changeOptions[mpath])) {
|
|
5380
5644
|
await changeOptions[mpath].call(
|
|
5381
5645
|
this.req,
|
|
5382
5646
|
context.originalDocumentSnapshot[mpath],
|
|
@@ -5400,7 +5664,7 @@ var Core = class {
|
|
|
5400
5664
|
async genDocPermissions(modelName, doc, access, context) {
|
|
5401
5665
|
const docPermissionsFn = getModelOption(modelName, `docPermissions.${access}`, null);
|
|
5402
5666
|
let docPermissions = {};
|
|
5403
|
-
if ((0,
|
|
5667
|
+
if ((0, import_utils24.isFunction)(docPermissionsFn)) {
|
|
5404
5668
|
const permissions = this.getGlobalPermissions();
|
|
5405
5669
|
try {
|
|
5406
5670
|
docPermissions = await docPermissionsFn.call(this.req, doc, permissions, context);
|
|
@@ -5451,7 +5715,7 @@ var Core = class {
|
|
|
5451
5715
|
readExists ? this.genAllowedFields(modelName, doc, "read") : [],
|
|
5452
5716
|
updateExists ? this.genAllowedFields(modelName, doc, "update") : []
|
|
5453
5717
|
]);
|
|
5454
|
-
const viewObj = (0,
|
|
5718
|
+
const viewObj = (0, import_utils24.reduce)(
|
|
5455
5719
|
views,
|
|
5456
5720
|
(ret, view) => {
|
|
5457
5721
|
ret[view] = true;
|
|
@@ -5459,7 +5723,7 @@ var Core = class {
|
|
|
5459
5723
|
},
|
|
5460
5724
|
{}
|
|
5461
5725
|
);
|
|
5462
|
-
const editObj = (0,
|
|
5726
|
+
const editObj = (0, import_utils24.reduce)(
|
|
5463
5727
|
edits,
|
|
5464
5728
|
(ret, view) => {
|
|
5465
5729
|
ret[view] = true;
|
|
@@ -5483,9 +5747,9 @@ var Core = class {
|
|
|
5483
5747
|
return runDecorateAllHook({ req: this.req, hook: decorateAll, docs, permissions, context });
|
|
5484
5748
|
}
|
|
5485
5749
|
runTasks(modelName, docObject, task) {
|
|
5486
|
-
const tasks = (0,
|
|
5750
|
+
const tasks = (0, import_utils24.compact)((0, import_utils24.castArray)(task));
|
|
5487
5751
|
if (tasks.length === 0) return docObject;
|
|
5488
|
-
(0,
|
|
5752
|
+
(0, import_utils24.forEach)(tasks, (task2) => {
|
|
5489
5753
|
const { type, args, options } = task2;
|
|
5490
5754
|
switch (type) {
|
|
5491
5755
|
case "COPY_AND_DEPOPULATE":
|
|
@@ -5553,9 +5817,9 @@ var Core = class {
|
|
|
5553
5817
|
}
|
|
5554
5818
|
const [, field, op] = keys2;
|
|
5555
5819
|
const subOption = getExactModelOption(modelName, `operationAccess.${access}`);
|
|
5556
|
-
if ((0,
|
|
5820
|
+
if ((0, import_utils24.isUndefined)(subOption)) {
|
|
5557
5821
|
const subFieldOption = getExactModelOption(modelName, `operationAccess.subs.${field}`);
|
|
5558
|
-
if ((0,
|
|
5822
|
+
if ((0, import_utils24.isUndefined)(subFieldOption)) {
|
|
5559
5823
|
const opOption = getModelOption(modelName, `operationAccess.${op}`);
|
|
5560
5824
|
return this.canActivate(opOption);
|
|
5561
5825
|
}
|
|
@@ -5607,25 +5871,25 @@ function guard(condition) {
|
|
|
5607
5871
|
const permissions = req[PERMISSIONS];
|
|
5608
5872
|
let cond = condition;
|
|
5609
5873
|
let phas = (key) => permissions.has(key);
|
|
5610
|
-
if ((0,
|
|
5874
|
+
if ((0, import_utils25.isPlainObject)(condition)) {
|
|
5611
5875
|
const { modelName, id, condition: _cond } = condition;
|
|
5612
5876
|
const svc = req.macl.getPublicService(modelName);
|
|
5613
5877
|
const select = getModelOption(modelName, `alwaysSelectFields.read`, void 0);
|
|
5614
|
-
let _id = (0,
|
|
5615
|
-
if ((0,
|
|
5878
|
+
let _id = (0, import_utils25.isString)(id) ? id : null;
|
|
5879
|
+
if ((0, import_utils25.isPlainObject)(id)) {
|
|
5616
5880
|
const { type = "param", key } = id;
|
|
5617
5881
|
if (type === "param") {
|
|
5618
5882
|
const paramValue = req.params[key];
|
|
5619
|
-
_id = (0,
|
|
5883
|
+
_id = (0, import_utils25.isArray)(paramValue) ? paramValue[0] ?? null : paramValue ?? null;
|
|
5620
5884
|
} else if (type === "query") {
|
|
5621
5885
|
const _qval = req.query[key];
|
|
5622
|
-
if ((0,
|
|
5886
|
+
if ((0, import_utils25.isArray)(_qval)) _id = _qval.length > 0 ? _qval[0] : null;
|
|
5623
5887
|
else _id = _qval;
|
|
5624
5888
|
} else {
|
|
5625
5889
|
_id = null;
|
|
5626
5890
|
}
|
|
5627
5891
|
}
|
|
5628
|
-
if (!(0,
|
|
5892
|
+
if (!(0, import_utils25.isString)(_id) || !_id) {
|
|
5629
5893
|
return next(new import_express_json_router2.default.clientErrors.BadRequestError());
|
|
5630
5894
|
}
|
|
5631
5895
|
const result = await svc._read(_id, { select });
|
|
@@ -5637,11 +5901,11 @@ function guard(condition) {
|
|
|
5637
5901
|
cond = _cond;
|
|
5638
5902
|
}
|
|
5639
5903
|
const { stringHandler, arrayHandler } = createValidator(phas);
|
|
5640
|
-
if ((0,
|
|
5904
|
+
if ((0, import_utils25.isString)(cond)) {
|
|
5641
5905
|
if (stringHandler(cond)) return next();
|
|
5642
|
-
} else if ((0,
|
|
5906
|
+
} else if ((0, import_utils25.isArray)(cond)) {
|
|
5643
5907
|
if (arrayHandler(cond)) return next();
|
|
5644
|
-
} else if ((0,
|
|
5908
|
+
} else if ((0, import_utils25.isFunction)(cond)) {
|
|
5645
5909
|
const result = await cond.call(req, permissions);
|
|
5646
5910
|
if (!!result) return next();
|
|
5647
5911
|
}
|
|
@@ -5654,7 +5918,7 @@ var import_express2 = __toESM(require("express"));
|
|
|
5654
5918
|
|
|
5655
5919
|
// src/routers/model-router.ts
|
|
5656
5920
|
var import_express_json_router5 = __toESM(require("@web-ts-toolkit/express-json-router"));
|
|
5657
|
-
var
|
|
5921
|
+
var import_utils29 = require("@web-ts-toolkit/utils");
|
|
5658
5922
|
|
|
5659
5923
|
// src/routers/router-mutation.ts
|
|
5660
5924
|
var MODEL_BUILD_TIME_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -5783,7 +6047,7 @@ var import_express_json_router4 = __toESM(require("@web-ts-toolkit/express-json-
|
|
|
5783
6047
|
|
|
5784
6048
|
// src/validation/common.ts
|
|
5785
6049
|
var import_zod2 = require("zod");
|
|
5786
|
-
var
|
|
6050
|
+
var import_utils26 = require("@web-ts-toolkit/utils");
|
|
5787
6051
|
var stringOrStringArray = import_zod2.z.union([import_zod2.z.string(), import_zod2.z.array(import_zod2.z.string())]);
|
|
5788
6052
|
var safeIntegerString = (min, message) => import_zod2.z.string().regex(/^\d+$/, message).refine((value) => Number.isSafeInteger(Number(value)), "Expected a safe integer").refine((value) => Number(value) >= min, message);
|
|
5789
6053
|
var queryBooleanString = import_zod2.z.enum(["true", "false"]);
|
|
@@ -5883,7 +6147,7 @@ var correlatedFilterSchema = import_zod2.z.record(import_zod2.z.string(), import
|
|
|
5883
6147
|
}
|
|
5884
6148
|
});
|
|
5885
6149
|
var correlatedEmptyOptionsSchema = import_zod2.z.unknown().refine(
|
|
5886
|
-
(value) => value === void 0 || (0,
|
|
6150
|
+
(value) => value === void 0 || (0, import_utils26.isPlainObject)(value) && Object.keys(value).length === 0,
|
|
5887
6151
|
"Correlated include options must be absent or empty"
|
|
5888
6152
|
).optional();
|
|
5889
6153
|
var correlatedPathSchema = import_zod2.z.string().min(1).superRefine((path, ctx) => {
|
|
@@ -5920,7 +6184,7 @@ var correlatedListArgsSchema = import_zod2.z.object({
|
|
|
5920
6184
|
include: import_zod2.z.lazy(() => correlatedNestedIncludeSchema).optional()
|
|
5921
6185
|
}).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
|
|
5922
6186
|
var correlatedCountArgsSchema = import_zod2.z.unknown().refine(
|
|
5923
|
-
(value) => value === void 0 || (0,
|
|
6187
|
+
(value) => value === void 0 || (0, import_utils26.isPlainObject)(value) && Object.keys(value).length === 0,
|
|
5924
6188
|
"Count includes accept no args"
|
|
5925
6189
|
).optional();
|
|
5926
6190
|
var correlatedReadByIdSchema = import_zod2.z.object({
|
|
@@ -5970,7 +6234,7 @@ var correlatedNestedIncludeSchema = import_zod2.z.union([includeItemSchema, impo
|
|
|
5970
6234
|
var rejectDuplicateCorrelatedPaths = (items, ctx) => {
|
|
5971
6235
|
const seen = /* @__PURE__ */ new Set();
|
|
5972
6236
|
items.forEach((item, index) => {
|
|
5973
|
-
if ((0,
|
|
6237
|
+
if ((0, import_utils26.isPlainObject)(item) && item.mode === "correlated" && typeof item.path === "string") {
|
|
5974
6238
|
if (seen.has(item.path)) {
|
|
5975
6239
|
ctx.addIssue({
|
|
5976
6240
|
code: import_zod2.z.ZodIssueCode.custom,
|
|
@@ -6169,19 +6433,12 @@ function fromJoi(schema) {
|
|
|
6169
6433
|
}
|
|
6170
6434
|
function fromAjv(validator) {
|
|
6171
6435
|
return async (value) => {
|
|
6172
|
-
|
|
6173
|
-
if (isThenable(outcome)) {
|
|
6436
|
+
if (validator.$async === true) {
|
|
6174
6437
|
try {
|
|
6175
|
-
const data = await
|
|
6176
|
-
if (data === false) {
|
|
6177
|
-
return {
|
|
6178
|
-
success: false,
|
|
6179
|
-
issues: normalizeAjvIssues(validator.errors ?? [])
|
|
6180
|
-
};
|
|
6181
|
-
}
|
|
6438
|
+
const data = await validator(value);
|
|
6182
6439
|
return {
|
|
6183
6440
|
success: true,
|
|
6184
|
-
data
|
|
6441
|
+
data
|
|
6185
6442
|
};
|
|
6186
6443
|
} catch (error2) {
|
|
6187
6444
|
if (!isAjvValidationError(error2)) {
|
|
@@ -6189,11 +6446,21 @@ function fromAjv(validator) {
|
|
|
6189
6446
|
}
|
|
6190
6447
|
return {
|
|
6191
6448
|
success: false,
|
|
6192
|
-
issues: normalizeAjvIssues(error2.errors
|
|
6449
|
+
issues: normalizeAjvIssues(error2.errors)
|
|
6193
6450
|
};
|
|
6194
6451
|
}
|
|
6195
6452
|
}
|
|
6196
|
-
const
|
|
6453
|
+
const outcome = validator(value);
|
|
6454
|
+
if (isThenable(outcome)) {
|
|
6455
|
+
void Promise.resolve(outcome).catch(() => {
|
|
6456
|
+
});
|
|
6457
|
+
throw new TypeError(
|
|
6458
|
+
"fromAjv: promise/thenable validators must declare $async: true and resolve with validated data"
|
|
6459
|
+
);
|
|
6460
|
+
}
|
|
6461
|
+
if (typeof outcome !== "boolean") {
|
|
6462
|
+
throw new TypeError("fromAjv: synchronous validators must return a boolean verdict");
|
|
6463
|
+
}
|
|
6197
6464
|
if (outcome) {
|
|
6198
6465
|
return {
|
|
6199
6466
|
success: true,
|
|
@@ -6202,7 +6469,9 @@ function fromAjv(validator) {
|
|
|
6202
6469
|
}
|
|
6203
6470
|
return {
|
|
6204
6471
|
success: false,
|
|
6205
|
-
|
|
6472
|
+
// Normalize immediately, copying message/path before another call can
|
|
6473
|
+
// replace the errors array or mutate its entries.
|
|
6474
|
+
issues: normalizeAjvIssues(validator.errors ?? [])
|
|
6206
6475
|
};
|
|
6207
6476
|
};
|
|
6208
6477
|
}
|
|
@@ -6432,14 +6701,14 @@ function isArkTypeErrors(value) {
|
|
|
6432
6701
|
return record.arkKind === "errors" || record[" arkKind"] === "errors";
|
|
6433
6702
|
}
|
|
6434
6703
|
function isThenable(value) {
|
|
6435
|
-
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
6704
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
6436
6705
|
}
|
|
6437
6706
|
function isAjvValidationError(error2) {
|
|
6438
6707
|
if (typeof error2 !== "object" || error2 === null || !("errors" in error2)) {
|
|
6439
6708
|
return false;
|
|
6440
6709
|
}
|
|
6441
|
-
const
|
|
6442
|
-
return
|
|
6710
|
+
const candidate = error2;
|
|
6711
|
+
return candidate.ajv === true && candidate.validation === true && Array.isArray(candidate.errors);
|
|
6443
6712
|
}
|
|
6444
6713
|
function isVineValidationError(error2) {
|
|
6445
6714
|
if (typeof error2 !== "object" || error2 === null || !("messages" in error2)) {
|
|
@@ -6878,7 +7147,7 @@ var rootDataQueryEntrySchema = import_zod5.z.union([
|
|
|
6878
7147
|
var rootQuerySchema = import_zod5.z.array(import_zod5.z.union([rootModelQueryEntrySchema, rootDataQueryEntrySchema]));
|
|
6879
7148
|
|
|
6880
7149
|
// src/routers/shared.ts
|
|
6881
|
-
var
|
|
7150
|
+
var import_utils27 = require("@web-ts-toolkit/utils");
|
|
6882
7151
|
|
|
6883
7152
|
// src/routers/model-router-collection-routes.ts
|
|
6884
7153
|
function setModelCollectionRoutes(context) {
|
|
@@ -6896,14 +7165,14 @@ function setModelCollectionRoutes(context) {
|
|
|
6896
7165
|
await context.assertAllowed(req, "list");
|
|
6897
7166
|
const { skip, limit, page, page_size, skim, include_permissions, include_count, include_extra_headers } = parseQuery(requestSchemas.listQuery, req.query);
|
|
6898
7167
|
const svc = context.getPublicService(req);
|
|
6899
|
-
const includeCount = (0,
|
|
6900
|
-
const includeExtraHeaders = (0,
|
|
7168
|
+
const includeCount = (0, import_utils27.parseBooleanString)(include_count);
|
|
7169
|
+
const includeExtraHeaders = (0, import_utils27.parseBooleanString)(include_extra_headers);
|
|
6901
7170
|
const result = await svc._list(
|
|
6902
7171
|
{},
|
|
6903
7172
|
{ skip, limit, page, pageSize: page_size },
|
|
6904
7173
|
{
|
|
6905
|
-
skim: (0,
|
|
6906
|
-
includePermissions: (0,
|
|
7174
|
+
skim: (0, import_utils27.parseBooleanString)(skim),
|
|
7175
|
+
includePermissions: (0, import_utils27.parseBooleanString)(include_permissions),
|
|
6907
7176
|
includeCount
|
|
6908
7177
|
}
|
|
6909
7178
|
);
|
|
@@ -6958,7 +7227,7 @@ function setModelCollectionRoutes(context) {
|
|
|
6958
7227
|
context.getRequestSchema("requestSchemas.create")
|
|
6959
7228
|
);
|
|
6960
7229
|
const svc = context.getPublicService(req);
|
|
6961
|
-
const result = await svc._create(data, {}, { includePermissions: (0,
|
|
7230
|
+
const result = await svc._create(data, {}, { includePermissions: (0, import_utils27.parseBooleanString)(include_permissions) });
|
|
6962
7231
|
handleResultError(result);
|
|
6963
7232
|
return formatModelCreatedResponse(result);
|
|
6964
7233
|
});
|
|
@@ -6994,7 +7263,7 @@ function setModelCollectionRoutes(context) {
|
|
|
6994
7263
|
finalData,
|
|
6995
7264
|
{ select: finalSelect, populate: finalPopulate, tasks: finalTasks },
|
|
6996
7265
|
{
|
|
6997
|
-
includePermissions: includePermissions ?? (0,
|
|
7266
|
+
includePermissions: includePermissions ?? (0, import_utils27.parseBooleanString)(include_permissions),
|
|
6998
7267
|
populateAccess
|
|
6999
7268
|
}
|
|
7000
7269
|
);
|
|
@@ -7086,8 +7355,8 @@ function setModelDocumentRoutes(context) {
|
|
|
7086
7355
|
id,
|
|
7087
7356
|
{},
|
|
7088
7357
|
{
|
|
7089
|
-
includePermissions: (0,
|
|
7090
|
-
tryList: (0,
|
|
7358
|
+
includePermissions: (0, import_utils27.parseBooleanString)(include_permissions),
|
|
7359
|
+
tryList: (0, import_utils27.parseBooleanString)(try_list)
|
|
7091
7360
|
}
|
|
7092
7361
|
);
|
|
7093
7362
|
handleResultError(result);
|
|
@@ -7172,8 +7441,8 @@ function setModelDocumentRoutes(context) {
|
|
|
7172
7441
|
data,
|
|
7173
7442
|
{},
|
|
7174
7443
|
{
|
|
7175
|
-
returningAll: (0,
|
|
7176
|
-
includePermissions: (0,
|
|
7444
|
+
returningAll: (0, import_utils27.parseBooleanString)(returning_all),
|
|
7445
|
+
includePermissions: (0, import_utils27.parseBooleanString)(include_permissions)
|
|
7177
7446
|
}
|
|
7178
7447
|
);
|
|
7179
7448
|
handleResultError(result);
|
|
@@ -7219,8 +7488,8 @@ function setModelDocumentRoutes(context) {
|
|
|
7219
7488
|
finalData,
|
|
7220
7489
|
{ select: finalSelect, populate: finalPopulate, tasks: finalTasks },
|
|
7221
7490
|
{
|
|
7222
|
-
returningAll: returningAll ?? (0,
|
|
7223
|
-
includePermissions: includePermissions ?? (0,
|
|
7491
|
+
returningAll: returningAll ?? (0, import_utils27.parseBooleanString)(returning_all),
|
|
7492
|
+
includePermissions: includePermissions ?? (0, import_utils27.parseBooleanString)(include_permissions),
|
|
7224
7493
|
populateAccess
|
|
7225
7494
|
}
|
|
7226
7495
|
);
|
|
@@ -7248,8 +7517,8 @@ function setModelDocumentRoutes(context) {
|
|
|
7248
7517
|
body,
|
|
7249
7518
|
{},
|
|
7250
7519
|
{
|
|
7251
|
-
returningAll: (0,
|
|
7252
|
-
includePermissions: (0,
|
|
7520
|
+
returningAll: (0, import_utils27.parseBooleanString)(returning_all),
|
|
7521
|
+
includePermissions: (0, import_utils27.parseBooleanString)(include_permissions)
|
|
7253
7522
|
}
|
|
7254
7523
|
);
|
|
7255
7524
|
handleResultError(result);
|
|
@@ -7293,8 +7562,8 @@ function setModelDocumentRoutes(context) {
|
|
|
7293
7562
|
finalData,
|
|
7294
7563
|
{ select: finalSelect, populate: finalPopulate, tasks: finalTasks },
|
|
7295
7564
|
{
|
|
7296
|
-
returningAll: returningAll ?? (0,
|
|
7297
|
-
includePermissions: includePermissions ?? (0,
|
|
7565
|
+
returningAll: returningAll ?? (0, import_utils27.parseBooleanString)(returning_all),
|
|
7566
|
+
includePermissions: includePermissions ?? (0, import_utils27.parseBooleanString)(include_permissions),
|
|
7298
7567
|
populateAccess
|
|
7299
7568
|
}
|
|
7300
7569
|
);
|
|
@@ -7532,11 +7801,11 @@ function setModelSubDocumentRoutes(context) {
|
|
|
7532
7801
|
}
|
|
7533
7802
|
|
|
7534
7803
|
// src/openapi/route-registration.ts
|
|
7535
|
-
var
|
|
7804
|
+
var import_utils28 = require("@web-ts-toolkit/utils");
|
|
7536
7805
|
function registerOpenApiRoute(runtime, basePath, defaultTag, route) {
|
|
7537
7806
|
runtime.registerOpenApiRoute({
|
|
7538
7807
|
...route,
|
|
7539
|
-
path: (0,
|
|
7808
|
+
path: (0, import_utils28.normalizeUrlPath)(basePath + route.path),
|
|
7540
7809
|
tags: route.tags ?? [defaultTag]
|
|
7541
7810
|
});
|
|
7542
7811
|
}
|
|
@@ -7544,8 +7813,8 @@ function registerOpenApiRoute(runtime, basePath, defaultTag, route) {
|
|
|
7544
7813
|
// src/routers/model-router.ts
|
|
7545
7814
|
var clientErrors2 = import_express_json_router5.default.clientErrors;
|
|
7546
7815
|
function setOption(parentKey, optionKey, option) {
|
|
7547
|
-
const key = (0,
|
|
7548
|
-
const value = (0,
|
|
7816
|
+
const key = (0, import_utils29.isUndefined)(option) ? parentKey : `${parentKey}.${optionKey}`;
|
|
7817
|
+
const value = (0, import_utils29.isUndefined)(option) ? optionKey : option;
|
|
7549
7818
|
assertMutableRouterOption("model", key);
|
|
7550
7819
|
this.runtime.setModelOption(this.modelName, key, value);
|
|
7551
7820
|
return this;
|
|
@@ -7707,7 +7976,7 @@ var ModelRouter = class _ModelRouter {
|
|
|
7707
7976
|
this.runtime = runtime;
|
|
7708
7977
|
this.runtime.setModelOptions(modelName, initialOptions);
|
|
7709
7978
|
this.options = this.runtime.getModelOptions(modelName);
|
|
7710
|
-
this.fullBasePath = (0,
|
|
7979
|
+
this.fullBasePath = (0, import_utils29.normalizeUrlPath)(this.options.parentPath + this.options.basePath);
|
|
7711
7980
|
this.modelName = modelName;
|
|
7712
7981
|
this.router = new import_express_json_router5.default(this.options.basePath, createSetCore(this.runtime), accessRouterResponseHandler);
|
|
7713
7982
|
this.model = new model_default(modelName, this.runtime);
|
|
@@ -7787,13 +8056,13 @@ var ModelRouter = class _ModelRouter {
|
|
|
7787
8056
|
}
|
|
7788
8057
|
logEndpoints() {
|
|
7789
8058
|
runWithRuntime(this.runtime, () => {
|
|
7790
|
-
(0,
|
|
7791
|
-
logInfoMessage(`${(0,
|
|
8059
|
+
(0, import_utils29.forEach)(this.router.getEndpoints(), ({ method, path }) => {
|
|
8060
|
+
logInfoMessage(`${(0, import_utils29.padEnd)(method, 6)} ${(0, import_utils29.normalizeUrlPath)(this.options.parentPath + path)}`);
|
|
7792
8061
|
});
|
|
7793
8062
|
});
|
|
7794
8063
|
}
|
|
7795
8064
|
set(keyOrOptions, value) {
|
|
7796
|
-
if (arguments.length === 2 && (0,
|
|
8065
|
+
if (arguments.length === 2 && (0, import_utils29.isString)(keyOrOptions)) {
|
|
7797
8066
|
assertMutableRouterOption("model", keyOrOptions);
|
|
7798
8067
|
this.runtime.setModelOption(
|
|
7799
8068
|
this.modelName,
|
|
@@ -7801,7 +8070,7 @@ var ModelRouter = class _ModelRouter {
|
|
|
7801
8070
|
value
|
|
7802
8071
|
);
|
|
7803
8072
|
}
|
|
7804
|
-
if (arguments.length === 1 && (0,
|
|
8073
|
+
if (arguments.length === 1 && (0, import_utils29.isPlainObject)(keyOrOptions)) {
|
|
7805
8074
|
assertMutableRouterOptions("model", keyOrOptions);
|
|
7806
8075
|
this.runtime.setModelOptions(this.modelName, keyOrOptions);
|
|
7807
8076
|
}
|
|
@@ -7824,7 +8093,7 @@ var ModelRouter = class _ModelRouter {
|
|
|
7824
8093
|
|
|
7825
8094
|
// src/routers/root-router.ts
|
|
7826
8095
|
var import_express_json_router6 = __toESM(require("@web-ts-toolkit/express-json-router"));
|
|
7827
|
-
var
|
|
8096
|
+
var import_utils30 = require("@web-ts-toolkit/utils");
|
|
7828
8097
|
|
|
7829
8098
|
// src/core-data.ts
|
|
7830
8099
|
var DataCore = class {
|
|
@@ -8090,7 +8359,7 @@ var RootRouter = class {
|
|
|
8090
8359
|
this.setRoutes();
|
|
8091
8360
|
}
|
|
8092
8361
|
registerOpenApiRoute(route) {
|
|
8093
|
-
registerOpenApiRoute(this.runtime, (0,
|
|
8362
|
+
registerOpenApiRoute(this.runtime, (0, import_utils30.normalizeUrlPath)(this.basename), "root", route);
|
|
8094
8363
|
}
|
|
8095
8364
|
wrapResult(index, item, result) {
|
|
8096
8365
|
return {
|
|
@@ -8151,7 +8420,7 @@ var RootRouter = class {
|
|
|
8151
8420
|
groupItemsByOrder(items) {
|
|
8152
8421
|
const groups = /* @__PURE__ */ new Map();
|
|
8153
8422
|
items.forEach((item, index) => {
|
|
8154
|
-
const order = (0,
|
|
8423
|
+
const order = (0, import_utils30.isNumber)(item.order) ? item.order : 0;
|
|
8155
8424
|
const group = groups.get(order);
|
|
8156
8425
|
if (group) {
|
|
8157
8426
|
group.push({ index, item });
|
|
@@ -8222,7 +8491,7 @@ var RootRouter = class {
|
|
|
8222
8491
|
const arrResult = await this.runGroup(req, groupedItems[x]);
|
|
8223
8492
|
results.push(...arrResult);
|
|
8224
8493
|
}
|
|
8225
|
-
return (0,
|
|
8494
|
+
return (0, import_utils30.orderBy)(results, ["index"], ["asc"]);
|
|
8226
8495
|
});
|
|
8227
8496
|
this.registerOpenApiRoute({
|
|
8228
8497
|
method: "post",
|
|
@@ -8240,11 +8509,11 @@ var RootRouter = class {
|
|
|
8240
8509
|
|
|
8241
8510
|
// src/routers/data-router.ts
|
|
8242
8511
|
var import_express_json_router7 = __toESM(require("@web-ts-toolkit/express-json-router"));
|
|
8243
|
-
var
|
|
8512
|
+
var import_utils31 = require("@web-ts-toolkit/utils");
|
|
8244
8513
|
var clientErrors4 = import_express_json_router7.default.clientErrors;
|
|
8245
8514
|
function setOption2(parentKey, optionKey, option) {
|
|
8246
|
-
const key = (0,
|
|
8247
|
-
const value = (0,
|
|
8515
|
+
const key = (0, import_utils31.isUndefined)(option) ? parentKey : `${parentKey}.${optionKey}`;
|
|
8516
|
+
const value = (0, import_utils31.isUndefined)(option) ? optionKey : option;
|
|
8248
8517
|
assertMutableRouterOption("data", key);
|
|
8249
8518
|
this.runtime.setDataOption(this.dataName, key, value);
|
|
8250
8519
|
return this;
|
|
@@ -8285,7 +8554,7 @@ var DataRouter = class {
|
|
|
8285
8554
|
this.runtime = runtime;
|
|
8286
8555
|
this.runtime.setDataOptions(dataName, initialOptions);
|
|
8287
8556
|
this.options = this.runtime.getDataOptions(dataName);
|
|
8288
|
-
this.fullBasePath = (0,
|
|
8557
|
+
this.fullBasePath = (0, import_utils31.normalizeUrlPath)(this.options.parentPath + this.options.basePath);
|
|
8289
8558
|
this.dataName = dataName;
|
|
8290
8559
|
this.router = new import_express_json_router7.default(this.options.basePath, createSetDataCore(this.runtime), accessRouterResponseHandler);
|
|
8291
8560
|
this.setCollectionRoutes();
|
|
@@ -8318,8 +8587,8 @@ var DataRouter = class {
|
|
|
8318
8587
|
req.query
|
|
8319
8588
|
);
|
|
8320
8589
|
const svc = this.getService(req);
|
|
8321
|
-
const includeCount = (0,
|
|
8322
|
-
const includeExtraHeaders = (0,
|
|
8590
|
+
const includeCount = (0, import_utils27.parseBooleanString)(include_count);
|
|
8591
|
+
const includeExtraHeaders = (0, import_utils27.parseBooleanString)(include_extra_headers);
|
|
8323
8592
|
const result = await svc.find(
|
|
8324
8593
|
{},
|
|
8325
8594
|
{ skip, limit, page, pageSize: page_size },
|
|
@@ -8437,11 +8706,11 @@ var DataRouter = class {
|
|
|
8437
8706
|
});
|
|
8438
8707
|
}
|
|
8439
8708
|
set(keyOrOptions, value) {
|
|
8440
|
-
if (arguments.length === 2 && (0,
|
|
8709
|
+
if (arguments.length === 2 && (0, import_utils31.isString)(keyOrOptions)) {
|
|
8441
8710
|
assertMutableRouterOption("data", keyOrOptions);
|
|
8442
8711
|
this.runtime.setDataOption(this.dataName, keyOrOptions, value);
|
|
8443
8712
|
}
|
|
8444
|
-
if (arguments.length === 1 && (0,
|
|
8713
|
+
if (arguments.length === 1 && (0, import_utils31.isPlainObject)(keyOrOptions)) {
|
|
8445
8714
|
assertMutableRouterOptions("data", keyOrOptions);
|
|
8446
8715
|
this.runtime.setDataOptions(this.dataName, keyOrOptions);
|
|
8447
8716
|
}
|
|
@@ -8564,7 +8833,7 @@ function createRuntimeApi(runtime) {
|
|
|
8564
8833
|
const wtt2 = runtimeMiddleware;
|
|
8565
8834
|
wtt2.runtime = runtime;
|
|
8566
8835
|
wtt2.createRouter = function(modelName, options) {
|
|
8567
|
-
if ((0,
|
|
8836
|
+
if ((0, import_utils32.isUndefined)(options)) {
|
|
8568
8837
|
return new RootRouter(modelName, runtime);
|
|
8569
8838
|
}
|
|
8570
8839
|
if (typeof modelName === "string") {
|
|
@@ -8585,10 +8854,10 @@ function createRuntimeApi(runtime) {
|
|
|
8585
8854
|
};
|
|
8586
8855
|
wtt2.combineRoutes = combineRoutes;
|
|
8587
8856
|
wtt2.set = function(keyOrOptions, value) {
|
|
8588
|
-
if (arguments.length === 2 && (0,
|
|
8857
|
+
if (arguments.length === 2 && (0, import_utils32.isString)(keyOrOptions)) {
|
|
8589
8858
|
return runtime.setGlobalOption(keyOrOptions, value);
|
|
8590
8859
|
}
|
|
8591
|
-
if (arguments.length === 1 && (0,
|
|
8860
|
+
if (arguments.length === 1 && (0, import_utils32.isPlainObject)(keyOrOptions)) {
|
|
8592
8861
|
return runtime.setGlobalOptions(keyOrOptions);
|
|
8593
8862
|
}
|
|
8594
8863
|
};
|