@emkodev/emroute 1.7.3 → 1.8.0-beta.2

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 (238) hide show
  1. package/README.md +1 -1
  2. package/core/component/abstract.component.ts +74 -0
  3. package/{src → core}/component/page.component.ts +3 -61
  4. package/core/component/widget.component.ts +54 -0
  5. package/core/pipeline/pipeline.ts +224 -0
  6. package/{src/renderer/ssr → core/renderer}/html.renderer.ts +26 -47
  7. package/{src/renderer/ssr → core/renderer}/md.renderer.ts +22 -41
  8. package/{src/renderer/ssr → core/renderer}/ssr.renderer.ts +44 -58
  9. package/{src/route → core/router}/route.resolver.ts +1 -10
  10. package/core/router/route.trie.ts +175 -0
  11. package/core/runtime/abstract.runtime.ts +47 -0
  12. package/core/server/emroute.server.ts +324 -0
  13. package/core/type/component.type.ts +39 -0
  14. package/core/type/element.type.ts +10 -0
  15. package/core/type/logger.type.ts +20 -0
  16. package/core/type/markdown.type.ts +8 -0
  17. package/core/type/route-tree.type.ts +28 -0
  18. package/core/type/route.type.ts +75 -0
  19. package/core/type/widget.type.ts +27 -0
  20. package/core/util/html.util.ts +50 -0
  21. package/{src → core}/util/md.util.ts +3 -5
  22. package/{src/route → core/util}/route-tree.util.ts +0 -2
  23. package/{src → core}/util/widget-resolve.util.ts +15 -46
  24. package/{src → core}/widget/widget.parser.ts +2 -23
  25. package/core/widget/widget.registry.ts +36 -0
  26. package/dist/core/component/abstract.component.d.ts +48 -0
  27. package/dist/core/component/abstract.component.js +42 -0
  28. package/dist/core/component/abstract.component.js.map +1 -0
  29. package/dist/core/component/page.component.d.ts +23 -0
  30. package/dist/core/component/page.component.js +49 -0
  31. package/dist/core/component/page.component.js.map +1 -0
  32. package/dist/core/component/widget.component.d.ts +17 -0
  33. package/dist/core/component/widget.component.js +37 -0
  34. package/dist/core/component/widget.component.js.map +1 -0
  35. package/dist/core/pipeline/pipeline.d.ts +61 -0
  36. package/dist/core/pipeline/pipeline.js +189 -0
  37. package/dist/core/pipeline/pipeline.js.map +1 -0
  38. package/dist/{src/renderer/ssr → core/renderer}/html.renderer.d.ts +8 -24
  39. package/dist/{src/renderer/ssr → core/renderer}/html.renderer.js +20 -35
  40. package/dist/core/renderer/html.renderer.js.map +1 -0
  41. package/dist/{src/renderer/ssr → core/renderer}/md.renderer.d.ts +6 -21
  42. package/dist/{src/renderer/ssr → core/renderer}/md.renderer.js +16 -32
  43. package/dist/core/renderer/md.renderer.js.map +1 -0
  44. package/dist/{src/renderer/ssr → core/renderer}/ssr.renderer.d.ts +11 -27
  45. package/dist/{src/renderer/ssr → core/renderer}/ssr.renderer.js +33 -37
  46. package/dist/core/renderer/ssr.renderer.js.map +1 -0
  47. package/dist/{src/route → core/router}/route.resolver.d.ts +1 -8
  48. package/dist/{src/route → core/router}/route.resolver.js +0 -1
  49. package/dist/core/router/route.resolver.js.map +1 -0
  50. package/dist/core/router/route.trie.d.ts +32 -0
  51. package/dist/core/router/route.trie.js +152 -0
  52. package/dist/core/router/route.trie.js.map +1 -0
  53. package/dist/core/runtime/abstract.runtime.d.ts +32 -0
  54. package/dist/core/runtime/abstract.runtime.js +26 -0
  55. package/dist/core/runtime/abstract.runtime.js.map +1 -0
  56. package/dist/core/server/emroute.server.d.ts +48 -0
  57. package/dist/core/server/emroute.server.js +239 -0
  58. package/dist/core/server/emroute.server.js.map +1 -0
  59. package/dist/core/server/server.type.d.ts +45 -0
  60. package/dist/core/server/server.type.js +11 -0
  61. package/dist/core/server/server.type.js.map +1 -0
  62. package/dist/core/type/component.type.d.ts +37 -0
  63. package/dist/core/type/component.type.js +7 -0
  64. package/dist/core/type/component.type.js.map +1 -0
  65. package/dist/core/type/element.type.d.ts +9 -0
  66. package/dist/core/type/element.type.js +5 -0
  67. package/dist/core/type/element.type.js.map +1 -0
  68. package/dist/core/type/logger.type.d.ts +14 -0
  69. package/dist/core/type/logger.type.js +8 -0
  70. package/dist/core/type/logger.type.js.map +1 -0
  71. package/dist/core/type/markdown.type.d.ts +7 -0
  72. package/dist/core/type/markdown.type.js +5 -0
  73. package/dist/core/type/markdown.type.js.map +1 -0
  74. package/dist/{src → core}/type/route-tree.type.d.ts +0 -12
  75. package/dist/{src → core}/type/route-tree.type.js +0 -1
  76. package/dist/core/type/route-tree.type.js.map +1 -0
  77. package/dist/core/type/route.type.d.ts +62 -0
  78. package/dist/core/type/route.type.js +7 -0
  79. package/dist/core/type/route.type.js.map +1 -0
  80. package/dist/core/type/widget.type.d.ts +27 -0
  81. package/dist/core/type/widget.type.js +5 -0
  82. package/dist/core/type/widget.type.js.map +1 -0
  83. package/dist/core/util/html.util.d.ts +14 -0
  84. package/dist/core/util/html.util.js +43 -0
  85. package/dist/core/util/html.util.js.map +1 -0
  86. package/dist/{src → core}/util/md.util.d.ts +0 -1
  87. package/dist/{src → core}/util/md.util.js +0 -2
  88. package/dist/core/util/md.util.js.map +1 -0
  89. package/dist/{src/route → core/util}/route-tree.util.js +0 -2
  90. package/dist/core/util/route-tree.util.js.map +1 -0
  91. package/dist/core/util/widget-resolve.util.d.ts +28 -0
  92. package/dist/{src → core}/util/widget-resolve.util.js +12 -42
  93. package/dist/core/util/widget-resolve.util.js.map +1 -0
  94. package/dist/{src → core}/widget/widget.parser.d.ts +0 -13
  95. package/dist/{src → core}/widget/widget.parser.js +1 -22
  96. package/dist/core/widget/widget.parser.js.map +1 -0
  97. package/dist/core/widget/widget.registry.d.ts +14 -0
  98. package/dist/core/widget/widget.registry.js +26 -0
  99. package/dist/core/widget/widget.registry.js.map +1 -0
  100. package/dist/emroute.js +1092 -1220
  101. package/dist/emroute.js.map +36 -5
  102. package/dist/runtime/abstract.runtime.d.ts +41 -7
  103. package/dist/runtime/abstract.runtime.js +404 -9
  104. package/dist/runtime/abstract.runtime.js.map +1 -1
  105. package/dist/runtime/bun/fs/bun-fs.runtime.d.ts +1 -0
  106. package/dist/runtime/bun/fs/bun-fs.runtime.js +15 -1
  107. package/dist/runtime/bun/fs/bun-fs.runtime.js.map +1 -1
  108. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.d.ts +2 -0
  109. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js +8 -0
  110. package/dist/runtime/bun/sqlite/bun-sqlite.runtime.js.map +1 -1
  111. package/dist/runtime/fetch.runtime.d.ts +3 -3
  112. package/dist/runtime/fetch.runtime.js +3 -3
  113. package/dist/runtime/sitemap.generator.d.ts +1 -1
  114. package/dist/runtime/sitemap.generator.js +1 -1
  115. package/dist/runtime/sitemap.generator.js.map +1 -1
  116. package/dist/runtime/universal/fs/universal-fs.runtime.d.ts +1 -0
  117. package/dist/runtime/universal/fs/universal-fs.runtime.js +15 -1
  118. package/dist/runtime/universal/fs/universal-fs.runtime.js.map +1 -1
  119. package/dist/server/build.util.d.ts +9 -10
  120. package/dist/server/build.util.js +11 -31
  121. package/dist/server/build.util.js.map +1 -1
  122. package/dist/server/codegen.util.d.ts +1 -1
  123. package/dist/server/emroute.server.d.ts +8 -35
  124. package/dist/server/emroute.server.js +7 -351
  125. package/dist/server/emroute.server.js.map +1 -1
  126. package/dist/server/esbuild-manifest.plugin.js +1 -1
  127. package/dist/server/esbuild-manifest.plugin.js.map +1 -1
  128. package/dist/server/server-api.type.d.ts +3 -71
  129. package/dist/server/server-api.type.js +1 -8
  130. package/dist/server/server-api.type.js.map +1 -1
  131. package/dist/src/element/component.element.d.ts +6 -14
  132. package/dist/src/element/component.element.js +13 -40
  133. package/dist/src/element/component.element.js.map +1 -1
  134. package/dist/src/element/markdown.element.d.ts +2 -2
  135. package/dist/src/element/markdown.element.js +3 -2
  136. package/dist/src/element/markdown.element.js.map +1 -1
  137. package/dist/src/index.d.ts +15 -14
  138. package/dist/src/index.js +8 -8
  139. package/dist/src/index.js.map +1 -1
  140. package/dist/src/renderer/spa/emroute.app.d.ts +50 -0
  141. package/dist/src/renderer/spa/emroute.app.js +246 -0
  142. package/dist/src/renderer/spa/emroute.app.js.map +1 -0
  143. package/dist/src/renderer/spa/mod.d.ts +17 -16
  144. package/dist/src/renderer/spa/mod.js +9 -9
  145. package/dist/src/renderer/spa/mod.js.map +1 -1
  146. package/dist/src/renderer/spa/thin-client.d.ts +3 -3
  147. package/dist/src/renderer/spa/thin-client.js +7 -7
  148. package/dist/src/renderer/spa/thin-client.js.map +1 -1
  149. package/dist/src/route/route.core.d.ts +3 -3
  150. package/dist/src/util/html.util.d.ts +5 -22
  151. package/dist/src/util/html.util.js +8 -56
  152. package/dist/src/util/html.util.js.map +1 -1
  153. package/dist/src/widget/breadcrumb.widget.d.ts +2 -2
  154. package/dist/src/widget/breadcrumb.widget.js +2 -2
  155. package/dist/src/widget/breadcrumb.widget.js.map +1 -1
  156. package/dist/src/widget/page-title.widget.d.ts +1 -1
  157. package/dist/src/widget/page-title.widget.js +1 -1
  158. package/dist/src/widget/page-title.widget.js.map +1 -1
  159. package/package.json +8 -8
  160. package/runtime/abstract.runtime.ts +433 -17
  161. package/runtime/bun/fs/bun-fs.runtime.ts +15 -1
  162. package/runtime/bun/sqlite/bun-sqlite.runtime.ts +9 -0
  163. package/runtime/fetch.runtime.ts +3 -3
  164. package/runtime/sitemap.generator.ts +2 -2
  165. package/runtime/universal/fs/universal-fs.runtime.ts +15 -1
  166. package/server/build.util.ts +17 -43
  167. package/server/codegen.util.ts +1 -1
  168. package/server/emroute.server.ts +12 -426
  169. package/src/element/component.element.ts +14 -54
  170. package/src/element/markdown.element.ts +4 -3
  171. package/src/index.ts +22 -19
  172. package/src/renderer/spa/{thin-client.ts → emroute.app.ts} +19 -20
  173. package/src/renderer/spa/mod.ts +22 -22
  174. package/src/util/html.util.ts +16 -61
  175. package/src/widget/breadcrumb.widget.ts +3 -3
  176. package/src/widget/page-title.widget.ts +1 -1
  177. package/dist/src/component/abstract.component.d.ts +0 -199
  178. package/dist/src/component/abstract.component.js +0 -84
  179. package/dist/src/component/abstract.component.js.map +0 -1
  180. package/dist/src/component/page.component.d.ts +0 -74
  181. package/dist/src/component/page.component.js +0 -107
  182. package/dist/src/component/page.component.js.map +0 -1
  183. package/dist/src/component/widget.component.d.ts +0 -47
  184. package/dist/src/component/widget.component.js +0 -69
  185. package/dist/src/component/widget.component.js.map +0 -1
  186. package/dist/src/renderer/ssr/html.renderer.js.map +0 -1
  187. package/dist/src/renderer/ssr/md.renderer.js.map +0 -1
  188. package/dist/src/renderer/ssr/ssr.renderer.js.map +0 -1
  189. package/dist/src/route/route-tree.util.js.map +0 -1
  190. package/dist/src/route/route.matcher.d.ts +0 -86
  191. package/dist/src/route/route.matcher.js +0 -214
  192. package/dist/src/route/route.matcher.js.map +0 -1
  193. package/dist/src/route/route.resolver.js.map +0 -1
  194. package/dist/src/route/route.trie.d.ts +0 -38
  195. package/dist/src/route/route.trie.js +0 -206
  196. package/dist/src/route/route.trie.js.map +0 -1
  197. package/dist/src/type/element.type.d.ts +0 -19
  198. package/dist/src/type/element.type.js +0 -9
  199. package/dist/src/type/element.type.js.map +0 -1
  200. package/dist/src/type/logger.type.d.ts +0 -17
  201. package/dist/src/type/logger.type.js +0 -9
  202. package/dist/src/type/logger.type.js.map +0 -1
  203. package/dist/src/type/markdown.type.d.ts +0 -20
  204. package/dist/src/type/markdown.type.js +0 -2
  205. package/dist/src/type/markdown.type.js.map +0 -1
  206. package/dist/src/type/route-tree.type.js.map +0 -1
  207. package/dist/src/type/route.type.d.ts +0 -94
  208. package/dist/src/type/route.type.js +0 -8
  209. package/dist/src/type/route.type.js.map +0 -1
  210. package/dist/src/type/widget.type.d.ts +0 -55
  211. package/dist/src/type/widget.type.js +0 -10
  212. package/dist/src/type/widget.type.js.map +0 -1
  213. package/dist/src/util/logger.util.d.ts +0 -26
  214. package/dist/src/util/logger.util.js +0 -80
  215. package/dist/src/util/logger.util.js.map +0 -1
  216. package/dist/src/util/md.util.js.map +0 -1
  217. package/dist/src/util/widget-resolve.util.d.ts +0 -52
  218. package/dist/src/util/widget-resolve.util.js.map +0 -1
  219. package/dist/src/widget/widget.parser.js.map +0 -1
  220. package/dist/src/widget/widget.registry.d.ts +0 -23
  221. package/dist/src/widget/widget.registry.js +0 -42
  222. package/dist/src/widget/widget.registry.js.map +0 -1
  223. package/runtime/bun/esbuild-runtime-loader.plugin.ts +0 -112
  224. package/server/esbuild-manifest.plugin.ts +0 -209
  225. package/server/server-api.type.ts +0 -101
  226. package/src/component/abstract.component.ts +0 -231
  227. package/src/component/widget.component.ts +0 -85
  228. package/src/route/route.core.ts +0 -371
  229. package/src/route/route.trie.ts +0 -265
  230. package/src/type/element.type.ts +0 -22
  231. package/src/type/logger.type.ts +0 -24
  232. package/src/type/markdown.type.ts +0 -21
  233. package/src/type/route-tree.type.ts +0 -51
  234. package/src/type/route.type.ts +0 -124
  235. package/src/type/widget.type.ts +0 -65
  236. package/src/util/logger.util.ts +0 -83
  237. package/src/widget/widget.registry.ts +0 -51
  238. /package/dist/{src/route → core/util}/route-tree.util.d.ts +0 -0
