@marko/run 0.0.1-beta1

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.
Files changed (43) hide show
  1. package/README.md +267 -0
  2. package/dist/adapter/default-entry.mjs +18 -0
  3. package/dist/adapter/dev-server.d.ts +4 -0
  4. package/dist/adapter/index.cjs +159 -0
  5. package/dist/adapter/index.d.ts +4 -0
  6. package/dist/adapter/index.js +126 -0
  7. package/dist/adapter/server-old.d.ts +3 -0
  8. package/dist/adapter/server.d.ts +6 -0
  9. package/dist/adapters/node/index.d.ts +5 -0
  10. package/dist/adapters/node/server.d.ts +3 -0
  11. package/dist/adapters/static/crawler.d.ts +9 -0
  12. package/dist/adapters/static/default-entry.mjs +1 -0
  13. package/dist/adapters/static/index.cjs +371 -0
  14. package/dist/adapters/static/index.d.ts +5 -0
  15. package/dist/adapters/static/index.js +341 -0
  16. package/dist/adapters/static/server.d.ts +3 -0
  17. package/dist/cli/default.config.mjs +7 -0
  18. package/dist/cli/index.mjs +223 -0
  19. package/dist/runtime/index.cjs +34 -0
  20. package/dist/runtime/index.d.ts +2 -0
  21. package/dist/runtime/index.js +7 -0
  22. package/dist/runtime/request.d.ts +4 -0
  23. package/dist/runtime/router.cjs +39 -0
  24. package/dist/runtime/router.d.ts +4 -0
  25. package/dist/runtime/router.js +12 -0
  26. package/dist/runtime/types.d.ts +22 -0
  27. package/dist/vite/codegen/index.d.ts +5 -0
  28. package/dist/vite/codegen/writer.d.ts +20 -0
  29. package/dist/vite/constants.d.ts +19 -0
  30. package/dist/vite/index.cjs +1394 -0
  31. package/dist/vite/index.d.ts +3 -0
  32. package/dist/vite/index.js +1359 -0
  33. package/dist/vite/plugin.d.ts +3 -0
  34. package/dist/vite/routes/builder.d.ts +7 -0
  35. package/dist/vite/routes/routeTrie.d.ts +2 -0
  36. package/dist/vite/routes/walk.d.ts +14 -0
  37. package/dist/vite/types.d.ts +62 -0
  38. package/dist/vite/utils/ast.d.ts +1 -0
  39. package/dist/vite/utils/config.d.ts +3 -0
  40. package/dist/vite/utils/log.d.ts +3 -0
  41. package/dist/vite/utils/route.d.ts +3 -0
  42. package/dist/vite/utils/server.d.ts +7 -0
  43. package/package.json +93 -0
