@mokup/server 1.0.4 → 1.1.1
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/dist/index.cjs +253 -78
- package/dist/index.d.cts +4 -2
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.mjs +246 -75
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const runtime = require('@mokup/runtime');
|
|
4
4
|
const fetch = require('./shared/server.BdTl0qJd.cjs');
|
|
5
|
-
const
|
|
5
|
+
const process = require('node:process');
|
|
6
6
|
const hono = require('@mokup/shared/hono');
|
|
7
7
|
const pathe = require('@mokup/shared/pathe');
|
|
8
8
|
const node_fs = require('node:fs');
|
|
@@ -13,6 +13,10 @@ const esbuild = require('@mokup/shared/esbuild');
|
|
|
13
13
|
const jsoncParser = require('@mokup/shared/jsonc-parser');
|
|
14
14
|
|
|
15
15
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
16
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
17
|
+
|
|
18
|
+
const process__default = /*#__PURE__*/_interopDefaultCompat(process);
|
|
19
|
+
|
|
16
20
|
function createConnectMiddleware(options) {
|
|
17
21
|
const runtime$1 = runtime.createRuntime(fetch.toRuntimeOptions(options));
|
|
18
22
|
const onNotFound = options.onNotFound ?? "next";
|
|
@@ -89,6 +93,7 @@ const supportedExtensions = /* @__PURE__ */ new Set([
|
|
|
89
93
|
".mjs",
|
|
90
94
|
".cjs"
|
|
91
95
|
]);
|
|
96
|
+
const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
|
|
92
97
|
|
|
93
98
|
function normalizePrefix(prefix) {
|
|
94
99
|
if (!prefix) {
|
|
@@ -358,7 +363,7 @@ function isAncestor(parent, child) {
|
|
|
358
363
|
}
|
|
359
364
|
function resolveGroupRoot(dirs, serverRoot) {
|
|
360
365
|
if (!dirs || dirs.length === 0) {
|
|
361
|
-
return serverRoot ??
|
|
366
|
+
return serverRoot ?? process.cwd();
|
|
362
367
|
}
|
|
363
368
|
if (serverRoot) {
|
|
364
369
|
const normalizedRoot = normalizePath(serverRoot);
|
|
@@ -382,7 +387,7 @@ function resolveGroupRoot(dirs, serverRoot) {
|
|
|
382
387
|
}
|
|
383
388
|
}
|
|
384
389
|
if (!common || common === "/") {
|
|
385
|
-
return serverRoot ??
|
|
390
|
+
return serverRoot ?? process.cwd();
|
|
386
391
|
}
|
|
387
392
|
return common;
|
|
388
393
|
}
|
|
@@ -394,12 +399,23 @@ const disabledReasonSet = /* @__PURE__ */ new Set([
|
|
|
394
399
|
"include",
|
|
395
400
|
"unknown"
|
|
396
401
|
]);
|
|
402
|
+
const ignoredReasonSet = /* @__PURE__ */ new Set([
|
|
403
|
+
"unsupported",
|
|
404
|
+
"invalid-route",
|
|
405
|
+
"unknown"
|
|
406
|
+
]);
|
|
397
407
|
function normalizeDisabledReason(reason) {
|
|
398
408
|
if (reason && disabledReasonSet.has(reason)) {
|
|
399
409
|
return reason;
|
|
400
410
|
}
|
|
401
411
|
return "unknown";
|
|
402
412
|
}
|
|
413
|
+
function normalizeIgnoredReason(reason) {
|
|
414
|
+
if (reason && ignoredReasonSet.has(reason)) {
|
|
415
|
+
return reason;
|
|
416
|
+
}
|
|
417
|
+
return "unknown";
|
|
418
|
+
}
|
|
403
419
|
function formatRouteFile(file, root) {
|
|
404
420
|
if (!root) {
|
|
405
421
|
return toPosixPath(file);
|
|
@@ -462,14 +478,44 @@ function toPlaygroundRoute(route, root, groups) {
|
|
|
462
478
|
}
|
|
463
479
|
function toPlaygroundDisabledRoute(route, root, groups) {
|
|
464
480
|
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
465
|
-
|
|
481
|
+
const disabled = {
|
|
466
482
|
file: formatRouteFile(route.file, root),
|
|
467
|
-
reason: normalizeDisabledReason(route.reason)
|
|
468
|
-
method: route.method,
|
|
469
|
-
url: route.url,
|
|
470
|
-
groupKey: matchedGroup?.key,
|
|
471
|
-
group: matchedGroup?.label
|
|
483
|
+
reason: normalizeDisabledReason(route.reason)
|
|
472
484
|
};
|
|
485
|
+
if (typeof route.method !== "undefined") {
|
|
486
|
+
disabled.method = route.method;
|
|
487
|
+
}
|
|
488
|
+
if (typeof route.url !== "undefined") {
|
|
489
|
+
disabled.url = route.url;
|
|
490
|
+
}
|
|
491
|
+
if (matchedGroup) {
|
|
492
|
+
disabled.groupKey = matchedGroup.key;
|
|
493
|
+
disabled.group = matchedGroup.label;
|
|
494
|
+
}
|
|
495
|
+
return disabled;
|
|
496
|
+
}
|
|
497
|
+
function toPlaygroundIgnoredRoute(route, root, groups) {
|
|
498
|
+
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
499
|
+
const ignored = {
|
|
500
|
+
file: formatRouteFile(route.file, root),
|
|
501
|
+
reason: normalizeIgnoredReason(route.reason)
|
|
502
|
+
};
|
|
503
|
+
if (matchedGroup) {
|
|
504
|
+
ignored.groupKey = matchedGroup.key;
|
|
505
|
+
ignored.group = matchedGroup.label;
|
|
506
|
+
}
|
|
507
|
+
return ignored;
|
|
508
|
+
}
|
|
509
|
+
function toPlaygroundConfigFile(entry, root, groups) {
|
|
510
|
+
const matchedGroup = resolveRouteGroup(entry.file, groups);
|
|
511
|
+
const configFile = {
|
|
512
|
+
file: formatRouteFile(entry.file, root)
|
|
513
|
+
};
|
|
514
|
+
if (matchedGroup) {
|
|
515
|
+
configFile.groupKey = matchedGroup.key;
|
|
516
|
+
configFile.group = matchedGroup.label;
|
|
517
|
+
}
|
|
518
|
+
return configFile;
|
|
473
519
|
}
|
|
474
520
|
function registerPlaygroundRoutes(params) {
|
|
475
521
|
if (!params.config.enabled) {
|
|
@@ -509,7 +555,12 @@ function registerPlaygroundRoutes(params) {
|
|
|
509
555
|
count: params.routes.length,
|
|
510
556
|
groups: groups.map((group) => ({ key: group.key, label: group.label })),
|
|
511
557
|
routes: params.routes.map((route) => toPlaygroundRoute(route, baseRoot, groups)),
|
|
512
|
-
disabled: (params.disabledRoutes ?? []).map((route) => toPlaygroundDisabledRoute(route, baseRoot, groups))
|
|
558
|
+
disabled: (params.disabledRoutes ?? []).map((route) => toPlaygroundDisabledRoute(route, baseRoot, groups)),
|
|
559
|
+
ignored: (params.ignoredRoutes ?? []).map((route) => toPlaygroundIgnoredRoute(route, baseRoot, groups)),
|
|
560
|
+
configs: (params.configFiles ?? []).map((entry) => toPlaygroundConfigFile(entry, baseRoot, groups)),
|
|
561
|
+
disabledConfigs: (params.disabledConfigFiles ?? []).map(
|
|
562
|
+
(entry) => toPlaygroundConfigFile(entry, baseRoot, groups)
|
|
563
|
+
)
|
|
513
564
|
});
|
|
514
565
|
});
|
|
515
566
|
params.app.get(`${playgroundPath}/*`, async (c) => {
|
|
@@ -655,8 +706,78 @@ function sortRoutes(routes) {
|
|
|
655
706
|
});
|
|
656
707
|
}
|
|
657
708
|
|
|
658
|
-
|
|
659
|
-
|
|
709
|
+
let registerPromise = null;
|
|
710
|
+
let hasLoggedFailure = false;
|
|
711
|
+
async function ensureTsxRegister(logger) {
|
|
712
|
+
if (registerPromise) {
|
|
713
|
+
return registerPromise;
|
|
714
|
+
}
|
|
715
|
+
registerPromise = (async () => {
|
|
716
|
+
try {
|
|
717
|
+
const mod = await import('tsx/esm/api');
|
|
718
|
+
const setSourceMapsEnabled = process__default.setSourceMapsEnabled;
|
|
719
|
+
if (typeof setSourceMapsEnabled === "function") {
|
|
720
|
+
setSourceMapsEnabled(true);
|
|
721
|
+
}
|
|
722
|
+
if (typeof mod.register === "function") {
|
|
723
|
+
mod.register();
|
|
724
|
+
}
|
|
725
|
+
return true;
|
|
726
|
+
} catch (error) {
|
|
727
|
+
if (!hasLoggedFailure && logger) {
|
|
728
|
+
logger.warn(
|
|
729
|
+
"Failed to register tsx loader; falling back to bundled TS loader.",
|
|
730
|
+
error
|
|
731
|
+
);
|
|
732
|
+
hasLoggedFailure = true;
|
|
733
|
+
}
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
})();
|
|
737
|
+
return registerPromise;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function isUnknownFileExtensionError$1(error) {
|
|
741
|
+
if (!error || typeof error !== "object") {
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
const code = error.code;
|
|
745
|
+
if (code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
const message = error.message;
|
|
749
|
+
return typeof message === "string" && message.includes("Unknown file extension");
|
|
750
|
+
}
|
|
751
|
+
async function loadTsModule$1(file, logger) {
|
|
752
|
+
const cacheBust = Date.now();
|
|
753
|
+
const fileUrl = `${node_url.pathToFileURL(file).href}?t=${cacheBust}`;
|
|
754
|
+
const registered = await ensureTsxRegister(logger);
|
|
755
|
+
if (registered) {
|
|
756
|
+
try {
|
|
757
|
+
return await import(fileUrl);
|
|
758
|
+
} catch (error) {
|
|
759
|
+
if (!isUnknownFileExtensionError$1(error)) {
|
|
760
|
+
throw error;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
const result = await esbuild.build({
|
|
765
|
+
entryPoints: [file],
|
|
766
|
+
bundle: true,
|
|
767
|
+
format: "esm",
|
|
768
|
+
platform: "node",
|
|
769
|
+
sourcemap: "inline",
|
|
770
|
+
target: "es2020",
|
|
771
|
+
write: false
|
|
772
|
+
});
|
|
773
|
+
const output = result.outputFiles[0];
|
|
774
|
+
const code = output?.text ?? "";
|
|
775
|
+
const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
|
|
776
|
+
"base64"
|
|
777
|
+
)}`;
|
|
778
|
+
return import(`${dataUrl}#${cacheBust}`);
|
|
779
|
+
}
|
|
780
|
+
async function loadModule$1(file, logger) {
|
|
660
781
|
const ext = configExtensions.find((extension) => file.endsWith(extension));
|
|
661
782
|
if (ext === ".cjs") {
|
|
662
783
|
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
@@ -667,21 +788,7 @@ async function loadModule$1(file) {
|
|
|
667
788
|
return import(`${node_url.pathToFileURL(file).href}?t=${Date.now()}`);
|
|
668
789
|
}
|
|
669
790
|
if (ext === ".ts") {
|
|
670
|
-
|
|
671
|
-
entryPoints: [file],
|
|
672
|
-
bundle: true,
|
|
673
|
-
format: "esm",
|
|
674
|
-
platform: "node",
|
|
675
|
-
sourcemap: "inline",
|
|
676
|
-
target: "es2020",
|
|
677
|
-
write: false
|
|
678
|
-
});
|
|
679
|
-
const output = result.outputFiles[0];
|
|
680
|
-
const code = output?.text ?? "";
|
|
681
|
-
const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
|
|
682
|
-
"base64"
|
|
683
|
-
)}`;
|
|
684
|
-
return import(`${dataUrl}#${Date.now()}`);
|
|
791
|
+
return loadTsModule$1(file, logger);
|
|
685
792
|
}
|
|
686
793
|
return null;
|
|
687
794
|
}
|
|
@@ -705,8 +812,8 @@ async function findConfigFile(dir, cache) {
|
|
|
705
812
|
cache.set(dir, null);
|
|
706
813
|
return null;
|
|
707
814
|
}
|
|
708
|
-
async function loadConfig(file) {
|
|
709
|
-
const mod = await loadModule$1(file);
|
|
815
|
+
async function loadConfig(file, logger) {
|
|
816
|
+
const mod = await loadModule$1(file, logger);
|
|
710
817
|
if (!mod) {
|
|
711
818
|
return null;
|
|
712
819
|
}
|
|
@@ -757,7 +864,7 @@ async function resolveDirectoryConfig(params) {
|
|
|
757
864
|
}
|
|
758
865
|
let config = configCache.get(configPath);
|
|
759
866
|
if (config === void 0) {
|
|
760
|
-
config = await loadConfig(configPath);
|
|
867
|
+
config = await loadConfig(configPath, logger);
|
|
761
868
|
configCache.set(configPath, config);
|
|
762
869
|
}
|
|
763
870
|
if (!config) {
|
|
@@ -831,14 +938,65 @@ function isSupportedFile(file) {
|
|
|
831
938
|
if (file.endsWith(".d.ts")) {
|
|
832
939
|
return false;
|
|
833
940
|
}
|
|
834
|
-
if (
|
|
941
|
+
if (isConfigFile(file)) {
|
|
835
942
|
return false;
|
|
836
943
|
}
|
|
837
944
|
const ext = pathe.extname(file).toLowerCase();
|
|
838
945
|
return supportedExtensions.has(ext);
|
|
839
946
|
}
|
|
947
|
+
function isConfigFile(file) {
|
|
948
|
+
if (file.endsWith(".d.ts")) {
|
|
949
|
+
return false;
|
|
950
|
+
}
|
|
951
|
+
const base = pathe.basename(file);
|
|
952
|
+
if (!base.startsWith("index.config.")) {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
const ext = pathe.extname(file).toLowerCase();
|
|
956
|
+
return configExtensions.includes(ext);
|
|
957
|
+
}
|
|
840
958
|
|
|
841
|
-
|
|
959
|
+
function isUnknownFileExtensionError(error) {
|
|
960
|
+
if (!error || typeof error !== "object") {
|
|
961
|
+
return false;
|
|
962
|
+
}
|
|
963
|
+
const code = error.code;
|
|
964
|
+
if (code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
965
|
+
return true;
|
|
966
|
+
}
|
|
967
|
+
const message = error.message;
|
|
968
|
+
return typeof message === "string" && message.includes("Unknown file extension");
|
|
969
|
+
}
|
|
970
|
+
async function loadTsModule(file, logger) {
|
|
971
|
+
const cacheBust = Date.now();
|
|
972
|
+
const fileUrl = `${node_url.pathToFileURL(file).href}?t=${cacheBust}`;
|
|
973
|
+
const registered = await ensureTsxRegister(logger);
|
|
974
|
+
if (registered) {
|
|
975
|
+
try {
|
|
976
|
+
return await import(fileUrl);
|
|
977
|
+
} catch (error) {
|
|
978
|
+
if (!isUnknownFileExtensionError(error)) {
|
|
979
|
+
throw error;
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
const result = await esbuild.build({
|
|
984
|
+
entryPoints: [file],
|
|
985
|
+
bundle: true,
|
|
986
|
+
format: "esm",
|
|
987
|
+
platform: "node",
|
|
988
|
+
sourcemap: "inline",
|
|
989
|
+
target: "es2020",
|
|
990
|
+
write: false
|
|
991
|
+
});
|
|
992
|
+
const output = result.outputFiles[0];
|
|
993
|
+
const code = output?.text ?? "";
|
|
994
|
+
const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
|
|
995
|
+
"base64"
|
|
996
|
+
)}`;
|
|
997
|
+
return import(`${dataUrl}#${cacheBust}`);
|
|
998
|
+
}
|
|
999
|
+
async function loadModule(file, logger) {
|
|
842
1000
|
const ext = pathe.extname(file).toLowerCase();
|
|
843
1001
|
if (ext === ".cjs") {
|
|
844
1002
|
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
@@ -849,21 +1007,7 @@ async function loadModule(file) {
|
|
|
849
1007
|
return import(`${node_url.pathToFileURL(file).href}?t=${Date.now()}`);
|
|
850
1008
|
}
|
|
851
1009
|
if (ext === ".ts") {
|
|
852
|
-
|
|
853
|
-
entryPoints: [file],
|
|
854
|
-
bundle: true,
|
|
855
|
-
format: "esm",
|
|
856
|
-
platform: "node",
|
|
857
|
-
sourcemap: "inline",
|
|
858
|
-
target: "es2020",
|
|
859
|
-
write: false
|
|
860
|
-
});
|
|
861
|
-
const output = result.outputFiles[0];
|
|
862
|
-
const code = output?.text ?? "";
|
|
863
|
-
const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
|
|
864
|
-
"base64"
|
|
865
|
-
)}`;
|
|
866
|
-
return import(`${dataUrl}#${Date.now()}`);
|
|
1010
|
+
return loadTsModule(file, logger);
|
|
867
1011
|
}
|
|
868
1012
|
return null;
|
|
869
1013
|
}
|
|
@@ -898,7 +1042,7 @@ async function loadRules(file, logger) {
|
|
|
898
1042
|
}
|
|
899
1043
|
];
|
|
900
1044
|
}
|
|
901
|
-
const mod = await loadModule(file);
|
|
1045
|
+
const mod = await loadModule(file, logger);
|
|
902
1046
|
const value = mod?.default ?? mod;
|
|
903
1047
|
if (!value) {
|
|
904
1048
|
return [];
|
|
@@ -945,6 +1089,14 @@ function resolveSkipRoute(params) {
|
|
|
945
1089
|
url: resolved.template
|
|
946
1090
|
};
|
|
947
1091
|
}
|
|
1092
|
+
function buildSkipInfo(file, reason, resolved) {
|
|
1093
|
+
const info = { file, reason };
|
|
1094
|
+
if (resolved) {
|
|
1095
|
+
info.method = resolved.method;
|
|
1096
|
+
info.url = resolved.url;
|
|
1097
|
+
}
|
|
1098
|
+
return info;
|
|
1099
|
+
}
|
|
948
1100
|
async function scanRoutes(params) {
|
|
949
1101
|
const routes = [];
|
|
950
1102
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -953,7 +1105,22 @@ async function scanRoutes(params) {
|
|
|
953
1105
|
const configCache = /* @__PURE__ */ new Map();
|
|
954
1106
|
const fileCache = /* @__PURE__ */ new Map();
|
|
955
1107
|
const shouldCollectSkip = typeof params.onSkip === "function";
|
|
1108
|
+
const shouldCollectIgnore = typeof params.onIgnore === "function";
|
|
1109
|
+
const shouldCollectConfig = typeof params.onConfig === "function";
|
|
956
1110
|
for (const fileInfo of files) {
|
|
1111
|
+
if (isConfigFile(fileInfo.file)) {
|
|
1112
|
+
if (shouldCollectConfig) {
|
|
1113
|
+
const config2 = await resolveDirectoryConfig({
|
|
1114
|
+
file: fileInfo.file,
|
|
1115
|
+
rootDir: fileInfo.rootDir,
|
|
1116
|
+
logger: params.logger,
|
|
1117
|
+
configCache,
|
|
1118
|
+
fileCache
|
|
1119
|
+
});
|
|
1120
|
+
params.onConfig?.({ file: fileInfo.file, enabled: config2.enabled !== false });
|
|
1121
|
+
}
|
|
1122
|
+
continue;
|
|
1123
|
+
}
|
|
957
1124
|
const config = await resolveDirectoryConfig({
|
|
958
1125
|
file: fileInfo.file,
|
|
959
1126
|
rootDir: fileInfo.rootDir,
|
|
@@ -968,12 +1135,7 @@ async function scanRoutes(params) {
|
|
|
968
1135
|
rootDir: fileInfo.rootDir,
|
|
969
1136
|
prefix: params.prefix
|
|
970
1137
|
});
|
|
971
|
-
params.onSkip?.(
|
|
972
|
-
file: fileInfo.file,
|
|
973
|
-
reason: "disabled-dir",
|
|
974
|
-
method: resolved?.method,
|
|
975
|
-
url: resolved?.url
|
|
976
|
-
});
|
|
1138
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled-dir", resolved));
|
|
977
1139
|
}
|
|
978
1140
|
continue;
|
|
979
1141
|
}
|
|
@@ -985,16 +1147,14 @@ async function scanRoutes(params) {
|
|
|
985
1147
|
rootDir: fileInfo.rootDir,
|
|
986
1148
|
prefix: params.prefix
|
|
987
1149
|
});
|
|
988
|
-
params.onSkip?.(
|
|
989
|
-
file: fileInfo.file,
|
|
990
|
-
reason: "ignore-prefix",
|
|
991
|
-
method: resolved?.method,
|
|
992
|
-
url: resolved?.url
|
|
993
|
-
});
|
|
1150
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "ignore-prefix", resolved));
|
|
994
1151
|
}
|
|
995
1152
|
continue;
|
|
996
1153
|
}
|
|
997
1154
|
if (!isSupportedFile(fileInfo.file)) {
|
|
1155
|
+
if (shouldCollectIgnore) {
|
|
1156
|
+
params.onIgnore?.({ file: fileInfo.file, reason: "unsupported" });
|
|
1157
|
+
}
|
|
998
1158
|
continue;
|
|
999
1159
|
}
|
|
1000
1160
|
const effectiveInclude = typeof config.include !== "undefined" ? config.include : params.include;
|
|
@@ -1007,17 +1167,15 @@ async function scanRoutes(params) {
|
|
|
1007
1167
|
prefix: params.prefix
|
|
1008
1168
|
});
|
|
1009
1169
|
const reason = effectiveExclude && matchesFilter(fileInfo.file, void 0, effectiveExclude) ? "exclude" : "include";
|
|
1010
|
-
params.onSkip?.(
|
|
1011
|
-
file: fileInfo.file,
|
|
1012
|
-
reason,
|
|
1013
|
-
method: resolved?.method,
|
|
1014
|
-
url: resolved?.url
|
|
1015
|
-
});
|
|
1170
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, reason, resolved));
|
|
1016
1171
|
}
|
|
1017
1172
|
continue;
|
|
1018
1173
|
}
|
|
1019
1174
|
const derived = deriveRouteFromFile(fileInfo.file, fileInfo.rootDir, params.logger);
|
|
1020
1175
|
if (!derived) {
|
|
1176
|
+
if (shouldCollectIgnore) {
|
|
1177
|
+
params.onIgnore?.({ file: fileInfo.file, reason: "invalid-route" });
|
|
1178
|
+
}
|
|
1021
1179
|
continue;
|
|
1022
1180
|
}
|
|
1023
1181
|
const rules = await loadRules(fileInfo.file, params.logger);
|
|
@@ -1033,12 +1191,7 @@ async function scanRoutes(params) {
|
|
|
1033
1191
|
prefix: params.prefix,
|
|
1034
1192
|
derived
|
|
1035
1193
|
});
|
|
1036
|
-
params.onSkip?.(
|
|
1037
|
-
file: fileInfo.file,
|
|
1038
|
-
reason: "disabled",
|
|
1039
|
-
method: resolved2?.method,
|
|
1040
|
-
url: resolved2?.url
|
|
1041
|
-
});
|
|
1194
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled", resolved2));
|
|
1042
1195
|
}
|
|
1043
1196
|
continue;
|
|
1044
1197
|
}
|
|
@@ -1121,7 +1274,7 @@ function resolveRoot(list) {
|
|
|
1121
1274
|
if (deno?.cwd) {
|
|
1122
1275
|
return deno.cwd();
|
|
1123
1276
|
}
|
|
1124
|
-
return
|
|
1277
|
+
return process.cwd();
|
|
1125
1278
|
}
|
|
1126
1279
|
function resolveAllDirs(list, root) {
|
|
1127
1280
|
const dirs = [];
|
|
@@ -1143,6 +1296,9 @@ function buildApp(params) {
|
|
|
1143
1296
|
app,
|
|
1144
1297
|
routes: params.routes,
|
|
1145
1298
|
disabledRoutes: params.disabledRoutes,
|
|
1299
|
+
ignoredRoutes: params.ignoredRoutes,
|
|
1300
|
+
configFiles: params.configFiles,
|
|
1301
|
+
disabledConfigFiles: params.disabledConfigFiles,
|
|
1146
1302
|
dirs: params.dirs,
|
|
1147
1303
|
logger: params.logger,
|
|
1148
1304
|
config: params.playground,
|
|
@@ -1152,7 +1308,8 @@ function buildApp(params) {
|
|
|
1152
1308
|
app.get(`${params.playground.path}/ws`, params.wsHandler);
|
|
1153
1309
|
}
|
|
1154
1310
|
if (params.routes.length > 0) {
|
|
1155
|
-
const
|
|
1311
|
+
const mockAppOptions = params.onResponse ? { onResponse: params.onResponse } : {};
|
|
1312
|
+
const mockApp = createHonoApp(params.routes, mockAppOptions);
|
|
1156
1313
|
app.route("/", mockApp);
|
|
1157
1314
|
}
|
|
1158
1315
|
return app;
|
|
@@ -1307,26 +1464,36 @@ async function createFetchServer(options = {}) {
|
|
|
1307
1464
|
}
|
|
1308
1465
|
let routes = [];
|
|
1309
1466
|
let disabledRoutes = [];
|
|
1467
|
+
let ignoredRoutes = [];
|
|
1468
|
+
let configFiles = [];
|
|
1469
|
+
let disabledConfigFiles = [];
|
|
1310
1470
|
let app = buildApp({
|
|
1311
1471
|
routes,
|
|
1312
1472
|
disabledRoutes,
|
|
1473
|
+
ignoredRoutes,
|
|
1474
|
+
configFiles,
|
|
1475
|
+
disabledConfigFiles,
|
|
1313
1476
|
dirs,
|
|
1314
1477
|
playground: playgroundConfig,
|
|
1315
1478
|
root,
|
|
1316
1479
|
logger,
|
|
1317
1480
|
onResponse: handleRouteResponse,
|
|
1318
|
-
wsHandler
|
|
1481
|
+
...wsHandler ? { wsHandler } : {}
|
|
1319
1482
|
});
|
|
1320
1483
|
const refreshRoutes = async () => {
|
|
1321
1484
|
try {
|
|
1322
1485
|
const collected = [];
|
|
1323
1486
|
const collectedDisabled = [];
|
|
1487
|
+
const collectedIgnored = [];
|
|
1488
|
+
const collectedConfigs = [];
|
|
1324
1489
|
for (const entry of optionList) {
|
|
1325
1490
|
const scanParams = {
|
|
1326
1491
|
dirs: resolveDirs(entry.dir, root),
|
|
1327
1492
|
prefix: entry.prefix ?? "",
|
|
1328
1493
|
logger,
|
|
1329
|
-
onSkip: (info) => collectedDisabled.push(info)
|
|
1494
|
+
onSkip: (info) => collectedDisabled.push(info),
|
|
1495
|
+
onIgnore: (info) => collectedIgnored.push(info),
|
|
1496
|
+
onConfig: (info) => collectedConfigs.push(info)
|
|
1330
1497
|
};
|
|
1331
1498
|
if (entry.include) {
|
|
1332
1499
|
scanParams.include = entry.include;
|
|
@@ -1343,15 +1510,23 @@ async function createFetchServer(options = {}) {
|
|
|
1343
1510
|
const resolvedRoutes = sortRoutes(collected);
|
|
1344
1511
|
routes = resolvedRoutes;
|
|
1345
1512
|
disabledRoutes = collectedDisabled;
|
|
1513
|
+
ignoredRoutes = collectedIgnored;
|
|
1514
|
+
const configMap = new Map(collectedConfigs.map((entry) => [entry.file, entry]));
|
|
1515
|
+
const resolvedConfigs = Array.from(configMap.values());
|
|
1516
|
+
configFiles = resolvedConfigs.filter((entry) => entry.enabled);
|
|
1517
|
+
disabledConfigFiles = resolvedConfigs.filter((entry) => !entry.enabled);
|
|
1346
1518
|
app = buildApp({
|
|
1347
1519
|
routes,
|
|
1348
1520
|
disabledRoutes,
|
|
1521
|
+
ignoredRoutes,
|
|
1522
|
+
configFiles,
|
|
1523
|
+
disabledConfigFiles,
|
|
1349
1524
|
dirs,
|
|
1350
1525
|
playground: playgroundConfig,
|
|
1351
1526
|
root,
|
|
1352
1527
|
logger,
|
|
1353
1528
|
onResponse: handleRouteResponse,
|
|
1354
|
-
wsHandler
|
|
1529
|
+
...wsHandler ? { wsHandler } : {}
|
|
1355
1530
|
});
|
|
1356
1531
|
logger.info(`Loaded ${routes.length} mock routes.`);
|
|
1357
1532
|
} catch (error) {
|
|
@@ -1377,7 +1552,7 @@ async function createFetchServer(options = {}) {
|
|
|
1377
1552
|
fetch,
|
|
1378
1553
|
refresh: refreshRoutes,
|
|
1379
1554
|
getRoutes: () => routes,
|
|
1380
|
-
injectWebSocket
|
|
1555
|
+
...injectWebSocket ? { injectWebSocket } : {}
|
|
1381
1556
|
};
|
|
1382
1557
|
if (watcher) {
|
|
1383
1558
|
server.close = async () => {
|
package/dist/index.d.cts
CHANGED
|
@@ -41,8 +41,10 @@ declare function createFastifyPlugin(options: ServerOptions): (instance: Fastify
|
|
|
41
41
|
declare function createFetchHandler(options: ServerOptions): FetchHandler;
|
|
42
42
|
|
|
43
43
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
|
44
|
-
type
|
|
45
|
-
type
|
|
44
|
+
type RouteStaticResponse = string | number | boolean | bigint | symbol | null | undefined | object;
|
|
45
|
+
type RouteHandlerResult = RouteStaticResponse | Response;
|
|
46
|
+
type RequestHandler = (context: Context) => RouteHandlerResult | Promise<RouteHandlerResult>;
|
|
47
|
+
type RouteResponse = RouteStaticResponse | RequestHandler;
|
|
46
48
|
interface ResolvedMiddleware {
|
|
47
49
|
handle: MiddlewareHandler;
|
|
48
50
|
source: string;
|
package/dist/index.d.mts
CHANGED
|
@@ -41,8 +41,10 @@ declare function createFastifyPlugin(options: ServerOptions): (instance: Fastify
|
|
|
41
41
|
declare function createFetchHandler(options: ServerOptions): FetchHandler;
|
|
42
42
|
|
|
43
43
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
|
44
|
-
type
|
|
45
|
-
type
|
|
44
|
+
type RouteStaticResponse = string | number | boolean | bigint | symbol | null | undefined | object;
|
|
45
|
+
type RouteHandlerResult = RouteStaticResponse | Response;
|
|
46
|
+
type RequestHandler = (context: Context) => RouteHandlerResult | Promise<RouteHandlerResult>;
|
|
47
|
+
type RouteResponse = RouteStaticResponse | RequestHandler;
|
|
46
48
|
interface ResolvedMiddleware {
|
|
47
49
|
handle: MiddlewareHandler;
|
|
48
50
|
source: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -41,8 +41,10 @@ declare function createFastifyPlugin(options: ServerOptions): (instance: Fastify
|
|
|
41
41
|
declare function createFetchHandler(options: ServerOptions): FetchHandler;
|
|
42
42
|
|
|
43
43
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS' | 'HEAD';
|
|
44
|
-
type
|
|
45
|
-
type
|
|
44
|
+
type RouteStaticResponse = string | number | boolean | bigint | symbol | null | undefined | object;
|
|
45
|
+
type RouteHandlerResult = RouteStaticResponse | Response;
|
|
46
|
+
type RequestHandler = (context: Context) => RouteHandlerResult | Promise<RouteHandlerResult>;
|
|
47
|
+
type RouteResponse = RouteStaticResponse | RequestHandler;
|
|
46
48
|
interface ResolvedMiddleware {
|
|
47
49
|
handle: MiddlewareHandler;
|
|
48
50
|
source: string;
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createRuntime, compareRouteScore, parseRouteTemplate } from '@mokup/runtime';
|
|
2
2
|
import { t as toRuntimeOptions, a as toRuntimeRequestFromNode, b as applyRuntimeResultToNode, d as toBinaryBody, c as createFetchHandler } from './shared/server.Dje1y79O.mjs';
|
|
3
|
-
import { cwd } from 'node:process';
|
|
3
|
+
import process, { cwd } from 'node:process';
|
|
4
4
|
import { Hono, PatternRouter } from '@mokup/shared/hono';
|
|
5
5
|
import { resolve, isAbsolute, relative, join, normalize, extname, dirname, basename } from '@mokup/shared/pathe';
|
|
6
6
|
import { promises } from 'node:fs';
|
|
@@ -86,6 +86,7 @@ const supportedExtensions = /* @__PURE__ */ new Set([
|
|
|
86
86
|
".mjs",
|
|
87
87
|
".cjs"
|
|
88
88
|
]);
|
|
89
|
+
const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
|
|
89
90
|
|
|
90
91
|
function normalizePrefix(prefix) {
|
|
91
92
|
if (!prefix) {
|
|
@@ -391,12 +392,23 @@ const disabledReasonSet = /* @__PURE__ */ new Set([
|
|
|
391
392
|
"include",
|
|
392
393
|
"unknown"
|
|
393
394
|
]);
|
|
395
|
+
const ignoredReasonSet = /* @__PURE__ */ new Set([
|
|
396
|
+
"unsupported",
|
|
397
|
+
"invalid-route",
|
|
398
|
+
"unknown"
|
|
399
|
+
]);
|
|
394
400
|
function normalizeDisabledReason(reason) {
|
|
395
401
|
if (reason && disabledReasonSet.has(reason)) {
|
|
396
402
|
return reason;
|
|
397
403
|
}
|
|
398
404
|
return "unknown";
|
|
399
405
|
}
|
|
406
|
+
function normalizeIgnoredReason(reason) {
|
|
407
|
+
if (reason && ignoredReasonSet.has(reason)) {
|
|
408
|
+
return reason;
|
|
409
|
+
}
|
|
410
|
+
return "unknown";
|
|
411
|
+
}
|
|
400
412
|
function formatRouteFile(file, root) {
|
|
401
413
|
if (!root) {
|
|
402
414
|
return toPosixPath(file);
|
|
@@ -459,14 +471,44 @@ function toPlaygroundRoute(route, root, groups) {
|
|
|
459
471
|
}
|
|
460
472
|
function toPlaygroundDisabledRoute(route, root, groups) {
|
|
461
473
|
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
462
|
-
|
|
474
|
+
const disabled = {
|
|
463
475
|
file: formatRouteFile(route.file, root),
|
|
464
|
-
reason: normalizeDisabledReason(route.reason)
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
476
|
+
reason: normalizeDisabledReason(route.reason)
|
|
477
|
+
};
|
|
478
|
+
if (typeof route.method !== "undefined") {
|
|
479
|
+
disabled.method = route.method;
|
|
480
|
+
}
|
|
481
|
+
if (typeof route.url !== "undefined") {
|
|
482
|
+
disabled.url = route.url;
|
|
483
|
+
}
|
|
484
|
+
if (matchedGroup) {
|
|
485
|
+
disabled.groupKey = matchedGroup.key;
|
|
486
|
+
disabled.group = matchedGroup.label;
|
|
487
|
+
}
|
|
488
|
+
return disabled;
|
|
489
|
+
}
|
|
490
|
+
function toPlaygroundIgnoredRoute(route, root, groups) {
|
|
491
|
+
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
492
|
+
const ignored = {
|
|
493
|
+
file: formatRouteFile(route.file, root),
|
|
494
|
+
reason: normalizeIgnoredReason(route.reason)
|
|
495
|
+
};
|
|
496
|
+
if (matchedGroup) {
|
|
497
|
+
ignored.groupKey = matchedGroup.key;
|
|
498
|
+
ignored.group = matchedGroup.label;
|
|
499
|
+
}
|
|
500
|
+
return ignored;
|
|
501
|
+
}
|
|
502
|
+
function toPlaygroundConfigFile(entry, root, groups) {
|
|
503
|
+
const matchedGroup = resolveRouteGroup(entry.file, groups);
|
|
504
|
+
const configFile = {
|
|
505
|
+
file: formatRouteFile(entry.file, root)
|
|
469
506
|
};
|
|
507
|
+
if (matchedGroup) {
|
|
508
|
+
configFile.groupKey = matchedGroup.key;
|
|
509
|
+
configFile.group = matchedGroup.label;
|
|
510
|
+
}
|
|
511
|
+
return configFile;
|
|
470
512
|
}
|
|
471
513
|
function registerPlaygroundRoutes(params) {
|
|
472
514
|
if (!params.config.enabled) {
|
|
@@ -506,7 +548,12 @@ function registerPlaygroundRoutes(params) {
|
|
|
506
548
|
count: params.routes.length,
|
|
507
549
|
groups: groups.map((group) => ({ key: group.key, label: group.label })),
|
|
508
550
|
routes: params.routes.map((route) => toPlaygroundRoute(route, baseRoot, groups)),
|
|
509
|
-
disabled: (params.disabledRoutes ?? []).map((route) => toPlaygroundDisabledRoute(route, baseRoot, groups))
|
|
551
|
+
disabled: (params.disabledRoutes ?? []).map((route) => toPlaygroundDisabledRoute(route, baseRoot, groups)),
|
|
552
|
+
ignored: (params.ignoredRoutes ?? []).map((route) => toPlaygroundIgnoredRoute(route, baseRoot, groups)),
|
|
553
|
+
configs: (params.configFiles ?? []).map((entry) => toPlaygroundConfigFile(entry, baseRoot, groups)),
|
|
554
|
+
disabledConfigs: (params.disabledConfigFiles ?? []).map(
|
|
555
|
+
(entry) => toPlaygroundConfigFile(entry, baseRoot, groups)
|
|
556
|
+
)
|
|
510
557
|
});
|
|
511
558
|
});
|
|
512
559
|
params.app.get(`${playgroundPath}/*`, async (c) => {
|
|
@@ -652,8 +699,78 @@ function sortRoutes(routes) {
|
|
|
652
699
|
});
|
|
653
700
|
}
|
|
654
701
|
|
|
655
|
-
|
|
656
|
-
|
|
702
|
+
let registerPromise = null;
|
|
703
|
+
let hasLoggedFailure = false;
|
|
704
|
+
async function ensureTsxRegister(logger) {
|
|
705
|
+
if (registerPromise) {
|
|
706
|
+
return registerPromise;
|
|
707
|
+
}
|
|
708
|
+
registerPromise = (async () => {
|
|
709
|
+
try {
|
|
710
|
+
const mod = await import('tsx/esm/api');
|
|
711
|
+
const setSourceMapsEnabled = process.setSourceMapsEnabled;
|
|
712
|
+
if (typeof setSourceMapsEnabled === "function") {
|
|
713
|
+
setSourceMapsEnabled(true);
|
|
714
|
+
}
|
|
715
|
+
if (typeof mod.register === "function") {
|
|
716
|
+
mod.register();
|
|
717
|
+
}
|
|
718
|
+
return true;
|
|
719
|
+
} catch (error) {
|
|
720
|
+
if (!hasLoggedFailure && logger) {
|
|
721
|
+
logger.warn(
|
|
722
|
+
"Failed to register tsx loader; falling back to bundled TS loader.",
|
|
723
|
+
error
|
|
724
|
+
);
|
|
725
|
+
hasLoggedFailure = true;
|
|
726
|
+
}
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
})();
|
|
730
|
+
return registerPromise;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
function isUnknownFileExtensionError$1(error) {
|
|
734
|
+
if (!error || typeof error !== "object") {
|
|
735
|
+
return false;
|
|
736
|
+
}
|
|
737
|
+
const code = error.code;
|
|
738
|
+
if (code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
739
|
+
return true;
|
|
740
|
+
}
|
|
741
|
+
const message = error.message;
|
|
742
|
+
return typeof message === "string" && message.includes("Unknown file extension");
|
|
743
|
+
}
|
|
744
|
+
async function loadTsModule$1(file, logger) {
|
|
745
|
+
const cacheBust = Date.now();
|
|
746
|
+
const fileUrl = `${pathToFileURL(file).href}?t=${cacheBust}`;
|
|
747
|
+
const registered = await ensureTsxRegister(logger);
|
|
748
|
+
if (registered) {
|
|
749
|
+
try {
|
|
750
|
+
return await import(fileUrl);
|
|
751
|
+
} catch (error) {
|
|
752
|
+
if (!isUnknownFileExtensionError$1(error)) {
|
|
753
|
+
throw error;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
const result = await build({
|
|
758
|
+
entryPoints: [file],
|
|
759
|
+
bundle: true,
|
|
760
|
+
format: "esm",
|
|
761
|
+
platform: "node",
|
|
762
|
+
sourcemap: "inline",
|
|
763
|
+
target: "es2020",
|
|
764
|
+
write: false
|
|
765
|
+
});
|
|
766
|
+
const output = result.outputFiles[0];
|
|
767
|
+
const code = output?.text ?? "";
|
|
768
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString(
|
|
769
|
+
"base64"
|
|
770
|
+
)}`;
|
|
771
|
+
return import(`${dataUrl}#${cacheBust}`);
|
|
772
|
+
}
|
|
773
|
+
async function loadModule$1(file, logger) {
|
|
657
774
|
const ext = configExtensions.find((extension) => file.endsWith(extension));
|
|
658
775
|
if (ext === ".cjs") {
|
|
659
776
|
const require = createRequire(import.meta.url);
|
|
@@ -664,21 +781,7 @@ async function loadModule$1(file) {
|
|
|
664
781
|
return import(`${pathToFileURL(file).href}?t=${Date.now()}`);
|
|
665
782
|
}
|
|
666
783
|
if (ext === ".ts") {
|
|
667
|
-
|
|
668
|
-
entryPoints: [file],
|
|
669
|
-
bundle: true,
|
|
670
|
-
format: "esm",
|
|
671
|
-
platform: "node",
|
|
672
|
-
sourcemap: "inline",
|
|
673
|
-
target: "es2020",
|
|
674
|
-
write: false
|
|
675
|
-
});
|
|
676
|
-
const output = result.outputFiles[0];
|
|
677
|
-
const code = output?.text ?? "";
|
|
678
|
-
const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString(
|
|
679
|
-
"base64"
|
|
680
|
-
)}`;
|
|
681
|
-
return import(`${dataUrl}#${Date.now()}`);
|
|
784
|
+
return loadTsModule$1(file, logger);
|
|
682
785
|
}
|
|
683
786
|
return null;
|
|
684
787
|
}
|
|
@@ -702,8 +805,8 @@ async function findConfigFile(dir, cache) {
|
|
|
702
805
|
cache.set(dir, null);
|
|
703
806
|
return null;
|
|
704
807
|
}
|
|
705
|
-
async function loadConfig(file) {
|
|
706
|
-
const mod = await loadModule$1(file);
|
|
808
|
+
async function loadConfig(file, logger) {
|
|
809
|
+
const mod = await loadModule$1(file, logger);
|
|
707
810
|
if (!mod) {
|
|
708
811
|
return null;
|
|
709
812
|
}
|
|
@@ -754,7 +857,7 @@ async function resolveDirectoryConfig(params) {
|
|
|
754
857
|
}
|
|
755
858
|
let config = configCache.get(configPath);
|
|
756
859
|
if (config === void 0) {
|
|
757
|
-
config = await loadConfig(configPath);
|
|
860
|
+
config = await loadConfig(configPath, logger);
|
|
758
861
|
configCache.set(configPath, config);
|
|
759
862
|
}
|
|
760
863
|
if (!config) {
|
|
@@ -828,14 +931,65 @@ function isSupportedFile(file) {
|
|
|
828
931
|
if (file.endsWith(".d.ts")) {
|
|
829
932
|
return false;
|
|
830
933
|
}
|
|
831
|
-
if (
|
|
934
|
+
if (isConfigFile(file)) {
|
|
832
935
|
return false;
|
|
833
936
|
}
|
|
834
937
|
const ext = extname(file).toLowerCase();
|
|
835
938
|
return supportedExtensions.has(ext);
|
|
836
939
|
}
|
|
940
|
+
function isConfigFile(file) {
|
|
941
|
+
if (file.endsWith(".d.ts")) {
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
944
|
+
const base = basename(file);
|
|
945
|
+
if (!base.startsWith("index.config.")) {
|
|
946
|
+
return false;
|
|
947
|
+
}
|
|
948
|
+
const ext = extname(file).toLowerCase();
|
|
949
|
+
return configExtensions.includes(ext);
|
|
950
|
+
}
|
|
837
951
|
|
|
838
|
-
|
|
952
|
+
function isUnknownFileExtensionError(error) {
|
|
953
|
+
if (!error || typeof error !== "object") {
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
const code = error.code;
|
|
957
|
+
if (code === "ERR_UNKNOWN_FILE_EXTENSION") {
|
|
958
|
+
return true;
|
|
959
|
+
}
|
|
960
|
+
const message = error.message;
|
|
961
|
+
return typeof message === "string" && message.includes("Unknown file extension");
|
|
962
|
+
}
|
|
963
|
+
async function loadTsModule(file, logger) {
|
|
964
|
+
const cacheBust = Date.now();
|
|
965
|
+
const fileUrl = `${pathToFileURL(file).href}?t=${cacheBust}`;
|
|
966
|
+
const registered = await ensureTsxRegister(logger);
|
|
967
|
+
if (registered) {
|
|
968
|
+
try {
|
|
969
|
+
return await import(fileUrl);
|
|
970
|
+
} catch (error) {
|
|
971
|
+
if (!isUnknownFileExtensionError(error)) {
|
|
972
|
+
throw error;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
const result = await build({
|
|
977
|
+
entryPoints: [file],
|
|
978
|
+
bundle: true,
|
|
979
|
+
format: "esm",
|
|
980
|
+
platform: "node",
|
|
981
|
+
sourcemap: "inline",
|
|
982
|
+
target: "es2020",
|
|
983
|
+
write: false
|
|
984
|
+
});
|
|
985
|
+
const output = result.outputFiles[0];
|
|
986
|
+
const code = output?.text ?? "";
|
|
987
|
+
const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString(
|
|
988
|
+
"base64"
|
|
989
|
+
)}`;
|
|
990
|
+
return import(`${dataUrl}#${cacheBust}`);
|
|
991
|
+
}
|
|
992
|
+
async function loadModule(file, logger) {
|
|
839
993
|
const ext = extname(file).toLowerCase();
|
|
840
994
|
if (ext === ".cjs") {
|
|
841
995
|
const require = createRequire(import.meta.url);
|
|
@@ -846,21 +1000,7 @@ async function loadModule(file) {
|
|
|
846
1000
|
return import(`${pathToFileURL(file).href}?t=${Date.now()}`);
|
|
847
1001
|
}
|
|
848
1002
|
if (ext === ".ts") {
|
|
849
|
-
|
|
850
|
-
entryPoints: [file],
|
|
851
|
-
bundle: true,
|
|
852
|
-
format: "esm",
|
|
853
|
-
platform: "node",
|
|
854
|
-
sourcemap: "inline",
|
|
855
|
-
target: "es2020",
|
|
856
|
-
write: false
|
|
857
|
-
});
|
|
858
|
-
const output = result.outputFiles[0];
|
|
859
|
-
const code = output?.text ?? "";
|
|
860
|
-
const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString(
|
|
861
|
-
"base64"
|
|
862
|
-
)}`;
|
|
863
|
-
return import(`${dataUrl}#${Date.now()}`);
|
|
1003
|
+
return loadTsModule(file, logger);
|
|
864
1004
|
}
|
|
865
1005
|
return null;
|
|
866
1006
|
}
|
|
@@ -895,7 +1035,7 @@ async function loadRules(file, logger) {
|
|
|
895
1035
|
}
|
|
896
1036
|
];
|
|
897
1037
|
}
|
|
898
|
-
const mod = await loadModule(file);
|
|
1038
|
+
const mod = await loadModule(file, logger);
|
|
899
1039
|
const value = mod?.default ?? mod;
|
|
900
1040
|
if (!value) {
|
|
901
1041
|
return [];
|
|
@@ -942,6 +1082,14 @@ function resolveSkipRoute(params) {
|
|
|
942
1082
|
url: resolved.template
|
|
943
1083
|
};
|
|
944
1084
|
}
|
|
1085
|
+
function buildSkipInfo(file, reason, resolved) {
|
|
1086
|
+
const info = { file, reason };
|
|
1087
|
+
if (resolved) {
|
|
1088
|
+
info.method = resolved.method;
|
|
1089
|
+
info.url = resolved.url;
|
|
1090
|
+
}
|
|
1091
|
+
return info;
|
|
1092
|
+
}
|
|
945
1093
|
async function scanRoutes(params) {
|
|
946
1094
|
const routes = [];
|
|
947
1095
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -950,7 +1098,22 @@ async function scanRoutes(params) {
|
|
|
950
1098
|
const configCache = /* @__PURE__ */ new Map();
|
|
951
1099
|
const fileCache = /* @__PURE__ */ new Map();
|
|
952
1100
|
const shouldCollectSkip = typeof params.onSkip === "function";
|
|
1101
|
+
const shouldCollectIgnore = typeof params.onIgnore === "function";
|
|
1102
|
+
const shouldCollectConfig = typeof params.onConfig === "function";
|
|
953
1103
|
for (const fileInfo of files) {
|
|
1104
|
+
if (isConfigFile(fileInfo.file)) {
|
|
1105
|
+
if (shouldCollectConfig) {
|
|
1106
|
+
const config2 = await resolveDirectoryConfig({
|
|
1107
|
+
file: fileInfo.file,
|
|
1108
|
+
rootDir: fileInfo.rootDir,
|
|
1109
|
+
logger: params.logger,
|
|
1110
|
+
configCache,
|
|
1111
|
+
fileCache
|
|
1112
|
+
});
|
|
1113
|
+
params.onConfig?.({ file: fileInfo.file, enabled: config2.enabled !== false });
|
|
1114
|
+
}
|
|
1115
|
+
continue;
|
|
1116
|
+
}
|
|
954
1117
|
const config = await resolveDirectoryConfig({
|
|
955
1118
|
file: fileInfo.file,
|
|
956
1119
|
rootDir: fileInfo.rootDir,
|
|
@@ -965,12 +1128,7 @@ async function scanRoutes(params) {
|
|
|
965
1128
|
rootDir: fileInfo.rootDir,
|
|
966
1129
|
prefix: params.prefix
|
|
967
1130
|
});
|
|
968
|
-
params.onSkip?.(
|
|
969
|
-
file: fileInfo.file,
|
|
970
|
-
reason: "disabled-dir",
|
|
971
|
-
method: resolved?.method,
|
|
972
|
-
url: resolved?.url
|
|
973
|
-
});
|
|
1131
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled-dir", resolved));
|
|
974
1132
|
}
|
|
975
1133
|
continue;
|
|
976
1134
|
}
|
|
@@ -982,16 +1140,14 @@ async function scanRoutes(params) {
|
|
|
982
1140
|
rootDir: fileInfo.rootDir,
|
|
983
1141
|
prefix: params.prefix
|
|
984
1142
|
});
|
|
985
|
-
params.onSkip?.(
|
|
986
|
-
file: fileInfo.file,
|
|
987
|
-
reason: "ignore-prefix",
|
|
988
|
-
method: resolved?.method,
|
|
989
|
-
url: resolved?.url
|
|
990
|
-
});
|
|
1143
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "ignore-prefix", resolved));
|
|
991
1144
|
}
|
|
992
1145
|
continue;
|
|
993
1146
|
}
|
|
994
1147
|
if (!isSupportedFile(fileInfo.file)) {
|
|
1148
|
+
if (shouldCollectIgnore) {
|
|
1149
|
+
params.onIgnore?.({ file: fileInfo.file, reason: "unsupported" });
|
|
1150
|
+
}
|
|
995
1151
|
continue;
|
|
996
1152
|
}
|
|
997
1153
|
const effectiveInclude = typeof config.include !== "undefined" ? config.include : params.include;
|
|
@@ -1004,17 +1160,15 @@ async function scanRoutes(params) {
|
|
|
1004
1160
|
prefix: params.prefix
|
|
1005
1161
|
});
|
|
1006
1162
|
const reason = effectiveExclude && matchesFilter(fileInfo.file, void 0, effectiveExclude) ? "exclude" : "include";
|
|
1007
|
-
params.onSkip?.(
|
|
1008
|
-
file: fileInfo.file,
|
|
1009
|
-
reason,
|
|
1010
|
-
method: resolved?.method,
|
|
1011
|
-
url: resolved?.url
|
|
1012
|
-
});
|
|
1163
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, reason, resolved));
|
|
1013
1164
|
}
|
|
1014
1165
|
continue;
|
|
1015
1166
|
}
|
|
1016
1167
|
const derived = deriveRouteFromFile(fileInfo.file, fileInfo.rootDir, params.logger);
|
|
1017
1168
|
if (!derived) {
|
|
1169
|
+
if (shouldCollectIgnore) {
|
|
1170
|
+
params.onIgnore?.({ file: fileInfo.file, reason: "invalid-route" });
|
|
1171
|
+
}
|
|
1018
1172
|
continue;
|
|
1019
1173
|
}
|
|
1020
1174
|
const rules = await loadRules(fileInfo.file, params.logger);
|
|
@@ -1030,12 +1184,7 @@ async function scanRoutes(params) {
|
|
|
1030
1184
|
prefix: params.prefix,
|
|
1031
1185
|
derived
|
|
1032
1186
|
});
|
|
1033
|
-
params.onSkip?.(
|
|
1034
|
-
file: fileInfo.file,
|
|
1035
|
-
reason: "disabled",
|
|
1036
|
-
method: resolved2?.method,
|
|
1037
|
-
url: resolved2?.url
|
|
1038
|
-
});
|
|
1187
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled", resolved2));
|
|
1039
1188
|
}
|
|
1040
1189
|
continue;
|
|
1041
1190
|
}
|
|
@@ -1140,6 +1289,9 @@ function buildApp(params) {
|
|
|
1140
1289
|
app,
|
|
1141
1290
|
routes: params.routes,
|
|
1142
1291
|
disabledRoutes: params.disabledRoutes,
|
|
1292
|
+
ignoredRoutes: params.ignoredRoutes,
|
|
1293
|
+
configFiles: params.configFiles,
|
|
1294
|
+
disabledConfigFiles: params.disabledConfigFiles,
|
|
1143
1295
|
dirs: params.dirs,
|
|
1144
1296
|
logger: params.logger,
|
|
1145
1297
|
config: params.playground,
|
|
@@ -1149,7 +1301,8 @@ function buildApp(params) {
|
|
|
1149
1301
|
app.get(`${params.playground.path}/ws`, params.wsHandler);
|
|
1150
1302
|
}
|
|
1151
1303
|
if (params.routes.length > 0) {
|
|
1152
|
-
const
|
|
1304
|
+
const mockAppOptions = params.onResponse ? { onResponse: params.onResponse } : {};
|
|
1305
|
+
const mockApp = createHonoApp(params.routes, mockAppOptions);
|
|
1153
1306
|
app.route("/", mockApp);
|
|
1154
1307
|
}
|
|
1155
1308
|
return app;
|
|
@@ -1304,26 +1457,36 @@ async function createFetchServer(options = {}) {
|
|
|
1304
1457
|
}
|
|
1305
1458
|
let routes = [];
|
|
1306
1459
|
let disabledRoutes = [];
|
|
1460
|
+
let ignoredRoutes = [];
|
|
1461
|
+
let configFiles = [];
|
|
1462
|
+
let disabledConfigFiles = [];
|
|
1307
1463
|
let app = buildApp({
|
|
1308
1464
|
routes,
|
|
1309
1465
|
disabledRoutes,
|
|
1466
|
+
ignoredRoutes,
|
|
1467
|
+
configFiles,
|
|
1468
|
+
disabledConfigFiles,
|
|
1310
1469
|
dirs,
|
|
1311
1470
|
playground: playgroundConfig,
|
|
1312
1471
|
root,
|
|
1313
1472
|
logger,
|
|
1314
1473
|
onResponse: handleRouteResponse,
|
|
1315
|
-
wsHandler
|
|
1474
|
+
...wsHandler ? { wsHandler } : {}
|
|
1316
1475
|
});
|
|
1317
1476
|
const refreshRoutes = async () => {
|
|
1318
1477
|
try {
|
|
1319
1478
|
const collected = [];
|
|
1320
1479
|
const collectedDisabled = [];
|
|
1480
|
+
const collectedIgnored = [];
|
|
1481
|
+
const collectedConfigs = [];
|
|
1321
1482
|
for (const entry of optionList) {
|
|
1322
1483
|
const scanParams = {
|
|
1323
1484
|
dirs: resolveDirs(entry.dir, root),
|
|
1324
1485
|
prefix: entry.prefix ?? "",
|
|
1325
1486
|
logger,
|
|
1326
|
-
onSkip: (info) => collectedDisabled.push(info)
|
|
1487
|
+
onSkip: (info) => collectedDisabled.push(info),
|
|
1488
|
+
onIgnore: (info) => collectedIgnored.push(info),
|
|
1489
|
+
onConfig: (info) => collectedConfigs.push(info)
|
|
1327
1490
|
};
|
|
1328
1491
|
if (entry.include) {
|
|
1329
1492
|
scanParams.include = entry.include;
|
|
@@ -1340,15 +1503,23 @@ async function createFetchServer(options = {}) {
|
|
|
1340
1503
|
const resolvedRoutes = sortRoutes(collected);
|
|
1341
1504
|
routes = resolvedRoutes;
|
|
1342
1505
|
disabledRoutes = collectedDisabled;
|
|
1506
|
+
ignoredRoutes = collectedIgnored;
|
|
1507
|
+
const configMap = new Map(collectedConfigs.map((entry) => [entry.file, entry]));
|
|
1508
|
+
const resolvedConfigs = Array.from(configMap.values());
|
|
1509
|
+
configFiles = resolvedConfigs.filter((entry) => entry.enabled);
|
|
1510
|
+
disabledConfigFiles = resolvedConfigs.filter((entry) => !entry.enabled);
|
|
1343
1511
|
app = buildApp({
|
|
1344
1512
|
routes,
|
|
1345
1513
|
disabledRoutes,
|
|
1514
|
+
ignoredRoutes,
|
|
1515
|
+
configFiles,
|
|
1516
|
+
disabledConfigFiles,
|
|
1346
1517
|
dirs,
|
|
1347
1518
|
playground: playgroundConfig,
|
|
1348
1519
|
root,
|
|
1349
1520
|
logger,
|
|
1350
1521
|
onResponse: handleRouteResponse,
|
|
1351
|
-
wsHandler
|
|
1522
|
+
...wsHandler ? { wsHandler } : {}
|
|
1352
1523
|
});
|
|
1353
1524
|
logger.info(`Loaded ${routes.length} mock routes.`);
|
|
1354
1525
|
} catch (error) {
|
|
@@ -1374,7 +1545,7 @@ async function createFetchServer(options = {}) {
|
|
|
1374
1545
|
fetch,
|
|
1375
1546
|
refresh: refreshRoutes,
|
|
1376
1547
|
getRoutes: () => routes,
|
|
1377
|
-
injectWebSocket
|
|
1548
|
+
...injectWebSocket ? { injectWebSocket } : {}
|
|
1378
1549
|
};
|
|
1379
1550
|
if (watcher) {
|
|
1380
1551
|
server.close = async () => {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mokup/server",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"description": "Server adapters for @mokup/runtime.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://mokup.icebreaker.top",
|
|
@@ -39,8 +39,9 @@
|
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@hono/node-server": "^1.19.9",
|
|
41
41
|
"@hono/node-ws": "^1.1.1",
|
|
42
|
-
"
|
|
43
|
-
"@mokup/
|
|
42
|
+
"tsx": "^4.21.0",
|
|
43
|
+
"@mokup/playground": "0.0.10",
|
|
44
|
+
"@mokup/runtime": "1.0.1",
|
|
44
45
|
"@mokup/shared": "1.0.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|