koatty_router 2.1.10 → 2.2.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/.turbo/turbo-build.log +201 -45
- package/.turbo/turbo-clean.log +4 -0
- package/.turbo/turbo-test.log +77 -0
- package/CHANGELOG.md +35 -2
- package/dist/index.d.ts +4 -3
- package/dist/index.js +145 -235
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -238
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +9 -9
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -0
package/dist/index.js
CHANGED
|
@@ -54,7 +54,7 @@ var onFinished__default = /*#__PURE__*/_interopDefault(onFinished);
|
|
|
54
54
|
|
|
55
55
|
/*!
|
|
56
56
|
* @Author: richen
|
|
57
|
-
* @Date: 2026-
|
|
57
|
+
* @Date: 2026-04-24 08:20:32
|
|
58
58
|
* @License: BSD (3-Clause)
|
|
59
59
|
* @Copyright (c) - <richenlin(at)gmail.com>
|
|
60
60
|
* @HomePage: https://koatty.org/
|
|
@@ -789,6 +789,9 @@ function RegisterMiddleware(app, config) {
|
|
|
789
789
|
};
|
|
790
790
|
}
|
|
791
791
|
__name(RegisterMiddleware, "RegisterMiddleware");
|
|
792
|
+
|
|
793
|
+
// src/payload/interface.ts
|
|
794
|
+
var FILE_KEY = /* @__PURE__ */ Symbol.for("koatty.files");
|
|
792
795
|
function parseText(ctx, opts) {
|
|
793
796
|
return getRawBody__default.default(inflate__default.default(ctx.req), opts).catch((err) => {
|
|
794
797
|
koatty_logger.DefaultLogger.Error(err);
|
|
@@ -800,8 +803,9 @@ async function parseJson(ctx, opts) {
|
|
|
800
803
|
const str = await parseText(ctx, opts);
|
|
801
804
|
if (!str) return {};
|
|
802
805
|
try {
|
|
803
|
-
|
|
804
|
-
|
|
806
|
+
const parsed = JSON.parse(str);
|
|
807
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {
|
|
808
|
+
value: parsed
|
|
805
809
|
};
|
|
806
810
|
} catch (error) {
|
|
807
811
|
koatty_logger.DefaultLogger.Error(error);
|
|
@@ -810,18 +814,13 @@ async function parseJson(ctx, opts) {
|
|
|
810
814
|
}
|
|
811
815
|
__name(parseJson, "parseJson");
|
|
812
816
|
async function parseForm(ctx, opts) {
|
|
813
|
-
if (!ctx.request.headers["content-length"] || !ctx.request.headers["content-type"]?.includes("application/x-www-form-urlencoded")) {
|
|
814
|
-
return {};
|
|
815
|
-
}
|
|
816
817
|
const str = await parseText(ctx, opts);
|
|
817
818
|
if (!str || str.trim().length === 0) {
|
|
818
819
|
return {};
|
|
819
820
|
}
|
|
820
821
|
try {
|
|
821
822
|
const result = fastQuerystring.parse(str);
|
|
822
|
-
return
|
|
823
|
-
body: result
|
|
824
|
-
};
|
|
823
|
+
return result;
|
|
825
824
|
} catch (error) {
|
|
826
825
|
koatty_logger.DefaultLogger.Error("[FormParseError]", error);
|
|
827
826
|
return {};
|
|
@@ -853,12 +852,6 @@ __name(deleteFiles, "deleteFiles");
|
|
|
853
852
|
|
|
854
853
|
// src/payload/parser/multipart.ts
|
|
855
854
|
function parseMultipart(ctx, opts) {
|
|
856
|
-
if (!ctx.request.headers["content-type"]?.includes("multipart/form-data")) {
|
|
857
|
-
return Promise.resolve({
|
|
858
|
-
body: {},
|
|
859
|
-
file: {}
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
855
|
const form = new formidable.IncomingForm({
|
|
863
856
|
encoding: opts.encoding,
|
|
864
857
|
multiples: opts.multiples,
|
|
@@ -881,15 +874,12 @@ function parseMultipart(ctx, opts) {
|
|
|
881
874
|
if (err) {
|
|
882
875
|
cleanup();
|
|
883
876
|
koatty_logger.DefaultLogger.Error("[MultipartParseError]", err);
|
|
884
|
-
return resolve({
|
|
885
|
-
body: {},
|
|
886
|
-
file: {}
|
|
887
|
-
});
|
|
877
|
+
return resolve({});
|
|
888
878
|
}
|
|
889
879
|
uploadFiles = files;
|
|
890
880
|
resolve({
|
|
891
|
-
|
|
892
|
-
|
|
881
|
+
...fields,
|
|
882
|
+
[FILE_KEY]: files
|
|
893
883
|
});
|
|
894
884
|
});
|
|
895
885
|
});
|
|
@@ -903,8 +893,9 @@ async function parseXml(ctx, opts) {
|
|
|
903
893
|
const str = await parseText(ctx, opts);
|
|
904
894
|
if (!str) return {};
|
|
905
895
|
try {
|
|
906
|
-
|
|
907
|
-
|
|
896
|
+
const parsed = xmlParser.parse(str);
|
|
897
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {
|
|
898
|
+
value: parsed
|
|
908
899
|
};
|
|
909
900
|
} catch (error) {
|
|
910
901
|
koatty_logger.DefaultLogger.Error(error);
|
|
@@ -945,11 +936,14 @@ async function parseWebSocket(ctx, opts) {
|
|
|
945
936
|
const str = await parseText(ctx, opts);
|
|
946
937
|
if (!str) return {};
|
|
947
938
|
try {
|
|
948
|
-
|
|
949
|
-
|
|
939
|
+
const parsed = JSON.parse(str);
|
|
940
|
+
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {
|
|
941
|
+
value: parsed
|
|
950
942
|
};
|
|
951
943
|
} catch {
|
|
952
|
-
return
|
|
944
|
+
return {
|
|
945
|
+
value: str
|
|
946
|
+
};
|
|
953
947
|
}
|
|
954
948
|
} catch (error) {
|
|
955
949
|
koatty_logger.DefaultLogger.Error("[WebSocketParseError]", error);
|
|
@@ -1169,6 +1163,7 @@ var PayloadCacheManager = class _PayloadCacheManager {
|
|
|
1169
1163
|
var cacheManager = PayloadCacheManager.getInstance();
|
|
1170
1164
|
|
|
1171
1165
|
// src/payload/payload.ts
|
|
1166
|
+
var bodyCache = /* @__PURE__ */ new WeakMap();
|
|
1172
1167
|
var supportedMethods = /* @__PURE__ */ new Set([
|
|
1173
1168
|
"POST",
|
|
1174
1169
|
"PUT",
|
|
@@ -1226,7 +1221,7 @@ function payload(options) {
|
|
|
1226
1221
|
if (!Object.prototype.hasOwnProperty.call(ctx, "requestFile")) {
|
|
1227
1222
|
Helper5.Helper.define(ctx, "requestFile", async (name) => {
|
|
1228
1223
|
const body = await bodyParser(ctx, opts);
|
|
1229
|
-
const files = body
|
|
1224
|
+
const files = body[FILE_KEY] ?? {};
|
|
1230
1225
|
return name ? files[name] : files;
|
|
1231
1226
|
});
|
|
1232
1227
|
}
|
|
@@ -1246,22 +1241,32 @@ function queryParser(ctx, _options) {
|
|
|
1246
1241
|
return Object.assign({}, query, params);
|
|
1247
1242
|
}
|
|
1248
1243
|
__name(queryParser, "queryParser");
|
|
1249
|
-
|
|
1244
|
+
function bodyParser(ctx, options) {
|
|
1245
|
+
const cached = bodyCache.get(ctx);
|
|
1246
|
+
if (cached !== void 0) return cached;
|
|
1247
|
+
return parseBodyAndCache(ctx, options);
|
|
1248
|
+
}
|
|
1249
|
+
__name(bodyParser, "bodyParser");
|
|
1250
|
+
async function parseBodyAndCache(ctx, options) {
|
|
1250
1251
|
try {
|
|
1251
|
-
|
|
1252
|
-
if (
|
|
1253
|
-
return body;
|
|
1254
|
-
}
|
|
1252
|
+
const cached = bodyCache.get(ctx);
|
|
1253
|
+
if (cached !== void 0) return cached;
|
|
1255
1254
|
const opts = cacheManager.getMergedOptions(options);
|
|
1256
|
-
body = await parseBody(ctx, opts);
|
|
1257
|
-
|
|
1255
|
+
const body = await parseBody(ctx, opts);
|
|
1256
|
+
bodyCache.set(ctx, body);
|
|
1257
|
+
try {
|
|
1258
|
+
ctx.setMetaData("_body", body);
|
|
1259
|
+
} catch {
|
|
1260
|
+
}
|
|
1258
1261
|
return body;
|
|
1259
1262
|
} catch (err) {
|
|
1260
1263
|
koatty_logger.DefaultLogger.Error(err);
|
|
1261
|
-
|
|
1264
|
+
const empty = {};
|
|
1265
|
+
bodyCache.set(ctx, empty);
|
|
1266
|
+
return empty;
|
|
1262
1267
|
}
|
|
1263
1268
|
}
|
|
1264
|
-
__name(
|
|
1269
|
+
__name(parseBodyAndCache, "parseBodyAndCache");
|
|
1265
1270
|
function parseBody(ctx, options) {
|
|
1266
1271
|
if (!isSupportedMethod(ctx.method)) {
|
|
1267
1272
|
return Promise.resolve({});
|
|
@@ -1495,27 +1500,6 @@ function injectParamMetaData(app, target, options) {
|
|
|
1495
1500
|
if (!v.sourceType) {
|
|
1496
1501
|
v.sourceType = "custom";
|
|
1497
1502
|
}
|
|
1498
|
-
switch (v.sourceType) {
|
|
1499
|
-
case "query":
|
|
1500
|
-
v.extractorType = "query";
|
|
1501
|
-
break;
|
|
1502
|
-
case "body":
|
|
1503
|
-
v.extractorType = "body";
|
|
1504
|
-
break;
|
|
1505
|
-
case "header":
|
|
1506
|
-
v.extractorType = "header";
|
|
1507
|
-
break;
|
|
1508
|
-
case "path":
|
|
1509
|
-
v.extractorType = "path";
|
|
1510
|
-
break;
|
|
1511
|
-
case "file":
|
|
1512
|
-
v.extractorType = "file";
|
|
1513
|
-
break;
|
|
1514
|
-
case "custom":
|
|
1515
|
-
v.extractorType = "custom";
|
|
1516
|
-
break;
|
|
1517
|
-
}
|
|
1518
|
-
koatty_logger.DefaultLogger.Debug(`Set extractorType ${v.extractorType} for param ${v.name}`);
|
|
1519
1503
|
const validEntry = validData.find((it) => v.index === it.index && it.name === v.name);
|
|
1520
1504
|
if (validEntry) {
|
|
1521
1505
|
v.validRule = validEntry.rule;
|
|
@@ -1589,15 +1573,6 @@ function injectParamMetaData(app, target, options) {
|
|
|
1589
1573
|
}
|
|
1590
1574
|
}
|
|
1591
1575
|
});
|
|
1592
|
-
const fastPathScenario = detectFastPathScenario(data);
|
|
1593
|
-
if (fastPathScenario) {
|
|
1594
|
-
const fastPathHandler = createFastPathHandler(fastPathScenario, data);
|
|
1595
|
-
if (fastPathHandler) {
|
|
1596
|
-
koatty_logger.DefaultLogger.Debug(`Created fast path handler for ${target.constructor.name}.${meta}, scenario: ${fastPathScenario}`);
|
|
1597
|
-
data.fastPathHandler = fastPathHandler;
|
|
1598
|
-
data.fastPathScenario = fastPathScenario;
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
1576
|
const hasAsyncParams = data.some(
|
|
1602
1577
|
(p) => p.sourceType === "body" || p.sourceType === "file" || p.isDto
|
|
1603
1578
|
// DTO validation might be async
|
|
@@ -1663,104 +1638,6 @@ function getControllerPath(className) {
|
|
|
1663
1638
|
return process.env.APP_PATH + "/controller/" + className + ".ts";
|
|
1664
1639
|
}
|
|
1665
1640
|
__name(getControllerPath, "getControllerPath");
|
|
1666
|
-
function detectFastPathScenario(params) {
|
|
1667
|
-
if (!params || params.length === 0) {
|
|
1668
|
-
return null;
|
|
1669
|
-
}
|
|
1670
|
-
if (params.length === 1) {
|
|
1671
|
-
const param = params[0];
|
|
1672
|
-
const fnName = param.fn?.name || "";
|
|
1673
|
-
if (fnName === "Get" && !param.validRule && !param.isDto) {
|
|
1674
|
-
koatty_logger.DefaultLogger.Debug(`Detected fast path scenario A: single query param without validation`);
|
|
1675
|
-
return "SINGLE_QUERY_NO_VALIDATION";
|
|
1676
|
-
}
|
|
1677
|
-
if ((fnName === "Post" || fnName === "RequestBody") && param.isDto) {
|
|
1678
|
-
koatty_logger.DefaultLogger.Debug(`Detected fast path scenario B: single DTO from body`);
|
|
1679
|
-
return "SINGLE_DTO_FROM_BODY";
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1682
|
-
if (params.length > 1) {
|
|
1683
|
-
const allQueryNoValidation = params.every((param) => {
|
|
1684
|
-
const fnName = param.fn?.name || "";
|
|
1685
|
-
return fnName === "Get" && !param.validRule && !param.isDto;
|
|
1686
|
-
});
|
|
1687
|
-
if (allQueryNoValidation) {
|
|
1688
|
-
koatty_logger.DefaultLogger.Debug(`Detected fast path scenario C: multiple query params without validation`);
|
|
1689
|
-
return "MULTIPLE_QUERY_NO_VALIDATION";
|
|
1690
|
-
}
|
|
1691
|
-
}
|
|
1692
|
-
return null;
|
|
1693
|
-
}
|
|
1694
|
-
__name(detectFastPathScenario, "detectFastPathScenario");
|
|
1695
|
-
function createFastPathHandler(scenario, params) {
|
|
1696
|
-
switch (scenario) {
|
|
1697
|
-
case "SINGLE_QUERY_NO_VALIDATION": {
|
|
1698
|
-
const param = params[0];
|
|
1699
|
-
const paramName = param.name;
|
|
1700
|
-
const paramType = param.type;
|
|
1701
|
-
if (paramName) {
|
|
1702
|
-
return (ctx) => {
|
|
1703
|
-
const value = ctx.query?.[paramName];
|
|
1704
|
-
const converted = koatty_validation.convertParamsType(value, paramType);
|
|
1705
|
-
return [
|
|
1706
|
-
converted
|
|
1707
|
-
];
|
|
1708
|
-
};
|
|
1709
|
-
} else {
|
|
1710
|
-
return (ctx) => {
|
|
1711
|
-
const query = ctx.query || {};
|
|
1712
|
-
return [
|
|
1713
|
-
query
|
|
1714
|
-
];
|
|
1715
|
-
};
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
case "SINGLE_DTO_FROM_BODY": {
|
|
1719
|
-
const param = params[0];
|
|
1720
|
-
const clazz = param.clazz;
|
|
1721
|
-
const dtoCheck = param.dtoCheck;
|
|
1722
|
-
if (!clazz) {
|
|
1723
|
-
koatty_logger.DefaultLogger.Debug(`Cannot create fast path: DTO class not found`);
|
|
1724
|
-
return null;
|
|
1725
|
-
}
|
|
1726
|
-
return async (ctx) => {
|
|
1727
|
-
const body = await bodyParser(ctx, param.options);
|
|
1728
|
-
let validatedValue;
|
|
1729
|
-
if (dtoCheck) {
|
|
1730
|
-
validatedValue = await koatty_validation.ClassValidator.valid(clazz, body, true);
|
|
1731
|
-
} else {
|
|
1732
|
-
validatedValue = koatty_validation.plainToClass(clazz, body, true);
|
|
1733
|
-
}
|
|
1734
|
-
return [
|
|
1735
|
-
validatedValue
|
|
1736
|
-
];
|
|
1737
|
-
};
|
|
1738
|
-
}
|
|
1739
|
-
case "MULTIPLE_QUERY_NO_VALIDATION": {
|
|
1740
|
-
const paramConfigs = params.map((p) => ({
|
|
1741
|
-
name: p.name,
|
|
1742
|
-
type: p.type
|
|
1743
|
-
}));
|
|
1744
|
-
return (ctx) => {
|
|
1745
|
-
const query = ctx.query || {};
|
|
1746
|
-
const results = [];
|
|
1747
|
-
for (const config of paramConfigs) {
|
|
1748
|
-
if (config.name) {
|
|
1749
|
-
const value = query[config.name];
|
|
1750
|
-
const converted = koatty_validation.convertParamsType(value, config.type);
|
|
1751
|
-
results.push(converted);
|
|
1752
|
-
} else {
|
|
1753
|
-
results.push(query);
|
|
1754
|
-
}
|
|
1755
|
-
}
|
|
1756
|
-
return results;
|
|
1757
|
-
};
|
|
1758
|
-
}
|
|
1759
|
-
default:
|
|
1760
|
-
return null;
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
__name(createFastPathHandler, "createFastPathHandler");
|
|
1764
1641
|
function compileTypeConverter(type) {
|
|
1765
1642
|
const normalizedType = type.toLowerCase();
|
|
1766
1643
|
if (normalizedType === "string") {
|
|
@@ -1769,53 +1646,24 @@ function compileTypeConverter(type) {
|
|
|
1769
1646
|
switch (normalizedType) {
|
|
1770
1647
|
case "number":
|
|
1771
1648
|
return (value) => {
|
|
1649
|
+
if (typeof value === "number") return value;
|
|
1772
1650
|
if (value === null || value === void 0 || value === "") return value;
|
|
1773
|
-
|
|
1774
|
-
return isNaN(num) ? value : num;
|
|
1651
|
+
return koatty_validation.convertParamsType(value, "number");
|
|
1775
1652
|
};
|
|
1776
1653
|
case "boolean":
|
|
1777
1654
|
return (value) => {
|
|
1778
|
-
if (value === null || value === void 0) return value;
|
|
1779
1655
|
if (typeof value === "boolean") return value;
|
|
1780
|
-
|
|
1781
|
-
const lower = value.toLowerCase();
|
|
1782
|
-
if (lower === "true" || lower === "1") return true;
|
|
1783
|
-
if (lower === "false" || lower === "0") return false;
|
|
1784
|
-
}
|
|
1785
|
-
return Boolean(value);
|
|
1656
|
+
return koatty_validation.convertParamsType(value, "boolean");
|
|
1786
1657
|
};
|
|
1787
1658
|
case "array":
|
|
1788
1659
|
return (value) => {
|
|
1789
|
-
if (value === null || value === void 0) return value;
|
|
1790
1660
|
if (Array.isArray(value)) return value;
|
|
1791
|
-
|
|
1792
|
-
try {
|
|
1793
|
-
const parsed = JSON.parse(value);
|
|
1794
|
-
return Array.isArray(parsed) ? parsed : [
|
|
1795
|
-
value
|
|
1796
|
-
];
|
|
1797
|
-
} catch {
|
|
1798
|
-
return [
|
|
1799
|
-
value
|
|
1800
|
-
];
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
return [
|
|
1804
|
-
value
|
|
1805
|
-
];
|
|
1661
|
+
return koatty_validation.convertParamsType(value, "array");
|
|
1806
1662
|
};
|
|
1807
1663
|
case "object":
|
|
1808
1664
|
return (value) => {
|
|
1809
|
-
if (value
|
|
1810
|
-
|
|
1811
|
-
if (typeof value === "string") {
|
|
1812
|
-
try {
|
|
1813
|
-
return JSON.parse(value);
|
|
1814
|
-
} catch {
|
|
1815
|
-
return value;
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
return value;
|
|
1665
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) return value;
|
|
1666
|
+
return koatty_validation.convertParamsType(value, "object");
|
|
1819
1667
|
};
|
|
1820
1668
|
default:
|
|
1821
1669
|
return (value) => koatty_validation.convertParamsType(value, type);
|
|
@@ -1843,7 +1691,22 @@ function generatePrecompiledExtractor(param) {
|
|
|
1843
1691
|
} else {
|
|
1844
1692
|
return (ctx) => ctx.params || {};
|
|
1845
1693
|
}
|
|
1846
|
-
case "body":
|
|
1694
|
+
case "body": {
|
|
1695
|
+
const bodyOpts = param.options;
|
|
1696
|
+
if (paramName !== void 0) {
|
|
1697
|
+
return async (ctx) => {
|
|
1698
|
+
const parsed = await bodyParser(ctx, bodyOpts);
|
|
1699
|
+
return (parsed ?? {})[paramName];
|
|
1700
|
+
};
|
|
1701
|
+
} else {
|
|
1702
|
+
return async (ctx) => {
|
|
1703
|
+
const parsed = await bodyParser(ctx, bodyOpts);
|
|
1704
|
+
if (!parsed) return {};
|
|
1705
|
+
const { [FILE_KEY]: _files, ...bodyOnly } = parsed;
|
|
1706
|
+
return bodyOnly;
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1847
1710
|
case "file":
|
|
1848
1711
|
return null;
|
|
1849
1712
|
case "custom":
|
|
@@ -1906,14 +1769,19 @@ function extractValueFromSource(source, param) {
|
|
|
1906
1769
|
switch (param.sourceType) {
|
|
1907
1770
|
case ParamSourceType.QUERY:
|
|
1908
1771
|
return paramName ? source.query?.[paramName] : source.query;
|
|
1909
|
-
case ParamSourceType.BODY:
|
|
1910
|
-
|
|
1772
|
+
case ParamSourceType.BODY: {
|
|
1773
|
+
if (paramName) return source.body?.[paramName];
|
|
1774
|
+
const { [FILE_KEY]: _files, ...bodyFields } = source.body || {};
|
|
1775
|
+
return bodyFields;
|
|
1776
|
+
}
|
|
1911
1777
|
case ParamSourceType.HEADER:
|
|
1912
1778
|
return paramName ? source.headers?.[paramName] : source.headers;
|
|
1913
1779
|
case ParamSourceType.PATH:
|
|
1914
1780
|
return paramName ? source.params?.[paramName] : source.params;
|
|
1915
|
-
case ParamSourceType.FILE:
|
|
1916
|
-
|
|
1781
|
+
case ParamSourceType.FILE: {
|
|
1782
|
+
const files = source.body?.[FILE_KEY] || {};
|
|
1783
|
+
return paramName ? files[paramName] : files;
|
|
1784
|
+
}
|
|
1917
1785
|
case ParamSourceType.CUSTOM:
|
|
1918
1786
|
return null;
|
|
1919
1787
|
default:
|
|
@@ -1925,21 +1793,18 @@ async function extractParamSources(ctx, params) {
|
|
|
1925
1793
|
const needsBody = params.some((param) => {
|
|
1926
1794
|
return param.sourceType === ParamSourceType.BODY || param.sourceType === ParamSourceType.FILE;
|
|
1927
1795
|
});
|
|
1928
|
-
|
|
1796
|
+
let body = {};
|
|
1929
1797
|
if (needsBody) {
|
|
1930
1798
|
try {
|
|
1931
1799
|
const parsedBody = await bodyParser(ctx, params[0]?.options);
|
|
1932
|
-
|
|
1933
|
-
if (typeof parsedBody === "object" && "file" in parsedBody) {
|
|
1934
|
-
bodyData.file = parsedBody.file;
|
|
1935
|
-
}
|
|
1800
|
+
body = parsedBody || {};
|
|
1936
1801
|
} catch (err) {
|
|
1937
1802
|
koatty_logger.DefaultLogger.Error(`extractParamSources: Failed to parse body: ${err.message}`);
|
|
1938
1803
|
}
|
|
1939
1804
|
}
|
|
1940
1805
|
return {
|
|
1941
1806
|
query: ctx.query || {},
|
|
1942
|
-
body
|
|
1807
|
+
body,
|
|
1943
1808
|
params: ctx.params || {},
|
|
1944
1809
|
headers: ctx.headers || {}
|
|
1945
1810
|
};
|
|
@@ -1969,7 +1834,7 @@ async function validateParam(app, ctx, value, opt, compiledValidator, compiledTy
|
|
|
1969
1834
|
}
|
|
1970
1835
|
return validatedValue;
|
|
1971
1836
|
} else {
|
|
1972
|
-
const needsConversion = compiledTypeConverter
|
|
1837
|
+
const needsConversion = compiledTypeConverter != null;
|
|
1973
1838
|
const needsValidation = !!(compiledValidator || opt.validRule);
|
|
1974
1839
|
if (!needsConversion && !needsValidation) {
|
|
1975
1840
|
return value;
|
|
@@ -1977,8 +1842,6 @@ async function validateParam(app, ctx, value, opt, compiledValidator, compiledTy
|
|
|
1977
1842
|
let convertedValue = value;
|
|
1978
1843
|
if (compiledTypeConverter) {
|
|
1979
1844
|
convertedValue = compiledTypeConverter(value);
|
|
1980
|
-
} else if (opt.type && opt.type !== "string") {
|
|
1981
|
-
convertedValue = koatty_validation.convertParamsType(value, opt.type);
|
|
1982
1845
|
}
|
|
1983
1846
|
if (compiledValidator) {
|
|
1984
1847
|
compiledValidator(convertedValue);
|
|
@@ -2283,17 +2146,27 @@ var StrategyHandlerFactory = class {
|
|
|
2283
2146
|
return converted;
|
|
2284
2147
|
};
|
|
2285
2148
|
});
|
|
2149
|
+
const allAsyncHaveExtractor = asyncParams.every((p) => !!p.precompiledExtractor || p.fn && typeof p.fn === "function");
|
|
2286
2150
|
return async (ctx) => {
|
|
2287
|
-
const bodyData = await extractParamSources(ctx, params);
|
|
2288
|
-
const asyncResults = asyncParams.map((p) => {
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2151
|
+
const bodyData = allAsyncHaveExtractor ? null : await extractParamSources(ctx, params);
|
|
2152
|
+
const asyncResults = asyncParams.map(async (p) => {
|
|
2153
|
+
if (p.precompiledExtractor) {
|
|
2154
|
+
const rawValue2 = await p.precompiledExtractor(ctx);
|
|
2155
|
+
const value = rawValue2 === void 0 && p.defaultValue !== void 0 ? p.defaultValue : rawValue2;
|
|
2156
|
+
const paramOptions2 = p.precompiledOptions || createParamOptions(p, p.index ?? 0);
|
|
2157
|
+
return validateParam(app, ctx, value, paramOptions2, p.compiledValidator, p.compiledTypeConverter);
|
|
2292
2158
|
}
|
|
2159
|
+
if (p.fn && typeof p.fn === "function") {
|
|
2160
|
+
const rawValue2 = await Promise.resolve(p.fn(ctx, p.options));
|
|
2161
|
+
const value = rawValue2 === void 0 && p.defaultValue !== void 0 ? p.defaultValue : rawValue2;
|
|
2162
|
+
const paramOptions2 = p.precompiledOptions || createParamOptions(p, p.index ?? 0);
|
|
2163
|
+
return validateParam(app, ctx, value, paramOptions2, p.compiledValidator, p.compiledTypeConverter);
|
|
2164
|
+
}
|
|
2165
|
+
const rawValue = bodyData ? extractValueFromSource(bodyData, p) : void 0;
|
|
2293
2166
|
if (rawValue === void 0 && p.defaultValue !== void 0) {
|
|
2294
2167
|
return p.defaultValue;
|
|
2295
2168
|
}
|
|
2296
|
-
const paramOptions = p.precompiledOptions || createParamOptions(p, 0);
|
|
2169
|
+
const paramOptions = p.precompiledOptions || createParamOptions(p, p.index ?? 0);
|
|
2297
2170
|
return validateParam(app, ctx, rawValue, paramOptions, p.compiledValidator, p.compiledTypeConverter);
|
|
2298
2171
|
});
|
|
2299
2172
|
const syncResults = syncHandlers.map((h) => h(ctx));
|
|
@@ -2346,17 +2219,27 @@ var StrategyHandlerFactory = class {
|
|
|
2346
2219
|
* Fallback: Generic async path
|
|
2347
2220
|
*/
|
|
2348
2221
|
static createGenericAsyncHandler(params, app) {
|
|
2222
|
+
const allHaveExtractorOrFn = params.every((p) => !!p.precompiledExtractor || p.fn && typeof p.fn === "function");
|
|
2349
2223
|
return async (ctx) => {
|
|
2350
|
-
const sources = await extractParamSources(ctx, params);
|
|
2351
|
-
const paramPromises = params.map((v, k) => {
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2224
|
+
const sources = allHaveExtractorOrFn ? null : await extractParamSources(ctx, params);
|
|
2225
|
+
const paramPromises = params.map(async (v, k) => {
|
|
2226
|
+
if (v.precompiledExtractor) {
|
|
2227
|
+
const rawValue2 = await v.precompiledExtractor(ctx);
|
|
2228
|
+
const value = rawValue2 === void 0 && v.defaultValue !== void 0 ? v.defaultValue : rawValue2;
|
|
2229
|
+
const paramOptions2 = v.precompiledOptions || createParamOptions(v, v.index ?? k);
|
|
2230
|
+
return validateParam(app, ctx, value, paramOptions2, v.compiledValidator, v.compiledTypeConverter);
|
|
2231
|
+
}
|
|
2232
|
+
if (v.fn && typeof v.fn === "function") {
|
|
2233
|
+
const rawValue2 = await Promise.resolve(v.fn(ctx, v.options));
|
|
2234
|
+
const value = rawValue2 === void 0 && v.defaultValue !== void 0 ? v.defaultValue : rawValue2;
|
|
2235
|
+
const paramOptions2 = v.precompiledOptions || createParamOptions(v, v.index ?? k);
|
|
2236
|
+
return validateParam(app, ctx, value, paramOptions2, v.compiledValidator, v.compiledTypeConverter);
|
|
2355
2237
|
}
|
|
2238
|
+
let rawValue = sources ? extractValueFromSource(sources, v) : void 0;
|
|
2356
2239
|
if (rawValue === void 0 && v.defaultValue !== void 0) {
|
|
2357
|
-
|
|
2240
|
+
return v.defaultValue;
|
|
2358
2241
|
}
|
|
2359
|
-
const paramOptions = v.precompiledOptions || createParamOptions(v, k);
|
|
2242
|
+
const paramOptions = v.precompiledOptions || createParamOptions(v, v.index ?? k);
|
|
2360
2243
|
return validateParam(app, ctx, rawValue, paramOptions, v.compiledValidator, v.compiledTypeConverter);
|
|
2361
2244
|
});
|
|
2362
2245
|
return Promise.all(paramPromises);
|
|
@@ -2569,7 +2452,19 @@ var GraphQLRouter = class {
|
|
|
2569
2452
|
rootValue: routeHandler,
|
|
2570
2453
|
validationRules: validationRules.length > 0 ? validationRules : void 0,
|
|
2571
2454
|
formatError: this.options.ext?.debug ? void 0 : (error) => {
|
|
2572
|
-
|
|
2455
|
+
const formatted = {
|
|
2456
|
+
message: error.message
|
|
2457
|
+
};
|
|
2458
|
+
if (error.extensions) {
|
|
2459
|
+
formatted.extensions = error.extensions;
|
|
2460
|
+
}
|
|
2461
|
+
if (error.locations) {
|
|
2462
|
+
formatted.locations = error.locations;
|
|
2463
|
+
}
|
|
2464
|
+
if (error.path) {
|
|
2465
|
+
formatted.path = error.path;
|
|
2466
|
+
}
|
|
2467
|
+
return formatted;
|
|
2573
2468
|
},
|
|
2574
2469
|
context: /* @__PURE__ */ __name((req) => {
|
|
2575
2470
|
return req.koattyContext;
|
|
@@ -3213,8 +3108,12 @@ var GrpcRouter = class {
|
|
|
3213
3108
|
}
|
|
3214
3109
|
koatty_logger.DefaultLogger.Debug(`[GRPC_ROUTER] \u2705 Register request mapping: ["${path3}" => ${ctlItem.name}.${ctlItem.method}]`);
|
|
3215
3110
|
impl[handler.name] = (call, callback) => {
|
|
3216
|
-
|
|
3217
|
-
|
|
3111
|
+
const methodPath = `${si.name}/${handler.name}`;
|
|
3112
|
+
koatty_logger.DefaultLogger.Warn(`[GRPC_ROUTER] Placeholder handler invoked for ${methodPath}. No controller matched this gRPC method.`);
|
|
3113
|
+
callback({
|
|
3114
|
+
code: 12,
|
|
3115
|
+
message: `Method ${methodPath} not implemented. Ensure a controller with @GrpcMethod('${handler.name}') is registered.`
|
|
3116
|
+
});
|
|
3218
3117
|
};
|
|
3219
3118
|
}
|
|
3220
3119
|
if (Object.keys(impl).length > 0) {
|
|
@@ -4011,17 +3910,28 @@ function Get(name, defaultValue) {
|
|
|
4011
3910
|
}
|
|
4012
3911
|
__name(Get, "Get");
|
|
4013
3912
|
function Post(name, defaultValue) {
|
|
4014
|
-
return injectParam(
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
3913
|
+
return injectParam(
|
|
3914
|
+
// NOTE: This fn is a fallback path only. At runtime the strategy extractor uses
|
|
3915
|
+
// param.precompiledExtractor (generated by generatePrecompiledExtractor for BODY type)
|
|
3916
|
+
// which bypasses this fn entirely. This fn is invoked only when precompiledExtractor
|
|
3917
|
+
// is unavailable (e.g. startup compilation failure or CUSTOM source type fallback).
|
|
3918
|
+
async (ctx, opt) => {
|
|
3919
|
+
const data = await bodyParser(ctx, opt);
|
|
3920
|
+
if (name) return data[name];
|
|
3921
|
+
const { [FILE_KEY]: _files, ...bodyOnly } = data || {};
|
|
3922
|
+
return bodyOnly;
|
|
3923
|
+
},
|
|
3924
|
+
"Post",
|
|
3925
|
+
ParamSourceType.BODY,
|
|
3926
|
+
name,
|
|
3927
|
+
defaultValue
|
|
3928
|
+
);
|
|
4019
3929
|
}
|
|
4020
3930
|
__name(Post, "Post");
|
|
4021
3931
|
function File(name, defaultValue) {
|
|
4022
3932
|
return injectParam(async (ctx, opt) => {
|
|
4023
3933
|
const body = await bodyParser(ctx, opt);
|
|
4024
|
-
const params = body
|
|
3934
|
+
const params = body[FILE_KEY] ?? {};
|
|
4025
3935
|
return name ? params[name] : params;
|
|
4026
3936
|
}, "File", ParamSourceType.FILE, name, defaultValue);
|
|
4027
3937
|
}
|