@@ -0,0 +1,1359 @@
1
+ // src/vite/plugin.ts
2
+ import path2 from "path";
3
+ import crypto from "crypto";
4
+ import { mergeConfig, normalizePath } from "vite";
5
+ import markoVitePlugin, { FileStore } from "@marko/vite";
6
+
7
+ // src/vite/constants.ts
8
+ var markoServeFilePrefix = "__marko-serve__";
9
+ var virtualFilePrefix = "virtual:marko-serve";
10
+ var virtualRoutesPrefix = `${virtualFilePrefix}/routes`;
11
+ var httpVerbs = ["get", "post", "put", "delete"];
12
+ var serverEntryQuery = "?marko-server-entry";
13
+ var browserEntryQuery = "?marko-browser-entry";
14
+ var RoutableFileTypes = {
15
+ Page: "page",
16
+ Layout: "layout",
17
+ Handler: "handler",
18
+ Middleware: "middleware",
19
+ Meta: "meta",
20
+ NotFound: "404",
21
+ Error: "500"
22
+ };
23
+
24
+ // src/vite/routes/builder.ts
25
+ var markoFiles = `(${RoutableFileTypes.Layout}|${RoutableFileTypes.Page}|${RoutableFileTypes.NotFound}|${RoutableFileTypes.Error})\\.(?:.*\\.)?(marko)`;
26
+ var nonMarkoFiles = `(${RoutableFileTypes.Middleware}|${RoutableFileTypes.Handler}|${RoutableFileTypes.Meta})\\.(?:.*\\.)?(.+)`;
27
+ var routeableFileRegex = new RegExp(
28
+ `^[+](?:${markoFiles}|${nonMarkoFiles})$`,
29
+ "i"
30
+ );
31
+ function isRoutableFile(filename) {
32
+ return routeableFileRegex.test(filename);
33
+ }
34
+ function matchRoutableFile(filename) {
35
+ const match = filename.match(routeableFileRegex);
36
+ return match && (match[1] || match[3]).toLowerCase();
37
+ }
38
+ function scorePath(path3, index) {
39
+ const [pattern, splat] = path3.split("/$$", 2);
40
+ const segments = pattern.split("/").filter(Boolean);
41
+ return segments.reduce(
42
+ (score, segment) => score + (segment.startsWith("$") ? 3 : 4),
43
+ segments.length + (splat === void 0 ? 1 : 2)
44
+ ) * 1e4 - index;
45
+ }
46
+ function isSpecialType(type) {
47
+ return type === RoutableFileTypes.NotFound || type === RoutableFileTypes.Error;
48
+ }
49
+ async function buildRoutes(walk, basePath) {
50
+ const dirStack = basePath ? basePath.split("/") : [];
51
+ const pathStack = [];
52
+ const paramStack = [];
53
+ const layoutsStack = [];
54
+ const middlewareStack = [];
55
+ const routes = /* @__PURE__ */ new Map();
56
+ const special = {};
57
+ let isRoot = true;
58
+ let nextId = 1;
59
+ let current;
60
+ let children = [];
61
+ await walk({
62
+ onFile(entry) {
63
+ const type = matchRoutableFile(entry.name);
64
+ if (!type) {
65
+ return;
66
+ }
67
+ if (!isRoot && isSpecialType(type)) {
68
+ console.warn(
69
+ `Special pages '${RoutableFileTypes.NotFound}' and '${RoutableFileTypes.Error}' are only considered in the root directory - ignoring ${entry.path}`
70
+ );
71
+ return;
72
+ }
73
+ if (!current) {
74
+ current = {
75
+ path: "/" + pathStack.join("/"),
76
+ originalPath: dirStack.join("/"),
77
+ children: [],
78
+ files: /* @__PURE__ */ new Map()
79
+ };
80
+ children.push(current);
81
+ }
82
+ let entries = current.files.get(type);
83
+ if (!entries) {
84
+ current.files.set(type, entries = []);
85
+ }
86
+ entries.push({
87
+ type,
88
+ filePath: entry.path,
89
+ importPath: `${current.originalPath}/${entry.name}`,
90
+ name: entry.name,
91
+ verbs: type === RoutableFileTypes.Page ? ["get"] : void 0
92
+ });
93
+ },
94
+ onDir(dir) {
95
+ var _a, _b, _c, _d, _e;
96
+ if (!current) {
97
+ return;
98
+ }
99
+ const { path: path3, files } = current;
100
+ const middleware = (_a = files.get(RoutableFileTypes.Middleware)) == null ? void 0 : _a[0];
101
+ const layout = (_b = files.get(RoutableFileTypes.Layout)) == null ? void 0 : _b[0];
102
+ const handler = (_c = files.get(RoutableFileTypes.Handler)) == null ? void 0 : _c[0];
103
+ const page = (_d = files.get(RoutableFileTypes.Page)) == null ? void 0 : _d[0];
104
+ const middlewareStackLength = middlewareStack.length;
105
+ const layoutsStackLength = layoutsStack.length;
106
+ middleware && middlewareStack.push(middleware);
107
+ layout && layoutsStack.push(layout);
108
+ if (handler || page) {
109
+ const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
110
+ if (routes.has(key)) {
111
+ console.warn(`Duplicate route for path ${path3} -- ignoring`, current);
112
+ } else {
113
+ const index = nextId++;
114
+ routes.set(key, {
115
+ index,
116
+ key,
117
+ path: path3,
118
+ params: [...paramStack],
119
+ middleware: [...middlewareStack],
120
+ layouts: page ? [...layoutsStack] : [],
121
+ meta: (_e = files.get(RoutableFileTypes.Meta)) == null ? void 0 : _e[0],
122
+ page,
123
+ handler,
124
+ score: scorePath(path3, index)
125
+ });
126
+ }
127
+ }
128
+ if (isRoot) {
129
+ for (const [type, entries] of files) {
130
+ if (isSpecialType(type)) {
131
+ special[type] = {
132
+ index: 0,
133
+ key: type,
134
+ path: path3,
135
+ middleware: [],
136
+ layouts: [...layoutsStack],
137
+ page: entries[0],
138
+ score: 0
139
+ };
140
+ }
141
+ }
142
+ } else if (dir.startsWith("$$")) {
143
+ return false;
144
+ }
145
+ return () => {
146
+ middlewareStack.length = middlewareStackLength;
147
+ layoutsStack.length = layoutsStackLength;
148
+ };
149
+ },
150
+ onEnter({ name }) {
151
+ const pathStackLength = pathStack.length;
152
+ const paramStackLength = paramStack.length;
153
+ const prevChildren = children;
154
+ const prevCurrent = current;
155
+ const prevIsRoot = isRoot;
156
+ if (name.charCodeAt(0) === 95 || name.charCodeAt(0) === 40 && name.charCodeAt(name.length - 1) === 41 || name.toLowerCase() === "index") {
157
+ } else {
158
+ if (name.charCodeAt(0) === 36) {
159
+ if (name.charCodeAt(1) === 36) {
160
+ paramStack.push({
161
+ name: name.slice(2) || "*",
162
+ index: -1
163
+ });
164
+ } else if (name.length > 1) {
165
+ paramStack.push({
166
+ name: name.slice(1),
167
+ index: pathStackLength
168
+ });
169
+ }
170
+ }
171
+ pathStack.push(name.toLowerCase());
172
+ }
173
+ dirStack.push(name);
174
+ isRoot = false;
175
+ if (current) {
176
+ children = current.children;
177
+ current = void 0;
178
+ }
179
+ return () => {
180
+ dirStack.pop();
181
+ pathStack.length = pathStackLength;
182
+ paramStack.length = paramStackLength;
183
+ children = prevChildren;
184
+ current = prevCurrent;
185
+ isRoot = prevIsRoot;
186
+ };
187
+ }
188
+ });
189
+ return {
190
+ list: [...routes.values()],
191
+ special
192
+ };
193
+ }
194
+
195
+ // src/vite/routes/walk.ts
196
+ import fs from "fs";
197
+ import path from "path";
198
+ function createFSWalker(dir) {
199
+ return async function walkFS({ onFile, onEnter, onDir, maxDepth = 50 }) {
200
+ async function walk(dir2, depth) {
201
+ const dirs = [];
202
+ const entries = await fs.promises.readdir(dir2, { withFileTypes: true });
203
+ const prefix = dir2 + path.sep;
204
+ for (const dirEntry of entries) {
205
+ const entry = {
206
+ name: dirEntry.name,
207
+ path: prefix + dirEntry.name
208
+ };
209
+ if (dirEntry.isDirectory()) {
210
+ dirs.push(entry);
211
+ } else {
212
+ onFile == null ? void 0 : onFile(entry);
213
+ }
214
+ }
215
+ const onAfter = onDir == null ? void 0 : onDir(dir2);
216
+ if (onAfter !== false) {
217
+ if (--depth > 0) {
218
+ for (const entry of dirs) {
219
+ const onExit = onEnter == null ? void 0 : onEnter(entry);
220
+ if (onExit !== false) {
221
+ await walk(entry.path, depth);
222
+ onExit == null ? void 0 : onExit();
223
+ }
224
+ }
225
+ }
226
+ onAfter == null ? void 0 : onAfter();
227
+ }
228
+ }
229
+ await walk(dir, maxDepth);
230
+ };
231
+ }
232
+
233
+ // src/vite/codegen/writer.ts
234
+ function createWriter(sink, options) {
235
+ let buffer = "";
236
+ let indentLevel = 0;
237
+ let indentString = "";
238
+ let firstOpenIndex = 0;
239
+ const branches = [];
240
+ const openWriters = /* @__PURE__ */ new Map();
241
+ const writer = {
242
+ __isActive: true,
243
+ get indent() {
244
+ return indentLevel;
245
+ },
246
+ set indent(value) {
247
+ if (options == null ? void 0 : options.indentWith) {
248
+ if (value < 0) {
249
+ value = 0;
250
+ }
251
+ if (value !== indentLevel) {
252
+ indentLevel = value;
253
+ indentString = options.indentWith.repeat(indentLevel);
254
+ }
255
+ }
256
+ },
257
+ write(data) {
258
+ if (!writer.__isActive) {
259
+ throw new Error("Cannot write to branch that has been joined");
260
+ }
261
+ if (openWriters.size) {
262
+ buffer += data;
263
+ } else {
264
+ sink(data);
265
+ }
266
+ return writer;
267
+ },
268
+ writeLines(...lines) {
269
+ for (const line of lines) {
270
+ if (line) {
271
+ if (indentString) {
272
+ writer.write(indentString);
273
+ }
274
+ writer.write(line);
275
+ }
276
+ writer.write("\n");
277
+ }
278
+ return writer;
279
+ },
280
+ writeBlockStart(data) {
281
+ writer.writeLines(data).indent++;
282
+ return writer;
283
+ },
284
+ writeBlockEnd(data = "}") {
285
+ writer.indent--;
286
+ writer.writeLines(data);
287
+ return writer;
288
+ },
289
+ writeBlock(start, lines, end) {
290
+ return writer.writeBlockStart(start).writeLines(...lines).writeBlockEnd(end);
291
+ },
292
+ branch(name) {
293
+ let existing = openWriters.get(name);
294
+ if (existing) {
295
+ return existing;
296
+ }
297
+ const branch = {
298
+ buffer,
299
+ writer: createWriter(
300
+ (data) => {
301
+ branch.buffer += data;
302
+ },
303
+ {
304
+ ...options,
305
+ onJoin() {
306
+ openWriters.delete(name);
307
+ for (let i = firstOpenIndex; i < branches.length; i++) {
308
+ const b = branches[i];
309
+ if (!b) {
310
+ continue;
311
+ } else if (b.writer.__isActive) {
312
+ break;
313
+ }
314
+ sink(b.buffer);
315
+ branches[i] = null;
316
+ firstOpenIndex++;
317
+ }
318
+ }
319
+ }
320
+ )
321
+ };
322
+ branch.writer.indent = indentLevel;
323
+ openWriters.set(name, branch.writer);
324
+ branches.push(branch);
325
+ buffer = "";
326
+ return branch.writer;
327
+ },
328
+ join(recursive) {
329
+ var _a;
330
+ if (writer.__isActive) {
331
+ if (openWriters.size) {
332
+ if (recursive) {
333
+ for (const branch of openWriters.values()) {
334
+ branch.join(true);
335
+ }
336
+ } else {
337
+ throw new Error(
338
+ `Cannot join a Writer with un-joined branches - use the \`recursive\` argument to join all open branches`
339
+ );
340
+ }
341
+ }
342
+ buffer && sink(buffer);
343
+ writer.__isActive = false;
344
+ (_a = options == null ? void 0 : options.onJoin) == null ? void 0 : _a.call(options, writer);
345
+ }
346
+ }
347
+ };
348
+ return writer;
349
+ }
350
+ function createStringWriter(opts) {
351
+ let code = "";
352
+ const writer = createWriter((data) => {
353
+ code += data;
354
+ }, { indentWith: " ", ...opts });
355
+ return Object.assign(writer, {
356
+ end() {
357
+ writer.join(true);
358
+ return code;
359
+ }
360
+ });
361
+ }
362
+
363
+ // src/vite/routes/routeTrie.ts
364
+ function createRouteTrie(routes) {
365
+ const root = {
366
+ key: ""
367
+ };
368
+ function insert(keys, value) {
369
+ let node = root;
370
+ for (const key of keys) {
371
+ if (key.startsWith("$$")) {
372
+ if (!node.catchAll) {
373
+ node.catchAll = value;
374
+ return true;
375
+ }
376
+ return false;
377
+ } else if (key.startsWith("$")) {
378
+ node = node.dynamic ?? (node.dynamic = {
379
+ key: ""
380
+ });
381
+ } else {
382
+ node.static ?? (node.static = /* @__PURE__ */ new Map());
383
+ let next = node.static.get(key);
384
+ if (!next) {
385
+ next = {
386
+ key
387
+ };
388
+ node.static.set(key, next);
389
+ }
390
+ node = next;
391
+ }
392
+ }
393
+ if (node.route === void 0) {
394
+ node.route = value;
395
+ return true;
396
+ }
397
+ return false;
398
+ }
399
+ for (const route of routes) {
400
+ const keys = route.path === "/" ? [] : route.path.split("/").slice(1);
401
+ insert(keys, route);
402
+ }
403
+ return root;
404
+ }
405
+
406
+ // src/vite/utils/route.ts
407
+ function getVerbs(route) {
408
+ var _a, _b;
409
+ const verbs = ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.slice()) || [];
410
+ if (route.page && !verbs.includes("get")) {
411
+ verbs.unshift("get");
412
+ }
413
+ return verbs;
414
+ }
415
+ function hasVerb(route, verb) {
416
+ var _a, _b;
417
+ return verb === "get" && route.page || ((_b = (_a = route.handler) == null ? void 0 : _a.verbs) == null ? void 0 : _b.includes(verb));
418
+ }
419
+
420
+ // src/vite/codegen/index.ts
421
+ var DefaultCodegenOptions = {
422
+ trailingSlashes: "RedirectWithout"
423
+ };
424
+ function renderRouteTemplate(route) {
425
+ if (!route.page) {
426
+ throw new Error(`Route ${route.key} has no page to render`);
427
+ }
428
+ const writer = createStringWriter();
429
+ writer.writeLines(
430
+ `// ${virtualFilePrefix}/${markoServeFilePrefix}route__${route.key}.marko`
431
+ );
432
+ writer.branch("imports");
433
+ writer.writeLines("");
434
+ writeRouteTemplateTag(writer, [...route.layouts, route.page]);
435
+ return writer.end();
436
+ }
437
+ function writeRouteTemplateTag(writer, [file, ...rest], index = 1) {
438
+ if (file) {
439
+ const isLast = !rest.length;
440
+ const tag = isLast ? "page" : `layout${index}`;
441
+ writer.branch("imports").writeLines(`import ${tag} from './${file.importPath}';`);
442
+ if (isLast) {
443
+ writer.writeLines(`<${tag} ...input />`);
444
+ } else {
445
+ writer.writeBlockStart(`<${tag} ...input>`);
446
+ writeRouteTemplateTag(writer, rest, index + 1);
447
+ writer.writeBlockEnd(`</>`);
448
+ }
449
+ }
450
+ }
451
+ function renderRouteEntry(route) {
452
+ var _a;
453
+ const { key, index, handler, page, middleware, meta } = route;
454
+ const verbs = getVerbs(route);
455
+ if (!verbs) {
456
+ throw new Error(
457
+ `Route ${key} doesn't have a handler or page for any HTTP verbs`
458
+ );
459
+ }
460
+ const writer = createStringWriter();
461
+ writer.writeLines(
462
+ `// ${virtualFilePrefix}/${markoServeFilePrefix}route__${key}.js`
463
+ );
464
+ const imports = writer.branch("imports");
465
+ let i = 1;
466
+ for (const { importPath } of middleware) {
467
+ imports.writeLines(`import middleware$${i} from './${importPath}';`);
468
+ i++;
469
+ }
470
+ if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.length) {
471
+ const names = handler.verbs.map(
472
+ (verb) => `${verb === "delete" ? "del" : verb} as handler$${verb}`
473
+ );
474
+ imports.writeLines(
475
+ `import { ${names.join(", ")} } from './${handler.importPath}';`
476
+ );
477
+ }
478
+ if (page) {
479
+ imports.writeLines(
480
+ `import page from '${virtualFilePrefix}/${markoServeFilePrefix}route__${key}.marko${serverEntryQuery}';`
481
+ );
482
+ }
483
+ if (meta) {
484
+ imports.writeLines(
485
+ `export { default as meta$${index} } from './${meta.importPath}';`
486
+ );
487
+ }
488
+ if (!page || verbs.length > 1) {
489
+ writer.writeLines("").writeBlockStart(`function create204Response() {`).writeBlockStart(`return new Response(null, {`).writeLines(`status: 204`).writeBlockEnd(`})`).writeBlockEnd(`}`);
490
+ }
491
+ for (const verb of verbs) {
492
+ writeRouteEntryHandler(writer, route, verb);
493
+ }
494
+ return writer.end();
495
+ }
496
+ function writePageResponseContinuation(writer) {
497
+ writer.writeBlock(
498
+ `return new Response(page.stream(ctx), {`,
499
+ ["status: 200,", 'headers: { "content-type": "text/html;charset=UTF-8" }'],
500
+ "});"
501
+ );
502
+ }
503
+ function writeRouteEntryHandler(writer, route, verb) {
504
+ var _a;
505
+ const { key, index, page, handler, middleware } = route;
506
+ const len = middleware.length;
507
+ let nextName;
508
+ let currentName;
509
+ let hasBody = false;
510
+ writer.writeLines("").writeBlockStart(`export async function ${verb}$${index}(ctx) {`);
511
+ const continuations = writer.branch("cont");
512
+ if (page && verb === "get") {
513
+ currentName = "createPageResponse";
514
+ if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
515
+ continuations.writeBlockStart(`async function ${currentName}() {`);
516
+ writePageResponseContinuation(continuations);
517
+ continuations.writeBlockEnd("}");
518
+ if (len) {
519
+ nextName = currentName;
520
+ currentName = `__handler$${verb}`;
521
+ continuations.writeBlock(
522
+ `async function ${currentName}() {`,
523
+ [`return await handler$${verb}(ctx, ${nextName});`],
524
+ "}"
525
+ );
526
+ } else {
527
+ writer.writeLines(`return await handler$${verb}(ctx, ${currentName})`);
528
+ hasBody = true;
529
+ }
530
+ } else if (len) {
531
+ continuations.writeBlockStart(`async function ${currentName}() {`);
532
+ writePageResponseContinuation(continuations);
533
+ continuations.writeBlockEnd("}");
534
+ nextName = currentName;
535
+ } else {
536
+ writePageResponseContinuation(continuations);
537
+ hasBody = true;
538
+ }
539
+ } else if (handler) {
540
+ currentName = `__handler$${verb}`;
541
+ if (len) {
542
+ continuations.writeBlock(
543
+ `async function ${currentName}() {`,
544
+ [`return await handler$${verb}(ctx, create204Response);`],
545
+ "}"
546
+ );
547
+ } else {
548
+ writer.writeLines(
549
+ `return await handler$${verb}(ctx, create204Response);`
550
+ );
551
+ hasBody = true;
552
+ }
553
+ } else {
554
+ throw new Error(`Route ${key} has no handler for ${verb} requests`);
555
+ }
556
+ if (!hasBody) {
557
+ let i = len;
558
+ while (--i) {
559
+ nextName = currentName;
560
+ currentName = `__middleware${i + 1}`;
561
+ continuations.writeLines("").writeBlock(
562
+ `async function ${currentName}() {`,
563
+ [`return await middleware$${i + 1}(ctx, ${nextName});`],
564
+ "}"
565
+ );
566
+ }
567
+ writer.writeLines(`return await middleware$1(ctx, ${currentName});`);
568
+ }
569
+ continuations.join();
570
+ writer.writeBlockEnd("}");
571
+ }
572
+ function renderRouter(routes, options = DefaultCodegenOptions) {
573
+ const writer = createStringWriter();
574
+ writer.writeLines(`// @marko/run/router`);
575
+ const imports = writer.branch("imports");
576
+ for (const route of routes.list) {
577
+ const verbs = getVerbs(route);
578
+ const names = verbs.map((verb) => `${verb}$${route.index}`);
579
+ route.meta && names.push(`meta$${route.index}`);
580
+ imports.writeLines(
581
+ `import { ${names.join(
582
+ ", "
583
+ )} } from '${virtualFilePrefix}/${markoServeFilePrefix}route__${route.key}.js';`
584
+ );
585
+ }
586
+ for (const { key } of Object.values(routes.special)) {
587
+ imports.writeLines(
588
+ `import page$${key} from '${virtualFilePrefix}/${markoServeFilePrefix}special__${key}.marko${serverEntryQuery}';`
589
+ );
590
+ }
591
+ writer.writeLines("").writeBlockStart(`function matchRoute(method, pathname) {`).writeBlockStart(`switch (method.toLowerCase()) {`);
592
+ for (const verb of httpVerbs) {
593
+ const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
594
+ if (filteredRoutes.length) {
595
+ const trie = createRouteTrie(filteredRoutes);
596
+ writer.writeBlockStart(`case '${verb}': {`);
597
+ writeRouterVerb(writer, trie, verb);
598
+ writer.writeBlockEnd("}");
599
+ }
600
+ }
601
+ writer.writeBlockEnd("}").writeBlockEnd("}");
602
+ writer.writeLines("").writeBlockStart(`async function invokeRoute(route, url, request) {`);
603
+ const errorRoute = routes.special[RoutableFileTypes.Error];
604
+ if (errorRoute) {
605
+ writer.writeBlockStart(`try {`);
606
+ }
607
+ writer.writeBlock(
608
+ `if (route) {`,
609
+ [
610
+ `const [handler, params = {}, meta] = route;`,
611
+ `const response = await handler({ request, url, params, meta });`,
612
+ `if (response) return response;`
613
+ ],
614
+ `}`
615
+ );
616
+ const notFoundRoute = routes.special[RoutableFileTypes.NotFound];
617
+ if (notFoundRoute) {
618
+ writer.writeBlockStart(
619
+ `if (request.headers.get('Accept')?.includes('text/html')) {`
620
+ ).writeBlock(
621
+ `return new Response(page$404.stream({ request, url, params: {} }), {`,
622
+ [
623
+ `status: 404,`,
624
+ `headers: { "content-type": "text/html;charset=UTF-8" },`
625
+ ],
626
+ `});`
627
+ ).writeBlockEnd("}");
628
+ }
629
+ writer.writeLines(`return null;`);
630
+ if (errorRoute) {
631
+ writer.indent--;
632
+ writer.writeBlockStart(`} catch (err) {`).writeBlockStart(
633
+ `if (request.headers.get('Accept')?.includes('text/html')) {`
634
+ ).writeBlock(
635
+ `return new Response(page$500.stream({ request, url, params: {}, error: err }), {`,
636
+ [
637
+ `status: 500,`,
638
+ `headers: { "content-type": "text/html;charset=UTF-8" },`
639
+ ],
640
+ `});`
641
+ ).writeBlockEnd("}").writeLines(`throw err;`).writeBlockEnd("}");
642
+ }
643
+ writer.writeBlockEnd("}");
644
+ writer.write(`
645
+ export function getMatchedRoute(method, url) {
646
+ const route = matchRoute(method, url.pathname);
647
+ if (route) {
648
+ const [handler, params = {}, meta] = route;
649
+ return {
650
+ handler,
651
+ params,
652
+ meta,
653
+ async invoke(request) {
654
+ return await invokeRoute(route, url, request);
655
+ }
656
+ }
657
+ }
658
+ return null;
659
+ }
660
+
661
+ export async function handler(context) {
662
+ const response = await router(context.request);
663
+ //if (response.body) {
664
+ // context.waitUntil?.(once(Readable.from(response.body), "end"));
665
+ //}
666
+ return response;
667
+ }
668
+
669
+ export async function router(request) {
670
+ try {
671
+ const url = new URL(request.url);
672
+ let { pathname } = url;
673
+
674
+ if (pathname !== '/') {
675
+ if (pathname.endsWith('/')) {
676
+ pathname = pathname.replace(/\\/+$/, '');
677
+ `);
678
+ switch (options.trailingSlashes) {
679
+ case "RedirectWithout":
680
+ writer.write(`
681
+ url.pathname = pathname;
682
+ return Response.redirect(url.href);
683
+ `);
684
+ break;
685
+ case "RedirectWith":
686
+ writer.write(`
687
+ } else {
688
+ url.pathname = pathname + '/';
689
+ return Response.redirect(url.href);
690
+ `);
691
+ break;
692
+ case "RewriteWithout":
693
+ writer.write(`
694
+ url.pathname = pathname;
695
+ `);
696
+ break;
697
+ case "RewriteWith":
698
+ writer.write(`
699
+ } else {
700
+ url.pathname = pathname + '/';
701
+ `);
702
+ break;
703
+ }
704
+ writer.write(`
705
+ }
706
+ }
707
+ const route = matchRoute(request.method, pathname);
708
+ return await invokeRoute(route, url, request) || new Response(null, {
709
+ statusText: \`Not Found (No route matched \${pathname})\`,
710
+ status: 404
711
+ });
712
+ } catch (err) {
713
+ const message = import.meta.env.DEV
714
+ ? \`Internal Server Error (\${err.message})\`
715
+ : "Internal Server Error";
716
+
717
+ return new Response(
718
+ JSON.stringify({
719
+ error: {
720
+ message,
721
+ stack: import.meta.env.DEV
722
+ ? \`This will only be seen in development mode\\n\\n\${err.stack}\`
723
+ : ""
724
+ }
725
+ }),
726
+ {
727
+ statusText: message,
728
+ status: 500,
729
+ }
730
+ );
731
+ }
732
+ }`);
733
+ return writer.end();
734
+ }
735
+ function writeRouterVerb(writer, trie, verb, level = 0, pathIndex = 0, useSwitch) {
736
+ const { key, route: value, static: children, dynamic, catchAll } = trie;
737
+ pathIndex += key.length;
738
+ if (level <= 0) {
739
+ level = 0;
740
+ if (value) {
741
+ writer.writeLines(
742
+ `if (pathname === '/') return ${renderMatch(verb, value)}; // ${value.path}`
743
+ );
744
+ }
745
+ if (children || dynamic) {
746
+ writer.writeLines(
747
+ `const segments = pathname.split('/');`,
748
+ `const len = segments.length;`
749
+ );
750
+ }
751
+ } else {
752
+ if (!key) {
753
+ writer.writeBlockStart(`if (segments[${level}]) {`);
754
+ } else if (useSwitch) {
755
+ writer.writeBlockStart(`case '${key}':`);
756
+ } else {
757
+ writer.writeBlockStart(
758
+ `if (segments[${level}]?.toLowerCase() === '${key}') {`
759
+ );
760
+ }
761
+ if (value) {
762
+ writer.writeLines(
763
+ `if (len === ${level + 1}) return ${renderMatch(verb, value)}; // ${value.path}`
764
+ );
765
+ }
766
+ }
767
+ if (children || dynamic) {
768
+ if (children) {
769
+ if (children.size > 1) {
770
+ writer.writeBlockStart(
771
+ `switch(segments[${level + 1}]?.toLowerCase()) {`
772
+ );
773
+ for (const child of children.values()) {
774
+ writeRouterVerb(writer, child, verb, level + 1, pathIndex, true);
775
+ }
776
+ writer.writeBlockEnd("}");
777
+ } else {
778
+ for (const child of children.values()) {
779
+ writeRouterVerb(writer, child, verb, level + 1, pathIndex);
780
+ }
781
+ }
782
+ }
783
+ if (dynamic) {
784
+ writeRouterVerb(writer, dynamic, verb, level + 1, pathIndex);
785
+ }
786
+ }
787
+ if (catchAll) {
788
+ writer.writeLines(
789
+ `return ${renderMatch(verb, catchAll, pathIndex)}; // ${catchAll.path}`
790
+ );
791
+ if (level > 0) {
792
+ writer.indent--;
793
+ }
794
+ } else if (level === 0) {
795
+ writer.writeLines("return;");
796
+ } else if (useSwitch) {
797
+ writer.writeLines("break;").indent--;
798
+ } else {
799
+ writer.writeBlockEnd("}");
800
+ }
801
+ }
802
+ function renderParamsInfo(params, pathIndex) {
803
+ let result = "";
804
+ let catchAll = "";
805
+ let dynamicLength = "";
806
+ for (const { name, index } of params) {
807
+ if (index >= 0) {
808
+ result += result ? ", " : "{ ";
809
+ result += `'${name}': segments[${index + 1}]`;
810
+ dynamicLength += ` + segments[${index + 1}].length`;
811
+ } else if (pathIndex && pathIndex >= 0) {
812
+ catchAll = name;
813
+ }
814
+ }
815
+ if (catchAll) {
816
+ result += result ? ", " : "{ ";
817
+ result += `'${catchAll}': pathname.slice(${pathIndex}${dynamicLength})`;
818
+ }
819
+ return result ? result + " }" : "{}";
820
+ }
821
+ function renderMatch(verb, { index, params, meta }, pathIndex) {
822
+ const tuple = [`${verb}$${index}`];
823
+ if (params == null ? void 0 : params.length) {
824
+ tuple[1] = renderParamsInfo(params, pathIndex);
825
+ }
826
+ if (meta) {
827
+ tuple[2] = `meta$${index}`;
828
+ }
829
+ return `[${tuple.join(", ")}]`;
830
+ }
831
+
832
+ // src/vite/utils/ast.ts
833
+ import * as t from "@babel/types";
834
+ function getExportIdentifiers(astProgramNode) {
835
+ const result = [];
836
+ if (t.isProgram(astProgramNode)) {
837
+ for (const node of astProgramNode.body) {
838
+ if (t.isExportNamedDeclaration(node)) {
839
+ const { declaration, specifiers } = node;
840
+ if (declaration) {
841
+ if (t.isFunctionDeclaration(declaration) && declaration.id) {
842
+ result.push(declaration.id.name);
843
+ } else if (t.isVariableDeclaration(declaration)) {
844
+ for (const declarator of declaration.declarations) {
845
+ if (t.isIdentifier(declarator.id)) {
846
+ result.push(declarator.id.name);
847
+ }
848
+ }
849
+ }
850
+ } else if (specifiers) {
851
+ for (const specifier of specifiers) {
852
+ if (t.isExportSpecifier(specifier) && t.isIdentifier(specifier.exported)) {
853
+ result.push(specifier.exported.name);
854
+ }
855
+ }
856
+ }
857
+ } else if (t.isExportDefaultDeclaration(node)) {
858
+ const { declaration } = node;
859
+ if (t.isObjectExpression(declaration)) {
860
+ for (const property of declaration.properties) {
861
+ if (t.isObjectMember(property) && t.isIdentifier(property.key)) {
862
+ result.push(property.key.name);
863
+ }
864
+ }
865
+ }
866
+ }
867
+ }
868
+ }
869
+ return result;
870
+ }
871
+
872
+ // src/vite/utils/log.ts
873
+ import Table from "cli-table3";
874
+ import kleur from "kleur";
875
+ import { gzipSizeSync } from "gzip-size";
876
+ import prettyBytes from "pretty-bytes";
877
+ var HttpVerbColors = {
878
+ get: kleur.green,
879
+ post: kleur.magenta,
880
+ put: kleur.cyan,
881
+ delete: kleur.red,
882
+ other: kleur.white
883
+ };
884
+ var HttpVerbOrder = {
885
+ get: 0,
886
+ post: 1,
887
+ put: 2,
888
+ delete: 3
889
+ };
890
+ function logRoutesTable(routes, bundle) {
891
+ const hasMiddleware = routes.list.some((route) => route.middleware.length);
892
+ const hasMeta = routes.list.some((route) => route.meta);
893
+ const headings = ["Method", "Path", "Entry"];
894
+ const colAligns = ["left", "left", "left"];
895
+ if (hasMiddleware) {
896
+ headings.push("MW");
897
+ colAligns.push("right");
898
+ }
899
+ if (hasMeta) {
900
+ headings.push("Meta");
901
+ colAligns.push("center");
902
+ }
903
+ headings.push("Size");
904
+ colAligns.push("right");
905
+ const table = new Table({
906
+ head: headings.map((title) => kleur.bold(kleur.white(title.toUpperCase()))),
907
+ wordWrap: true,
908
+ colAligns,
909
+ style: { compact: true }
910
+ });
911
+ for (const route of routes.list.sort((a, b) => b.score - a.score)) {
912
+ const verbs = getVerbs(route).sort(
913
+ (a, b) => HttpVerbOrder[a] - HttpVerbOrder[b]
914
+ );
915
+ let firstRow = true;
916
+ for (const verb of verbs) {
917
+ let size = "";
918
+ const entryType = [];
919
+ if (route.handler) {
920
+ entryType.push(kleur.blue("handler"));
921
+ }
922
+ if (verb === "get" && route.page) {
923
+ entryType.push(kleur.yellow("page"));
924
+ size = prettySize(computeRouteSize(route, bundle));
925
+ }
926
+ const row = [kleur.bold(HttpVerbColors[verb](verb.toUpperCase()))];
927
+ if (verbs.length === 1 || firstRow) {
928
+ row.push({ rowSpan: verbs.length, content: prettyPath(route.path) });
929
+ firstRow = false;
930
+ }
931
+ row.push(entryType.join(" -> "));
932
+ hasMiddleware && row.push(route.middleware.length || "");
933
+ hasMeta && row.push(route.meta ? "\u2713" : "");
934
+ row.push(size || { hAlign: "center", content: "-" });
935
+ table.push(row);
936
+ }
937
+ }
938
+ for (const [key, route] of Object.entries(routes.special).sort()) {
939
+ const row = [kleur.bold(kleur.white("*")), key, kleur.yellow("page")];
940
+ hasMiddleware && row.push("");
941
+ hasMeta && row.push("");
942
+ row.push(prettySize(computeRouteSize(route, bundle)));
943
+ table.push(row);
944
+ }
945
+ console.log(table.toString());
946
+ }
947
+ function computeRouteSize(route, bundle) {
948
+ if (route.page) {
949
+ for (const chunk of Object.values(bundle)) {
950
+ if (chunk.type === "chunk" && chunk.modules[route.page.filePath]) {
951
+ return computeChunkSize(chunk, bundle);
952
+ }
953
+ }
954
+ }
955
+ return 0;
956
+ }
957
+ function computeChunkSize(chunk, bundle, seen = /* @__PURE__ */ new Set()) {
958
+ if (chunk.type === "asset") {
959
+ return gzipSizeSync(chunk.source);
960
+ }
961
+ let size = gzipSizeSync(chunk.code);
962
+ for (const id of chunk.imports) {
963
+ if (!seen.has(id)) {
964
+ size += computeChunkSize(bundle[id], bundle, seen);
965
+ seen.add(id);
966
+ }
967
+ }
968
+ return size;
969
+ }
970
+ function prettySize(size) {
971
+ const _size = prettyBytes(size, {
972
+ minimumFractionDigits: 1,
973
+ maximumFractionDigits: 1
974
+ }).replace(/\sB$/, " B ");
975
+ if (size < 20 * 1e3)
976
+ return kleur.green(_size);
977
+ if (size < 50 * 1e3)
978
+ return kleur.yellow(_size);
979
+ return kleur.bold(kleur.red(_size));
980
+ }
981
+ function prettyPath(path3) {
982
+ return path3.replace(/\/\$\$(.*)$/, (_, p) => "/" + kleur.bold(kleur.dim(`*${p}`))).replace(/\/\$([^/]+)/g, (_, p) => "/" + kleur.bold(kleur.dim(`:${p}`)));
983
+ }
984
+
985
+ // src/vite/utils/config.ts
986
+ var KEY = "__MARKO_SERVE_OPTIONS__";
987
+ function getMarkoServeOptions(viteConfig) {
988
+ return viteConfig[KEY];
989
+ }
990
+ function setMarkoServeOptions(viteConfig, options) {
991
+ viteConfig[KEY] = options;
992
+ return viteConfig;
993
+ }
994
+
995
+ // src/vite/plugin.ts
996
+ var markoExt = ".marko";
997
+ var markoServeFilePrefix2 = "__marko-serve__";
998
+ function isMarkoFile(id) {
999
+ return id.endsWith(markoExt);
1000
+ }
1001
+ function markoServe(opts = {}) {
1002
+ const { routesDir = "src/routes", adapter, ...markoOptions } = opts;
1003
+ let store;
1004
+ let root;
1005
+ let resolvedRoutesDir;
1006
+ let isBuild = false;
1007
+ let isSSRBuild = false;
1008
+ let ssrEntryFiles;
1009
+ let devEntryFile;
1010
+ let devServer;
1011
+ let routes;
1012
+ let routeData;
1013
+ let routeDataFilename = "routes.json";
1014
+ let extractVerbs;
1015
+ let resolvedConfig;
1016
+ let isStale = true;
1017
+ let isRendered = false;
1018
+ const virtualFiles = /* @__PURE__ */ new Map();
1019
+ let times = {
1020
+ routesBuild: 0,
1021
+ routesRender: 0
1022
+ };
1023
+ async function setVirtualFiles(render = false) {
1024
+ for (const route of routes.list) {
1025
+ if (render && route.handler) {
1026
+ route.handler.verbs = await extractVerbs(route.handler.filePath);
1027
+ if (!route.handler.verbs.length) {
1028
+ console.warn(
1029
+ `Did not find any valid exports in middleware entry file:'${route.handler.filePath}' - expected to find any of 'get', 'post', 'put' or 'del'`
1030
+ );
1031
+ }
1032
+ }
1033
+ if (route.page) {
1034
+ virtualFiles.set(
1035
+ path2.join(root, `${markoServeFilePrefix2}route__${route.key}.marko`),
1036
+ render ? renderRouteTemplate(route) : ""
1037
+ );
1038
+ }
1039
+ virtualFiles.set(
1040
+ path2.join(root, `${markoServeFilePrefix2}route__${route.key}.js`),
1041
+ render ? renderRouteEntry(route) : ""
1042
+ );
1043
+ }
1044
+ for (const route of Object.values(routes.special)) {
1045
+ virtualFiles.set(
1046
+ path2.join(root, `${markoServeFilePrefix2}special__${route.key}.marko`),
1047
+ render ? renderRouteTemplate(route) : ""
1048
+ );
1049
+ }
1050
+ virtualFiles.set(
1051
+ "@marko/run/router",
1052
+ render ? renderRouter(routes, opts.codegen) : ""
1053
+ );
1054
+ }
1055
+ const buildVirtualFiles = single(async () => {
1056
+ const startTime = performance.now();
1057
+ routes = await buildRoutes(createFSWalker(resolvedRoutesDir), routesDir);
1058
+ times.routesBuild = performance.now() - startTime;
1059
+ await setVirtualFiles(false);
1060
+ isStale = false;
1061
+ isRendered = false;
1062
+ });
1063
+ const renderVirtualFiles = single(async () => {
1064
+ const startTime = performance.now();
1065
+ await setVirtualFiles(true);
1066
+ times.routesRender = performance.now() - startTime;
1067
+ isRendered = true;
1068
+ });
1069
+ return [
1070
+ {
1071
+ name: "marko-run-vite:pre",
1072
+ enforce: "pre",
1073
+ async config(config, env) {
1074
+ var _a, _b, _c;
1075
+ const externalPluginOptions = getMarkoServeOptions(config);
1076
+ if (externalPluginOptions) {
1077
+ opts = mergeConfig(opts, externalPluginOptions);
1078
+ }
1079
+ const adapterOptions = await ((_a = adapter == null ? void 0 : adapter.pluginOptions) == null ? void 0 : _a.call(adapter, opts));
1080
+ if (adapterOptions) {
1081
+ opts = mergeConfig(opts, adapterOptions);
1082
+ }
1083
+ root = normalizePath(config.root || process.cwd());
1084
+ store = opts.store || new FileStore(
1085
+ `marko-serve-vite-${crypto.createHash("SHA1").update(root).digest("hex")}`
1086
+ );
1087
+ isBuild = env.command === "build";
1088
+ isSSRBuild = isBuild && Boolean((_b = config.build) == null ? void 0 : _b.ssr);
1089
+ resolvedRoutesDir = path2.resolve(root, routesDir);
1090
+ devEntryFile = path2.join(root, "index.html");
1091
+ let pluginConfig = {
1092
+ logLevel: isBuild ? "warn" : void 0,
1093
+ define: isBuild ? {
1094
+ "process.env.NODE_ENV": "'production'"
1095
+ } : void 0,
1096
+ build: {
1097
+ emptyOutDir: isSSRBuild
1098
+ }
1099
+ };
1100
+ const adapterConfig = await ((_c = adapter == null ? void 0 : adapter.viteConfig) == null ? void 0 : _c.call(adapter, config));
1101
+ if (adapterConfig) {
1102
+ pluginConfig = mergeConfig(pluginConfig, adapterConfig);
1103
+ }
1104
+ return setMarkoServeOptions(pluginConfig, opts);
1105
+ },
1106
+ configResolved(config) {
1107
+ resolvedConfig = config;
1108
+ const {
1109
+ ssr,
1110
+ rollupOptions: { input }
1111
+ } = config.build;
1112
+ if (typeof ssr === "string") {
1113
+ ssrEntryFiles = [ssr];
1114
+ } else if (typeof input === "string") {
1115
+ ssrEntryFiles = [input];
1116
+ } else if (Array.isArray(input)) {
1117
+ ssrEntryFiles = input;
1118
+ } else if (input) {
1119
+ ssrEntryFiles = Object.values(input);
1120
+ } else {
1121
+ ssrEntryFiles = [];
1122
+ }
1123
+ },
1124
+ configureServer(_server) {
1125
+ devServer = _server;
1126
+ devServer.watcher.on("all", async (type, filename) => {
1127
+ const file = path2.parse(filename);
1128
+ if (filename.startsWith(resolvedRoutesDir) && isRoutableFile(file.base)) {
1129
+ if (type === "add") {
1130
+ isStale = true;
1131
+ } else if (type === "unlink") {
1132
+ isStale = true;
1133
+ } else if (type === "change") {
1134
+ const match = matchRoutableFile(file.base);
1135
+ if (match === RoutableFileTypes.Handler) {
1136
+ isStale = true;
1137
+ }
1138
+ }
1139
+ if (isStale) {
1140
+ for (const id of virtualFiles.keys()) {
1141
+ devServer.watcher.emit("change", id);
1142
+ }
1143
+ }
1144
+ }
1145
+ });
1146
+ },
1147
+ async buildStart(_options) {
1148
+ if (isBuild && !isSSRBuild) {
1149
+ try {
1150
+ routeData = JSON.parse(
1151
+ await store.get(routeDataFilename)
1152
+ );
1153
+ } catch {
1154
+ this.error(
1155
+ `You must run the "ssr" build before the "browser" build.`
1156
+ );
1157
+ }
1158
+ routes = routeData.routes;
1159
+ times = routeData.times;
1160
+ for (const { key, code } of routeData.files) {
1161
+ virtualFiles.set(key, code);
1162
+ }
1163
+ isStale = false;
1164
+ isRendered = true;
1165
+ } else {
1166
+ extractVerbs = isBuild ? getVerbsFromFileBuild.bind(null, this) : getVerbsFromFileDev.bind(null, devServer);
1167
+ }
1168
+ },
1169
+ async resolveId(importee, importer, { ssr }) {
1170
+ let resolved;
1171
+ if (importee.startsWith(virtualFilePrefix)) {
1172
+ importee = path2.resolve(
1173
+ root,
1174
+ importee.slice(virtualFilePrefix.length + 1)
1175
+ );
1176
+ } else if (!isBuild && importer === devEntryFile && importee.startsWith(`/${markoServeFilePrefix2}`)) {
1177
+ importee = path2.resolve(root, "." + importee);
1178
+ }
1179
+ if (isStale) {
1180
+ await buildVirtualFiles();
1181
+ }
1182
+ if (virtualFiles.has(importee)) {
1183
+ resolved = importee;
1184
+ if (isBuild && !ssr && isMarkoFile(resolved)) {
1185
+ resolved += browserEntryQuery;
1186
+ }
1187
+ }
1188
+ return resolved || null;
1189
+ },
1190
+ async load(id) {
1191
+ var _a;
1192
+ if (virtualFiles.has(id)) {
1193
+ if (!isRendered) {
1194
+ await renderVirtualFiles();
1195
+ if (!isBuild) {
1196
+ await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
1197
+ }
1198
+ }
1199
+ return virtualFiles.get(id);
1200
+ }
1201
+ }
1202
+ },
1203
+ ...markoVitePlugin({
1204
+ ...markoOptions,
1205
+ get store() {
1206
+ return store;
1207
+ }
1208
+ }),
1209
+ {
1210
+ name: "marko-run-vite:post",
1211
+ enforce: "post",
1212
+ async writeBundle(options, bundle) {
1213
+ var _a;
1214
+ if (isSSRBuild) {
1215
+ const builtEntries = Object.values(bundle).reduce(
1216
+ (acc, item) => {
1217
+ if (item.type === "chunk" && item.isEntry) {
1218
+ acc.push(path2.join(options.dir, item.fileName));
1219
+ }
1220
+ return acc;
1221
+ },
1222
+ []
1223
+ );
1224
+ routeData = {
1225
+ routes,
1226
+ files: [],
1227
+ times,
1228
+ builtEntries,
1229
+ sourceEntries: ssrEntryFiles
1230
+ };
1231
+ for (const [key, code] of virtualFiles) {
1232
+ routeData.files.push({ key, code });
1233
+ }
1234
+ await store.set(routeDataFilename, JSON.stringify(routeData));
1235
+ await ((_a = opts == null ? void 0 : opts.emitRoutes) == null ? void 0 : _a.call(opts, routes.list));
1236
+ } else if (isBuild) {
1237
+ logRoutesTable(routes, bundle);
1238
+ }
1239
+ },
1240
+ async closeBundle() {
1241
+ if (isBuild && !isSSRBuild && (adapter == null ? void 0 : adapter.buildEnd)) {
1242
+ await adapter.buildEnd(
1243
+ resolvedConfig,
1244
+ routes.list,
1245
+ routeData.builtEntries,
1246
+ routeData.sourceEntries
1247
+ );
1248
+ }
1249
+ }
1250
+ }
1251
+ ];
1252
+ }
1253
+ async function getVerbsFromFileBuild(context, filePath) {
1254
+ const verbs = [];
1255
+ const result = await context.load({
1256
+ id: filePath,
1257
+ resolveDependencies: false
1258
+ });
1259
+ if (result) {
1260
+ const exportIds = getExportIdentifiers(result.ast);
1261
+ for (const id of exportIds) {
1262
+ const verb = id === "del" ? "delete" : id;
1263
+ if (httpVerbs.includes(verb)) {
1264
+ verbs.push(verb);
1265
+ }
1266
+ }
1267
+ }
1268
+ return verbs;
1269
+ }
1270
+ async function getVerbsFromFileDev(devServer, filePath) {
1271
+ const verbs = [];
1272
+ const result = await devServer.transformRequest(filePath, { ssr: true });
1273
+ if (result && result.code) {
1274
+ const verbMatchReg = /__vite_ssr_exports__,\s+["'](get|post|put|del)["']/g;
1275
+ let match = verbMatchReg.exec(result.code);
1276
+ while (match) {
1277
+ const verb = match[1] === "del" ? "delete" : match[1];
1278
+ if (httpVerbs.includes(verb)) {
1279
+ verbs.push(verb);
1280
+ }
1281
+ match = verbMatchReg.exec(result.code);
1282
+ }
1283
+ }
1284
+ return verbs;
1285
+ }
1286
+ function single(fn) {
1287
+ let promise;
1288
+ return async (...args) => {
1289
+ if (promise) {
1290
+ return promise;
1291
+ }
1292
+ promise = fn(...args);
1293
+ const result = await promise;
1294
+ promise = void 0;
1295
+ return result;
1296
+ };
1297
+ }
1298
+
1299
+ // src/vite/utils/server.ts
1300
+ import net from "net";
1301
+ import cp from "child_process";
1302
+ async function spawnServer(cmd, port = 0, cwd = process.cwd(), wait = 3e4) {
1303
+ if (port <= 0) {
1304
+ port = await getAvailablePort();
1305
+ }
1306
+ const proc = cp.spawn(cmd, {
1307
+ cwd,
1308
+ shell: true,
1309
+ stdio: "inherit",
1310
+ windowsHide: true,
1311
+ env: { NODE_ENV: "development", ...process.env, PORT: `${port}` }
1312
+ });
1313
+ const close = () => {
1314
+ proc.unref();
1315
+ proc.kill();
1316
+ };
1317
+ let remaining = wait > 0 ? wait : Infinity;
1318
+ while (!await isPortInUse(port)) {
1319
+ if (remaining >= 100) {
1320
+ remaining -= 100;
1321
+ await sleep(100);
1322
+ } else {
1323
+ close();
1324
+ throw new Error(
1325
+ `site-write: timeout while wating for server to start on port "${port}".`
1326
+ );
1327
+ }
1328
+ }
1329
+ return {
1330
+ port,
1331
+ close
1332
+ };
1333
+ }
1334
+ async function isPortInUse(port) {
1335
+ return new Promise((resolve) => {
1336
+ const connection = net.connect(port).setNoDelay(true).setKeepAlive(false).on("error", () => done(false)).on("connect", () => done(true));
1337
+ function done(connected) {
1338
+ connection.end();
1339
+ resolve(connected);
1340
+ }
1341
+ });
1342
+ }
1343
+ async function getAvailablePort() {
1344
+ return new Promise((resolve) => {
1345
+ const server = net.createServer().listen(0, () => {
1346
+ const { port } = server.address();
1347
+ server.close(() => resolve(port));
1348
+ });
1349
+ });
1350
+ }
1351
+ function sleep(ms) {
1352
+ return new Promise((resolve) => setTimeout(resolve, ms));
1353
+ }
1354
+ export {
1355
+ markoServe as default,
1356
+ getAvailablePort,
1357
+ isPortInUse,
1358
+ spawnServer
1359
+ };