mokup 0.2.2 → 1.0.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/cli-bin.cjs +6 -102
- package/dist/cli-bin.mjs +4 -104
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/shared/mokup.C6zZ8YEh.mjs +1420 -0
- package/dist/shared/mokup.zAF8ClCC.cjs +1436 -0
- package/dist/vite.cjs +33 -1440
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.mts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.mjs +11 -1418
- package/dist/webpack.cjs +452 -0
- package/dist/webpack.d.cts +88 -0
- package/dist/webpack.d.mts +86 -0
- package/dist/webpack.d.ts +88 -0
- package/dist/webpack.mjs +442 -0
- package/package.json +25 -11
package/dist/vite.cjs
CHANGED
|
@@ -1,1430 +1,23 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const node_fs = require('node:fs');
|
|
4
|
-
const
|
|
4
|
+
const process = require('node:process');
|
|
5
5
|
const node_url = require('node:url');
|
|
6
|
-
const chokidar = require('chokidar');
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
const chokidar = require('@mokup/shared/chokidar');
|
|
7
|
+
const sw = require('./shared/mokup.zAF8ClCC.cjs');
|
|
8
|
+
require('node:buffer');
|
|
9
|
+
require('@mokup/shared/hono');
|
|
10
|
+
require('node:module');
|
|
11
|
+
require('@mokup/shared/pathe');
|
|
12
|
+
require('@mokup/shared/esbuild');
|
|
13
|
+
require('@mokup/shared/jsonc-parser');
|
|
14
|
+
require('@mokup/runtime');
|
|
15
15
|
|
|
16
16
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
17
17
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
18
18
|
|
|
19
19
|
const chokidar__default = /*#__PURE__*/_interopDefaultCompat(chokidar);
|
|
20
20
|
|
|
21
|
-
function createLogger(enabled) {
|
|
22
|
-
return {
|
|
23
|
-
info: (...args) => {
|
|
24
|
-
if (enabled) {
|
|
25
|
-
console.info("[mokup]", ...args);
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
warn: (...args) => {
|
|
29
|
-
if (enabled) {
|
|
30
|
-
console.warn("[mokup]", ...args);
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
error: (...args) => {
|
|
34
|
-
if (enabled) {
|
|
35
|
-
console.error("[mokup]", ...args);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const methodSet = /* @__PURE__ */ new Set([
|
|
42
|
-
"GET",
|
|
43
|
-
"POST",
|
|
44
|
-
"PUT",
|
|
45
|
-
"PATCH",
|
|
46
|
-
"DELETE",
|
|
47
|
-
"OPTIONS",
|
|
48
|
-
"HEAD"
|
|
49
|
-
]);
|
|
50
|
-
const methodSuffixSet = new Set(
|
|
51
|
-
Array.from(methodSet, (method) => method.toLowerCase())
|
|
52
|
-
);
|
|
53
|
-
const supportedExtensions = /* @__PURE__ */ new Set([
|
|
54
|
-
".json",
|
|
55
|
-
".jsonc",
|
|
56
|
-
".ts",
|
|
57
|
-
".js",
|
|
58
|
-
".mjs",
|
|
59
|
-
".cjs"
|
|
60
|
-
]);
|
|
61
|
-
|
|
62
|
-
function normalizeMethod(method) {
|
|
63
|
-
if (!method) {
|
|
64
|
-
return void 0;
|
|
65
|
-
}
|
|
66
|
-
const normalized = method.toUpperCase();
|
|
67
|
-
if (methodSet.has(normalized)) {
|
|
68
|
-
return normalized;
|
|
69
|
-
}
|
|
70
|
-
return void 0;
|
|
71
|
-
}
|
|
72
|
-
function normalizePrefix(prefix) {
|
|
73
|
-
if (!prefix) {
|
|
74
|
-
return "";
|
|
75
|
-
}
|
|
76
|
-
const normalized = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
77
|
-
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
78
|
-
}
|
|
79
|
-
function resolveDirs(dir, root) {
|
|
80
|
-
const raw = typeof dir === "function" ? dir(root) : dir;
|
|
81
|
-
const resolved = Array.isArray(raw) ? raw : raw ? [raw] : ["mock"];
|
|
82
|
-
const normalized = resolved.map(
|
|
83
|
-
(entry) => pathe.isAbsolute(entry) ? entry : pathe.resolve(root, entry)
|
|
84
|
-
);
|
|
85
|
-
return Array.from(new Set(normalized));
|
|
86
|
-
}
|
|
87
|
-
function createDebouncer(delayMs, fn) {
|
|
88
|
-
let timer = null;
|
|
89
|
-
return () => {
|
|
90
|
-
if (timer) {
|
|
91
|
-
clearTimeout(timer);
|
|
92
|
-
}
|
|
93
|
-
timer = setTimeout(() => {
|
|
94
|
-
timer = null;
|
|
95
|
-
fn();
|
|
96
|
-
}, delayMs);
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
function toPosix(value) {
|
|
100
|
-
return value.replace(/\\/g, "/");
|
|
101
|
-
}
|
|
102
|
-
function isInDirs(file, dirs) {
|
|
103
|
-
const normalized = toPosix(file);
|
|
104
|
-
return dirs.some((dir) => {
|
|
105
|
-
const normalizedDir = toPosix(dir).replace(/\/$/, "");
|
|
106
|
-
return normalized === normalizedDir || normalized.startsWith(`${normalizedDir}/`);
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
function testPatterns(patterns, value) {
|
|
110
|
-
const list = Array.isArray(patterns) ? patterns : [patterns];
|
|
111
|
-
return list.some((pattern) => pattern.test(value));
|
|
112
|
-
}
|
|
113
|
-
function matchesFilter(file, include, exclude) {
|
|
114
|
-
const normalized = toPosix(file);
|
|
115
|
-
if (exclude && testPatterns(exclude, normalized)) {
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
118
|
-
if (include) {
|
|
119
|
-
return testPatterns(include, normalized);
|
|
120
|
-
}
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
function delay(ms) {
|
|
124
|
-
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function toHonoPath(route) {
|
|
128
|
-
if (!route.tokens || route.tokens.length === 0) {
|
|
129
|
-
return "/";
|
|
130
|
-
}
|
|
131
|
-
const segments = route.tokens.map((token) => {
|
|
132
|
-
if (token.type === "static") {
|
|
133
|
-
return token.value;
|
|
134
|
-
}
|
|
135
|
-
if (token.type === "param") {
|
|
136
|
-
return `:${token.name}`;
|
|
137
|
-
}
|
|
138
|
-
if (token.type === "catchall") {
|
|
139
|
-
return `:${token.name}{.+}`;
|
|
140
|
-
}
|
|
141
|
-
return `:${token.name}{.+}?`;
|
|
142
|
-
});
|
|
143
|
-
return `/${segments.join("/")}`;
|
|
144
|
-
}
|
|
145
|
-
function isValidStatus(status) {
|
|
146
|
-
return typeof status === "number" && Number.isFinite(status) && status >= 200 && status <= 599;
|
|
147
|
-
}
|
|
148
|
-
function resolveStatus(routeStatus, responseStatus) {
|
|
149
|
-
if (isValidStatus(routeStatus)) {
|
|
150
|
-
return routeStatus;
|
|
151
|
-
}
|
|
152
|
-
if (isValidStatus(responseStatus)) {
|
|
153
|
-
return responseStatus;
|
|
154
|
-
}
|
|
155
|
-
return 200;
|
|
156
|
-
}
|
|
157
|
-
function applyRouteOverrides(response, route) {
|
|
158
|
-
const headers = new Headers(response.headers);
|
|
159
|
-
const hasHeaders = !!route.headers && Object.keys(route.headers).length > 0;
|
|
160
|
-
if (route.headers) {
|
|
161
|
-
for (const [key, value] of Object.entries(route.headers)) {
|
|
162
|
-
headers.set(key, value);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
const status = resolveStatus(route.status, response.status);
|
|
166
|
-
if (status === response.status && !hasHeaders) {
|
|
167
|
-
return response;
|
|
168
|
-
}
|
|
169
|
-
return new Response(response.body, { status, headers });
|
|
170
|
-
}
|
|
171
|
-
function normalizeHandlerValue(c, value) {
|
|
172
|
-
if (value instanceof Response) {
|
|
173
|
-
return value;
|
|
174
|
-
}
|
|
175
|
-
if (typeof value === "undefined") {
|
|
176
|
-
const response = c.body(null);
|
|
177
|
-
if (response.status === 200) {
|
|
178
|
-
return new Response(response.body, {
|
|
179
|
-
status: 204,
|
|
180
|
-
headers: response.headers
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
return response;
|
|
184
|
-
}
|
|
185
|
-
if (typeof value === "string") {
|
|
186
|
-
return c.text(value);
|
|
187
|
-
}
|
|
188
|
-
if (value instanceof Uint8Array || value instanceof ArrayBuffer) {
|
|
189
|
-
if (!c.res.headers.get("content-type")) {
|
|
190
|
-
c.header("content-type", "application/octet-stream");
|
|
191
|
-
}
|
|
192
|
-
const data = value instanceof ArrayBuffer ? new Uint8Array(value) : new Uint8Array(value);
|
|
193
|
-
return c.body(data);
|
|
194
|
-
}
|
|
195
|
-
return c.json(value);
|
|
196
|
-
}
|
|
197
|
-
function createRouteHandler(route) {
|
|
198
|
-
return async (c) => {
|
|
199
|
-
const value = typeof route.handler === "function" ? await route.handler(c) : route.handler;
|
|
200
|
-
return normalizeHandlerValue(c, value);
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
function createFinalizeMiddleware(route) {
|
|
204
|
-
return async (c, next) => {
|
|
205
|
-
const response = await next();
|
|
206
|
-
const resolved = response ?? c.res;
|
|
207
|
-
if (route.delay && route.delay > 0) {
|
|
208
|
-
await delay(route.delay);
|
|
209
|
-
}
|
|
210
|
-
return applyRouteOverrides(resolved, route);
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
function wrapMiddleware(handler) {
|
|
214
|
-
return async (c, next) => {
|
|
215
|
-
const response = await handler(c, next);
|
|
216
|
-
return response ?? c.res;
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
function createHonoApp(routes) {
|
|
220
|
-
const app = new hono.Hono({ router: new patternRouter.PatternRouter(), strict: false });
|
|
221
|
-
for (const route of routes) {
|
|
222
|
-
const middlewares = route.middlewares?.map((entry) => wrapMiddleware(entry.handle)) ?? [];
|
|
223
|
-
app.on(
|
|
224
|
-
route.method,
|
|
225
|
-
toHonoPath(route),
|
|
226
|
-
createFinalizeMiddleware(route),
|
|
227
|
-
...middlewares,
|
|
228
|
-
createRouteHandler(route)
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
return app;
|
|
232
|
-
}
|
|
233
|
-
async function readRawBody(req) {
|
|
234
|
-
return await new Promise((resolve, reject) => {
|
|
235
|
-
const chunks = [];
|
|
236
|
-
req.on("data", (chunk) => {
|
|
237
|
-
if (typeof chunk === "string") {
|
|
238
|
-
chunks.push(node_buffer.Buffer.from(chunk));
|
|
239
|
-
return;
|
|
240
|
-
}
|
|
241
|
-
if (chunk instanceof Uint8Array) {
|
|
242
|
-
chunks.push(chunk);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
chunks.push(node_buffer.Buffer.from(String(chunk)));
|
|
246
|
-
});
|
|
247
|
-
req.on("end", () => {
|
|
248
|
-
if (chunks.length === 0) {
|
|
249
|
-
resolve(null);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
resolve(node_buffer.Buffer.concat(chunks));
|
|
253
|
-
});
|
|
254
|
-
req.on("error", reject);
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
function buildHeaders(headers) {
|
|
258
|
-
const result = new Headers();
|
|
259
|
-
for (const [key, value] of Object.entries(headers)) {
|
|
260
|
-
if (typeof value === "undefined") {
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
if (Array.isArray(value)) {
|
|
264
|
-
result.set(key, value.join(","));
|
|
265
|
-
} else {
|
|
266
|
-
result.set(key, value);
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
return result;
|
|
270
|
-
}
|
|
271
|
-
async function toRequest(req) {
|
|
272
|
-
const url = new URL(req.url ?? "/", "http://mokup.local");
|
|
273
|
-
const method = req.method ?? "GET";
|
|
274
|
-
const headers = buildHeaders(req.headers);
|
|
275
|
-
const init = { method, headers };
|
|
276
|
-
const rawBody = await readRawBody(req);
|
|
277
|
-
if (rawBody && method !== "GET" && method !== "HEAD") {
|
|
278
|
-
init.body = rawBody;
|
|
279
|
-
}
|
|
280
|
-
return new Request(url.toString(), init);
|
|
281
|
-
}
|
|
282
|
-
async function sendResponse(res, response) {
|
|
283
|
-
res.statusCode = response.status;
|
|
284
|
-
response.headers.forEach((value, key) => {
|
|
285
|
-
res.setHeader(key, value);
|
|
286
|
-
});
|
|
287
|
-
if (!response.body) {
|
|
288
|
-
res.end();
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
const buffer = new Uint8Array(await response.arrayBuffer());
|
|
292
|
-
res.end(buffer);
|
|
293
|
-
}
|
|
294
|
-
function hasMatch(app, method, pathname) {
|
|
295
|
-
const matchMethod = method === "HEAD" ? "GET" : method;
|
|
296
|
-
const match = app.router.match(matchMethod, pathname);
|
|
297
|
-
return !!match && match[0].length > 0;
|
|
298
|
-
}
|
|
299
|
-
function createMiddleware(getApp, logger) {
|
|
300
|
-
return async (req, res, next) => {
|
|
301
|
-
const app = getApp();
|
|
302
|
-
if (!app) {
|
|
303
|
-
return next();
|
|
304
|
-
}
|
|
305
|
-
const url = req.url ?? "/";
|
|
306
|
-
const parsedUrl = new URL(url, "http://mokup.local");
|
|
307
|
-
const pathname = parsedUrl.pathname;
|
|
308
|
-
const method = normalizeMethod(req.method) ?? "GET";
|
|
309
|
-
if (!hasMatch(app, method, pathname)) {
|
|
310
|
-
return next();
|
|
311
|
-
}
|
|
312
|
-
const startedAt = Date.now();
|
|
313
|
-
try {
|
|
314
|
-
const response = await app.fetch(await toRequest(req));
|
|
315
|
-
if (res.writableEnded) {
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
await sendResponse(res, response);
|
|
319
|
-
logger.info(`${method} ${pathname} ${Date.now() - startedAt}ms`);
|
|
320
|
-
} catch (error) {
|
|
321
|
-
if (!res.headersSent) {
|
|
322
|
-
res.statusCode = 500;
|
|
323
|
-
res.setHeader("Content-Type", "text/plain; charset=utf-8");
|
|
324
|
-
}
|
|
325
|
-
res.end("Mock handler error");
|
|
326
|
-
logger.error("Mock handler failed:", error);
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href)));
|
|
332
|
-
const mimeTypes = {
|
|
333
|
-
".html": "text/html; charset=utf-8",
|
|
334
|
-
".css": "text/css; charset=utf-8",
|
|
335
|
-
".js": "text/javascript; charset=utf-8",
|
|
336
|
-
".map": "application/json; charset=utf-8",
|
|
337
|
-
".json": "application/json; charset=utf-8",
|
|
338
|
-
".svg": "image/svg+xml",
|
|
339
|
-
".png": "image/png",
|
|
340
|
-
".jpg": "image/jpeg",
|
|
341
|
-
".jpeg": "image/jpeg",
|
|
342
|
-
".ico": "image/x-icon"
|
|
343
|
-
};
|
|
344
|
-
function normalizePlaygroundPath(value) {
|
|
345
|
-
if (!value) {
|
|
346
|
-
return "/_mokup";
|
|
347
|
-
}
|
|
348
|
-
const normalized = value.startsWith("/") ? value : `/${value}`;
|
|
349
|
-
return normalized.length > 1 && normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
350
|
-
}
|
|
351
|
-
function normalizeBase$1(base) {
|
|
352
|
-
if (!base || base === "/") {
|
|
353
|
-
return "";
|
|
354
|
-
}
|
|
355
|
-
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
356
|
-
}
|
|
357
|
-
function resolvePlaygroundRequestPath(base, playgroundPath) {
|
|
358
|
-
const normalizedBase = normalizeBase$1(base);
|
|
359
|
-
const normalizedPath = normalizePlaygroundPath(playgroundPath);
|
|
360
|
-
if (!normalizedBase) {
|
|
361
|
-
return normalizedPath;
|
|
362
|
-
}
|
|
363
|
-
if (normalizedPath.startsWith(normalizedBase)) {
|
|
364
|
-
return normalizedPath;
|
|
365
|
-
}
|
|
366
|
-
return `${normalizedBase}${normalizedPath}`;
|
|
367
|
-
}
|
|
368
|
-
function injectPlaygroundHmr(html, base) {
|
|
369
|
-
if (html.includes("mokup-playground-hmr")) {
|
|
370
|
-
return html;
|
|
371
|
-
}
|
|
372
|
-
const normalizedBase = normalizeBase$1(base);
|
|
373
|
-
const clientPath = `${normalizedBase}/@vite/client`;
|
|
374
|
-
const snippet = [
|
|
375
|
-
'<script type="module" id="mokup-playground-hmr">',
|
|
376
|
-
`import('${clientPath}').then(({ createHotContext }) => {`,
|
|
377
|
-
" const hot = createHotContext('/@mokup/playground')",
|
|
378
|
-
" hot.on('mokup:routes-changed', () => {",
|
|
379
|
-
" const api = window.__MOKUP_PLAYGROUND__",
|
|
380
|
-
" if (api && typeof api.reloadRoutes === 'function') {",
|
|
381
|
-
" api.reloadRoutes()",
|
|
382
|
-
" return",
|
|
383
|
-
" }",
|
|
384
|
-
" window.location.reload()",
|
|
385
|
-
" })",
|
|
386
|
-
"}).catch(() => {})",
|
|
387
|
-
"<\/script>"
|
|
388
|
-
].join("\n");
|
|
389
|
-
if (html.includes("</body>")) {
|
|
390
|
-
return html.replace("</body>", `${snippet}
|
|
391
|
-
</body>`);
|
|
392
|
-
}
|
|
393
|
-
return `${html}
|
|
394
|
-
${snippet}`;
|
|
395
|
-
}
|
|
396
|
-
function injectPlaygroundSw(html, script) {
|
|
397
|
-
if (!script) {
|
|
398
|
-
return html;
|
|
399
|
-
}
|
|
400
|
-
if (html.includes("mokup-playground-sw")) {
|
|
401
|
-
return html;
|
|
402
|
-
}
|
|
403
|
-
const snippet = [
|
|
404
|
-
'<script type="module" id="mokup-playground-sw">',
|
|
405
|
-
script,
|
|
406
|
-
"<\/script>"
|
|
407
|
-
].join("\n");
|
|
408
|
-
if (html.includes("</head>")) {
|
|
409
|
-
return html.replace("</head>", `${snippet}
|
|
410
|
-
</head>`);
|
|
411
|
-
}
|
|
412
|
-
if (html.includes("</body>")) {
|
|
413
|
-
return html.replace("</body>", `${snippet}
|
|
414
|
-
</body>`);
|
|
415
|
-
}
|
|
416
|
-
return `${html}
|
|
417
|
-
${snippet}`;
|
|
418
|
-
}
|
|
419
|
-
function isViteDevServer$1(server) {
|
|
420
|
-
return !!server && "ws" in server;
|
|
421
|
-
}
|
|
422
|
-
function resolvePlaygroundOptions(playground) {
|
|
423
|
-
if (playground === false) {
|
|
424
|
-
return { enabled: false, path: "/_mokup" };
|
|
425
|
-
}
|
|
426
|
-
if (playground && typeof playground === "object") {
|
|
427
|
-
return {
|
|
428
|
-
enabled: playground.enabled !== false,
|
|
429
|
-
path: normalizePlaygroundPath(playground.path)
|
|
430
|
-
};
|
|
431
|
-
}
|
|
432
|
-
return { enabled: true, path: "/_mokup" };
|
|
433
|
-
}
|
|
434
|
-
function resolvePlaygroundDist() {
|
|
435
|
-
const pkgPath = require$1.resolve("@mokup/playground/package.json");
|
|
436
|
-
return pathe.join(pkgPath, "..", "dist");
|
|
437
|
-
}
|
|
438
|
-
function sendJson(res, data, statusCode = 200) {
|
|
439
|
-
res.statusCode = statusCode;
|
|
440
|
-
res.setHeader("Content-Type", "application/json; charset=utf-8");
|
|
441
|
-
res.end(JSON.stringify(data, null, 2));
|
|
442
|
-
}
|
|
443
|
-
function sendFile(res, content, contentType) {
|
|
444
|
-
res.statusCode = 200;
|
|
445
|
-
res.setHeader("Content-Type", contentType);
|
|
446
|
-
res.end(content);
|
|
447
|
-
}
|
|
448
|
-
function toPosixPath(value) {
|
|
449
|
-
return value.replace(/\\/g, "/");
|
|
450
|
-
}
|
|
451
|
-
function normalizePath(value) {
|
|
452
|
-
return toPosixPath(pathe.normalize(value));
|
|
453
|
-
}
|
|
454
|
-
function isAncestor(parent, child) {
|
|
455
|
-
const normalizedParent = normalizePath(parent).replace(/\/$/, "");
|
|
456
|
-
const normalizedChild = normalizePath(child);
|
|
457
|
-
return normalizedChild === normalizedParent || normalizedChild.startsWith(`${normalizedParent}/`);
|
|
458
|
-
}
|
|
459
|
-
function resolveGroupRoot(dirs, serverRoot) {
|
|
460
|
-
if (!dirs || dirs.length === 0) {
|
|
461
|
-
return serverRoot ?? node_process.cwd();
|
|
462
|
-
}
|
|
463
|
-
if (serverRoot) {
|
|
464
|
-
const normalizedRoot = normalizePath(serverRoot);
|
|
465
|
-
const canUseRoot = dirs.every((dir) => isAncestor(normalizedRoot, dir));
|
|
466
|
-
if (canUseRoot) {
|
|
467
|
-
return normalizedRoot;
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
if (dirs.length === 1) {
|
|
471
|
-
return normalizePath(pathe.dirname(dirs[0]));
|
|
472
|
-
}
|
|
473
|
-
let common = normalizePath(dirs[0]);
|
|
474
|
-
for (const dir of dirs.slice(1)) {
|
|
475
|
-
const normalizedDir = normalizePath(dir);
|
|
476
|
-
while (common && !isAncestor(common, normalizedDir)) {
|
|
477
|
-
const parent = normalizePath(pathe.dirname(common));
|
|
478
|
-
if (parent === common) {
|
|
479
|
-
break;
|
|
480
|
-
}
|
|
481
|
-
common = parent;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
if (!common || common === "/") {
|
|
485
|
-
return serverRoot ?? node_process.cwd();
|
|
486
|
-
}
|
|
487
|
-
return common;
|
|
488
|
-
}
|
|
489
|
-
function formatRouteFile(file, root) {
|
|
490
|
-
if (!root) {
|
|
491
|
-
return toPosixPath(file);
|
|
492
|
-
}
|
|
493
|
-
const rel = toPosixPath(pathe.relative(root, file));
|
|
494
|
-
if (!rel || rel.startsWith("..")) {
|
|
495
|
-
return toPosixPath(file);
|
|
496
|
-
}
|
|
497
|
-
return rel;
|
|
498
|
-
}
|
|
499
|
-
function resolveGroups(dirs, root) {
|
|
500
|
-
const groups = [];
|
|
501
|
-
const seen = /* @__PURE__ */ new Set();
|
|
502
|
-
for (const dir of dirs) {
|
|
503
|
-
const normalized = normalizePath(dir);
|
|
504
|
-
if (seen.has(normalized)) {
|
|
505
|
-
continue;
|
|
506
|
-
}
|
|
507
|
-
seen.add(normalized);
|
|
508
|
-
const rel = toPosixPath(pathe.relative(root, normalized));
|
|
509
|
-
const label = rel && !rel.startsWith("..") ? rel : normalized;
|
|
510
|
-
groups.push({
|
|
511
|
-
key: normalized,
|
|
512
|
-
label,
|
|
513
|
-
path: normalized
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
return groups;
|
|
517
|
-
}
|
|
518
|
-
function resolveRouteGroup(routeFile, groups) {
|
|
519
|
-
if (groups.length === 0) {
|
|
520
|
-
return void 0;
|
|
521
|
-
}
|
|
522
|
-
const normalizedFile = toPosixPath(pathe.normalize(routeFile));
|
|
523
|
-
let matched;
|
|
524
|
-
for (const group of groups) {
|
|
525
|
-
if (normalizedFile === group.path || normalizedFile.startsWith(`${group.path}/`)) {
|
|
526
|
-
if (!matched || group.path.length > matched.path.length) {
|
|
527
|
-
matched = group;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
return matched;
|
|
532
|
-
}
|
|
533
|
-
function toPlaygroundRoute(route, root, groups) {
|
|
534
|
-
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
535
|
-
const middlewareSources = route.middlewares?.map((entry) => formatRouteFile(entry.source, root));
|
|
536
|
-
return {
|
|
537
|
-
method: route.method,
|
|
538
|
-
url: route.template,
|
|
539
|
-
file: formatRouteFile(route.file, root),
|
|
540
|
-
type: typeof route.handler === "function" ? "handler" : "static",
|
|
541
|
-
status: route.status,
|
|
542
|
-
delay: route.delay,
|
|
543
|
-
middlewareCount: middlewareSources?.length ?? 0,
|
|
544
|
-
middlewares: middlewareSources,
|
|
545
|
-
groupKey: matchedGroup?.key,
|
|
546
|
-
group: matchedGroup?.label
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
function createPlaygroundMiddleware(params) {
|
|
550
|
-
const distDir = resolvePlaygroundDist();
|
|
551
|
-
const playgroundPath = params.config.path;
|
|
552
|
-
const indexPath = pathe.join(distDir, "index.html");
|
|
553
|
-
return async (req, res, next) => {
|
|
554
|
-
if (!params.config.enabled) {
|
|
555
|
-
return next();
|
|
556
|
-
}
|
|
557
|
-
const server = params.getServer?.();
|
|
558
|
-
const requestPath = resolvePlaygroundRequestPath(server?.config?.base ?? "/", playgroundPath);
|
|
559
|
-
const requestUrl = req.url ?? "/";
|
|
560
|
-
const url = new URL(requestUrl, "http://mokup.local");
|
|
561
|
-
const pathname = url.pathname;
|
|
562
|
-
const matchedPath = pathname.startsWith(requestPath) ? requestPath : pathname.startsWith(playgroundPath) ? playgroundPath : null;
|
|
563
|
-
if (!matchedPath) {
|
|
564
|
-
return next();
|
|
565
|
-
}
|
|
566
|
-
const subPath = pathname.slice(matchedPath.length);
|
|
567
|
-
if (subPath === "") {
|
|
568
|
-
const suffix = url.search ?? "";
|
|
569
|
-
res.statusCode = 302;
|
|
570
|
-
res.setHeader("Location", `${matchedPath}/${suffix}`);
|
|
571
|
-
res.end();
|
|
572
|
-
return;
|
|
573
|
-
}
|
|
574
|
-
if (subPath === "" || subPath === "/" || subPath === "/index.html") {
|
|
575
|
-
try {
|
|
576
|
-
const html = await node_fs.promises.readFile(indexPath, "utf8");
|
|
577
|
-
let output = html;
|
|
578
|
-
if (isViteDevServer$1(server)) {
|
|
579
|
-
output = injectPlaygroundHmr(output, server.config.base ?? "/");
|
|
580
|
-
output = injectPlaygroundSw(output, params.getSwScript?.());
|
|
581
|
-
}
|
|
582
|
-
const contentType = mimeTypes[".html"] ?? "text/html; charset=utf-8";
|
|
583
|
-
sendFile(res, output, contentType);
|
|
584
|
-
} catch (error) {
|
|
585
|
-
params.logger.error("Failed to load playground index:", error);
|
|
586
|
-
res.statusCode = 500;
|
|
587
|
-
res.end("Playground is not available.");
|
|
588
|
-
}
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
if (subPath === "/routes") {
|
|
592
|
-
const dirs = params.getDirs?.() ?? [];
|
|
593
|
-
const baseRoot = resolveGroupRoot(dirs, server?.config?.root);
|
|
594
|
-
const groups = resolveGroups(dirs, baseRoot);
|
|
595
|
-
const routes = params.getRoutes();
|
|
596
|
-
sendJson(res, {
|
|
597
|
-
basePath: matchedPath,
|
|
598
|
-
root: baseRoot,
|
|
599
|
-
count: routes.length,
|
|
600
|
-
groups: groups.map((group) => ({ key: group.key, label: group.label })),
|
|
601
|
-
routes: routes.map((route) => toPlaygroundRoute(route, baseRoot, groups))
|
|
602
|
-
});
|
|
603
|
-
return;
|
|
604
|
-
}
|
|
605
|
-
const relPath = subPath.replace(/^\/+/, "");
|
|
606
|
-
if (relPath.includes("..")) {
|
|
607
|
-
res.statusCode = 400;
|
|
608
|
-
res.end("Invalid path.");
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
const normalizedPath = pathe.normalize(relPath);
|
|
612
|
-
const filePath = pathe.join(distDir, normalizedPath);
|
|
613
|
-
try {
|
|
614
|
-
const content = await node_fs.promises.readFile(filePath);
|
|
615
|
-
const ext = pathe.extname(filePath);
|
|
616
|
-
const contentType = mimeTypes[ext] ?? "application/octet-stream";
|
|
617
|
-
sendFile(res, content, contentType);
|
|
618
|
-
} catch {
|
|
619
|
-
return next();
|
|
620
|
-
}
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
const jsonExtensions = /* @__PURE__ */ new Set([".json", ".jsonc"]);
|
|
625
|
-
function resolveTemplate(template, prefix) {
|
|
626
|
-
const normalized = template.startsWith("/") ? template : `/${template}`;
|
|
627
|
-
if (!prefix) {
|
|
628
|
-
return normalized;
|
|
629
|
-
}
|
|
630
|
-
const normalizedPrefix = normalizePrefix(prefix);
|
|
631
|
-
if (!normalizedPrefix) {
|
|
632
|
-
return normalized;
|
|
633
|
-
}
|
|
634
|
-
if (normalized === normalizedPrefix || normalized.startsWith(`${normalizedPrefix}/`)) {
|
|
635
|
-
return normalized;
|
|
636
|
-
}
|
|
637
|
-
if (normalized === "/") {
|
|
638
|
-
return `${normalizedPrefix}/`;
|
|
639
|
-
}
|
|
640
|
-
return `${normalizedPrefix}${normalized}`;
|
|
641
|
-
}
|
|
642
|
-
function stripMethodSuffix(base) {
|
|
643
|
-
const segments = base.split(".");
|
|
644
|
-
const last = segments.at(-1);
|
|
645
|
-
if (last && methodSuffixSet.has(last.toLowerCase())) {
|
|
646
|
-
segments.pop();
|
|
647
|
-
return {
|
|
648
|
-
name: segments.join("."),
|
|
649
|
-
method: last.toUpperCase()
|
|
650
|
-
};
|
|
651
|
-
}
|
|
652
|
-
return {
|
|
653
|
-
name: base,
|
|
654
|
-
method: void 0
|
|
655
|
-
};
|
|
656
|
-
}
|
|
657
|
-
function deriveRouteFromFile(file, rootDir, logger) {
|
|
658
|
-
const rel = toPosix(pathe.relative(rootDir, file));
|
|
659
|
-
const ext = pathe.extname(rel);
|
|
660
|
-
const withoutExt = rel.slice(0, rel.length - ext.length);
|
|
661
|
-
const dir = pathe.dirname(withoutExt);
|
|
662
|
-
const base = pathe.basename(withoutExt);
|
|
663
|
-
const { name, method } = stripMethodSuffix(base);
|
|
664
|
-
const resolvedMethod = method ?? (jsonExtensions.has(ext) ? "GET" : void 0);
|
|
665
|
-
if (!resolvedMethod) {
|
|
666
|
-
logger.warn(`Skip mock without method suffix: ${file}`);
|
|
667
|
-
return null;
|
|
668
|
-
}
|
|
669
|
-
if (!name) {
|
|
670
|
-
logger.warn(`Skip mock with empty route name: ${file}`);
|
|
671
|
-
return null;
|
|
672
|
-
}
|
|
673
|
-
const joined = dir === "." ? name : pathe.join(dir, name);
|
|
674
|
-
const segments = toPosix(joined).split("/");
|
|
675
|
-
if (segments.at(-1) === "index") {
|
|
676
|
-
segments.pop();
|
|
677
|
-
}
|
|
678
|
-
const template = segments.length === 0 ? "/" : `/${segments.join("/")}`;
|
|
679
|
-
const parsed = runtime.parseRouteTemplate(template);
|
|
680
|
-
if (parsed.errors.length > 0) {
|
|
681
|
-
for (const error of parsed.errors) {
|
|
682
|
-
logger.warn(`${error} in ${file}`);
|
|
683
|
-
}
|
|
684
|
-
return null;
|
|
685
|
-
}
|
|
686
|
-
for (const warning of parsed.warnings) {
|
|
687
|
-
logger.warn(`${warning} in ${file}`);
|
|
688
|
-
}
|
|
689
|
-
return {
|
|
690
|
-
template: parsed.template,
|
|
691
|
-
method: resolvedMethod,
|
|
692
|
-
tokens: parsed.tokens,
|
|
693
|
-
score: parsed.score
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
function resolveRule(params) {
|
|
697
|
-
const method = params.derivedMethod;
|
|
698
|
-
if (!method) {
|
|
699
|
-
params.logger.warn(`Skip mock without method suffix: ${params.file}`);
|
|
700
|
-
return null;
|
|
701
|
-
}
|
|
702
|
-
const template = resolveTemplate(params.derivedTemplate, params.prefix);
|
|
703
|
-
const parsed = runtime.parseRouteTemplate(template);
|
|
704
|
-
if (parsed.errors.length > 0) {
|
|
705
|
-
for (const error of parsed.errors) {
|
|
706
|
-
params.logger.warn(`${error} in ${params.file}`);
|
|
707
|
-
}
|
|
708
|
-
return null;
|
|
709
|
-
}
|
|
710
|
-
for (const warning of parsed.warnings) {
|
|
711
|
-
params.logger.warn(`${warning} in ${params.file}`);
|
|
712
|
-
}
|
|
713
|
-
const route = {
|
|
714
|
-
file: params.file,
|
|
715
|
-
template: parsed.template,
|
|
716
|
-
method,
|
|
717
|
-
tokens: parsed.tokens,
|
|
718
|
-
score: parsed.score,
|
|
719
|
-
handler: params.rule.handler
|
|
720
|
-
};
|
|
721
|
-
if (typeof params.rule.status === "number") {
|
|
722
|
-
route.status = params.rule.status;
|
|
723
|
-
}
|
|
724
|
-
if (params.rule.headers) {
|
|
725
|
-
route.headers = params.rule.headers;
|
|
726
|
-
}
|
|
727
|
-
if (typeof params.rule.delay === "number") {
|
|
728
|
-
route.delay = params.rule.delay;
|
|
729
|
-
}
|
|
730
|
-
return route;
|
|
731
|
-
}
|
|
732
|
-
function sortRoutes(routes) {
|
|
733
|
-
return routes.sort((a, b) => {
|
|
734
|
-
if (a.method !== b.method) {
|
|
735
|
-
return a.method.localeCompare(b.method);
|
|
736
|
-
}
|
|
737
|
-
const scoreCompare = runtime.compareRouteScore(a.score, b.score);
|
|
738
|
-
if (scoreCompare !== 0) {
|
|
739
|
-
return scoreCompare;
|
|
740
|
-
}
|
|
741
|
-
return a.template.localeCompare(b.template);
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
|
|
746
|
-
async function loadModule$1(file) {
|
|
747
|
-
const ext = configExtensions.find((extension) => file.endsWith(extension));
|
|
748
|
-
if (ext === ".cjs") {
|
|
749
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href)));
|
|
750
|
-
delete require$1.cache[file];
|
|
751
|
-
return require$1(file);
|
|
752
|
-
}
|
|
753
|
-
if (ext === ".js" || ext === ".mjs") {
|
|
754
|
-
return import(`${node_url.pathToFileURL(file).href}?t=${Date.now()}`);
|
|
755
|
-
}
|
|
756
|
-
if (ext === ".ts") {
|
|
757
|
-
const result = await esbuild.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,${node_buffer.Buffer.from(code).toString(
|
|
769
|
-
"base64"
|
|
770
|
-
)}`;
|
|
771
|
-
return import(`${dataUrl}#${Date.now()}`);
|
|
772
|
-
}
|
|
773
|
-
return null;
|
|
774
|
-
}
|
|
775
|
-
async function loadModuleWithVite$1(server, file) {
|
|
776
|
-
const asDevServer = server;
|
|
777
|
-
if ("ssrLoadModule" in asDevServer) {
|
|
778
|
-
const moduleNode = asDevServer.moduleGraph.getModuleById(file);
|
|
779
|
-
if (moduleNode) {
|
|
780
|
-
asDevServer.moduleGraph.invalidateModule(moduleNode);
|
|
781
|
-
}
|
|
782
|
-
return asDevServer.ssrLoadModule(file);
|
|
783
|
-
}
|
|
784
|
-
return loadModule$1(file);
|
|
785
|
-
}
|
|
786
|
-
function getConfigFileCandidates(dir) {
|
|
787
|
-
return configExtensions.map((extension) => pathe.join(dir, `index.config${extension}`));
|
|
788
|
-
}
|
|
789
|
-
async function findConfigFile(dir, cache) {
|
|
790
|
-
const cached = cache.get(dir);
|
|
791
|
-
if (cached !== void 0) {
|
|
792
|
-
return cached;
|
|
793
|
-
}
|
|
794
|
-
for (const candidate of getConfigFileCandidates(dir)) {
|
|
795
|
-
try {
|
|
796
|
-
await node_fs.promises.stat(candidate);
|
|
797
|
-
cache.set(dir, candidate);
|
|
798
|
-
return candidate;
|
|
799
|
-
} catch {
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
cache.set(dir, null);
|
|
804
|
-
return null;
|
|
805
|
-
}
|
|
806
|
-
async function loadConfig(file, server) {
|
|
807
|
-
const mod = server ? await loadModuleWithVite$1(server, file) : await loadModule$1(file);
|
|
808
|
-
if (!mod) {
|
|
809
|
-
return null;
|
|
810
|
-
}
|
|
811
|
-
const value = mod?.default ?? mod;
|
|
812
|
-
if (!value || typeof value !== "object") {
|
|
813
|
-
return null;
|
|
814
|
-
}
|
|
815
|
-
return value;
|
|
816
|
-
}
|
|
817
|
-
function normalizeMiddlewares(value, source, logger) {
|
|
818
|
-
if (!value) {
|
|
819
|
-
return [];
|
|
820
|
-
}
|
|
821
|
-
const list = Array.isArray(value) ? value : [value];
|
|
822
|
-
const middlewares = [];
|
|
823
|
-
for (const [index, entry] of list.entries()) {
|
|
824
|
-
if (typeof entry !== "function") {
|
|
825
|
-
logger.warn(`Invalid middleware in ${source}`);
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
middlewares.push({ handle: entry, source, index });
|
|
829
|
-
}
|
|
830
|
-
return middlewares;
|
|
831
|
-
}
|
|
832
|
-
async function resolveDirectoryConfig(params) {
|
|
833
|
-
const { file, rootDir, server, logger, configCache, fileCache } = params;
|
|
834
|
-
const resolvedRoot = pathe.normalize(rootDir);
|
|
835
|
-
const resolvedFileDir = pathe.normalize(pathe.dirname(file));
|
|
836
|
-
const chain = [];
|
|
837
|
-
let current = resolvedFileDir;
|
|
838
|
-
while (true) {
|
|
839
|
-
chain.push(current);
|
|
840
|
-
if (current === resolvedRoot) {
|
|
841
|
-
break;
|
|
842
|
-
}
|
|
843
|
-
const parent = pathe.dirname(current);
|
|
844
|
-
if (parent === current) {
|
|
845
|
-
break;
|
|
846
|
-
}
|
|
847
|
-
current = parent;
|
|
848
|
-
}
|
|
849
|
-
chain.reverse();
|
|
850
|
-
const merged = { middlewares: [] };
|
|
851
|
-
for (const dir of chain) {
|
|
852
|
-
const configPath = await findConfigFile(dir, fileCache);
|
|
853
|
-
if (!configPath) {
|
|
854
|
-
continue;
|
|
855
|
-
}
|
|
856
|
-
let config = configCache.get(configPath);
|
|
857
|
-
if (config === void 0) {
|
|
858
|
-
config = await loadConfig(configPath, server);
|
|
859
|
-
configCache.set(configPath, config);
|
|
860
|
-
}
|
|
861
|
-
if (!config) {
|
|
862
|
-
logger.warn(`Invalid config in ${configPath}`);
|
|
863
|
-
continue;
|
|
864
|
-
}
|
|
865
|
-
if (config.headers) {
|
|
866
|
-
merged.headers = { ...merged.headers ?? {}, ...config.headers };
|
|
867
|
-
}
|
|
868
|
-
if (typeof config.status === "number") {
|
|
869
|
-
merged.status = config.status;
|
|
870
|
-
}
|
|
871
|
-
if (typeof config.delay === "number") {
|
|
872
|
-
merged.delay = config.delay;
|
|
873
|
-
}
|
|
874
|
-
if (typeof config.enabled === "boolean") {
|
|
875
|
-
merged.enabled = config.enabled;
|
|
876
|
-
}
|
|
877
|
-
const normalized = normalizeMiddlewares(config.middleware, configPath, logger);
|
|
878
|
-
if (normalized.length > 0) {
|
|
879
|
-
merged.middlewares.push(...normalized);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
return merged;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
async function walkDir(dir, rootDir, files) {
|
|
886
|
-
const entries = await node_fs.promises.readdir(dir, { withFileTypes: true });
|
|
887
|
-
for (const entry of entries) {
|
|
888
|
-
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
889
|
-
continue;
|
|
890
|
-
}
|
|
891
|
-
const fullPath = pathe.join(dir, entry.name);
|
|
892
|
-
if (entry.isDirectory()) {
|
|
893
|
-
await walkDir(fullPath, rootDir, files);
|
|
894
|
-
continue;
|
|
895
|
-
}
|
|
896
|
-
if (entry.isFile()) {
|
|
897
|
-
files.push({ file: fullPath, rootDir });
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
async function exists(path) {
|
|
902
|
-
try {
|
|
903
|
-
await node_fs.promises.stat(path);
|
|
904
|
-
return true;
|
|
905
|
-
} catch {
|
|
906
|
-
return false;
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
async function collectFiles(dirs) {
|
|
910
|
-
const files = [];
|
|
911
|
-
for (const dir of dirs) {
|
|
912
|
-
if (!await exists(dir)) {
|
|
913
|
-
continue;
|
|
914
|
-
}
|
|
915
|
-
await walkDir(dir, dir, files);
|
|
916
|
-
}
|
|
917
|
-
return files;
|
|
918
|
-
}
|
|
919
|
-
function isSupportedFile(file) {
|
|
920
|
-
if (file.endsWith(".d.ts")) {
|
|
921
|
-
return false;
|
|
922
|
-
}
|
|
923
|
-
if (pathe.basename(file).startsWith("index.config.")) {
|
|
924
|
-
return false;
|
|
925
|
-
}
|
|
926
|
-
const ext = pathe.extname(file).toLowerCase();
|
|
927
|
-
return supportedExtensions.has(ext);
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
async function loadModule(file) {
|
|
931
|
-
const ext = pathe.extname(file).toLowerCase();
|
|
932
|
-
if (ext === ".cjs") {
|
|
933
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('vite.cjs', document.baseURI).href)));
|
|
934
|
-
delete require$1.cache[file];
|
|
935
|
-
return require$1(file);
|
|
936
|
-
}
|
|
937
|
-
if (ext === ".js" || ext === ".mjs") {
|
|
938
|
-
return import(`${node_url.pathToFileURL(file).href}?t=${Date.now()}`);
|
|
939
|
-
}
|
|
940
|
-
if (ext === ".ts") {
|
|
941
|
-
const result = await esbuild.build({
|
|
942
|
-
entryPoints: [file],
|
|
943
|
-
bundle: true,
|
|
944
|
-
format: "esm",
|
|
945
|
-
platform: "node",
|
|
946
|
-
sourcemap: "inline",
|
|
947
|
-
target: "es2020",
|
|
948
|
-
write: false
|
|
949
|
-
});
|
|
950
|
-
const output = result.outputFiles[0];
|
|
951
|
-
const code = output?.text ?? "";
|
|
952
|
-
const dataUrl = `data:text/javascript;base64,${node_buffer.Buffer.from(code).toString(
|
|
953
|
-
"base64"
|
|
954
|
-
)}`;
|
|
955
|
-
return import(`${dataUrl}#${Date.now()}`);
|
|
956
|
-
}
|
|
957
|
-
return null;
|
|
958
|
-
}
|
|
959
|
-
async function loadModuleWithVite(server, file) {
|
|
960
|
-
const asDevServer = server;
|
|
961
|
-
if ("ssrLoadModule" in asDevServer) {
|
|
962
|
-
const moduleNode = asDevServer.moduleGraph.getModuleById(file);
|
|
963
|
-
if (moduleNode) {
|
|
964
|
-
asDevServer.moduleGraph.invalidateModule(moduleNode);
|
|
965
|
-
}
|
|
966
|
-
return asDevServer.ssrLoadModule(file);
|
|
967
|
-
}
|
|
968
|
-
return loadModule(file);
|
|
969
|
-
}
|
|
970
|
-
async function readJsonFile(file, logger) {
|
|
971
|
-
try {
|
|
972
|
-
const content = await node_fs.promises.readFile(file, "utf8");
|
|
973
|
-
const errors = [];
|
|
974
|
-
const data = jsoncParser.parse(content, errors, {
|
|
975
|
-
allowTrailingComma: true,
|
|
976
|
-
disallowComments: false
|
|
977
|
-
});
|
|
978
|
-
if (errors.length > 0) {
|
|
979
|
-
logger.warn(`Invalid JSONC in ${file}`);
|
|
980
|
-
return void 0;
|
|
981
|
-
}
|
|
982
|
-
return data;
|
|
983
|
-
} catch (error) {
|
|
984
|
-
logger.warn(`Failed to read ${file}: ${String(error)}`);
|
|
985
|
-
return void 0;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
async function loadRules(file, server, logger) {
|
|
989
|
-
const ext = pathe.extname(file).toLowerCase();
|
|
990
|
-
if (ext === ".json" || ext === ".jsonc") {
|
|
991
|
-
const json = await readJsonFile(file, logger);
|
|
992
|
-
if (typeof json === "undefined") {
|
|
993
|
-
return [];
|
|
994
|
-
}
|
|
995
|
-
return [
|
|
996
|
-
{
|
|
997
|
-
handler: json
|
|
998
|
-
}
|
|
999
|
-
];
|
|
1000
|
-
}
|
|
1001
|
-
const mod = server ? await loadModuleWithVite(server, file) : await loadModule(file);
|
|
1002
|
-
const value = mod?.default ?? mod;
|
|
1003
|
-
if (!value) {
|
|
1004
|
-
return [];
|
|
1005
|
-
}
|
|
1006
|
-
if (Array.isArray(value)) {
|
|
1007
|
-
return value;
|
|
1008
|
-
}
|
|
1009
|
-
if (typeof value === "function") {
|
|
1010
|
-
return [
|
|
1011
|
-
{
|
|
1012
|
-
handler: value
|
|
1013
|
-
}
|
|
1014
|
-
];
|
|
1015
|
-
}
|
|
1016
|
-
return [value];
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
async function scanRoutes(params) {
|
|
1020
|
-
const routes = [];
|
|
1021
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1022
|
-
const files = await collectFiles(params.dirs);
|
|
1023
|
-
const configCache = /* @__PURE__ */ new Map();
|
|
1024
|
-
const fileCache = /* @__PURE__ */ new Map();
|
|
1025
|
-
for (const fileInfo of files) {
|
|
1026
|
-
if (!isSupportedFile(fileInfo.file)) {
|
|
1027
|
-
continue;
|
|
1028
|
-
}
|
|
1029
|
-
if (!matchesFilter(fileInfo.file, params.include, params.exclude)) {
|
|
1030
|
-
continue;
|
|
1031
|
-
}
|
|
1032
|
-
const configParams = {
|
|
1033
|
-
file: fileInfo.file,
|
|
1034
|
-
rootDir: fileInfo.rootDir,
|
|
1035
|
-
logger: params.logger,
|
|
1036
|
-
configCache,
|
|
1037
|
-
fileCache
|
|
1038
|
-
};
|
|
1039
|
-
if (params.server) {
|
|
1040
|
-
configParams.server = params.server;
|
|
1041
|
-
}
|
|
1042
|
-
const config = await resolveDirectoryConfig(configParams);
|
|
1043
|
-
if (config.enabled === false) {
|
|
1044
|
-
continue;
|
|
1045
|
-
}
|
|
1046
|
-
const derived = deriveRouteFromFile(fileInfo.file, fileInfo.rootDir, params.logger);
|
|
1047
|
-
if (!derived) {
|
|
1048
|
-
continue;
|
|
1049
|
-
}
|
|
1050
|
-
const rules = await loadRules(fileInfo.file, params.server, params.logger);
|
|
1051
|
-
for (const [index, rule] of rules.entries()) {
|
|
1052
|
-
if (!rule || typeof rule !== "object") {
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
const ruleValue = rule;
|
|
1056
|
-
const unsupportedKeys = ["response", "url", "method"].filter(
|
|
1057
|
-
(key2) => key2 in ruleValue
|
|
1058
|
-
);
|
|
1059
|
-
if (unsupportedKeys.length > 0) {
|
|
1060
|
-
params.logger.warn(
|
|
1061
|
-
`Skip mock with unsupported fields (${unsupportedKeys.join(", ")}): ${fileInfo.file}`
|
|
1062
|
-
);
|
|
1063
|
-
continue;
|
|
1064
|
-
}
|
|
1065
|
-
if (typeof rule.handler === "undefined") {
|
|
1066
|
-
params.logger.warn(`Skip mock without handler: ${fileInfo.file}`);
|
|
1067
|
-
continue;
|
|
1068
|
-
}
|
|
1069
|
-
const resolved = resolveRule({
|
|
1070
|
-
rule,
|
|
1071
|
-
derivedTemplate: derived.template,
|
|
1072
|
-
derivedMethod: derived.method,
|
|
1073
|
-
prefix: params.prefix,
|
|
1074
|
-
file: fileInfo.file,
|
|
1075
|
-
logger: params.logger
|
|
1076
|
-
});
|
|
1077
|
-
if (!resolved) {
|
|
1078
|
-
continue;
|
|
1079
|
-
}
|
|
1080
|
-
resolved.ruleIndex = index;
|
|
1081
|
-
if (config.headers) {
|
|
1082
|
-
resolved.headers = { ...config.headers, ...resolved.headers ?? {} };
|
|
1083
|
-
}
|
|
1084
|
-
if (typeof resolved.status === "undefined" && typeof config.status === "number") {
|
|
1085
|
-
resolved.status = config.status;
|
|
1086
|
-
}
|
|
1087
|
-
if (typeof resolved.delay === "undefined" && typeof config.delay === "number") {
|
|
1088
|
-
resolved.delay = config.delay;
|
|
1089
|
-
}
|
|
1090
|
-
if (config.middlewares.length > 0) {
|
|
1091
|
-
resolved.middlewares = config.middlewares;
|
|
1092
|
-
}
|
|
1093
|
-
const key = `${resolved.method} ${resolved.template}`;
|
|
1094
|
-
if (seen.has(key)) {
|
|
1095
|
-
params.logger.warn(`Duplicate mock route ${key} from ${fileInfo.file}`);
|
|
1096
|
-
}
|
|
1097
|
-
seen.add(key);
|
|
1098
|
-
routes.push(resolved);
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
return sortRoutes(routes);
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
const defaultSwPath = "/mokup-sw.js";
|
|
1105
|
-
const defaultSwScope = "/";
|
|
1106
|
-
function normalizeSwPath(path) {
|
|
1107
|
-
if (!path) {
|
|
1108
|
-
return defaultSwPath;
|
|
1109
|
-
}
|
|
1110
|
-
return path.startsWith("/") ? path : `/${path}`;
|
|
1111
|
-
}
|
|
1112
|
-
function normalizeSwScope(scope) {
|
|
1113
|
-
if (!scope) {
|
|
1114
|
-
return defaultSwScope;
|
|
1115
|
-
}
|
|
1116
|
-
return scope.startsWith("/") ? scope : `/${scope}`;
|
|
1117
|
-
}
|
|
1118
|
-
function normalizeBasePath(value) {
|
|
1119
|
-
if (!value) {
|
|
1120
|
-
return "/";
|
|
1121
|
-
}
|
|
1122
|
-
const normalized = value.startsWith("/") ? value : `/${value}`;
|
|
1123
|
-
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
1124
|
-
return normalized.slice(0, -1);
|
|
1125
|
-
}
|
|
1126
|
-
return normalized;
|
|
1127
|
-
}
|
|
1128
|
-
function resolveSwConfigFromEntries(entries, logger) {
|
|
1129
|
-
let path = defaultSwPath;
|
|
1130
|
-
let scope = defaultSwScope;
|
|
1131
|
-
let register = true;
|
|
1132
|
-
let unregister = false;
|
|
1133
|
-
const basePaths = [];
|
|
1134
|
-
let hasPath = false;
|
|
1135
|
-
let hasScope = false;
|
|
1136
|
-
let hasRegister = false;
|
|
1137
|
-
let hasUnregister = false;
|
|
1138
|
-
for (const entry of entries) {
|
|
1139
|
-
const config = entry.sw;
|
|
1140
|
-
if (config?.path) {
|
|
1141
|
-
const next = normalizeSwPath(config.path);
|
|
1142
|
-
if (!hasPath) {
|
|
1143
|
-
path = next;
|
|
1144
|
-
hasPath = true;
|
|
1145
|
-
} else if (path !== next) {
|
|
1146
|
-
logger.warn(`SW path "${next}" ignored; using "${path}".`);
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
if (config?.scope) {
|
|
1150
|
-
const next = normalizeSwScope(config.scope);
|
|
1151
|
-
if (!hasScope) {
|
|
1152
|
-
scope = next;
|
|
1153
|
-
hasScope = true;
|
|
1154
|
-
} else if (scope !== next) {
|
|
1155
|
-
logger.warn(`SW scope "${next}" ignored; using "${scope}".`);
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
if (typeof config?.register === "boolean") {
|
|
1159
|
-
if (!hasRegister) {
|
|
1160
|
-
register = config.register;
|
|
1161
|
-
hasRegister = true;
|
|
1162
|
-
} else if (register !== config.register) {
|
|
1163
|
-
logger.warn(
|
|
1164
|
-
`SW register="${String(config.register)}" ignored; using "${String(register)}".`
|
|
1165
|
-
);
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1168
|
-
if (typeof config?.unregister === "boolean") {
|
|
1169
|
-
if (!hasUnregister) {
|
|
1170
|
-
unregister = config.unregister;
|
|
1171
|
-
hasUnregister = true;
|
|
1172
|
-
} else if (unregister !== config.unregister) {
|
|
1173
|
-
logger.warn(
|
|
1174
|
-
`SW unregister="${String(config.unregister)}" ignored; using "${String(unregister)}".`
|
|
1175
|
-
);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
if (typeof config?.basePath !== "undefined") {
|
|
1179
|
-
const values = Array.isArray(config.basePath) ? config.basePath : [config.basePath];
|
|
1180
|
-
for (const value of values) {
|
|
1181
|
-
basePaths.push(normalizeBasePath(value));
|
|
1182
|
-
}
|
|
1183
|
-
continue;
|
|
1184
|
-
}
|
|
1185
|
-
const normalizedPrefix = normalizePrefix(entry.prefix ?? "");
|
|
1186
|
-
if (normalizedPrefix) {
|
|
1187
|
-
basePaths.push(normalizedPrefix);
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
return {
|
|
1191
|
-
path,
|
|
1192
|
-
scope,
|
|
1193
|
-
register,
|
|
1194
|
-
unregister,
|
|
1195
|
-
basePaths: Array.from(new Set(basePaths))
|
|
1196
|
-
};
|
|
1197
|
-
}
|
|
1198
|
-
function resolveSwConfig(options, logger) {
|
|
1199
|
-
const swEntries = options.filter((entry) => entry.mode === "sw");
|
|
1200
|
-
if (swEntries.length === 0) {
|
|
1201
|
-
return null;
|
|
1202
|
-
}
|
|
1203
|
-
return resolveSwConfigFromEntries(swEntries, logger);
|
|
1204
|
-
}
|
|
1205
|
-
function resolveSwUnregisterConfig(options, logger) {
|
|
1206
|
-
return resolveSwConfigFromEntries(options, logger);
|
|
1207
|
-
}
|
|
1208
|
-
function toViteImportPath(file, root) {
|
|
1209
|
-
const absolute = pathe.isAbsolute(file) ? file : pathe.resolve(root, file);
|
|
1210
|
-
const rel = pathe.relative(root, absolute);
|
|
1211
|
-
if (!rel.startsWith("..") && !pathe.isAbsolute(rel)) {
|
|
1212
|
-
return `/${toPosix(rel)}`;
|
|
1213
|
-
}
|
|
1214
|
-
return `/@fs/${toPosix(absolute)}`;
|
|
1215
|
-
}
|
|
1216
|
-
function shouldModuleize(handler) {
|
|
1217
|
-
if (typeof handler === "function") {
|
|
1218
|
-
return true;
|
|
1219
|
-
}
|
|
1220
|
-
if (typeof Response !== "undefined" && handler instanceof Response) {
|
|
1221
|
-
return true;
|
|
1222
|
-
}
|
|
1223
|
-
return false;
|
|
1224
|
-
}
|
|
1225
|
-
function toBinaryBody(handler) {
|
|
1226
|
-
if (handler instanceof ArrayBuffer) {
|
|
1227
|
-
return node_buffer.Buffer.from(new Uint8Array(handler)).toString("base64");
|
|
1228
|
-
}
|
|
1229
|
-
if (handler instanceof Uint8Array) {
|
|
1230
|
-
return node_buffer.Buffer.from(handler).toString("base64");
|
|
1231
|
-
}
|
|
1232
|
-
if (node_buffer.Buffer.isBuffer(handler)) {
|
|
1233
|
-
return handler.toString("base64");
|
|
1234
|
-
}
|
|
1235
|
-
return null;
|
|
1236
|
-
}
|
|
1237
|
-
function buildManifestResponse(route, moduleId) {
|
|
1238
|
-
if (moduleId) {
|
|
1239
|
-
const response = {
|
|
1240
|
-
type: "module",
|
|
1241
|
-
module: moduleId
|
|
1242
|
-
};
|
|
1243
|
-
if (typeof route.ruleIndex === "number") {
|
|
1244
|
-
response.ruleIndex = route.ruleIndex;
|
|
1245
|
-
}
|
|
1246
|
-
return response;
|
|
1247
|
-
}
|
|
1248
|
-
const handler = route.handler;
|
|
1249
|
-
if (typeof handler === "string") {
|
|
1250
|
-
return {
|
|
1251
|
-
type: "text",
|
|
1252
|
-
body: handler
|
|
1253
|
-
};
|
|
1254
|
-
}
|
|
1255
|
-
const binary = toBinaryBody(handler);
|
|
1256
|
-
if (binary) {
|
|
1257
|
-
return {
|
|
1258
|
-
type: "binary",
|
|
1259
|
-
body: binary,
|
|
1260
|
-
encoding: "base64"
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
|
-
return {
|
|
1264
|
-
type: "json",
|
|
1265
|
-
body: handler
|
|
1266
|
-
};
|
|
1267
|
-
}
|
|
1268
|
-
function buildSwScript(params) {
|
|
1269
|
-
const { routes, root } = params;
|
|
1270
|
-
const runtimeImportPath = params.runtimeImportPath ?? "mokup/runtime";
|
|
1271
|
-
const basePaths = params.basePaths ?? [];
|
|
1272
|
-
const ruleModules = /* @__PURE__ */ new Map();
|
|
1273
|
-
const middlewareModules = /* @__PURE__ */ new Map();
|
|
1274
|
-
const manifestRoutes = routes.map((route) => {
|
|
1275
|
-
const moduleId = shouldModuleize(route.handler) ? toViteImportPath(route.file, root) : null;
|
|
1276
|
-
if (moduleId) {
|
|
1277
|
-
ruleModules.set(moduleId, moduleId);
|
|
1278
|
-
}
|
|
1279
|
-
const middleware = route.middlewares?.map((entry) => {
|
|
1280
|
-
const modulePath = toViteImportPath(entry.source, root);
|
|
1281
|
-
middlewareModules.set(modulePath, modulePath);
|
|
1282
|
-
return {
|
|
1283
|
-
module: modulePath,
|
|
1284
|
-
ruleIndex: entry.index
|
|
1285
|
-
};
|
|
1286
|
-
});
|
|
1287
|
-
const response = buildManifestResponse(route, moduleId);
|
|
1288
|
-
const manifestRoute = {
|
|
1289
|
-
method: route.method,
|
|
1290
|
-
url: route.template,
|
|
1291
|
-
...route.tokens ? { tokens: route.tokens } : {},
|
|
1292
|
-
...route.score ? { score: route.score } : {},
|
|
1293
|
-
...route.status ? { status: route.status } : {},
|
|
1294
|
-
...route.headers ? { headers: route.headers } : {},
|
|
1295
|
-
...route.delay ? { delay: route.delay } : {},
|
|
1296
|
-
...middleware && middleware.length > 0 ? { middleware } : {},
|
|
1297
|
-
response
|
|
1298
|
-
};
|
|
1299
|
-
return manifestRoute;
|
|
1300
|
-
});
|
|
1301
|
-
const manifest = {
|
|
1302
|
-
version: 1,
|
|
1303
|
-
routes: manifestRoutes
|
|
1304
|
-
};
|
|
1305
|
-
const imports = [
|
|
1306
|
-
`import { createRuntimeApp, handle } from ${JSON.stringify(runtimeImportPath)}`
|
|
1307
|
-
];
|
|
1308
|
-
const moduleEntries = [];
|
|
1309
|
-
let moduleIndex = 0;
|
|
1310
|
-
for (const id of ruleModules.keys()) {
|
|
1311
|
-
const name = `module${moduleIndex++}`;
|
|
1312
|
-
imports.push(`import * as ${name} from '${id}'`);
|
|
1313
|
-
moduleEntries.push({ id, name, kind: "rule" });
|
|
1314
|
-
}
|
|
1315
|
-
for (const id of middlewareModules.keys()) {
|
|
1316
|
-
const name = `module${moduleIndex++}`;
|
|
1317
|
-
imports.push(`import * as ${name} from '${id}'`);
|
|
1318
|
-
moduleEntries.push({ id, name, kind: "middleware" });
|
|
1319
|
-
}
|
|
1320
|
-
const lines = [];
|
|
1321
|
-
lines.push(...imports, "");
|
|
1322
|
-
lines.push(
|
|
1323
|
-
"const resolveModuleExport = (mod) => mod?.default ?? mod",
|
|
1324
|
-
"",
|
|
1325
|
-
"const toRuntimeRule = (value) => {",
|
|
1326
|
-
" if (typeof value === 'undefined') {",
|
|
1327
|
-
" return null",
|
|
1328
|
-
" }",
|
|
1329
|
-
" if (typeof value === 'function') {",
|
|
1330
|
-
" return { response: value }",
|
|
1331
|
-
" }",
|
|
1332
|
-
" if (value === null) {",
|
|
1333
|
-
" return { response: null }",
|
|
1334
|
-
" }",
|
|
1335
|
-
" if (typeof value === 'object') {",
|
|
1336
|
-
" if ('response' in value) {",
|
|
1337
|
-
" return value",
|
|
1338
|
-
" }",
|
|
1339
|
-
" if ('handler' in value) {",
|
|
1340
|
-
" const handlerRule = value",
|
|
1341
|
-
" return {",
|
|
1342
|
-
" response: handlerRule.handler,",
|
|
1343
|
-
" ...(typeof handlerRule.status === 'number' ? { status: handlerRule.status } : {}),",
|
|
1344
|
-
" ...(handlerRule.headers ? { headers: handlerRule.headers } : {}),",
|
|
1345
|
-
" ...(typeof handlerRule.delay === 'number' ? { delay: handlerRule.delay } : {}),",
|
|
1346
|
-
" }",
|
|
1347
|
-
" }",
|
|
1348
|
-
" return { response: value }",
|
|
1349
|
-
" }",
|
|
1350
|
-
" return { response: value }",
|
|
1351
|
-
"}",
|
|
1352
|
-
"",
|
|
1353
|
-
"const toRuntimeRules = (value) => {",
|
|
1354
|
-
" if (typeof value === 'undefined') {",
|
|
1355
|
-
" return []",
|
|
1356
|
-
" }",
|
|
1357
|
-
" if (Array.isArray(value)) {",
|
|
1358
|
-
" return value.map(toRuntimeRule).filter(Boolean)",
|
|
1359
|
-
" }",
|
|
1360
|
-
" const rule = toRuntimeRule(value)",
|
|
1361
|
-
" return rule ? [rule] : []",
|
|
1362
|
-
"}",
|
|
1363
|
-
""
|
|
1364
|
-
);
|
|
1365
|
-
lines.push(
|
|
1366
|
-
`const manifest = ${JSON.stringify(manifest, null, 2)}`,
|
|
1367
|
-
""
|
|
1368
|
-
);
|
|
1369
|
-
if (moduleEntries.length > 0) {
|
|
1370
|
-
lines.push("const moduleMap = {");
|
|
1371
|
-
for (const entry of moduleEntries) {
|
|
1372
|
-
if (entry.kind === "rule") {
|
|
1373
|
-
lines.push(
|
|
1374
|
-
` ${JSON.stringify(entry.id)}: { default: toRuntimeRules(resolveModuleExport(${entry.name})) },`
|
|
1375
|
-
);
|
|
1376
|
-
continue;
|
|
1377
|
-
}
|
|
1378
|
-
lines.push(
|
|
1379
|
-
` ${JSON.stringify(entry.id)}: ${entry.name},`
|
|
1380
|
-
);
|
|
1381
|
-
}
|
|
1382
|
-
lines.push("}", "");
|
|
1383
|
-
}
|
|
1384
|
-
const runtimeOptions = moduleEntries.length > 0 ? "{ manifest, moduleMap }" : "{ manifest }";
|
|
1385
|
-
lines.push(
|
|
1386
|
-
`const basePaths = ${JSON.stringify(basePaths)}`,
|
|
1387
|
-
"",
|
|
1388
|
-
"self.addEventListener('install', () => {",
|
|
1389
|
-
" self.skipWaiting()",
|
|
1390
|
-
"})",
|
|
1391
|
-
"",
|
|
1392
|
-
"self.addEventListener('activate', (event) => {",
|
|
1393
|
-
" event.waitUntil(self.clients.claim())",
|
|
1394
|
-
"})",
|
|
1395
|
-
"",
|
|
1396
|
-
"const shouldHandle = (request) => {",
|
|
1397
|
-
" if (!basePaths || basePaths.length === 0) {",
|
|
1398
|
-
" return true",
|
|
1399
|
-
" }",
|
|
1400
|
-
" const pathname = new URL(request.url).pathname",
|
|
1401
|
-
" return basePaths.some((basePath) => {",
|
|
1402
|
-
" if (basePath === '/') {",
|
|
1403
|
-
" return true",
|
|
1404
|
-
" }",
|
|
1405
|
-
" return pathname === basePath || pathname.startsWith(basePath + '/')",
|
|
1406
|
-
" })",
|
|
1407
|
-
"}",
|
|
1408
|
-
"",
|
|
1409
|
-
"const registerHandler = async () => {",
|
|
1410
|
-
` const app = await createRuntimeApp(${runtimeOptions})`,
|
|
1411
|
-
" const handler = handle(app)",
|
|
1412
|
-
" self.addEventListener('fetch', (event) => {",
|
|
1413
|
-
" if (!shouldHandle(event.request)) {",
|
|
1414
|
-
" return",
|
|
1415
|
-
" }",
|
|
1416
|
-
" handler(event)",
|
|
1417
|
-
" })",
|
|
1418
|
-
"}",
|
|
1419
|
-
"",
|
|
1420
|
-
"registerHandler().catch((error) => {",
|
|
1421
|
-
" console.error('[mokup] Failed to build service worker app:', error)",
|
|
1422
|
-
"})",
|
|
1423
|
-
""
|
|
1424
|
-
);
|
|
1425
|
-
return lines.join("\n");
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
21
|
function buildRouteSignature(routes) {
|
|
1429
22
|
return routes.map(
|
|
1430
23
|
(route) => [
|
|
@@ -1514,7 +107,7 @@ function addMiddlewareFirst(server, middleware) {
|
|
|
1514
107
|
server.middlewares.use(middleware);
|
|
1515
108
|
}
|
|
1516
109
|
function createMokupPlugin(options = {}) {
|
|
1517
|
-
let root =
|
|
110
|
+
let root = process.cwd();
|
|
1518
111
|
let base = "/";
|
|
1519
112
|
let command = "serve";
|
|
1520
113
|
let assetsDir = "assets";
|
|
@@ -1528,16 +121,16 @@ function createMokupPlugin(options = {}) {
|
|
|
1528
121
|
const optionList = normalizeOptions(options);
|
|
1529
122
|
const logEnabled = optionList.every((entry) => entry.log !== false);
|
|
1530
123
|
const watchEnabled = optionList.every((entry) => entry.watch !== false);
|
|
1531
|
-
const playgroundConfig = resolvePlaygroundOptions(resolvePlaygroundInput(optionList));
|
|
1532
|
-
const logger = createLogger(logEnabled);
|
|
124
|
+
const playgroundConfig = sw.resolvePlaygroundOptions(resolvePlaygroundInput(optionList));
|
|
125
|
+
const logger = sw.createLogger(logEnabled);
|
|
1533
126
|
const hasSwEntries = optionList.some((entry) => entry.mode === "sw");
|
|
1534
|
-
const swConfig = resolveSwConfig(optionList, logger);
|
|
1535
|
-
const unregisterConfig = resolveSwUnregisterConfig(optionList, logger);
|
|
127
|
+
const swConfig = sw.resolveSwConfig(optionList, logger);
|
|
128
|
+
const unregisterConfig = sw.resolveSwUnregisterConfig(optionList, logger);
|
|
1536
129
|
const resolveAllDirs = () => {
|
|
1537
130
|
const dirs = [];
|
|
1538
131
|
const seen = /* @__PURE__ */ new Set();
|
|
1539
132
|
for (const entry of optionList) {
|
|
1540
|
-
for (const dir of resolveDirs(entry.dir, root)) {
|
|
133
|
+
for (const dir of sw.resolveDirs(entry.dir, root)) {
|
|
1541
134
|
if (seen.has(dir)) {
|
|
1542
135
|
continue;
|
|
1543
136
|
}
|
|
@@ -1614,7 +207,7 @@ function createMokupPlugin(options = {}) {
|
|
|
1614
207
|
"})()"
|
|
1615
208
|
].join("\n");
|
|
1616
209
|
}
|
|
1617
|
-
const playgroundMiddleware = createPlaygroundMiddleware({
|
|
210
|
+
const playgroundMiddleware = sw.createPlaygroundMiddleware({
|
|
1618
211
|
getRoutes: () => routes,
|
|
1619
212
|
config: playgroundConfig,
|
|
1620
213
|
logger,
|
|
@@ -1627,7 +220,7 @@ function createMokupPlugin(options = {}) {
|
|
|
1627
220
|
const collectedServer = [];
|
|
1628
221
|
const collectedSw = [];
|
|
1629
222
|
for (const entry of optionList) {
|
|
1630
|
-
const dirs = resolveDirs(entry.dir, root);
|
|
223
|
+
const dirs = sw.resolveDirs(entry.dir, root);
|
|
1631
224
|
const scanParams = {
|
|
1632
225
|
dirs,
|
|
1633
226
|
prefix: entry.prefix ?? "",
|
|
@@ -1642,7 +235,7 @@ function createMokupPlugin(options = {}) {
|
|
|
1642
235
|
if (server) {
|
|
1643
236
|
scanParams.server = server;
|
|
1644
237
|
}
|
|
1645
|
-
const scanned = await scanRoutes(scanParams);
|
|
238
|
+
const scanned = await sw.scanRoutes(scanParams);
|
|
1646
239
|
collected.push(...scanned);
|
|
1647
240
|
if (entry.mode === "sw") {
|
|
1648
241
|
collectedSw.push(...scanned);
|
|
@@ -1653,10 +246,10 @@ function createMokupPlugin(options = {}) {
|
|
|
1653
246
|
collectedServer.push(...scanned);
|
|
1654
247
|
}
|
|
1655
248
|
}
|
|
1656
|
-
routes = sortRoutes(collected);
|
|
1657
|
-
serverRoutes = sortRoutes(collectedServer);
|
|
1658
|
-
swRoutes = sortRoutes(collectedSw);
|
|
1659
|
-
app = serverRoutes.length > 0 ? createHonoApp(serverRoutes) : null;
|
|
249
|
+
routes = sw.sortRoutes(collected);
|
|
250
|
+
serverRoutes = sw.sortRoutes(collectedServer);
|
|
251
|
+
swRoutes = sw.sortRoutes(collectedSw);
|
|
252
|
+
app = serverRoutes.length > 0 ? sw.createHonoApp(serverRoutes) : null;
|
|
1660
253
|
const signature = buildRouteSignature(routes);
|
|
1661
254
|
if (isViteDevServer(server) && server.ws) {
|
|
1662
255
|
if (lastSignature && signature !== lastSignature) {
|
|
@@ -1698,7 +291,7 @@ function createMokupPlugin(options = {}) {
|
|
|
1698
291
|
if (swRoutes.length === 0) {
|
|
1699
292
|
await refreshRoutes();
|
|
1700
293
|
}
|
|
1701
|
-
return buildSwScript({
|
|
294
|
+
return sw.buildSwScript({
|
|
1702
295
|
routes: swRoutes,
|
|
1703
296
|
root,
|
|
1704
297
|
basePaths: swConfig?.basePaths ?? []
|
|
@@ -1786,7 +379,7 @@ function createMokupPlugin(options = {}) {
|
|
|
1786
379
|
return next();
|
|
1787
380
|
}
|
|
1788
381
|
try {
|
|
1789
|
-
const code = buildSwScript({
|
|
382
|
+
const code = sw.buildSwScript({
|
|
1790
383
|
routes: swRoutes,
|
|
1791
384
|
root,
|
|
1792
385
|
runtimeImportPath: resolveSwRuntimeImportPath(base),
|
|
@@ -1805,26 +398,26 @@ function createMokupPlugin(options = {}) {
|
|
|
1805
398
|
});
|
|
1806
399
|
}
|
|
1807
400
|
if (serverRoutes.length > 0) {
|
|
1808
|
-
server.middlewares.use(createMiddleware(() => app, logger));
|
|
401
|
+
server.middlewares.use(sw.createMiddleware(() => app, logger));
|
|
1809
402
|
}
|
|
1810
403
|
if (!watchEnabled) {
|
|
1811
404
|
return;
|
|
1812
405
|
}
|
|
1813
406
|
const dirs = resolveAllDirs();
|
|
1814
407
|
server.watcher.add(dirs);
|
|
1815
|
-
const scheduleRefresh = createDebouncer(80, () => refreshRoutes(server));
|
|
408
|
+
const scheduleRefresh = sw.createDebouncer(80, () => refreshRoutes(server));
|
|
1816
409
|
server.watcher.on("add", (file) => {
|
|
1817
|
-
if (isInDirs(file, dirs)) {
|
|
410
|
+
if (sw.isInDirs(file, dirs)) {
|
|
1818
411
|
scheduleRefresh();
|
|
1819
412
|
}
|
|
1820
413
|
});
|
|
1821
414
|
server.watcher.on("change", (file) => {
|
|
1822
|
-
if (isInDirs(file, dirs)) {
|
|
415
|
+
if (sw.isInDirs(file, dirs)) {
|
|
1823
416
|
scheduleRefresh();
|
|
1824
417
|
}
|
|
1825
418
|
});
|
|
1826
419
|
server.watcher.on("unlink", (file) => {
|
|
1827
|
-
if (isInDirs(file, dirs)) {
|
|
420
|
+
if (sw.isInDirs(file, dirs)) {
|
|
1828
421
|
scheduleRefresh();
|
|
1829
422
|
}
|
|
1830
423
|
});
|
|
@@ -1842,7 +435,7 @@ function createMokupPlugin(options = {}) {
|
|
|
1842
435
|
return next();
|
|
1843
436
|
}
|
|
1844
437
|
try {
|
|
1845
|
-
const code = buildSwScript({
|
|
438
|
+
const code = sw.buildSwScript({
|
|
1846
439
|
routes: swRoutes,
|
|
1847
440
|
root,
|
|
1848
441
|
basePaths: swConfig?.basePaths ?? []
|
|
@@ -1860,14 +453,14 @@ function createMokupPlugin(options = {}) {
|
|
|
1860
453
|
});
|
|
1861
454
|
}
|
|
1862
455
|
if (serverRoutes.length > 0) {
|
|
1863
|
-
server.middlewares.use(createMiddleware(() => app, logger));
|
|
456
|
+
server.middlewares.use(sw.createMiddleware(() => app, logger));
|
|
1864
457
|
}
|
|
1865
458
|
if (!watchEnabled) {
|
|
1866
459
|
return;
|
|
1867
460
|
}
|
|
1868
461
|
const dirs = resolveAllDirs();
|
|
1869
462
|
previewWatcher = chokidar__default.watch(dirs, { ignoreInitial: true });
|
|
1870
|
-
const scheduleRefresh = createDebouncer(80, () => refreshRoutes(server));
|
|
463
|
+
const scheduleRefresh = sw.createDebouncer(80, () => refreshRoutes(server));
|
|
1871
464
|
previewWatcher.on("add", scheduleRefresh);
|
|
1872
465
|
previewWatcher.on("change", scheduleRefresh);
|
|
1873
466
|
previewWatcher.on("unlink", scheduleRefresh);
|