@@ -5,8 +5,9 @@
5
5
  * Calls getData() + renderHTML() on widgets and injects SSR hydration data.
6
6
  */
7
7
 
8
- import type { Component, ComponentContext, ContextProvider } from '../component/abstract.component.ts';
9
- import { logger } from '../type/logger.type.ts';
8
+ import type { Component } from '../component/abstract.component.ts';
9
+ import type { ComponentContext, ContextProvider } from '../type/component.type.ts';
10
+ import { type Logger, defaultLogger } from '../type/logger.type.ts';
10
11
  import type { RouteInfo } from '../type/route.type.ts';
11
12
  import { LAZY_ATTR, SSR_ATTR } from './html.util.ts';
12
13
 
@@ -15,17 +16,6 @@ export const MAX_WIDGET_DEPTH = 10;
15
16
 
16
17
  /**
17
18
  * Recursively resolve widgets in content with depth limit.
18
- *
19
- * Generic utility used by both HTML and Markdown widget resolution.
20
- * Each depth level processes all widgets concurrently, then recurses
21
- * into each rendered result to resolve nested widgets.
22
- *
23
- * @param content - Content containing widgets
24
- * @param parse - Find widgets in content
25
- * @param resolve - Resolve a single widget to rendered output
26
- * @param replace - Replace widgets with resolved content
27
- * @param depth - Current recursion depth (internal)
28
- * @returns Content with all widgets recursively resolved
29
19
  */
