@marko/run 0.0.1-beta5 → 0.0.1-beta7

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.
@@ -160,7 +160,14 @@ async function buildRoutes(walk, basePath) {
160
160
  if (handler || page) {
161
161
  const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
162
162
  if (routes.has(key)) {
163
- console.warn(`Duplicate route for path ${path3} -- ignoring`, current);
163
+ const existing = routes.get(key);
164
+ const existingFiles = [existing.handler, existing.page].filter(Boolean).map((f) => f.filePath);
165
+ const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
166
+ throw new Error(`Duplicate routes for path ${path3} were defined. A route established by:
167
+ ${existingFiles}
168
+ collides with
169
+ ${currentFiles.join(" and ")}
170
+ `);
164
171
  } else {
165
172
  const index = nextRouteIndex++;
166
173
  routes.set(key, {
@@ -208,14 +215,16 @@ async function buildRoutes(walk, basePath) {
208
215
  const prevChildren = children;
209
216
  const prevCurrent = current;
210
217
  const prevIsRoot = isRoot;
211
- if (name.charCodeAt(0) === 95 || name.charCodeAt(0) === 40 && name.charCodeAt(name.length - 1) === 41 || name.toLowerCase() === "index") {
218
+ if (name.charCodeAt(0) === 95) {
212
219
  } else {
213
220
  if (name.charCodeAt(0) === 36) {
214
221
  if (name.charCodeAt(1) === 36) {
215
- paramStack.push({
216
- name: name.slice(2) || "rest",
217
- index: -1
218
- });
222
+ if (name.length > 2) {
223
+ paramStack.push({
224
+ name: name.slice(2),
225
+ index: -1
226
+ });
227
+ }
219
228
  } else if (name.length > 1) {
220
229
  paramStack.push({
221
230
  name: name.slice(1),
@@ -534,7 +543,7 @@ function renderRouteEntry(route) {
534
543
  );
535
544
  }
536
545
  if (middleware.length) {
537
- const names = middleware.map((m) => `mware$${m.id}`);
546
+ const names = middleware.map((m) => `mware${m.id}`);
538
547
  imports.writeLines(
539
548
  `import { ${names.join(
540
549
  ", "
@@ -545,9 +554,9 @@ function renderRouteEntry(route) {
545
554
  writer.writeLines("");
546
555
  const names = [];
547
556
  for (const verb of handler.verbs) {
548
- const name = verb === "delete" ? "del" : verb;
549
- names.push(name);
550
- writer.writeLines(`const handler$${name} = normalize(${name});`);
557
+ const importName = verb.toUpperCase();
558
+ names.push(importName);
559
+ writer.writeLines(`const ${verb}Handler = normalize(${importName});`);
551
560
  }
552
561
  imports.writeLines(
553
562
  `import { ${names.join(", ")} } from './${handler.importPath}';`
@@ -560,7 +569,7 @@ function renderRouteEntry(route) {
560
569
  }
561
570
  if (meta) {
562
571
  imports.writeLines(
563
- `export { default as meta$${index} } from './${meta.importPath}';`
572
+ `export { default as meta${index} } from './${meta.importPath}';`
564
573
  );
565
574
  }
566
575
  for (const verb of verbs) {
@@ -591,14 +600,19 @@ function writeRouteEntryHandler(writer, route, verb) {
591
600
  let nextName;
592
601
  let currentName;
593
602
  let hasBody = false;
594
- writer.writeLines("").writeBlockStart(
595
- `export async function ${verb}$${index}(context, buildInput) {`
596
- );
603
+ writer.writeLines("");
604
+ if (page) {
605
+ writer.writeBlockStart(
606
+ `export async function ${verb}${index}(context, buildInput) {`
607
+ );
608
+ } else {
609
+ writer.writeBlockStart(`export async function ${verb}${index}(context) {`);
610
+ }
597
611
  const continuations = writer.branch("cont");
598
612
  if (page && verb === "get") {
599
613
  currentName = "__page";
600
614
  if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
601
- const name = `handler$${verb}`;
615
+ const name = `${verb}Handler`;
602
616
  writePageResponse(continuations, currentName);
603
617
  if (len) {
604
618
  nextName = currentName;
@@ -616,7 +630,7 @@ function writeRouteEntryHandler(writer, route, verb) {
616
630
  hasBody = true;
617
631
  }
618
632
  } else if (handler) {
619
- const name = `handler$${verb}`;
633
+ const name = `${verb}Handler`;
620
634
  currentName = `__${name}`;
621
635
  nextName = "noContent";
622
636
  if (len) {
@@ -632,7 +646,7 @@ function writeRouteEntryHandler(writer, route, verb) {
632
646
  let i = len;
633
647
  while (i--) {
634
648
  const { id } = middleware[i];
635
- const name = `mware$${id}`;
649
+ const name = `mware${id}`;
636
650
  nextName = currentName;
637
651
  currentName = i ? `__${name}` : "";
638
652
  writeMiddleware(continuations, name, nextName, currentName);
@@ -648,12 +662,12 @@ function renderRouter(routes, options = {
648
662
  writer.writeLines(`// @marko/run/router`);
649
663
  const imports = writer.branch("imports");
650
664
  imports.writeLines(
651
- `import { RequestNotHandled, RequestNotMatched, createInput } from 'virtual:marko-run/internal';`
665
+ `import { NotHandled, NotMatched, createInput } from 'virtual:marko-run/internal';`
652
666
  );
653
667
  for (const route of routes.list) {
654
668
  const verbs = getVerbs(route);
655
- const names = verbs.map((verb) => `${verb}$${route.index}`);
656
- route.meta && names.push(`meta$${route.index}`);
669
+ const names = verbs.map((verb) => `${verb}${route.index}`);
670
+ route.meta && names.push(`meta${route.index}`);
657
671
  imports.writeLines(
658
672
  `import { ${names.join(
659
673
  ", "
@@ -662,10 +676,16 @@ function renderRouter(routes, options = {
662
676
  }
663
677
  for (const { key } of Object.values(routes.special)) {
664
678
  imports.writeLines(
665
- `import page$${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
679
+ `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
666
680
  );
667
681
  }
668
- writer.writeLines(``).writeBlockStart(`function findRoute(method, pathname) {`).writeBlockStart(`switch (method.toLowerCase()) {`);
682
+ writer.writeLines(``).writeBlockStart(`export function match(method, pathname) {`).writeLines(
683
+ `if (!pathname) {
684
+ pathname = '/';
685
+ } else if (pathname.charAt(0) !== '/') {
686
+ pathname = '/' + pathname;
687
+ }`
688
+ ).writeBlockStart(`switch (method.toLowerCase()) {`);
669
689
  for (const verb of httpVerbs) {
670
690
  const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
671
691
  if (filteredRoutes.length) {
@@ -677,16 +697,12 @@ function renderRouter(routes, options = {
677
697
  }
678
698
  writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
679
699
  writer.write(`
680
- export function matchRoute(method, pathname) {
681
- if (!pathname) {
682
- pathname = '/';
683
- } else if (pathname.charAt(0) !== '/') {
684
- pathname = '/' + pathname;
685
- }
686
- return findRoute(method, pathname);
687
- }
688
-
689
- export async function invokeRoute(route, context) {
700
+ export async function invoke(route, request, platform, url = new URL(request.url)) {
701
+ const context = {
702
+ url,
703
+ request,
704
+ platform
705
+ };
690
706
  try {
691
707
  const buildInput = createInput(context);
692
708
  if (route) {
@@ -696,9 +712,9 @@ export async function invokeRoute(route, context) {
696
712
  const response = await route.handler(context, buildInput);
697
713
  if (response) return response;
698
714
  } catch (error) {
699
- if (error === RequestNotHandled) {
715
+ if (error === NotHandled) {
700
716
  return;
701
- } else if (error !== RequestNotMatched) {
717
+ } else if (error !== NotMatched) {
702
718
  throw error;
703
719
  }
704
720
  }
@@ -710,7 +726,7 @@ export async function invokeRoute(route, context) {
710
726
  context.meta = {};
711
727
  }
712
728
  if (context.request.headers.get('Accept')?.includes('text/html')) {
713
- return new Response(page$404.stream(buildInput()), {
729
+ return new Response(page404.stream(buildInput()), {
714
730
  status: 404,
715
731
  headers: { "content-type": "text/html;charset=UTF-8" },
716
732
  });
@@ -726,7 +742,7 @@ export async function invokeRoute(route, context) {
726
742
  writer.writeBlockStart(
727
743
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
728
744
  ).writeBlock(
729
- `return new Response(page$500.stream(buildInput({ error })), {`,
745
+ `return new Response(page500.stream(buildInput({ error })), {`,
730
746
  [
731
747
  `status: 500,`,
732
748
  `headers: { "content-type": "text/html;charset=UTF-8" },`
@@ -735,9 +751,9 @@ export async function invokeRoute(route, context) {
735
751
  ).writeBlockEnd("}");
736
752
  }
737
753
  writer.writeLines(`throw error;`).writeBlockEnd("}").writeBlockEnd("}").write(`
738
- export async function router(context) {
754
+ export async function fetch(request, platform) {
739
755
  try {
740
- const { url, method } = context;
756
+ const url = new URL(request.url);
741
757
  let { pathname } = url;`);
742
758
  switch (options.trailingSlashes) {
743
759
  case "RedirectWithout":
@@ -769,8 +785,8 @@ export async function router(context) {
769
785
  }
770
786
  writer.write(`
771
787
 
772
- const route = matchRoute(method, pathname);
773
- return await invokeRoute(route, context);
788
+ const route = match(request.method, pathname);
789
+ return await invoke(route, request, platform, url);
774
790
  } catch (error) {
775
791
  const message = import.meta.env.DEV
776
792
  ? \`Internal Server Error (\${error.message})\`
@@ -948,9 +964,9 @@ function renderParamsInfoType(params) {
948
964
  }
949
965
  function renderMatch(verb, route, pathIndex) {
950
966
  var _a;
951
- const handler = `${verb}$${route.index}`;
967
+ const handler = `${verb}${route.index}`;
952
968
  const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
953
- const meta = route.meta ? `meta$${route.index}` : "{}";
969
+ const meta = route.meta ? `meta${route.index}` : "{}";
954
970
  return `{ handler: ${handler}, params: ${params}, meta: ${meta} }`;
955
971
  }
956
972
  function renderMiddleware(middleware) {
@@ -962,9 +978,9 @@ function renderMiddleware(middleware) {
962
978
  imports.writeLines(`import { normalize } from 'virtual:marko-run/internal';`);
963
979
  writer.writeLines("");
964
980
  for (const { id, importPath } of middleware) {
965
- const importName = `mware${id}`;
981
+ const importName = `middleware${id}`;
966
982
  imports.writeLines(`import ${importName} from './${importPath}';`);
967
- writer.writeLines(`export const mware$${id} = normalize(${importName});`);
983
+ writer.writeLines(`export const mware${id} = normalize(${importName});`);
968
984
  }
969
985
  imports.join();
970
986
  return writer.end();
@@ -979,7 +995,7 @@ function stripTsExtension(path3) {
979
995
  }
980
996
  return path3;
981
997
  }
982
- function renderRouteTypeInfo(routes, pathPrefix = ".") {
998
+ function renderRouteTypeInfo(routes, pathPrefix = ".", adapterTypes = "") {
983
999
  var _a, _b;
984
1000
  const writer = createStringWriter();
985
1001
  writer.writeLines(
@@ -987,8 +1003,10 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
987
1003
  WARNING: This file is automatically generated and any changes made to it will be overwritten without warning.
988
1004
  Do NOT manually edit this file or your changes will be lost.
989
1005
  */
990
- `,
991
- `import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";
1006
+ `,
1007
+ `import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";`,
1008
+ adapterTypes,
1009
+ `
992
1010
 
993
1011
  declare global {
994
1012
  namespace MarkoRun {`
@@ -1058,7 +1076,7 @@ declare module '${pathPrefix}/${page.relativePath}' {
1058
1076
 
1059
1077
  namespace MarkoRun {
1060
1078
  type CurrentRoute = ${routeType};
1061
- type CurrentContext = RouteContext<CurrentRoute>;
1079
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1062
1080
  }
1063
1081
  }`);
1064
1082
  }
@@ -1123,7 +1141,7 @@ declare module '${pathPrefix}/${file.relativePath}' {
1123
1141
 
1124
1142
  namespace MarkoRun {
1125
1143
  type CurrentRoute = ${routeTypes.join(" | ")};
1126
- type CurrentContext = RouteContext<CurrentRoute>;
1144
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1127
1145
  }
1128
1146
  }`);
1129
1147
  }
@@ -1141,7 +1159,7 @@ declare module '${pathPrefix}/${route.page.relativePath}' {
1141
1159
 
1142
1160
  namespace MarkoRun {
1143
1161
  type CurrentRoute = Route;
1144
- type CurrentContext = RouteContext<CurrentRoute>;
1162
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1145
1163
  }
1146
1164
  }`);
1147
1165
  }
@@ -1154,7 +1172,7 @@ function writeRouteTypeModule(writer, pathPrefix, path3, routeType) {
1154
1172
  declare module '${pathPrefix}/${stripTsExtension(path3)}' {
1155
1173
  namespace MarkoRun {
1156
1174
  type CurrentRoute = ${routeType};
1157
- type CurrentContext = RouteContext<CurrentRoute>;
1175
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1158
1176
  type Handler<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']> = HandlerLike<CurrentRoute>;
1159
1177
  function route(handler: Handler): typeof handler;
1160
1178
  function route<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']>(handler: Handler): typeof handler;
@@ -1385,7 +1403,7 @@ function markoServe(opts = {}) {
1385
1403
  ))) {
1386
1404
  const filepath = import_path2.default.join(typesDir, "routes.d.ts");
1387
1405
  const adapterTypeInfo = (adapter == null ? void 0 : adapter.writeTypeInfo) && await (adapter == null ? void 0 : adapter.writeTypeInfo());
1388
- const data = renderRouteTypeInfo(routes, import_path2.default.relative(typesDir, routesDir)) + adapterTypeInfo;
1406
+ const data = renderRouteTypeInfo(routes, import_path2.default.relative(typesDir, routesDir), adapterTypeInfo);
1389
1407
  if (data !== typesFile || !import_fs2.default.existsSync(filepath)) {
1390
1408
  await ensureDir(typesDir);
1391
1409
  await import_fs2.default.promises.writeFile(filepath, typesFile = data);
@@ -1652,8 +1670,8 @@ async function getVerbsFromFileBuild(context, filePath) {
1652
1670
  if (result) {
1653
1671
  const exportIds = getExportIdentifiers(result.ast);
1654
1672
  for (const id of exportIds) {
1655
- const verb = id === "del" ? "delete" : id;
1656
- if (httpVerbs.includes(verb)) {
1673
+ const verb = id.toLowerCase();
1674
+ if (id === verb.toUpperCase() && httpVerbs.includes(verb)) {
1657
1675
  verbs.push(verb);
1658
1676
  }
1659
1677
  }
@@ -1664,12 +1682,19 @@ async function getVerbsFromFileDev(devServer, filePath) {
1664
1682
  const verbs = [];
1665
1683
  const result = await devServer.transformRequest(filePath, { ssr: true });
1666
1684
  if (result && result.code) {
1667
- const verbMatchReg = /__vite_ssr_exports__,\s+["'](get|post|put|del)["']/g;
1685
+ const verbMatchReg = /__vite_ssr_exports__,\s+["'](GET|POST|PUT|DELETE)["']/gi;
1668
1686
  let match = verbMatchReg.exec(result.code);
1669
1687
  while (match) {
1670
- const verb = match[1] === "del" ? "delete" : match[1];
1688
+ const id = match[1];
1689
+ const verb = id.toLowerCase();
1671
1690
  if (httpVerbs.includes(verb)) {
1672
- verbs.push(verb);
1691
+ if (id === verb.toUpperCase()) {
1692
+ verbs.push(verb);
1693
+ } else {
1694
+ console.warn(
1695
+ `Found export '${id}' in handler ${filePath} which is close to '${verb.toUpperCase()}'. Exported handlers need to be uppercase: GET, POST, PUT or DELETE.`
1696
+ );
1697
+ }
1673
1698
  }
1674
1699
  match = verbMatchReg.exec(result.code);
1675
1700
  }
@@ -123,7 +123,14 @@ async function buildRoutes(walk, basePath) {
123
123
  if (handler || page) {
124
124
  const key = path3.replace(/(\$\$?)[^\/]*/g, "$1").replace(/^\/+/, "").replace(/[^a-z0-9_$\/]+/gi, "").replace(/\//g, "__") || "index";
125
125
  if (routes.has(key)) {
126
- console.warn(`Duplicate route for path ${path3} -- ignoring`, current);
126
+ const existing = routes.get(key);
127
+ const existingFiles = [existing.handler, existing.page].filter(Boolean).map((f) => f.filePath);
128
+ const currentFiles = [handler, page].filter(Boolean).map((f) => f.filePath);
129
+ throw new Error(`Duplicate routes for path ${path3} were defined. A route established by:
130
+ ${existingFiles}
131
+ collides with
132
+ ${currentFiles.join(" and ")}
133
+ `);
127
134
  } else {
128
135
  const index = nextRouteIndex++;
129
136
  routes.set(key, {
@@ -171,14 +178,16 @@ async function buildRoutes(walk, basePath) {
171
178
  const prevChildren = children;
172
179
  const prevCurrent = current;
173
180
  const prevIsRoot = isRoot;
174
- if (name.charCodeAt(0) === 95 || name.charCodeAt(0) === 40 && name.charCodeAt(name.length - 1) === 41 || name.toLowerCase() === "index") {
181
+ if (name.charCodeAt(0) === 95) {
175
182
  } else {
176
183
  if (name.charCodeAt(0) === 36) {
177
184
  if (name.charCodeAt(1) === 36) {
178
- paramStack.push({
179
- name: name.slice(2) || "rest",
180
- index: -1
181
- });
185
+ if (name.length > 2) {
186
+ paramStack.push({
187
+ name: name.slice(2),
188
+ index: -1
189
+ });
190
+ }
182
191
  } else if (name.length > 1) {
183
192
  paramStack.push({
184
193
  name: name.slice(1),
@@ -497,7 +506,7 @@ function renderRouteEntry(route) {
497
506
  );
498
507
  }
499
508
  if (middleware.length) {
500
- const names = middleware.map((m) => `mware$${m.id}`);
509
+ const names = middleware.map((m) => `mware${m.id}`);
501
510
  imports.writeLines(
502
511
  `import { ${names.join(
503
512
  ", "
@@ -508,9 +517,9 @@ function renderRouteEntry(route) {
508
517
  writer.writeLines("");
509
518
  const names = [];
510
519
  for (const verb of handler.verbs) {
511
- const name = verb === "delete" ? "del" : verb;
512
- names.push(name);
513
- writer.writeLines(`const handler$${name} = normalize(${name});`);
520
+ const importName = verb.toUpperCase();
521
+ names.push(importName);
522
+ writer.writeLines(`const ${verb}Handler = normalize(${importName});`);
514
523
  }
515
524
  imports.writeLines(
516
525
  `import { ${names.join(", ")} } from './${handler.importPath}';`
@@ -523,7 +532,7 @@ function renderRouteEntry(route) {
523
532
  }
524
533
  if (meta) {
525
534
  imports.writeLines(
526
- `export { default as meta$${index} } from './${meta.importPath}';`
535
+ `export { default as meta${index} } from './${meta.importPath}';`
527
536
  );
528
537
  }
529
538
  for (const verb of verbs) {
@@ -554,14 +563,19 @@ function writeRouteEntryHandler(writer, route, verb) {
554
563
  let nextName;
555
564
  let currentName;
556
565
  let hasBody = false;
557
- writer.writeLines("").writeBlockStart(
558
- `export async function ${verb}$${index}(context, buildInput) {`
559
- );
566
+ writer.writeLines("");
567
+ if (page) {
568
+ writer.writeBlockStart(
569
+ `export async function ${verb}${index}(context, buildInput) {`
570
+ );
571
+ } else {
572
+ writer.writeBlockStart(`export async function ${verb}${index}(context) {`);
573
+ }
560
574
  const continuations = writer.branch("cont");
561
575
  if (page && verb === "get") {
562
576
  currentName = "__page";
563
577
  if ((_a = handler == null ? void 0 : handler.verbs) == null ? void 0 : _a.includes(verb)) {
564
- const name = `handler$${verb}`;
578
+ const name = `${verb}Handler`;
565
579
  writePageResponse(continuations, currentName);
566
580
  if (len) {
567
581
  nextName = currentName;
@@ -579,7 +593,7 @@ function writeRouteEntryHandler(writer, route, verb) {
579
593
  hasBody = true;
580
594
  }
581
595
  } else if (handler) {
582
- const name = `handler$${verb}`;
596
+ const name = `${verb}Handler`;
583
597
  currentName = `__${name}`;
584
598
  nextName = "noContent";
585
599
  if (len) {
@@ -595,7 +609,7 @@ function writeRouteEntryHandler(writer, route, verb) {
595
609
  let i = len;
596
610
  while (i--) {
597
611
  const { id } = middleware[i];
598
- const name = `mware$${id}`;
612
+ const name = `mware${id}`;
599
613
  nextName = currentName;
600
614
  currentName = i ? `__${name}` : "";
601
615
  writeMiddleware(continuations, name, nextName, currentName);
@@ -611,12 +625,12 @@ function renderRouter(routes, options = {
611
625
  writer.writeLines(`// @marko/run/router`);
612
626
  const imports = writer.branch("imports");
613
627
  imports.writeLines(
614
- `import { RequestNotHandled, RequestNotMatched, createInput } from 'virtual:marko-run/internal';`
628
+ `import { NotHandled, NotMatched, createInput } from 'virtual:marko-run/internal';`
615
629
  );
616
630
  for (const route of routes.list) {
617
631
  const verbs = getVerbs(route);
618
- const names = verbs.map((verb) => `${verb}$${route.index}`);
619
- route.meta && names.push(`meta$${route.index}`);
632
+ const names = verbs.map((verb) => `${verb}${route.index}`);
633
+ route.meta && names.push(`meta${route.index}`);
620
634
  imports.writeLines(
621
635
  `import { ${names.join(
622
636
  ", "
@@ -625,10 +639,16 @@ function renderRouter(routes, options = {
625
639
  }
626
640
  for (const { key } of Object.values(routes.special)) {
627
641
  imports.writeLines(
628
- `import page$${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
642
+ `import page${key} from '${virtualFilePrefix}/${markoRunFilePrefix}special__${key}.marko${serverEntryQuery}';`
629
643
  );
630
644
  }
631
- writer.writeLines(``).writeBlockStart(`function findRoute(method, pathname) {`).writeBlockStart(`switch (method.toLowerCase()) {`);
645
+ writer.writeLines(``).writeBlockStart(`export function match(method, pathname) {`).writeLines(
646
+ `if (!pathname) {
647
+ pathname = '/';
648
+ } else if (pathname.charAt(0) !== '/') {
649
+ pathname = '/' + pathname;
650
+ }`
651
+ ).writeBlockStart(`switch (method.toLowerCase()) {`);
632
652
  for (const verb of httpVerbs) {
633
653
  const filteredRoutes = routes.list.filter((route) => hasVerb(route, verb));
634
654
  if (filteredRoutes.length) {
@@ -640,16 +660,12 @@ function renderRouter(routes, options = {
640
660
  }
641
661
  writer.writeBlockEnd("}").writeLines("return null;").writeBlockEnd("}");
642
662
  writer.write(`
643
- export function matchRoute(method, pathname) {
644
- if (!pathname) {
645
- pathname = '/';
646
- } else if (pathname.charAt(0) !== '/') {
647
- pathname = '/' + pathname;
648
- }
649
- return findRoute(method, pathname);
650
- }
651
-
652
- export async function invokeRoute(route, context) {
663
+ export async function invoke(route, request, platform, url = new URL(request.url)) {
664
+ const context = {
665
+ url,
666
+ request,
667
+ platform
668
+ };
653
669
  try {
654
670
  const buildInput = createInput(context);
655
671
  if (route) {
@@ -659,9 +675,9 @@ export async function invokeRoute(route, context) {
659
675
  const response = await route.handler(context, buildInput);
660
676
  if (response) return response;
661
677
  } catch (error) {
662
- if (error === RequestNotHandled) {
678
+ if (error === NotHandled) {
663
679
  return;
664
- } else if (error !== RequestNotMatched) {
680
+ } else if (error !== NotMatched) {
665
681
  throw error;
666
682
  }
667
683
  }
@@ -673,7 +689,7 @@ export async function invokeRoute(route, context) {
673
689
  context.meta = {};
674
690
  }
675
691
  if (context.request.headers.get('Accept')?.includes('text/html')) {
676
- return new Response(page$404.stream(buildInput()), {
692
+ return new Response(page404.stream(buildInput()), {
677
693
  status: 404,
678
694
  headers: { "content-type": "text/html;charset=UTF-8" },
679
695
  });
@@ -689,7 +705,7 @@ export async function invokeRoute(route, context) {
689
705
  writer.writeBlockStart(
690
706
  `if (context.request.headers.get('Accept')?.includes('text/html')) {`
691
707
  ).writeBlock(
692
- `return new Response(page$500.stream(buildInput({ error })), {`,
708
+ `return new Response(page500.stream(buildInput({ error })), {`,
693
709
  [
694
710
  `status: 500,`,
695
711
  `headers: { "content-type": "text/html;charset=UTF-8" },`
@@ -698,9 +714,9 @@ export async function invokeRoute(route, context) {
698
714
  ).writeBlockEnd("}");
699
715
  }
700
716
  writer.writeLines(`throw error;`).writeBlockEnd("}").writeBlockEnd("}").write(`
701
- export async function router(context) {
717
+ export async function fetch(request, platform) {
702
718
  try {
703
- const { url, method } = context;
719
+ const url = new URL(request.url);
704
720
  let { pathname } = url;`);
705
721
  switch (options.trailingSlashes) {
706
722
  case "RedirectWithout":
@@ -732,8 +748,8 @@ export async function router(context) {
732
748
  }
733
749
  writer.write(`
734
750
 
735
- const route = matchRoute(method, pathname);
736
- return await invokeRoute(route, context);
751
+ const route = match(request.method, pathname);
752
+ return await invoke(route, request, platform, url);
737
753
  } catch (error) {
738
754
  const message = import.meta.env.DEV
739
755
  ? \`Internal Server Error (\${error.message})\`
@@ -911,9 +927,9 @@ function renderParamsInfoType(params) {
911
927
  }
912
928
  function renderMatch(verb, route, pathIndex) {
913
929
  var _a;
914
- const handler = `${verb}$${route.index}`;
930
+ const handler = `${verb}${route.index}`;
915
931
  const params = ((_a = route.params) == null ? void 0 : _a.length) ? renderParamsInfo(route.params, pathIndex) : "{}";
916
- const meta = route.meta ? `meta$${route.index}` : "{}";
932
+ const meta = route.meta ? `meta${route.index}` : "{}";
917
933
  return `{ handler: ${handler}, params: ${params}, meta: ${meta} }`;
918
934
  }
919
935
  function renderMiddleware(middleware) {
@@ -925,9 +941,9 @@ function renderMiddleware(middleware) {
925
941
  imports.writeLines(`import { normalize } from 'virtual:marko-run/internal';`);
926
942
  writer.writeLines("");
927
943
  for (const { id, importPath } of middleware) {
928
- const importName = `mware${id}`;
944
+ const importName = `middleware${id}`;
929
945
  imports.writeLines(`import ${importName} from './${importPath}';`);
930
- writer.writeLines(`export const mware$${id} = normalize(${importName});`);
946
+ writer.writeLines(`export const mware${id} = normalize(${importName});`);
931
947
  }
932
948
  imports.join();
933
949
  return writer.end();
@@ -942,7 +958,7 @@ function stripTsExtension(path3) {
942
958
  }
943
959
  return path3;
944
960
  }
945
- function renderRouteTypeInfo(routes, pathPrefix = ".") {
961
+ function renderRouteTypeInfo(routes, pathPrefix = ".", adapterTypes = "") {
946
962
  var _a, _b;
947
963
  const writer = createStringWriter();
948
964
  writer.writeLines(
@@ -950,8 +966,10 @@ function renderRouteTypeInfo(routes, pathPrefix = ".") {
950
966
  WARNING: This file is automatically generated and any changes made to it will be overwritten without warning.
951
967
  Do NOT manually edit this file or your changes will be lost.
952
968
  */
953
- `,
954
- `import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";
969
+ `,
970
+ `import type { HandlerLike, Route, RouteContext, ValidatePath, ValidateHref } from "@marko/run";`,
971
+ adapterTypes,
972
+ `
955
973
 
956
974
  declare global {
957
975
  namespace MarkoRun {`
@@ -1021,7 +1039,7 @@ declare module '${pathPrefix}/${page.relativePath}' {
1021
1039
 
1022
1040
  namespace MarkoRun {
1023
1041
  type CurrentRoute = ${routeType};
1024
- type CurrentContext = RouteContext<CurrentRoute>;
1042
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1025
1043
  }
1026
1044
  }`);
1027
1045
  }
@@ -1086,7 +1104,7 @@ declare module '${pathPrefix}/${file.relativePath}' {
1086
1104
 
1087
1105
  namespace MarkoRun {
1088
1106
  type CurrentRoute = ${routeTypes.join(" | ")};
1089
- type CurrentContext = RouteContext<CurrentRoute>;
1107
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1090
1108
  }
1091
1109
  }`);
1092
1110
  }
@@ -1104,7 +1122,7 @@ declare module '${pathPrefix}/${route.page.relativePath}' {
1104
1122
 
1105
1123
  namespace MarkoRun {
1106
1124
  type CurrentRoute = Route;
1107
- type CurrentContext = RouteContext<CurrentRoute>;
1125
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1108
1126
  }
1109
1127
  }`);
1110
1128
  }
@@ -1117,7 +1135,7 @@ function writeRouteTypeModule(writer, pathPrefix, path3, routeType) {
1117
1135
  declare module '${pathPrefix}/${stripTsExtension(path3)}' {
1118
1136
  namespace MarkoRun {
1119
1137
  type CurrentRoute = ${routeType};
1120
- type CurrentContext = RouteContext<CurrentRoute>;
1138
+ type CurrentContext = RouteContext<RouteContext['platform'], CurrentRoute>;
1121
1139
  type Handler<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']> = HandlerLike<CurrentRoute>;
1122
1140
  function route(handler: Handler): typeof handler;
1123
1141
  function route<_Params = CurrentRoute['params'], _Meta = CurrentRoute['meta']>(handler: Handler): typeof handler;
@@ -1347,7 +1365,7 @@ function markoServe(opts = {}) {
1347
1365
  ))) {
1348
1366
  const filepath = path2.join(typesDir, "routes.d.ts");
1349
1367
  const adapterTypeInfo = (adapter == null ? void 0 : adapter.writeTypeInfo) && await (adapter == null ? void 0 : adapter.writeTypeInfo());
1350
- const data = renderRouteTypeInfo(routes, path2.relative(typesDir, routesDir)) + adapterTypeInfo;
1368
+ const data = renderRouteTypeInfo(routes, path2.relative(typesDir, routesDir), adapterTypeInfo);
1351
1369
  if (data !== typesFile || !fs2.existsSync(filepath)) {
1352
1370
  await ensureDir(typesDir);
1353
1371
  await fs2.promises.writeFile(filepath, typesFile = data);
@@ -1614,8 +1632,8 @@ async function getVerbsFromFileBuild(context, filePath) {
1614
1632
  if (result) {
1615
1633
  const exportIds = getExportIdentifiers(result.ast);
1616
1634
  for (const id of exportIds) {
1617
- const verb = id === "del" ? "delete" : id;
1618
- if (httpVerbs.includes(verb)) {
1635
+ const verb = id.toLowerCase();
1636
+ if (id === verb.toUpperCase() && httpVerbs.includes(verb)) {
1619
1637
  verbs.push(verb);
1620
1638
  }
1621
1639
  }
@@ -1626,12 +1644,19 @@ async function getVerbsFromFileDev(devServer, filePath) {
1626
1644
  const verbs = [];
1627
1645
  const result = await devServer.transformRequest(filePath, { ssr: true });
1628
1646
  if (result && result.code) {
1629
- const verbMatchReg = /__vite_ssr_exports__,\s+["'](get|post|put|del)["']/g;
1647
+ const verbMatchReg = /__vite_ssr_exports__,\s+["'](GET|POST|PUT|DELETE)["']/gi;
1630
1648
  let match = verbMatchReg.exec(result.code);
1631
1649
  while (match) {
1632
- const verb = match[1] === "del" ? "delete" : match[1];
1650
+ const id = match[1];
1651
+ const verb = id.toLowerCase();
1633
1652
  if (httpVerbs.includes(verb)) {
1634
- verbs.push(verb);
1653
+ if (id === verb.toUpperCase()) {
1654
+ verbs.push(verb);
1655
+ } else {
1656
+ console.warn(
1657
+ `Found export '${id}' in handler ${filePath} which is close to '${verb.toUpperCase()}'. Exported handlers need to be uppercase: GET, POST, PUT or DELETE.`
1658
+ );
1659
+ }
1635
1660
  }
1636
1661
  match = verbMatchReg.exec(result.code);
1637
1662
  }