@web-ts-toolkit/access-router 0.44.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 +323 -2
- package/advanced.d.mts +655 -19
- package/advanced.d.ts +655 -19
- package/advanced.js +362 -22
- package/advanced.mjs +364 -23
- package/index.d.mts +5 -186
- package/index.d.ts +5 -186
- package/index.js +1783 -263
- package/index.mjs +1702 -178
- package/llms.txt +83 -2
- package/package.json +3 -3
- package/{parsers-B5dbVmjm.d.mts → parsers-BKF7VX2-.d.mts} +417 -13
- package/{parsers-B5dbVmjm.d.ts → parsers-BKF7VX2-.d.ts} +417 -13
- package/processors.d.mts +151 -1
- package/processors.d.ts +151 -1
- package/processors.js +170 -6
- package/processors.mjs +165 -6
package/advanced.mjs
CHANGED
|
@@ -56,13 +56,20 @@ import {
|
|
|
56
56
|
isNil as isNil2,
|
|
57
57
|
isPlainObject as isPlainObject9,
|
|
58
58
|
isString as isString3,
|
|
59
|
-
keys
|
|
59
|
+
keys,
|
|
60
|
+
normalizeUrlPath
|
|
60
61
|
} from "@web-ts-toolkit/utils";
|
|
61
62
|
|
|
62
63
|
// src/helpers/query.ts
|
|
63
64
|
import { flattenDeep, isNil, isPlainObject, isString, reduce } from "@web-ts-toolkit/utils";
|
|
64
65
|
var DEFAULT_LIST_HARD_LIMIT = 1e3;
|
|
65
66
|
|
|
67
|
+
// src/helpers/sort-policy.ts
|
|
68
|
+
var fieldPathPattern = /^[A-Za-z_][A-Za-z0-9_$]*(\.[A-Za-z_][A-Za-z0-9_$]*)*$/;
|
|
69
|
+
function isValidFieldPath(field) {
|
|
70
|
+
return typeof field === "string" && fieldPathPattern.test(field);
|
|
71
|
+
}
|
|
72
|
+
|
|
66
73
|
// src/helpers/index.ts
|
|
67
74
|
import { forEach, isArray, isEmpty, isObject, isPlainObject as isPlainObject3, isString as isString2 } from "@web-ts-toolkit/utils";
|
|
68
75
|
|
|
@@ -645,7 +652,9 @@ var defaultRequestComplexity = {
|
|
|
645
652
|
maxIncludeCount: 10,
|
|
646
653
|
maxSubQueryCount: 10,
|
|
647
654
|
maxBulkConcurrency: 10,
|
|
648
|
-
maxHookConcurrency: 10
|
|
655
|
+
maxHookConcurrency: 10,
|
|
656
|
+
maxCorrelatedQueries: 100,
|
|
657
|
+
maxCorrelatedDepth: 5
|
|
649
658
|
};
|
|
650
659
|
var normalizePositiveInteger = (value, fallback) => {
|
|
651
660
|
return Number.isSafeInteger(value) && Number(value) > 0 ? Number(value) : fallback;
|
|
@@ -665,6 +674,14 @@ var resolveRequestComplexity = (options) => ({
|
|
|
665
674
|
maxHookConcurrency: normalizePositiveInteger(
|
|
666
675
|
options?.maxHookConcurrency,
|
|
667
676
|
defaultRequestComplexity.maxHookConcurrency
|
|
677
|
+
),
|
|
678
|
+
maxCorrelatedQueries: normalizePositiveInteger(
|
|
679
|
+
options?.maxCorrelatedQueries,
|
|
680
|
+
defaultRequestComplexity.maxCorrelatedQueries
|
|
681
|
+
),
|
|
682
|
+
maxCorrelatedDepth: normalizePositiveInteger(
|
|
683
|
+
options?.maxCorrelatedDepth,
|
|
684
|
+
defaultRequestComplexity.maxCorrelatedDepth
|
|
668
685
|
)
|
|
669
686
|
});
|
|
670
687
|
function validateRequestComplexity(value, options, scope = "request") {
|
|
@@ -857,6 +874,7 @@ var AccessRuntime = class {
|
|
|
857
874
|
this.modelAtts = {};
|
|
858
875
|
this.modelInstances = {};
|
|
859
876
|
this.openApiRegistry = new OpenApiRegistry();
|
|
877
|
+
this.openApiPathPrefix = "";
|
|
860
878
|
this.allowGlobalModelLookup = options.allowGlobalModelLookup ?? false;
|
|
861
879
|
ensureMongooseJsonSchemaInitialized();
|
|
862
880
|
}
|
|
@@ -885,7 +903,24 @@ var AccessRuntime = class {
|
|
|
885
903
|
return global;
|
|
886
904
|
}
|
|
887
905
|
registerOpenApiRoute(route) {
|
|
888
|
-
this.openApiRegistry.register(
|
|
906
|
+
this.openApiRegistry.register(
|
|
907
|
+
this.openApiPathPrefix ? { ...route, path: normalizeUrlPath(`${this.openApiPathPrefix}/${route.path}`) } : route
|
|
908
|
+
);
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Compose OpenAPI paths while synchronously constructing mounted routers.
|
|
912
|
+
* Prefixes apply before collision checks; prior descriptors and Express paths
|
|
913
|
+
* are unchanged. Nested calls compose and the prior scope is restored even on
|
|
914
|
+
* failure. The callback must finish registration synchronously (no async work).
|
|
915
|
+
*/
|
|
916
|
+
withOpenApiPathPrefix(prefix, build) {
|
|
917
|
+
const previous = this.openApiPathPrefix;
|
|
918
|
+
this.openApiPathPrefix = normalizeUrlPath(`${previous}/${prefix}`);
|
|
919
|
+
try {
|
|
920
|
+
return build();
|
|
921
|
+
} finally {
|
|
922
|
+
this.openApiPathPrefix = previous;
|
|
923
|
+
}
|
|
889
924
|
}
|
|
890
925
|
/**
|
|
891
926
|
* Enable strict OpenAPI collision detection for the remainder of this
|
|
@@ -1173,6 +1208,175 @@ var getGlobalOption = (key, defaultValue) => {
|
|
|
1173
1208
|
|
|
1174
1209
|
// src/validation/common.ts
|
|
1175
1210
|
import { z as z2 } from "zod";
|
|
1211
|
+
import { isPlainObject as isPlainObject11 } from "@web-ts-toolkit/utils";
|
|
1212
|
+
|
|
1213
|
+
// src/correlated-includes.ts
|
|
1214
|
+
import { cloneDeep, isArray as isArray5, isPlainObject as isPlainObject10 } from "@web-ts-toolkit/utils";
|
|
1215
|
+
var PARENT_MARKER_KEY = "$parent";
|
|
1216
|
+
var ESCAPE_WRAPPER_KEY = "$escape";
|
|
1217
|
+
var SUBQUERY_PAYLOAD_KEYS = /* @__PURE__ */ new Set(["$$sq", "$$date"]);
|
|
1218
|
+
var MARKER_FORBIDDEN_OPERATOR_KEYS = /* @__PURE__ */ new Set(["$text", "$where", "$comment"]);
|
|
1219
|
+
var LOGICAL_CLAUSE_KEYS = /* @__PURE__ */ new Set(["$and", "$or", "$nor"]);
|
|
1220
|
+
var DANGEROUS_PATH_SEGMENTS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
1221
|
+
var FIELD_SEGMENT_PATTERN = /^[A-Za-z_][A-Za-z0-9_$]*$/;
|
|
1222
|
+
var ARRAY_INDEX_SEGMENT_PATTERN = /^(0|[1-9]\d*)$/;
|
|
1223
|
+
var ownKeys = (value) => Object.keys(value);
|
|
1224
|
+
function isParentRefMarker(value) {
|
|
1225
|
+
return isPlainObject10(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === PARENT_MARKER_KEY;
|
|
1226
|
+
}
|
|
1227
|
+
function isEscapedParentRef(value) {
|
|
1228
|
+
return isPlainObject10(value) && ownKeys(value).length === 1 && ownKeys(value)[0] === ESCAPE_WRAPPER_KEY;
|
|
1229
|
+
}
|
|
1230
|
+
function hasMarkerKey(value) {
|
|
1231
|
+
return ownKeys(value).includes(PARENT_MARKER_KEY) || ownKeys(value).includes(ESCAPE_WRAPPER_KEY);
|
|
1232
|
+
}
|
|
1233
|
+
function isValidParentRefPath(path) {
|
|
1234
|
+
if (typeof path !== "string" || path.length === 0) return false;
|
|
1235
|
+
const segments = path.split(".");
|
|
1236
|
+
return segments.every(
|
|
1237
|
+
(segment) => (FIELD_SEGMENT_PATTERN.test(segment) || ARRAY_INDEX_SEGMENT_PATTERN.test(segment)) && !DANGEROUS_PATH_SEGMENTS.has(segment)
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
function isValidCorrelatedOutputPath(path) {
|
|
1241
|
+
return typeof path === "string" && path.length > 0 && isValidFieldPath(path) && path !== "_id" && !path.startsWith("$");
|
|
1242
|
+
}
|
|
1243
|
+
function containsParentMarkerShape(value) {
|
|
1244
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1245
|
+
const visit = (current) => {
|
|
1246
|
+
if (isParentRefMarker(current) || isEscapedParentRef(current)) return true;
|
|
1247
|
+
if (isArray5(current)) {
|
|
1248
|
+
if (seen.has(current)) return false;
|
|
1249
|
+
seen.add(current);
|
|
1250
|
+
return current.some(visit);
|
|
1251
|
+
}
|
|
1252
|
+
if (isPlainObject10(current)) {
|
|
1253
|
+
if (seen.has(current)) return false;
|
|
1254
|
+
seen.add(current);
|
|
1255
|
+
if (hasMarkerKey(current)) return true;
|
|
1256
|
+
return Object.values(current).some(visit);
|
|
1257
|
+
}
|
|
1258
|
+
return false;
|
|
1259
|
+
};
|
|
1260
|
+
return visit(value);
|
|
1261
|
+
}
|
|
1262
|
+
function scanTemplateValueNode(value, path, issues) {
|
|
1263
|
+
if (isEscapedParentRef(value)) {
|
|
1264
|
+
const inner = value.$escape;
|
|
1265
|
+
if (!isParentRefMarker(inner) || typeof inner.$parent !== "string" || (inner.$parent?.length ?? 0) === 0) {
|
|
1266
|
+
issues.push({
|
|
1267
|
+
message: 'Invalid $escape payload: expected { "$escape": { "$parent": "<field>" } }',
|
|
1268
|
+
path
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1271
|
+
return;
|
|
1272
|
+
}
|
|
1273
|
+
if (isParentRefMarker(value)) {
|
|
1274
|
+
if (!isValidParentRefPath(value.$parent)) {
|
|
1275
|
+
issues.push({
|
|
1276
|
+
message: `Invalid $parent reference path at ${path.length === 0 ? "#" : path.join(".")}`,
|
|
1277
|
+
path
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
return;
|
|
1281
|
+
}
|
|
1282
|
+
if (isPlainObject10(value)) {
|
|
1283
|
+
if (hasMarkerKey(value)) {
|
|
1284
|
+
issues.push({
|
|
1285
|
+
message: 'Malformed $parent reference: objects carrying $parent must be exactly { "$parent": "<field>" }',
|
|
1286
|
+
path
|
|
1287
|
+
});
|
|
1288
|
+
return;
|
|
1289
|
+
}
|
|
1290
|
+
scanTemplateObjectEntries(value, path, issues);
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
if (isArray5(value)) {
|
|
1294
|
+
value.forEach((item, index) => scanTemplateValueNode(item, [...path, index], issues));
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
function scanTemplateObjectEntries(obj, basePath, issues) {
|
|
1298
|
+
for (const [key, child] of Object.entries(obj)) {
|
|
1299
|
+
const childPath = [...basePath, key];
|
|
1300
|
+
if (key === PARENT_MARKER_KEY) {
|
|
1301
|
+
issues.push({ message: "$parent is never a field name in correlated templates", path: childPath });
|
|
1302
|
+
continue;
|
|
1303
|
+
}
|
|
1304
|
+
if (SUBQUERY_PAYLOAD_KEYS.has(key)) {
|
|
1305
|
+
if (containsParentMarkerShape(child)) {
|
|
1306
|
+
issues.push({
|
|
1307
|
+
message: `Unsupported $parent reference inside ${key}: markers are not resolved in subquery payloads`,
|
|
1308
|
+
path: childPath
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
continue;
|
|
1312
|
+
}
|
|
1313
|
+
if (MARKER_FORBIDDEN_OPERATOR_KEYS.has(key)) {
|
|
1314
|
+
if (containsParentMarkerShape(child)) {
|
|
1315
|
+
issues.push({
|
|
1316
|
+
message: `Unsupported $parent reference inside ${key}: markers are not resolved in ${key} values`,
|
|
1317
|
+
path: childPath
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
continue;
|
|
1321
|
+
}
|
|
1322
|
+
if (key === "$elemMatch") {
|
|
1323
|
+
if (isParentRefMarker(child) || isEscapedParentRef(child)) {
|
|
1324
|
+
issues.push({
|
|
1325
|
+
message: "Unsupported $parent reference as a direct $elemMatch value",
|
|
1326
|
+
path: childPath
|
|
1327
|
+
});
|
|
1328
|
+
continue;
|
|
1329
|
+
}
|
|
1330
|
+
scanTemplateValueNode(child, childPath, issues);
|
|
1331
|
+
continue;
|
|
1332
|
+
}
|
|
1333
|
+
if (LOGICAL_CLAUSE_KEYS.has(key)) {
|
|
1334
|
+
if (!isArray5(child)) {
|
|
1335
|
+
scanTemplateValueNode(child, childPath, issues);
|
|
1336
|
+
continue;
|
|
1337
|
+
}
|
|
1338
|
+
child.forEach((clause, index) => {
|
|
1339
|
+
const clausePath = [...childPath, index];
|
|
1340
|
+
if (isParentRefMarker(clause) || isEscapedParentRef(clause)) {
|
|
1341
|
+
issues.push({
|
|
1342
|
+
message: `Unsupported $parent reference as a direct ${key} clause: clauses must be filter objects`,
|
|
1343
|
+
path: clausePath
|
|
1344
|
+
});
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
if (isPlainObject10(clause)) {
|
|
1348
|
+
scanTemplateObjectEntries(clause, clausePath, issues);
|
|
1349
|
+
}
|
|
1350
|
+
});
|
|
1351
|
+
continue;
|
|
1352
|
+
}
|
|
1353
|
+
scanTemplateValueNode(child, childPath, issues);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
function validateCorrelatedFilterTemplate(filter) {
|
|
1357
|
+
const issues = [];
|
|
1358
|
+
if (!isPlainObject10(filter)) {
|
|
1359
|
+
issues.push({ message: "Correlated include filter must be an object", path: [] });
|
|
1360
|
+
return issues;
|
|
1361
|
+
}
|
|
1362
|
+
if (isParentRefMarker(filter) || isEscapedParentRef(filter)) {
|
|
1363
|
+
issues.push({ message: "Correlated include filter must not itself be a $parent reference", path: [] });
|
|
1364
|
+
return issues;
|
|
1365
|
+
}
|
|
1366
|
+
scanTemplateObjectEntries(filter, [], issues);
|
|
1367
|
+
return issues;
|
|
1368
|
+
}
|
|
1369
|
+
function findArgsMarkerIssue(value, where) {
|
|
1370
|
+
if (value !== void 0 && containsParentMarkerShape(value)) {
|
|
1371
|
+
return {
|
|
1372
|
+
message: `Unsupported $parent reference in ${where}: references are only supported in filter and id positions`,
|
|
1373
|
+
path: []
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
return null;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// src/validation/common.ts
|
|
1176
1380
|
var stringOrStringArray = z2.union([z2.string(), z2.array(z2.string())]);
|
|
1177
1381
|
var safeIntegerString = (min, message) => z2.string().regex(/^\d+$/, message).refine((value) => Number.isSafeInteger(Number(value)), "Expected a safe integer").refine((value) => Number(value) >= min, message);
|
|
1178
1382
|
var queryBooleanString = z2.enum(["true", "false"]);
|
|
@@ -1233,7 +1437,8 @@ var subPopulateSchema = z2.union([
|
|
|
1233
1437
|
select: projectionSchema.optional()
|
|
1234
1438
|
}).passthrough()
|
|
1235
1439
|
]);
|
|
1236
|
-
var
|
|
1440
|
+
var legacyIncludeItemSchema = z2.object({
|
|
1441
|
+
mode: z2.enum(["legacy"]).optional(),
|
|
1237
1442
|
model: z2.string().min(1),
|
|
1238
1443
|
op: z2.enum(["list", "read", "count"]),
|
|
1239
1444
|
path: z2.string().min(1),
|
|
@@ -1242,8 +1447,139 @@ var includeItemSchema = z2.object({
|
|
|
1242
1447
|
foreignField: z2.string().min(1),
|
|
1243
1448
|
args: z2.unknown().optional().describe("Forwarded to list/read includes. Count includes ignore pagination fields so counts remain exact."),
|
|
1244
1449
|
options: z2.unknown().optional()
|
|
1245
|
-
}).passthrough()
|
|
1246
|
-
|
|
1450
|
+
}).passthrough().superRefine((entry, ctx) => {
|
|
1451
|
+
if (entry.filter !== void 0 && containsParentMarkerShape(entry.filter)) {
|
|
1452
|
+
ctx.addIssue({
|
|
1453
|
+
code: z2.ZodIssueCode.custom,
|
|
1454
|
+
message: 'Legacy includes must not contain $parent markers; use a correlated include (mode: "correlated")',
|
|
1455
|
+
path: ["filter"]
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
var parentRefSchema = z2.object({ $parent: z2.string().min(1) }).strict().superRefine((value, ctx) => {
|
|
1460
|
+
if (!isValidParentRefPath(value.$parent)) {
|
|
1461
|
+
ctx.addIssue({
|
|
1462
|
+
code: z2.ZodIssueCode.custom,
|
|
1463
|
+
message: `Invalid $parent reference path: ${value.$parent}`,
|
|
1464
|
+
path: ["$parent"]
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
var correlatedIdSchema = z2.union([z2.string().min(1), parentRefSchema]);
|
|
1469
|
+
var correlatedFilterSchema = z2.record(z2.string(), z2.unknown()).superRefine((filter, ctx) => {
|
|
1470
|
+
for (const issue of validateCorrelatedFilterTemplate(filter)) {
|
|
1471
|
+
ctx.addIssue({
|
|
1472
|
+
code: z2.ZodIssueCode.custom,
|
|
1473
|
+
message: issue.message,
|
|
1474
|
+
path: issue.path.map(String)
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
});
|
|
1478
|
+
var correlatedEmptyOptionsSchema = z2.unknown().refine(
|
|
1479
|
+
(value) => value === void 0 || isPlainObject11(value) && Object.keys(value).length === 0,
|
|
1480
|
+
"Correlated include options must be absent or empty"
|
|
1481
|
+
).optional();
|
|
1482
|
+
var correlatedPathSchema = z2.string().min(1).superRefine((path, ctx) => {
|
|
1483
|
+
if (!isValidCorrelatedOutputPath(path)) {
|
|
1484
|
+
ctx.addIssue({
|
|
1485
|
+
code: z2.ZodIssueCode.custom,
|
|
1486
|
+
message: `Invalid correlated include output path: ${path}`,
|
|
1487
|
+
path: []
|
|
1488
|
+
});
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
var checkArgsMarkers = (select, sort, ctx) => {
|
|
1492
|
+
const selectIssue = findArgsMarkerIssue(select, "args.select");
|
|
1493
|
+
if (selectIssue) {
|
|
1494
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: selectIssue.message, path: ["select"] });
|
|
1495
|
+
}
|
|
1496
|
+
const sortIssue = findArgsMarkerIssue(sort, "args.sort");
|
|
1497
|
+
if (sortIssue) {
|
|
1498
|
+
ctx.addIssue({ code: z2.ZodIssueCode.custom, message: sortIssue.message, path: ["sort"] });
|
|
1499
|
+
}
|
|
1500
|
+
};
|
|
1501
|
+
var correlatedReadArgsSchema = z2.object({
|
|
1502
|
+
select: projectionSchema.optional(),
|
|
1503
|
+
sort: sortSchema.optional(),
|
|
1504
|
+
include: z2.lazy(() => correlatedNestedIncludeSchema).optional()
|
|
1505
|
+
}).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
|
|
1506
|
+
var correlatedListArgsSchema = z2.object({
|
|
1507
|
+
select: projectionSchema.optional(),
|
|
1508
|
+
sort: sortSchema.optional(),
|
|
1509
|
+
skip: z2.union([nonNegativeIntegerSchema, nonNegativeIntegerString]).optional(),
|
|
1510
|
+
limit: z2.union([positiveIntegerSchema, positiveIntegerString]).optional(),
|
|
1511
|
+
page: z2.union([nonNegativeIntegerSchema, nonNegativeIntegerString]).optional(),
|
|
1512
|
+
pageSize: z2.union([positiveIntegerSchema, positiveIntegerString]).optional(),
|
|
1513
|
+
include: z2.lazy(() => correlatedNestedIncludeSchema).optional()
|
|
1514
|
+
}).strict().superRefine((args, ctx) => checkArgsMarkers(args.select, args.sort, ctx));
|
|
1515
|
+
var correlatedCountArgsSchema = z2.unknown().refine(
|
|
1516
|
+
(value) => value === void 0 || isPlainObject11(value) && Object.keys(value).length === 0,
|
|
1517
|
+
"Count includes accept no args"
|
|
1518
|
+
).optional();
|
|
1519
|
+
var correlatedReadByIdSchema = z2.object({
|
|
1520
|
+
mode: z2.literal("correlated"),
|
|
1521
|
+
model: z2.string().min(1),
|
|
1522
|
+
op: z2.literal("read"),
|
|
1523
|
+
path: correlatedPathSchema,
|
|
1524
|
+
id: correlatedIdSchema,
|
|
1525
|
+
args: correlatedReadArgsSchema.optional(),
|
|
1526
|
+
options: correlatedEmptyOptionsSchema
|
|
1527
|
+
}).strict();
|
|
1528
|
+
var correlatedReadByFilterSchema = z2.object({
|
|
1529
|
+
mode: z2.literal("correlated"),
|
|
1530
|
+
model: z2.string().min(1),
|
|
1531
|
+
op: z2.literal("read"),
|
|
1532
|
+
path: correlatedPathSchema,
|
|
1533
|
+
filter: correlatedFilterSchema,
|
|
1534
|
+
args: correlatedReadArgsSchema.optional(),
|
|
1535
|
+
options: correlatedEmptyOptionsSchema
|
|
1536
|
+
}).strict();
|
|
1537
|
+
var correlatedListSchema = z2.object({
|
|
1538
|
+
mode: z2.literal("correlated"),
|
|
1539
|
+
model: z2.string().min(1),
|
|
1540
|
+
op: z2.literal("list"),
|
|
1541
|
+
path: correlatedPathSchema,
|
|
1542
|
+
filter: correlatedFilterSchema,
|
|
1543
|
+
args: correlatedListArgsSchema.optional(),
|
|
1544
|
+
options: correlatedEmptyOptionsSchema
|
|
1545
|
+
}).strict();
|
|
1546
|
+
var correlatedCountSchema = z2.object({
|
|
1547
|
+
mode: z2.literal("correlated"),
|
|
1548
|
+
model: z2.string().min(1),
|
|
1549
|
+
op: z2.literal("count"),
|
|
1550
|
+
path: correlatedPathSchema,
|
|
1551
|
+
filter: correlatedFilterSchema,
|
|
1552
|
+
args: correlatedCountArgsSchema,
|
|
1553
|
+
options: correlatedEmptyOptionsSchema
|
|
1554
|
+
}).strict();
|
|
1555
|
+
var includeItemSchema = z2.union([
|
|
1556
|
+
legacyIncludeItemSchema,
|
|
1557
|
+
correlatedReadByIdSchema,
|
|
1558
|
+
correlatedReadByFilterSchema,
|
|
1559
|
+
correlatedListSchema,
|
|
1560
|
+
correlatedCountSchema
|
|
1561
|
+
]);
|
|
1562
|
+
var correlatedNestedIncludeSchema = z2.union([includeItemSchema, z2.array(includeItemSchema)]);
|
|
1563
|
+
var rejectDuplicateCorrelatedPaths = (items, ctx) => {
|
|
1564
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1565
|
+
items.forEach((item, index) => {
|
|
1566
|
+
if (isPlainObject11(item) && item.mode === "correlated" && typeof item.path === "string") {
|
|
1567
|
+
if (seen.has(item.path)) {
|
|
1568
|
+
ctx.addIssue({
|
|
1569
|
+
code: z2.ZodIssueCode.custom,
|
|
1570
|
+
message: `Duplicate correlated include output path: ${item.path}`,
|
|
1571
|
+
path: [index, "path"]
|
|
1572
|
+
});
|
|
1573
|
+
} else {
|
|
1574
|
+
seen.add(item.path);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
});
|
|
1578
|
+
};
|
|
1579
|
+
var includeSchema = z2.union([
|
|
1580
|
+
includeItemSchema,
|
|
1581
|
+
z2.array(includeItemSchema).superRefine(rejectDuplicateCorrelatedPaths)
|
|
1582
|
+
]);
|
|
1247
1583
|
var fieldsSchema = z2.array(z2.string().min(1));
|
|
1248
1584
|
var taskSchema = z2.object({
|
|
1249
1585
|
type: z2.string().min(1),
|
|
@@ -1426,19 +1762,12 @@ function fromJoi(schema) {
|
|
|
1426
1762
|
}
|
|
1427
1763
|
function fromAjv(validator) {
|
|
1428
1764
|
return async (value) => {
|
|
1429
|
-
|
|
1430
|
-
if (isThenable(outcome)) {
|
|
1765
|
+
if (validator.$async === true) {
|
|
1431
1766
|
try {
|
|
1432
|
-
const data = await
|
|
1433
|
-
if (data === false) {
|
|
1434
|
-
return {
|
|
1435
|
-
success: false,
|
|
1436
|
-
issues: normalizeAjvIssues(validator.errors ?? [])
|
|
1437
|
-
};
|
|
1438
|
-
}
|
|
1767
|
+
const data = await validator(value);
|
|
1439
1768
|
return {
|
|
1440
1769
|
success: true,
|
|
1441
|
-
data
|
|
1770
|
+
data
|
|
1442
1771
|
};
|
|
1443
1772
|
} catch (error) {
|
|
1444
1773
|
if (!isAjvValidationError(error)) {
|
|
@@ -1446,11 +1775,21 @@ function fromAjv(validator) {
|
|
|
1446
1775
|
}
|
|
1447
1776
|
return {
|
|
1448
1777
|
success: false,
|
|
1449
|
-
issues: normalizeAjvIssues(error.errors
|
|
1778
|
+
issues: normalizeAjvIssues(error.errors)
|
|
1450
1779
|
};
|
|
1451
1780
|
}
|
|
1452
1781
|
}
|
|
1453
|
-
const
|
|
1782
|
+
const outcome = validator(value);
|
|
1783
|
+
if (isThenable(outcome)) {
|
|
1784
|
+
void Promise.resolve(outcome).catch(() => {
|
|
1785
|
+
});
|
|
1786
|
+
throw new TypeError(
|
|
1787
|
+
"fromAjv: promise/thenable validators must declare $async: true and resolve with validated data"
|
|
1788
|
+
);
|
|
1789
|
+
}
|
|
1790
|
+
if (typeof outcome !== "boolean") {
|
|
1791
|
+
throw new TypeError("fromAjv: synchronous validators must return a boolean verdict");
|
|
1792
|
+
}
|
|
1454
1793
|
if (outcome) {
|
|
1455
1794
|
return {
|
|
1456
1795
|
success: true,
|
|
@@ -1459,7 +1798,9 @@ function fromAjv(validator) {
|
|
|
1459
1798
|
}
|
|
1460
1799
|
return {
|
|
1461
1800
|
success: false,
|
|
1462
|
-
|
|
1801
|
+
// Normalize immediately, copying message/path before another call can
|
|
1802
|
+
// replace the errors array or mutate its entries.
|
|
1803
|
+
issues: normalizeAjvIssues(validator.errors ?? [])
|
|
1463
1804
|
};
|
|
1464
1805
|
};
|
|
1465
1806
|
}
|
|
@@ -1689,14 +2030,14 @@ function isArkTypeErrors(value) {
|
|
|
1689
2030
|
return record.arkKind === "errors" || record[" arkKind"] === "errors";
|
|
1690
2031
|
}
|
|
1691
2032
|
function isThenable(value) {
|
|
1692
|
-
return typeof value === "object" && value !== null && "then" in value && typeof value.then === "function";
|
|
2033
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && "then" in value && typeof value.then === "function";
|
|
1693
2034
|
}
|
|
1694
2035
|
function isAjvValidationError(error) {
|
|
1695
2036
|
if (typeof error !== "object" || error === null || !("errors" in error)) {
|
|
1696
2037
|
return false;
|
|
1697
2038
|
}
|
|
1698
|
-
const
|
|
1699
|
-
return
|
|
2039
|
+
const candidate = error;
|
|
2040
|
+
return candidate.ajv === true && candidate.validation === true && Array.isArray(candidate.errors);
|
|
1700
2041
|
}
|
|
1701
2042
|
function isVineValidationError(error) {
|
|
1702
2043
|
if (typeof error !== "object" || error === null || !("messages" in error)) {
|
|
@@ -1780,7 +2121,7 @@ var listBodySchema = z3.object({
|
|
|
1780
2121
|
}).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query"]));
|
|
1781
2122
|
var countBodySchema = z3.object({
|
|
1782
2123
|
filter: objectOrArraySchema.optional()
|
|
1783
|
-
}).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query", "access", "options"]));
|
|
2124
|
+
}).passthrough().superRefine((body, ctx) => rejectKeys(body, ctx, ["query", "access", "options", "include"]));
|
|
1784
2125
|
var readFilterBodySchema = z3.object({
|
|
1785
2126
|
filter: objectOrArraySchema.optional(),
|
|
1786
2127
|
select: projectionSchema.optional(),
|