30
20
  export async function resolveRecursively<T>(
31
21
  content: string,
@@ -33,6 +23,7 @@ export async function resolveRecursively<T>(
33
23
  resolve: (widget: T) => Promise<string>,
34
24
  replace: (content: string, replacements: Map<T, string>) => string,
35
25
  depth = 0,
26
+ logger: Logger = defaultLogger,
36
27
  ): Promise<string> {
37
28
  if (depth >= MAX_WIDGET_DEPTH) {
38
29
  logger.warn(
@@ -49,10 +40,7 @@ export async function resolveRecursively<T>(
49
40
  await Promise.all(
50
41
  widgets.map(async (widget) => {
51
42
  let rendered = await resolve(widget);
52
-
53
- // Recursively resolve any nested widgets in the rendered output
54
- rendered = await resolveRecursively(rendered, parse, resolve, replace, depth + 1);
55
-
43
+ rendered = await resolveRecursively(rendered, parse, resolve, replace, depth + 1, logger);
56
44
  replacements.set(widget, rendered);
57
45
  }),
58
46
  );
@@ -61,18 +49,7 @@ export async function resolveRecursively<T>(
61
49
  }
62
50
 
63
51
  /**
64
- * Resolve <widget-*> tags in HTML by calling getData() + renderHTML()
65
- * via the widget registry. Injects rendered content and boolean ssr attribute.
66
- *
67
- * Supports nested widgets: if a widget's renderHTML() returns HTML containing
68
- * other <widget-*> tags, those will be resolved recursively up to MAX_WIDGET_DEPTH.
69
- *
70
- * Before: <widget-crypto-price coin="bitcoin"></widget-crypto-price>
71
- * After: <widget-crypto-price coin="bitcoin" ssr><template shadowrootmode="open"><span>$42,000</span></template></widget-crypto-price>
72
- *
73
- * When a widget has `exposeSsrData = true`, the getData() result is serialized
74
- * as JSON text in the light DOM (alongside the shadow root template):
75
- * After: <widget-crypto-price coin="bitcoin" ssr><template shadowrootmode="open"><span>$42,000</span></template>{"price":42000}</widget-crypto-price>
52
+ * Resolve <widget-*> tags in HTML by calling getData() + renderHTML().
76
53
  */
77
54
  export function resolveWidgetTags(
78
55
  html: string,
@@ -80,20 +57,16 @@ export function resolveWidgetTags(
80
57
  routeInfo: RouteInfo,
81
58
  loadFiles?: (
82
59
  widgetName: string,
83
- declaredFiles?: { html?: string; md?: string; css?: string },
84
60
  ) => Promise<{ html?: string; md?: string; css?: string }>,
85
61
  contextProvider?: ContextProvider,
62
+ logger: Logger = defaultLogger,
86
63
  ): Promise<string> {
87
64
  const tagPattern =
88
65
  /<widget-(?<name>[a-z][a-z0-9-]*)(?<attrs>\s[^>]*)?>(?<content>.*?)<\/widget-\k<name>>/gis;
89
66
 
90
- // Wrapping info stored per-match so replace() can apply it after recursion
91
67
  const wrappers = new Map<RegExpExecArray, { tagName: string; attrs: string; ssrData: string }>();
92
-
93
- // Matches standalone ssr attribute (boolean or with value), not as substring of another value
94
68
  const ssrAttrPattern = new RegExp(`\\s${SSR_ATTR}(?:\\s|=|$)`);
95
69
 
96
- // Parse: find unprocessed widget tags
97
70
  const parse = (content: string) => {
98
71
  const matches = content.matchAll(tagPattern).toArray();
99
72
  return matches.filter((match) => {
@@ -102,20 +75,19 @@ export function resolveWidgetTags(
102
75
  });
103
76
  };
104
77
 
105
- // Resolve: render a single widget's inner content (no outer tag wrapping — that's in replace)
106
78
  const resolve = async (match: RegExpExecArray): Promise<string> => {
107
- const widgetName = match.groups!.name;
79
+ const widgetName = match.groups!.name!;
108
80
  const attrsString = match.groups!.attrs?.trim() ?? '';
109
81
  const widget = registry.get(widgetName);
110
82
 
111
- if (!widget) return match[0]; // no widget found — leave original tag as-is
83
+ if (!widget) return match[0];
112
84
 
113
85
  const params = parseAttrsToParams(attrsString);
114
86
 
115
87
  try {
116
88
  let files: { html?: string; md?: string; css?: string } | undefined;
117
89
  if (loadFiles) {
118
- files = await loadFiles(widgetName, widget.files);
90
+ files = await loadFiles(widgetName);
119
91
  }
120
92
 
121
93
  const baseContext: ComponentContext = {
@@ -129,7 +101,6 @@ export function resolveWidgetTags(
129
101
  const data = await widget.getData({ params, context });
130
102
  const rendered = widget.renderHTML({ data, params, context });
131
103
 
132
- // Store wrapping info — applied in replace() after recursion resolves nested widgets
133
104
  wrappers.set(match, {
134
105
  tagName: `widget-${widgetName}`,
135
106
  attrs: attrsString ? ` ${attrsString}` : '',
@@ -142,11 +113,10 @@ export function resolveWidgetTags(
142
113
  `[SSR HTML] Widget "${widgetName}" render failed`,
143
114
  e instanceof Error ? e : undefined,
144
115
  );
145
- return match[0]; // render failed — leave original tag as-is
116
+ return match[0];
146
117
  }
147
118
  };
148
119
 
149
- // Replace: wrap resolved content in outer tag + DSD template, then substitute by index
150
120
  const replace = (content: string, replacements: Map<RegExpExecArray, string>) => {
151
121
  let result = content;
152
122
  const entries = [...replacements.entries()].sort((a, b) => b[0].index! - a[0].index!);
@@ -157,16 +127,16 @@ export function resolveWidgetTags(
157
127
  const lightDomData = wrap?.ssrData ? wrap.ssrData : '';
158
128
  const replacement = wrap
159
129
  ? `<${wrap.tagName}${wrap.attrs} ${SSR_ATTR}><template shadowrootmode="open">${innerHtml}</template>${lightDomData}</${wrap.tagName}>`
160
- : innerHtml; // no wrapper = unresolved widget, innerHtml is the original tag
130
+ : innerHtml;
161
131
  result = result.slice(0, start) + replacement + result.slice(end);
162
132
  }
163
133
  return result;
164
134
  };
165
135
 
166
- return resolveRecursively(html, parse, resolve, replace);
136
+ return resolveRecursively(html, parse, resolve, replace, 0, logger);
167
137
  }
168
138
 
169
- /** Parse HTML attribute string into params object (kebab→camelCase, JSON.parse with string fallback). */
139
+ /** Parse HTML attribute string into params object. */
170
140
  export function parseAttrsToParams(attrsString: string): Record<string, unknown> {
171
141
  const params: Record<string, unknown> = {};
172
142
  if (!attrsString) return params;
@@ -175,7 +145,7 @@ export function parseAttrsToParams(attrsString: string): Record<string, unknown>
175
145
  /(?<attr>[a-z][a-z0-9-]*)(?:="(?<dq>[^"]*)"|='(?<sq>[^']*)'|=(?<uq>[^\s>]+))?/gi;
176
146
  for (const match of attrsString.matchAll(attrPattern)) {
177
147
  const { attr: attrName, dq, sq, uq } = match.groups!;
178
- if (attrName === SSR_ATTR || attrName === LAZY_ATTR) continue;
148
+ if (!attrName || attrName === SSR_ATTR || attrName === LAZY_ATTR) continue;
179
149
  const key = attrName.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
180
150
  const rawValue = dq ?? sq ?? uq;
181
151
  if (rawValue === undefined) {
@@ -196,7 +166,6 @@ export function parseAttrsToParams(attrsString: string): Record<string, unknown>
196
166
  return params;
197
167
  }
198
168
 
199
- /** Escape a value for use in a single-quoted HTML attribute. */
200
169
  function escapeAttr(value: string): string {
201
170
  return value.replaceAll('&', '&amp;').replaceAll("'", '&#39;');
202
171
  }
@@ -11,36 +11,25 @@
11
11
 
12
12
  import type { ParsedWidgetBlock } from '../type/widget.type.ts';
13
13
 
14
- /**
15
- * Pattern to match widget fenced code blocks.
16
- * Captures: widget name, params content
17
- */
18
14
  const WIDGET_PATTERN = /```widget:(?<name>[a-z][a-z0-9-]*)\n(?<params>.*?)```/gs;
19
15
 
20
- /**
21
- * Parse all widget blocks from markdown content.
22
- *
23
- * @param markdown - Markdown content to parse
24
- * @returns Array of parsed widget blocks with positions
25
- */
26
16
  export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
27
17
  const blocks: ParsedWidgetBlock[] = [];
28
18
 
29
19
  for (const match of markdown.matchAll(WIDGET_PATTERN)) {
30
20
  const fullMatch = match[0];
31
21
  const { name: widgetName, params: paramsRaw } = match.groups!;
32
- const paramsJson = paramsRaw.trim();
22
+ const paramsJson = paramsRaw!.trim();
33
23
  const startIndex = match.index;
34
24
 
35
25
  const block: ParsedWidgetBlock = {
36
26
  fullMatch,
37
- widgetName,
27
+ widgetName: widgetName!,
38
28
  params: null,
39
29
  startIndex,
40
30
  endIndex: startIndex + fullMatch.length,
41
31
  };
42
32
 
43
- // Parse JSON params if present
44
33
  if (paramsJson) {
45
34
  try {
46
35
  const parsed = JSON.parse(paramsJson);
@@ -53,7 +42,6 @@ export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
53
42
  block.parseError = `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`;
54
43
  }
55
44
  } else {
56
- // Empty params is valid - use empty object
57
45
  block.params = {};
58
46
  }
59
47
 
@@ -63,19 +51,10 @@ export function parseWidgetBlocks(markdown: string): ParsedWidgetBlock[] {
63
51
  return blocks;
64
52
  }
65
53
 
66
- /**
67
- * Replace widget blocks in markdown with rendered content.
68
- *
69
- * @param markdown - Original markdown content
70
- * @param replacements - Map of parsed blocks to replacement strings
71
- * @returns Markdown with widget blocks replaced
72
- */
73
54
  export function replaceWidgetBlocks(
74
55
  markdown: string,
75
56
  replacements: Map<ParsedWidgetBlock, string>,
76
57
  ): string {
77
- // Sort blocks by position descending to replace from end first
78
- // This preserves indices during replacement
79
58
  const sortedBlocks = [...replacements.entries()].sort(
80
59
  ([a], [b]) => b.startIndex - a.startIndex,
81
60
  );
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Widget Registry
3
+ *
4
+ * Name → Component lookup. Used by all renderers.
5
+ * Pages are NOT in this registry — they live in the routes manifest.
6
+ */
7
+
8
+ import type { WidgetComponent } from '../component/widget.component.ts';
9
+
10
+ interface RegistryEntry {
11
+ widget: WidgetComponent;
12
+ modulePath?: string | undefined;
13
+ }
14
+
15
+ export class WidgetRegistry {
16
+ private entries = new Map<string, RegistryEntry>();
17
+
18
+ add(widget: WidgetComponent, modulePath?: string): void {
19
+ this.entries.set(widget.name, { widget, modulePath });
20
+ }
21
+
22
+ get(name: string): WidgetComponent | undefined {
23
+ return this.entries.get(name)?.widget;
24
+ }
25
+
26
+ getModulePath(name: string): string | undefined {
27
+ return this.entries.get(name)?.modulePath;
28
+ }
29
+
30
+ [Symbol.iterator](): IterableIterator<WidgetComponent> {
31
+ const entries = this.entries.values();
32
+ return (function* () {
33
+ for (const entry of entries) yield entry.widget;
34
+ })();
35
+ }
36
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Component Base Class
3
+ *
4
+ * Everything is a Component: pages and widgets.
5
+ * Components render differently based on context:
6
+ * - /md/* → Markdown (LLMs, text clients)
7
+ * - /html/* → Pre-rendered HTML (SSR)
8
+ * - SPA → Hydrated custom elements
9
+ */
10
+ import type { ComponentContext } from '../type/component.type.ts';
11
+ export declare abstract class Component<TParams = unknown, TData = unknown, TContext extends ComponentContext = ComponentContext> {
12
+ readonly DataArgs: {
13
+ params: TParams;
14
+ signal?: AbortSignal;
15
+ context: TContext;
16
+ };
17
+ readonly RenderArgs: {
18
+ data: TData | null;
19
+ params: TParams;
20
+ context: TContext;
21
+ };
22
+ abstract readonly name: string;
23
+ /** Host element reference, set by ComponentElement in the browser. */
24
+ element?: HTMLElement | undefined;
25
+ /** Associated file paths for pre-loaded content (html, md, css). */
26
+ readonly files?: {
27
+ html?: string;
28
+ md?: string;
29
+ css?: string;
30
+ };
31
+ /**
32
+ * When true, SSR serializes the getData() result into the element's
33
+ * light DOM so the client can access it immediately in hydrate()
34
+ * without re-fetching.
35
+ */
36
+ readonly exposeSsrData?: boolean;
37
+ abstract getData(args: this['DataArgs']): Promise<TData | null>;
38
+ abstract renderMarkdown(args: this['RenderArgs']): string;
39
+ renderHTML(args: this['RenderArgs']): string;
40
+ hydrate?(args: this['RenderArgs']): void;
41
+ destroy?(): void;
42
+ validateParams?(params: TParams): string | undefined;
43
+ renderError(args: {
44
+ error: unknown;
45
+ params: TParams;
46
+ }): string;
47
+ renderMarkdownError(error: unknown): string;
48
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Component Base Class
3
+ *
4
+ * Everything is a Component: pages and widgets.
5
+ * Components render differently based on context:
6
+ * - /md/* → Markdown (LLMs, text clients)
7
+ * - /html/* → Pre-rendered HTML (SSR)
8
+ * - SPA → Hydrated custom elements
9
+ */
10
+ import { escapeHtml } from "../util/html.util.js";
11
+ export class Component {
12
+ /** Host element reference, set by ComponentElement in the browser. */
13
+ element;
14
+ /** Associated file paths for pre-loaded content (html, md, css). */
15
+ files;
16
+ /**
17
+ * When true, SSR serializes the getData() result into the element's
18
+ * light DOM so the client can access it immediately in hydrate()
19
+ * without re-fetching.
20
+ */
21
+ exposeSsrData;
22
+ renderHTML(args) {
23
+ if (args.data === null) {
24
+ return `<div data-component="${this.name}">Loading...</div>`;
25
+ }
26
+ const markdown = this.renderMarkdown({
27
+ data: args.data,
28
+ params: args.params,
29
+ context: args.context,
30
+ });
31
+ return `<div data-component="${this.name}" data-markdown>${escapeHtml(markdown)}</div>`;
32
+ }
33
+ renderError(args) {
34
+ const msg = args.error instanceof Error ? args.error.message : String(args.error);
35
+ return `<div data-component="${this.name}">Error: ${escapeHtml(msg)}</div>`;
36
+ }
37
+ renderMarkdownError(error) {
38
+ const msg = error instanceof Error ? error.message : String(error);
39
+ return `> **Error** (\`${this.name}\`): ${msg}`;
40
+ }
41
+ }
42
+ //# sourceMappingURL=abstract.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abstract.component.js","sourceRoot":"","sources":["../../../core/component/abstract.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,OAAgB,SAAS;IAmB7B,sEAAsE;IACtE,OAAO,CAA2B;IAElC,oEAAoE;IAC3D,KAAK,CAAgD;IAE9D;;;;OAIG;IACM,aAAa,CAAW;IAKjC,UAAU,CAAC,IAAwB;QACjC,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,wBAAwB,IAAI,CAAC,IAAI,oBAAoB,CAAC;QAC/D,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,CAAC;YACnC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QACH,OAAO,wBAAwB,IAAI,CAAC,IAAI,mBAAmB,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1F,CAAC;IAMD,WAAW,CAAC,IAAyC;QACnD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClF,OAAO,wBAAwB,IAAI,CAAC,IAAI,YAAY,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC9E,CAAC;IAED,mBAAmB,CAAC,KAAc;QAChC,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACnE,OAAO,kBAAkB,IAAI,CAAC,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClD,CAAC;CACF"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Page Component
3
+ *
4
+ * Params come from URL, context carries file content.
5
+ *
6
+ * Default implementations follow the fallback table:
7
+ * - renderHTML: html file → md via <mark-down> → <router-slot /> (non-leaf only)
8
+ * - renderMarkdown: md file → ```router-slot\n``` (non-leaf only)
9
+ * - getData: no-op (returns null)
10
+ */
11
+ import { Component } from './abstract.component.ts';
12
+ import type { ComponentContext } from '../type/component.type.ts';
13
+ export declare class PageComponent<TParams extends Record<string, string> = Record<string, string>, TData = unknown, TContext extends ComponentContext = ComponentContext> extends Component<TParams, TData, TContext> {
14
+ readonly name: string;
15
+ readonly pattern?: string;
16
+ getData(_args: this['DataArgs']): Promise<TData | null>;
17
+ renderHTML(args: this['RenderArgs']): string;
18
+ renderMarkdown(args: this['RenderArgs']): string;
19
+ getTitle(_args: this['RenderArgs']): string | undefined;
20
+ }
21
+ /** Shared default instance used by renderers when no custom .page.ts exists. */
22
+ declare const _default: PageComponent<Record<string, string>, unknown, ComponentContext>;
23
+ export default _default;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Page Component
3
+ *
4
+ * Params come from URL, context carries file content.
5
+ *
6
+ * Default implementations follow the fallback table:
7
+ * - renderHTML: html file → md via <mark-down> → <router-slot /> (non-leaf only)
8
+ * - renderMarkdown: md file → ```router-slot\n``` (non-leaf only)
9
+ * - getData: no-op (returns null)
10
+ */
11
+ import { Component } from "./abstract.component.js";
12
+ import { escapeHtml } from "../util/html.util.js";
13
+ export class PageComponent extends Component {
14
+ name = 'page';
15
+ pattern;
16
+ getData(_args) {
17
+ return Promise.resolve(null);
18
+ }
19
+ renderHTML(args) {
20
+ const files = args.context.files;
21
+ const style = files?.css ? `<style>${files.css}</style>\n` : '';
22
+ if (files?.html) {
23
+ let html = style + files.html;
24
+ if (files.md && html.includes('<mark-down></mark-down>')) {
25
+ html = html.replace('<mark-down></mark-down>', `<mark-down>${escapeHtml(files.md)}</mark-down>`);
26
+ }
27
+ return html;
28
+ }
29
+ if (files?.md) {
30
+ const hasSlot = files.md.includes('```router-slot');
31
+ const slot = args.context.isLeaf || hasSlot ? '' : '\n<router-slot></router-slot>';
32
+ return `${style}<mark-down>${escapeHtml(files.md)}</mark-down>${slot}`;
33
+ }
34
+ return args.context.isLeaf ? '' : '<router-slot></router-slot>';
35
+ }
36
+ renderMarkdown(args) {
37
+ const files = args.context.files;
38
+ if (files?.md) {
39
+ return files.md;
40
+ }
41
+ return args.context.isLeaf ? '' : '```router-slot\n```';
42
+ }
43
+ getTitle(_args) {
44
+ return undefined;
45
+ }
46
+ }
47
+ /** Shared default instance used by renderers when no custom .page.ts exists. */
48
+ export default new PageComponent();
49
+ //# sourceMappingURL=page.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"page.component.js","sourceRoot":"","sources":["../../../core/component/page.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,OAAO,aAIX,SAAQ,SAAmC;IACzB,IAAI,GAAW,MAAM,CAAC;IAC/B,OAAO,CAAU;IAEjB,OAAO,CACd,KAAuB;QAEvB,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;IAEQ,UAAU,CACjB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAEhE,IAAI,KAAK,EAAE,IAAI,EAAE,CAAC;YAChB,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;YAC9B,IAAI,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,CAAC;gBACzD,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,yBAAyB,EACzB,cAAc,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CACjD,CAAC;YACJ,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YACpD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,+BAA+B,CAAC;YACnF,OAAO,GAAG,KAAK,cAAc,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,eAAe,IAAI,EAAE,CAAC;QACzE,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,6BAA6B,CAAC;IAClE,CAAC;IAEQ,cAAc,CACrB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAEjC,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,CAAC;QAED,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,CAAC;IAC1D,CAAC;IAED,QAAQ,CACN,KAAyB;QAEzB,OAAO,SAAS,CAAC;IACnB,CAAC;CACF;AAED,gFAAgF;AAChF,eAAe,IAAI,aAAa,EAAE,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Widget Component
3
+ *
4
+ * Embeddable unit within page content. Everything reusable that is not
5
+ * a page is a Widget. Widgets render across all contexts (HTML, Markdown, SPA)
6
+ * and are resolved by name via WidgetRegistry.
7
+ *
8
+ * Default rendering fallback chains (parallel to PageComponent):
9
+ * - renderHTML: html file → md file in <mark-down> → base Component default
10
+ * - renderMarkdown: md file → ''
11
+ */
12
+ import { Component } from './abstract.component.ts';
13
+ import type { ComponentContext } from '../type/component.type.ts';
14
+ export declare abstract class WidgetComponent<TParams = unknown, TData = unknown, TContext extends ComponentContext = ComponentContext> extends Component<TParams, TData, TContext> {
15
+ renderHTML(args: this['RenderArgs']): string;
16
+ renderMarkdown(args: this['RenderArgs']): string;
17
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Widget Component
3
+ *
4
+ * Embeddable unit within page content. Everything reusable that is not
5
+ * a page is a Widget. Widgets render across all contexts (HTML, Markdown, SPA)
6
+ * and are resolved by name via WidgetRegistry.
7
+ *
8
+ * Default rendering fallback chains (parallel to PageComponent):
9
+ * - renderHTML: html file → md file in <mark-down> → base Component default
10
+ * - renderMarkdown: md file → ''
11
+ */
12
+ import { Component } from "./abstract.component.js";
13
+ import { escapeHtml, scopeWidgetCss } from "../util/html.util.js";
14
+ export class WidgetComponent extends Component {
15
+ renderHTML(args) {
16
+ const files = args.context.files;
17
+ const style = files?.css ? `<style>${scopeWidgetCss(files.css, this.name)}</style>\n` : '';
18
+ if (files?.html) {
19
+ return style + files.html;
20
+ }
21
+ if (files?.md) {
22
+ return `${style}<mark-down>${escapeHtml(files.md)}</mark-down>`;
23
+ }
24
+ if (style) {
25
+ return style + super.renderHTML(args);
26
+ }
27
+ return super.renderHTML(args);
28
+ }
29
+ renderMarkdown(args) {
30
+ const files = args.context.files;
31
+ if (files?.md) {
32
+ return files.md;
33
+ }
34
+ return '';
35
+ }
36
+ }
37
+ //# sourceMappingURL=widget.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"widget.component.js","sourceRoot":"","sources":["../../../core/component/widget.component.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAElE,MAAM,OAAgB,eAIpB,SAAQ,SAAmC;IAClC,UAAU,CACjB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,UAAU,cAAc,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;QAE3F,IAAI,KAAK,EAAE,IAAI,EAAE,CAAC;YAChB,OAAO,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;QAC5B,CAAC;QAED,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,OAAO,GAAG,KAAK,cAAc,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,cAAc,CAAC;QAClE,CAAC;QAED,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxC,CAAC;QAED,OAAO,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAEQ,cAAc,CACrB,IAAwB;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAEjC,IAAI,KAAK,EAAE,EAAE,EAAE,CAAC;YACd,OAAO,KAAK,CAAC,EAAE,CAAC;QAClB,CAAC;QAED,OAAO,EAAE,CAAC;IACZ,CAAC;CACF"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Pipeline
3
+ *
4
+ * Orchestration layer between Router, Runtime, and Component.
5
+ *
6
+ * Owns:
7
+ * - Route matching (reads manifest from Runtime, walks RouteNode tree)
8
+ * - Module loading (delegates to Runtime)
9
+ * - Companion file reading (delegates to Runtime)
10
+ * - ComponentContext building
11
+ * - Route hierarchy construction
12
+ *
13
+ * Does NOT own:
14
+ * - Rendering (that's Renderer)
15
+ * - HTTP routing / base paths (that's Server)
16
+ * - Storage I/O (that's Runtime)
17
+ * - Navigation events (that's the browser adapter)
18
+ */
19
+ import type { RouteConfig, MatchedRoute, RouteInfo } from '../type/route.type.ts';
20
+ import type { ComponentContext, ContextProvider, FileContents } from '../type/component.type.ts';
21
+ import type { Runtime } from '../runtime/abstract.runtime.ts';
22
+ import { type Logger } from '../type/logger.type.ts';
23
+ /** Default root route — renders a slot for child routes. */
24
+ export declare const DEFAULT_ROOT_ROUTE: RouteConfig;
25
+ /** Pipeline configuration. */
26
+ export interface PipelineOptions {
27
+ runtime: Runtime;
28
+ contextProvider?: ContextProvider;
29
+ /** Pre-bundled module loaders (browser boot passes these). */
30
+ moduleLoaders?: Record<string, () => Promise<unknown>>;
31
+ logger?: Logger;
32
+ }
33
+ export declare class Pipeline {
34
+ private readonly runtime;
35
+ readonly contextProvider: ContextProvider | undefined;
36
+ readonly logger: Logger;
37
+ private readonly moduleLoaders;
38
+ constructor(options: PipelineOptions);
39
+ private getResolver;
40
+ match(url: URL): Promise<MatchedRoute | undefined>;
41
+ findRoute(pattern: string): Promise<RouteConfig | undefined>;
42
+ findErrorBoundary(pathname: string): Promise<{
43
+ pattern: string;
44
+ modulePath: string;
45
+ } | undefined>;
46
+ getStatusPage(status: number): Promise<RouteConfig | undefined>;
47
+ getErrorHandler(): Promise<RouteConfig | undefined>;
48
+ buildRouteHierarchy(pattern: string): string[];
49
+ loadModule<T>(modulePath: string): Promise<T>;
50
+ /**
51
+ * Get inlined `__files` from a loaded module (merged module pattern).
52
+ */
53
+ getModuleFiles(mod: unknown): FileContents | undefined;
54
+ loadFiles(files: {
55
+ html?: string;
56
+ md?: string;
57
+ css?: string;
58
+ }): Promise<FileContents>;
59
+ toRouteInfo(matched: MatchedRoute, url: URL): RouteInfo;
60
+ buildContext(routeInfo: RouteInfo, route: RouteConfig, signal?: AbortSignal, isLeaf?: boolean, loadedModule?: unknown): Promise<ComponentContext>;
61
+ }