@kasperrt/smolter 0.0.1 → 0.3.0

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 (246) hide show
  1. package/{src/internal → .generated}/client/index.ts +1 -0
  2. package/.generated/core/environment.ts +43 -0
  3. package/{src/internal → .generated}/core/errors.ts +1 -1
  4. package/{src/internal → .generated}/core/index.ts +2 -0
  5. package/.generated/core/navigation-router.ts +107 -0
  6. package/.generated/core/navigation.ts +147 -0
  7. package/.generated/core/presentation.ts +108 -0
  8. package/.generated/core/resource-types.ts +44 -0
  9. package/.generated/core/resources.ts +444 -0
  10. package/.generated/core/responses.ts +86 -0
  11. package/{src/internal → .generated}/core/router.ts +136 -63
  12. package/.generated/core/serialize.ts +20 -0
  13. package/.generated/core/store.ts +25 -0
  14. package/.generated/core/submission.ts +116 -0
  15. package/{src/internal → .generated}/core/types.ts +18 -1
  16. package/.generated/core/url.ts +29 -0
  17. package/.generated/core/utils.ts +5 -0
  18. package/.generated/preact/await.tsx +41 -0
  19. package/.generated/preact/client.tsx +93 -0
  20. package/.generated/preact/context.ts +59 -0
  21. package/.generated/preact/document.tsx +198 -0
  22. package/{src/internal → .generated}/preact/fetcher.ts +43 -23
  23. package/.generated/preact/form.ts +58 -0
  24. package/{src/internal → .generated}/preact/hooks.ts +25 -28
  25. package/.generated/preact/index.ts +34 -0
  26. package/.generated/preact/lazy-route.ts +100 -0
  27. package/.generated/preact/navigation-state.ts +9 -0
  28. package/.generated/preact/navigation.tsx +147 -0
  29. package/.generated/preact/root-context.ts +21 -0
  30. package/.generated/preact/root-data.ts +45 -0
  31. package/.generated/preact/route-hooks.tsx +170 -0
  32. package/.generated/preact/route-types.ts +76 -0
  33. package/.generated/preact/router.tsx +107 -0
  34. package/{src/internal → .generated}/preact/routes.ts +17 -9
  35. package/.generated/react/context.ts +59 -0
  36. package/.generated/react/data.ts +25 -0
  37. package/{src/internal → .generated}/react/fetcher.ts +13 -11
  38. package/.generated/react/form.ts +58 -0
  39. package/{src/internal → .generated}/react/hooks.ts +9 -14
  40. package/{src/internal/preact → .generated/react}/index.ts +5 -1
  41. package/{src/internal → .generated}/react/link.ts +13 -21
  42. package/.generated/react/resources/components.tsx +404 -0
  43. package/{src/internal → .generated}/react/routes.ts +17 -9
  44. package/.generated/server/application.tsx +185 -0
  45. package/.generated/server/assets.ts +19 -0
  46. package/.generated/server/handler.ts +69 -0
  47. package/.generated/server/http.ts +55 -0
  48. package/{src/internal → .generated}/server/index.ts +4 -17
  49. package/.generated/server/node.ts +4 -0
  50. package/.generated/server/preact.ts +7 -0
  51. package/.generated/vite/application/browser-boundary.ts +42 -0
  52. package/.generated/vite/application/lazy-files.ts +136 -0
  53. package/.generated/vite/application/vite.ts +144 -0
  54. package/{src/internal → .generated}/vite/index.ts +4 -2
  55. package/.generated/vite/preact.ts +24 -0
  56. package/.generated/vite/react.ts +18 -0
  57. package/{src/internal → .generated}/vite/transport.ts +2 -1
  58. package/CHANGELOG.md +54 -0
  59. package/README.md +269 -55
  60. package/dist/client/deserialize.js +10 -0
  61. package/dist/{internal/client → client}/index.d.ts +1 -0
  62. package/dist/client/index.js +46 -0
  63. package/dist/core/environment.d.ts +12 -0
  64. package/dist/core/environment.js +23 -0
  65. package/dist/core/errors.js +7 -0
  66. package/dist/{internal/core → core}/index.d.ts +2 -0
  67. package/dist/core/match.js +33 -0
  68. package/dist/core/navigation-router.d.ts +15 -0
  69. package/dist/core/navigation-router.js +64 -0
  70. package/dist/core/navigation.d.ts +15 -0
  71. package/dist/core/navigation.js +92 -0
  72. package/dist/core/presentation.d.ts +5 -0
  73. package/dist/core/presentation.js +69 -0
  74. package/dist/core/resource-types.d.ts +37 -0
  75. package/dist/core/resources.d.ts +19 -0
  76. package/dist/core/resources.js +345 -0
  77. package/dist/core/responses.d.ts +15 -0
  78. package/dist/core/responses.js +48 -0
  79. package/dist/{internal/core → core}/router.d.ts +1 -1
  80. package/dist/core/router.js +204 -0
  81. package/dist/core/serialize.d.ts +5 -0
  82. package/dist/core/serialize.js +17 -0
  83. package/dist/core/store.d.ts +6 -0
  84. package/dist/core/store.js +21 -0
  85. package/dist/core/submission.d.ts +30 -0
  86. package/dist/core/submission.js +41 -0
  87. package/dist/{internal/core → core}/types.d.ts +16 -1
  88. package/dist/core/url.d.ts +7 -0
  89. package/dist/core/url.js +12 -0
  90. package/dist/core/utils.d.ts +5 -0
  91. package/dist/core/utils.js +5 -0
  92. package/dist/files/index.js +64 -0
  93. package/dist/preact/await.d.ts +7 -0
  94. package/dist/preact/await.js +19 -0
  95. package/dist/preact/client.d.ts +7 -0
  96. package/dist/preact/client.js +67 -0
  97. package/dist/preact/context.d.ts +18 -0
  98. package/dist/preact/context.js +23 -0
  99. package/dist/preact/document.d.ts +15 -0
  100. package/dist/preact/document.js +155 -0
  101. package/dist/{internal/preact → preact}/fetcher.d.ts +9 -5
  102. package/dist/preact/fetcher.js +45 -0
  103. package/dist/{internal/preact → preact}/form.d.ts +5 -6
  104. package/dist/preact/form.js +21 -0
  105. package/dist/{internal/preact → preact}/hooks.d.ts +7 -6
  106. package/dist/preact/hooks.js +25 -0
  107. package/dist/preact/index.d.ts +18 -0
  108. package/dist/preact/index.js +15 -0
  109. package/dist/preact/lazy-route.d.ts +19 -0
  110. package/dist/preact/lazy-route.js +51 -0
  111. package/dist/preact/navigation-state.d.ts +2 -0
  112. package/dist/preact/navigation-state.js +9 -0
  113. package/dist/preact/navigation.d.ts +28 -0
  114. package/dist/preact/navigation.js +60 -0
  115. package/dist/preact/root-context.d.ts +13 -0
  116. package/dist/preact/root-context.js +9 -0
  117. package/dist/preact/root-data.d.ts +8 -0
  118. package/dist/preact/root-data.js +28 -0
  119. package/dist/preact/route-hooks.d.ts +32 -0
  120. package/dist/preact/route-hooks.js +94 -0
  121. package/dist/preact/route-types.d.ts +54 -0
  122. package/dist/preact/router.d.ts +16 -0
  123. package/dist/preact/router.js +63 -0
  124. package/dist/{internal/preact → preact}/routes.d.ts +1 -1
  125. package/dist/preact/routes.js +12 -0
  126. package/dist/{internal/preact → preact}/runtime.js +1 -1
  127. package/dist/react/context.d.ts +18 -0
  128. package/dist/react/context.js +23 -0
  129. package/dist/react/data.d.ts +5 -0
  130. package/dist/react/data.js +3 -0
  131. package/dist/{internal/react → react}/fetcher.d.ts +2 -2
  132. package/dist/react/fetcher.js +34 -0
  133. package/dist/{internal/react → react}/form.d.ts +5 -6
  134. package/dist/react/form.js +21 -0
  135. package/dist/react/hooks.js +25 -0
  136. package/dist/{internal/react → react}/index.d.ts +1 -1
  137. package/dist/react/index.js +10 -0
  138. package/dist/{internal/react → react}/link.d.ts +2 -2
  139. package/dist/react/link.js +27 -0
  140. package/dist/react/resources/components.d.ts +64 -0
  141. package/dist/react/resources/components.js +239 -0
  142. package/dist/{internal/react → react}/routes.d.ts +1 -1
  143. package/dist/react/routes.js +12 -0
  144. package/dist/react/runtime.js +1 -0
  145. package/dist/server/application.d.ts +4 -0
  146. package/dist/server/application.js +119 -0
  147. package/dist/server/assets.d.ts +5 -0
  148. package/dist/server/assets.js +7 -0
  149. package/dist/server/handler.d.ts +19 -0
  150. package/dist/server/handler.js +22 -0
  151. package/dist/server/http.d.ts +4 -0
  152. package/dist/server/http.js +27 -0
  153. package/dist/{internal/server → server}/index.d.ts +2 -3
  154. package/dist/server/index.js +76 -0
  155. package/dist/server/node.d.ts +3 -0
  156. package/dist/server/node.js +3 -0
  157. package/dist/server/preact.d.ts +3 -0
  158. package/dist/server/preact.js +4 -0
  159. package/dist/vite/application/browser-boundary.d.ts +3 -0
  160. package/dist/vite/application/browser-boundary.js +35 -0
  161. package/dist/vite/application/lazy-files.d.ts +2 -0
  162. package/dist/vite/application/lazy-files.js +87 -0
  163. package/dist/vite/application/vite.d.ts +9 -0
  164. package/dist/vite/application/vite.js +101 -0
  165. package/dist/{internal/vite → vite}/index.d.ts +2 -1
  166. package/dist/vite/index.js +104 -0
  167. package/dist/vite/preact.d.ts +11 -0
  168. package/dist/vite/preact.js +15 -0
  169. package/dist/vite/react.d.ts +9 -0
  170. package/dist/vite/react.js +14 -0
  171. package/dist/{internal/vite → vite}/transport.d.ts +1 -1
  172. package/dist/vite/transport.js +35 -0
  173. package/jsr.json +28 -11
  174. package/package.json +119 -38
  175. package/dist/client.d.ts +0 -2
  176. package/dist/client.js +0 -2
  177. package/dist/core.d.ts +0 -2
  178. package/dist/core.js +0 -2
  179. package/dist/files.d.ts +0 -2
  180. package/dist/files.js +0 -2
  181. package/dist/internal/client/deserialize.js +0 -11
  182. package/dist/internal/client/index.js +0 -44
  183. package/dist/internal/core/errors.js +0 -6
  184. package/dist/internal/core/index.js +0 -6
  185. package/dist/internal/core/match.js +0 -27
  186. package/dist/internal/core/router.js +0 -189
  187. package/dist/internal/core/types.js +0 -5
  188. package/dist/internal/core/url.d.ts +0 -2
  189. package/dist/internal/core/url.js +0 -6
  190. package/dist/internal/files/index.js +0 -77
  191. package/dist/internal/preact/context.d.ts +0 -18
  192. package/dist/internal/preact/context.js +0 -20
  193. package/dist/internal/preact/fetcher.js +0 -28
  194. package/dist/internal/preact/form.js +0 -41
  195. package/dist/internal/preact/hooks.js +0 -35
  196. package/dist/internal/preact/index.d.ts +0 -9
  197. package/dist/internal/preact/index.js +0 -7
  198. package/dist/internal/preact/link.d.ts +0 -12
  199. package/dist/internal/preact/link.js +0 -28
  200. package/dist/internal/preact/routes.js +0 -22
  201. package/dist/internal/react/context.d.ts +0 -18
  202. package/dist/internal/react/context.js +0 -20
  203. package/dist/internal/react/fetcher.js +0 -28
  204. package/dist/internal/react/form.js +0 -41
  205. package/dist/internal/react/hooks.js +0 -35
  206. package/dist/internal/react/index.js +0 -7
  207. package/dist/internal/react/link.js +0 -28
  208. package/dist/internal/react/routes.js +0 -22
  209. package/dist/internal/react/runtime.js +0 -2
  210. package/dist/internal/server/index.js +0 -81
  211. package/dist/internal/vite/index.js +0 -132
  212. package/dist/internal/vite/transport.js +0 -42
  213. package/dist/preact.d.ts +0 -2
  214. package/dist/preact.js +0 -2
  215. package/dist/react.d.ts +0 -2
  216. package/dist/react.js +0 -2
  217. package/dist/server.d.ts +0 -2
  218. package/dist/server.js +0 -2
  219. package/dist/vite.d.ts +0 -2
  220. package/dist/vite.js +0 -2
  221. package/src/client.ts +0 -2
  222. package/src/core.ts +0 -2
  223. package/src/files.ts +0 -2
  224. package/src/internal/core/url.ts +0 -6
  225. package/src/internal/preact/context.ts +0 -46
  226. package/src/internal/preact/form.ts +0 -79
  227. package/src/internal/preact/link.ts +0 -46
  228. package/src/internal/react/context.ts +0 -46
  229. package/src/internal/react/form.ts +0 -79
  230. package/src/internal/react/index.ts +0 -13
  231. package/src/preact.ts +0 -2
  232. package/src/react.ts +0 -2
  233. package/src/server.ts +0 -2
  234. package/src/vite.ts +0 -2
  235. /package/{src/internal → .generated}/client/deserialize.ts +0 -0
  236. /package/{src/internal → .generated}/core/match.ts +0 -0
  237. /package/{src/internal → .generated}/files/index.ts +0 -0
  238. /package/{src/internal → .generated}/preact/runtime.ts +0 -0
  239. /package/{src/internal → .generated}/react/runtime.ts +0 -0
  240. /package/dist/{internal/client → client}/deserialize.d.ts +0 -0
  241. /package/dist/{internal/core → core}/errors.d.ts +0 -0
  242. /package/dist/{internal/core → core}/match.d.ts +0 -0
  243. /package/dist/{internal/files → files}/index.d.ts +0 -0
  244. /package/dist/{internal/preact → preact}/runtime.d.ts +0 -0
  245. /package/dist/{internal/react → react}/hooks.d.ts +0 -0
  246. /package/dist/{internal/react → react}/runtime.d.ts +0 -0
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # smolter _
2
2
 
3
3
  <!-- bundlejs:start -->
4
- [![react gzip size](https://deno.bundlejs.com/?q=%40kasperrt%2Fsmolter%400.0.1%2Freact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22react%2F*%22%5D%7D%7D&badge)](https://bundlejs.com/?q=%40kasperrt%2Fsmolter%400.0.1%2Freact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22react%2F*%22%5D%7D%7D&bundle)
5
- [![preact gzip size](https://deno.bundlejs.com/?q=%40kasperrt%2Fsmolter%400.0.1%2Fpreact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22preact%22%2C%22preact%2F*%22%5D%7D%7D&badge)](https://bundlejs.com/?q=%40kasperrt%2Fsmolter%400.0.1%2Fpreact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22preact%22%2C%22preact%2F*%22%5D%7D%7D&bundle)
4
+ [![react gzip size](https://deno.bundlejs.com/?q=%40kasperrt%2Fsmolter%400.3.0%2Freact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22react%2F*%22%5D%7D%7D&badge)](https://bundlejs.com/?q=%40kasperrt%2Fsmolter%400.3.0%2Freact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22react%22%2C%22react%2F*%22%5D%7D%7D&bundle)
5
+ [![preact gzip size](https://deno.bundlejs.com/?q=%40kasperrt%2Fsmolter%400.3.0%2Fpreact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22preact%22%2C%22preact%2F*%22%5D%7D%7D&badge)](https://bundlejs.com/?q=%40kasperrt%2Fsmolter%400.3.0%2Fpreact&treeshake=%5B*%5D&config=%7B%22compression%22%3A%22gzip%22%2C%22esbuild%22%3A%7B%22external%22%3A%5B%22preact%22%2C%22preact%2F*%22%5D%7D%7D&bundle)
6
6
  <!-- bundlejs:end -->
7
7
 
8
8
  A typed data router for React and Preact. **Zero runtime dependencies.**
@@ -14,6 +14,10 @@ loader; `shouldRevalidate` decides when that work is needed.
14
14
  Inspired by [wouter](https://github.com/molefrog/wouter)
15
15
  and [React Router](https://reactrouter.com/).
16
16
 
17
+ [Read the documentation](https://kasperrt.github.io/smolter/react/docs/) for guides and the complete API reference. The site itself uses smolter routes.
18
+
19
+ Start with [loaders](https://kasperrt.github.io/smolter/react/docs/loaders/), [actions](https://kasperrt.github.io/smolter/react/docs/actions/), [forms and validation](https://kasperrt.github.io/smolter/react/docs/forms/), or [fetcher reads and mutations](https://kasperrt.github.io/smolter/react/docs/fetchers/). Each guide connects the handler to an actual route URL and its consuming view.
20
+
17
21
  ## Contents
18
22
 
19
23
  - [Install](#install)
@@ -25,7 +29,10 @@ and [React Router](https://reactrouter.com/).
25
29
  - [Types follow the handler](#types-follow-the-handler)
26
30
  - [Server rendering](#server-rendering)
27
31
  - [Package entries](#package-entries)
32
+ - [Application integration](#application-integration)
33
+ - [Resource subscriptions](#resource-subscriptions)
28
34
  - [Size and checks](#size-and-checks)
35
+ - [Routing without data hooks](#routing-without-data-hooks)
29
36
 
30
37
  ## Install
31
38
 
@@ -36,7 +43,7 @@ pnpm add @kasperrt/smolter
36
43
  ```
37
44
 
38
45
  ```ts
39
- import { createRouter, useFetcher } from "@kasperrt/smolter/react";
46
+ import { createDataRouter, useFetcher } from "@kasperrt/smolter/react";
40
47
  // Preact: import from "@kasperrt/smolter/preact".
41
48
  ```
42
49
 
@@ -49,15 +56,16 @@ pnpm dev
49
56
 
50
57
  | App | Open | Data |
51
58
  | --- | --- | --- |
52
- | [React SPA](https://github.com/kasperrt/smolter/tree/main/apps/react) | http://127.0.0.1:5173 | Client loaders/actions, localStorage |
53
- | [Preact SPA](https://github.com/kasperrt/smolter/tree/main/apps/preact) | http://127.0.0.1:5174 | Client loaders/actions, localStorage |
54
- | [React SSR](https://github.com/kasperrt/smolter/tree/main/apps/react-ssr) | http://127.0.0.1:5175 | Server loaders/actions, hydration |
55
- | [Preact SSR](https://github.com/kasperrt/smolter/tree/main/apps/preact-ssr) | http://127.0.0.1:5176 | Server loaders/actions, hydration |
59
+ | [React SPA](./apps/react) | http://127.0.0.1:5173 | Client loaders/actions, localStorage |
60
+ | [Preact SPA](./apps/preact) | http://127.0.0.1:5174 | Client loaders/actions, localStorage |
61
+ | [React SSR](./apps/react-ssr) | http://127.0.0.1:5175 | Server loaders/actions, hydration |
62
+ | [Preact SSR](./apps/preact-ssr) | http://127.0.0.1:5176 | Server loaders/actions, hydration |
56
63
 
57
64
  Each app has its own entrypoints, routes, and data code. Only UI components are
58
65
  shared. Preact examples do not import React. Each includes:
59
66
 
60
- - `/`: counter, fetcher POST, automatic and manual revalidation.
67
+ - `/`: a short introduction and a link to the docs.
68
+ - `/examples/counter`: fetcher POST, automatic and manual revalidation.
61
69
  - `/tasks`: list, create form, and a fetcher-only task preview.
62
70
  - `/tasks/:id`: PATCH, DELETE, validation, and skipping no-op revalidation.
63
71
  - `/about`: the separation between data and rendering.
@@ -81,7 +89,7 @@ or filename parser enters the browser bundle.
81
89
  ```ts
82
90
  // vite.config.ts
83
91
  import { defineConfig } from "vite";
84
- import { fileRouter } from "@kasperrt/smolter/vite";
92
+ import { fileRouter } from "@kasperrt/smolter/react/vite";
85
93
 
86
94
  export default defineConfig({
87
95
  plugins: [fileRouter({ directory: "src/routes" })],
@@ -90,10 +98,10 @@ export default defineConfig({
90
98
 
91
99
  ```ts
92
100
  // app.ts
93
- import { createRouter } from "@kasperrt/smolter/react";
101
+ import { createDataRouter } from "@kasperrt/smolter/react";
94
102
  import routes from "virtual:smolter/routes";
95
103
 
96
- export const router = createRouter(routes, { browser: true });
104
+ export const router = createDataRouter(routes, { browser: true });
97
105
  ```
98
106
 
99
107
  | File or folder | URL |
@@ -121,25 +129,25 @@ For the virtual module, add this declaration to your app:
121
129
  // env.d.ts
122
130
  // Include vite/client in your tsconfig types as usual.
123
131
  declare module "virtual:smolter/routes" {
124
- const routes: import("@kasperrt/smolter/core").Route[];
132
+ const routes: import("@kasperrt/smolter/react").Route[];
125
133
  export default routes;
126
134
  }
127
135
  ```
128
136
 
129
- Outside Vite, `flatRoutes(directory)` from `@kasperrt/smolter/files` returns
137
+ Outside Vite, `flatRoutes(directory)` from `@kasperrt/smolter/react/vite` returns
130
138
  `{ path, file }[] | Error` for your build tool to turn into imports.
131
139
 
132
140
  ### Manual routes
133
141
 
134
142
  ```tsx
135
- import { createRouter, defineRoute } from "@kasperrt/smolter/react";
143
+ import { createDataRouter, defineRoute } from "@kasperrt/smolter/react";
136
144
  import * as tasks from "./tasks/route";
137
145
  import * as task from "./task/route";
138
146
 
139
147
  export const tasksRoute = defineRoute("/tasks", tasks);
140
148
  export const taskRoute = defineRoute("/tasks/:id", task);
141
149
  export const routes = [tasksRoute, taskRoute];
142
- export const router = createRouter(routes, { browser: true });
150
+ export const router = createDataRouter(routes, { browser: true });
143
151
  ```
144
152
 
145
153
  Or pass handlers directly to `defineRoute(path, { loader, action, default: View })`.
@@ -167,11 +175,12 @@ export { default } from "./view";
167
175
  export { loader } from "./loader";
168
176
  export { action } from "./action";
169
177
 
170
- export { clientLoader } from "./client-loader";
171
- export { clientAction } from "./client-action";
178
+ export { clientLoader } from "./clientLoader";
179
+ export { clientAction } from "./clientAction";
172
180
 
173
- export { shouldRevalidate } from "./should-revalidate";
174
- export { HydrateFallback, ErrorBoundary } from "../../boundaries";
181
+ export { shouldRevalidate } from "./shouldRevalidate";
182
+ export { HydrateFallback } from "./HydrateFallback";
183
+ export { ErrorBoundary } from "./ErrorBoundary";
175
184
  ```
176
185
 
177
186
  With the optional server integration:
@@ -183,8 +192,8 @@ With the optional server integration:
183
192
  - SSR executes the server loader and hydration reuses that data.
184
193
 
185
194
  ```ts
186
- // client-loader.ts
187
- import type { ClientLoaderArgs } from "@kasperrt/smolter/client";
195
+ // clientLoader.ts
196
+ import type { ClientLoaderArgs } from "@kasperrt/smolter/react/client";
188
197
  import type { loader } from "./loader";
189
198
 
190
199
  export async function clientLoader({ serverLoader }: ClientLoaderArgs<typeof loader>) {
@@ -193,8 +202,8 @@ export async function clientLoader({ serverLoader }: ClientLoaderArgs<typeof loa
193
202
  ```
194
203
 
195
204
  ```ts
196
- // client-action.ts
197
- import type { ClientActionArgs } from "@kasperrt/smolter/client";
205
+ // clientAction.ts
206
+ import type { ClientActionArgs } from "@kasperrt/smolter/react/client";
198
207
  import type { action } from "./action";
199
208
 
200
209
  export async function clientAction({ serverAction }: ClientActionArgs<typeof action>) {
@@ -234,17 +243,17 @@ in a client bundle. Type-only imports from server handlers are safe. Do not
234
243
  import server code directly into client views or client handlers.
235
244
 
236
245
  The Vite dev plugin mounts `/_smolter?url=...`. Production hosts dispatch that
237
- endpoint through `handleRequest(routes, request)` from `@kasperrt/smolter/server`, using
246
+ endpoint through `handleRequest(routes, request)` from `@kasperrt/smolter/react/server`, using
238
247
  the requested route URL. Both SSR examples include a working host. The host
239
248
  owns authentication, session cookies, HTTP policy, and deployment.
240
249
 
241
250
  Manual server routes use `serverRoute<typeof import("./route")>(path, clientModule)`
242
- from `@kasperrt/smolter/client` in the browser and `defineRoute` on the server. This keeps
251
+ from `@kasperrt/smolter/react/client` in the browser and `defineRoute` on the server. This keeps
243
252
  the type connection without importing server code at runtime. To use manual
244
253
  tables with the dev transport:
245
254
 
246
255
  ```ts
247
- import { routerPlugin } from "@kasperrt/smolter/vite";
256
+ import { routerPlugin } from "@kasperrt/smolter/react/vite";
248
257
 
249
258
  routerPlugin({
250
259
  clientRoutes: "src/manual-browser-routes.ts",
@@ -254,7 +263,7 @@ routerPlugin({
254
263
 
255
264
  Each table exports `routes`. The standalone examples contain both tables.
256
265
 
257
- Without the optional integration, `createRouter` invokes handlers locally:
266
+ Without the optional integration, `createDataRouter` invokes handlers locally:
258
267
  client handlers take precedence, with ordinary handlers as fallbacks.
259
268
  `loadRouter` selects server handlers only. Core-only usage does not create HTTP
260
269
  endpoints or compiler boundaries by itself.
@@ -315,7 +324,7 @@ Fetcher results belong to `fetcher.data`, not `useActionData()`.
315
324
  ## Decide when to revalidate
316
325
 
317
326
  ```ts
318
- // should-revalidate.ts
327
+ // shouldRevalidate.ts
319
328
  import type { RevalidationArgs } from "@kasperrt/smolter/react";
320
329
 
321
330
  export function shouldRevalidate({ actionResult, defaultShouldRevalidate }: RevalidationArgs) {
@@ -340,7 +349,25 @@ and explicit `fetcher.load()` calls always load their destination.
340
349
  This controls loader refreshes; it does not rerun actions or reload the document.
341
350
  Existing page data stays visible during manual and post-action refreshes.
342
351
 
343
- `const revalidate = useRevalidator(); await revalidate()` requests a manual refresh.
352
+ `useRevalidator()` returns an async function. Target a registered route ID or path
353
+ pattern to refresh only its active data, including loaded fetchers:
354
+
355
+ ```tsx
356
+ const revalidate = useRevalidator();
357
+
358
+ await revalidate({ route: "/tasks/:id" });
359
+ await revalidate({ route: "root" });
360
+ await revalidate({ route: ["root", "/tasks/:id"] });
361
+ ```
362
+
363
+ Without a target, `revalidate()` refreshes the active page, loaded fetchers, and
364
+ registered root/layout data. `shouldRevalidate` still applies. Inactive routes
365
+ are not loaded, unknown targets do nothing, and revalidation never navigates.
366
+
367
+ The Preact root integration uses `root` as its default ID. Configure its
368
+ `loaderPath` with a registered data route to enable root refreshes. Custom React
369
+ or Preact layouts can use `router.registerRevalidator(id, callback)`; call its
370
+ returned cleanup function when the layout is removed.
344
371
  The task-detail examples return `{ changed: false }` for an unchanged title;
345
372
  the corresponding loader is skipped.
346
373
 
@@ -366,7 +393,7 @@ remount the fallback during revalidation. Return a `Response` with a `Location`
366
393
  ## Server rendering
367
394
 
368
395
  ```tsx
369
- import { loadRouter, serialize } from "@kasperrt/smolter/server";
396
+ import { loadRouter, serialize } from "@kasperrt/smolter/react/server";
370
397
 
371
398
  const router = await loadRouter(routes, incomingRequest);
372
399
  const html = renderToString(
@@ -376,18 +403,18 @@ const hydrationJSON = serialize(router.getSnapshot());
376
403
  ```
377
404
 
378
405
  Create a fresh router per request. Embed the serialized snapshot in a JSON
379
- script, restore it with `deserialize` from `@kasperrt/smolter/client`, and pass it as
380
- `hydrationData` to `createRouter`. This preserves loader errors through hydration
406
+ script, restore it with `deserialize` from `@kasperrt/smolter/react/client`, and pass it as
407
+ `hydrationData` to `createDataRouter`. This preserves loader errors through hydration
381
408
  without exposing server stacks or causes. Error boundaries should display the
382
409
  error message, not its stack.
383
410
 
384
411
  ```ts
385
- import { deserialize } from "@kasperrt/smolter/client";
386
- import { createRouter } from "@kasperrt/smolter/react";
412
+ import { deserialize } from "@kasperrt/smolter/react/client";
413
+ import { createDataRouter } from "@kasperrt/smolter/react";
387
414
  import routes from "virtual:smolter/routes";
388
415
 
389
416
  const data = document.getElementById("smolter-data");
390
- const router = createRouter(routes, {
417
+ const router = createDataRouter(routes, {
391
418
  browser: true,
392
419
  hydrationData: data?.textContent ? deserialize(data.textContent) : undefined,
393
420
  });
@@ -402,47 +429,232 @@ The SSR examples use the same server route definitions for HTML and data request
402
429
 
403
430
  ## Package entries
404
431
 
405
- Use `@kasperrt/smolter/react` for React 18+ and `@kasperrt/smolter/preact` for Preact 10.25+.
406
- The root `@kasperrt/smolter` entry (also available as `@kasperrt/smolter/core`) is framework-independent.
407
- Server helpers live in `@kasperrt/smolter/server`; optional browser transport in `@kasperrt/smolter/client`;
408
- flat file routing in `@kasperrt/smolter/vite` and `@kasperrt/smolter/files`.
432
+ Use `@kasperrt/smolter/react` for React 18+ and `@kasperrt/smolter/preact` for Preact 11.0.1+.
433
+ Choose one renderer for your application. Both expose the same routing API:
434
+
435
+ | Purpose | React | Preact |
436
+ | --- | --- | --- |
437
+ | Components, hooks, router, data types | `@kasperrt/smolter/react` | `@kasperrt/smolter/preact` |
438
+ | Optional browser transport | `@kasperrt/smolter/react/client` | `@kasperrt/smolter/preact/client` |
439
+ | SSR and HTTP data dispatch | `@kasperrt/smolter/react/server` | `@kasperrt/smolter/preact/server` |
440
+ | Vite plugin and flat-file discovery | `@kasperrt/smolter/react/vite` | `@kasperrt/smolter/preact/vite` |
441
+
442
+ `@kasperrt/smolter/utils` contains browser-safe matching and error helpers.
443
+ The main renderer entries never import server or build modules. Named imports
444
+ are tree-shaken; optional transport is included only when you import `/client`.
445
+ Server entries do not import either UI renderer. Vite entries are build-time only.
446
+
447
+ **Migrating renderer subpaths:** replace `/core` imports for types, router factories, and
448
+ `defineRoute` with your renderer entry. Use `/utils` for `matchRoutes`,
449
+ `internalURL` and `safeWrapAsync`. Move `/client`, `/server`,
450
+ `/files`, and `/vite` imports to the corresponding renderer-prefixed path above.
451
+ The bare package root and old top-level subpaths are no longer exported.
452
+
453
+ See the [0.3 migration guide](https://kasperrt.github.io/smolter/react/docs/migration-0.3/) and [changelog](./CHANGELOG.md).
454
+
455
+ **Router factory migration:** code that previously used `createRouter` with
456
+ loaders, actions, fetchers or revalidation must now use `createDataRouter`.
457
+ `createRouter` now creates a navigation-only router. SSR and file-router
458
+ application helpers select `createDataRouter` automatically.
409
459
 
410
460
  On JSR, install `@kasperrt/smolter` using the
411
461
  [JSR package instructions](https://jsr.io/docs/npm-compatibility) and import
412
- `@kasperrt/smolter/react` or `@kasperrt/smolter/preact`. Its `core`, `client`,
413
- `server`, and `files` subpaths match npm. The Vite plugin is npm-only:
414
- use `@kasperrt/smolter/vite` from the npm package when adding file routing.
462
+ `@kasperrt/smolter/react` or `@kasperrt/smolter/preact`. Its renderer, client, server and utility subpaths match npm. The Vite plugin is npm-only:
463
+ use `@kasperrt/smolter/react/vite` from the npm package when adding file routing.
464
+
465
+ ## Application integration
466
+
467
+ Import routing, forms and data hooks from `@kasperrt/smolter/preact`.
468
+ Document rendering is optional: `@kasperrt/smolter/preact/document` supplies
469
+ `Document`, `Meta`, `Links`, `Scripts` and `ScrollRestoration`.
470
+ `@kasperrt/smolter/preact/client` supplies `mountApplication`,
471
+ `configureApplication` and the server transport helpers. Mounting connects
472
+ hydration, root data and navigation presentation to the same core router.
473
+ These modules remain tree-shakable; basic routing does not import the document
474
+ or mounting code. The size table also measures all three together, because
475
+ moving APIs to subpaths does not make their implementation disappear.
476
+
477
+ ```ts
478
+ // vite.config.ts
479
+ import { defineConfig } from "vite";
480
+ import { applicationPlugins } from "@kasperrt/smolter/preact/vite";
481
+
482
+ export default defineConfig({
483
+ plugins: applicationPlugins({ directory: "src/routes" }),
484
+ });
485
+ ```
486
+
487
+ ```tsx
488
+ // src/entry.client.tsx
489
+ import routes from "virtual:smolter/routes";
490
+ import { mountApplication } from "@kasperrt/smolter/preact/client";
491
+ import * as root from "./root";
492
+
493
+ mountApplication(routes, root);
494
+ ```
495
+
496
+ `root` exports a default component containing `Outlet` and a `Layout` wrapping
497
+ it in `Document`, a head, and a body containing `Scripts`. Its optional loader
498
+ supplies root data. `renderApplication(request, routes, root, entry)` from
499
+ `preact/server` renders the same tree and serializes hydration data;
500
+ `dispatchRoute(request, routes)` handles route data requests. Server rendering
501
+ requires the optional `preact-render-to-string` peer.
502
+
503
+ Deployment-specific URL mapping can be configured once at startup with
504
+ `configureApplication({ resolveURL, isDocumentHandoff, leaveDocument,
505
+ entryScript })`. Do not put user-specific or request-specific state there.
506
+ The library does not define application domains, ports, or branding.
507
+
508
+ `utils/http` contains the Node request/response adapter; `utils/assets` contains
509
+ manifest/preload helpers; `utils/responses` contains response normalization.
510
+ Keep the first two in server/build entrypoints. Browser application imports do
511
+ not include them.
512
+
513
+ ### Virtual modules and entrypoints
514
+
515
+ `virtual:smolter/routes` is the default route-array export generated by the Vite
516
+ plugin from `src/routes`. It is not a physical file or a runtime package.
517
+ The server build retains loaders/actions; the browser build strips their
518
+ re-exports and installs server proxies. `entry.client.tsx` and `entry.server.tsx`
519
+ are application-owned files wiring those manifests to hydration and SSR.
520
+ Manual tables can be imported directly instead.
521
+
522
+ See the [virtual routes guide](https://kasperrt.github.io/smolter/react/docs/virtual-routes)
523
+ for the exact contract, TypeScript declaration, and both entrypoint examples.
524
+
525
+ ### Express hosting
526
+
527
+ Keep Express in control of metrics, tracing, authentication and static files.
528
+ Mount `createRequestHandler({ build, entry })` from
529
+ `@kasperrt/smolter/utils/http` after those middleware. `build` is the compiled
530
+ server entry and `entry` is the browser entry URL from Vite's manifest. Do not
531
+ consume request bodies with Express body parsers before this handler.
532
+ The adapter has no Express dependency and forwards failures to `next(error)`.
533
+
534
+ See the [Express guide](https://kasperrt.github.io/smolter/react/docs/express)
535
+ for a complete server example and current buffering limitations.
536
+
537
+ ## Resource subscriptions
538
+
539
+ `@kasperrt/smolter/react/data` adds subscriptions to named resources when their
540
+ lifetime is independent of URL navigation. The state and cancellation logic
541
+ lives in core; the entry adds React bindings without DOM or HTTP globals.
542
+
543
+ ```ts
544
+ import { createResourceRouter } from "@kasperrt/smolter/react/data";
545
+
546
+ const resources = createResourceRouter(new Map([
547
+ ["settings", {
548
+ loader: async ({ signal }) => ({
549
+ data: await readSettings(signal),
550
+ error: "",
551
+ }),
552
+ action: async ({ input, signal }) => ({
553
+ data: await saveSettings(input, signal),
554
+ error: "",
555
+ }),
556
+ }],
557
+ ]));
558
+ ```
559
+
560
+ `ResourceProvider` owns the store lifetime. `Resource` selects a resource by
561
+ `routeId` and params. `useResourceData` reads it; `useRouteLoaderData` reads a
562
+ named resource. `useResourceFetcher` returns `[state, operations]`, with
563
+ independent `load` and `submit` operations. Successful mutations consult the
564
+ resource's `shouldRevalidate` before reloading its data. Last-subscriber cleanup
565
+ aborts pending work; `persistent` keeps a resource until explicitly disposed.
566
+ This optional entry does not contribute to the base React bundle measurement.
415
567
 
416
568
  ## Size and checks
417
569
 
418
- `pnpm size` measures every browser export with esbuild, Terser, and gzip level 9.
419
- Frameworks are excluded; library dependencies are included. It compares the same
420
- build settings against pinned wouter entries. Both adapters must be strictly
421
- smaller than their corresponding wouter entry; exceeding either fails the check. Optional server transport is measured separately and included in SSR
422
- example labels. File discovery is build-only.
570
+ Use `createRouter` for navigation only, or `createDataRouter` for loaders,
571
+ actions, fetchers and revalidation. Both are named exports from
572
+ `@kasperrt/smolter/preact` and `/react`. No extra package or plugin is required.
573
+ The production bundler can remove the data engine when only `createRouter` is used.
574
+
575
+ `pnpm size` regenerates this table and the site's size data using identical
576
+ minifiers. The routing-only gate compares our selected exports with wouter's
577
+ routing subset: `Router`, `Route`, `Switch`, `Link`, `useParams`, and `useLocation`.
578
+ Both complete wouter entries are reported too. The APIs differ; this is not
579
+ a claim of identical features.
423
580
 
424
581
  <!-- size-comparison:start -->
425
582
  | Browser exports | Gzip bytes |
426
583
  | --- | ---: |
427
- | `@kasperrt/smolter/react` | 2445 |
428
- | `@kasperrt/smolter/preact` | 2445 |
429
- | `@kasperrt/smolter/react + @kasperrt/smolter/client` | 2782 |
430
- | `@kasperrt/smolter/preact + @kasperrt/smolter/client` | 2781 |
584
+ | `React: routing-only named exports` | 1245 |
585
+ | `Preact: routing-only named exports` | 1405 |
586
+ | `@kasperrt/smolter/react` | 2873 |
587
+ | `@kasperrt/smolter/preact` | 4748 |
588
+ | `@kasperrt/smolter/react + @kasperrt/smolter/react/client` | 3219 |
589
+ | `@kasperrt/smolter/preact + server transport` | 5059 |
590
+ | `@kasperrt/smolter/preact + client + document (application without lazy routes)` | 7415 |
591
+ | `@kasperrt/smolter/preact + client + document + lazy-route (file-routed application)` | 7696 |
592
+ | `@kasperrt/smolter/react/data (optional resource API)` | 2962 |
593
+ | `React: common routing/data exports` | 2683 |
594
+ | `Preact: common routing/data exports` | 2966 |
595
+ | `wouter: routing subset (Router, Route, Switch, Link, useParams, useLocation)` | 2854 |
596
+ | `wouter-preact: same routing subset` | 2211 |
431
597
  | `wouter@3.13.0` | 3091 |
432
598
  | `wouter-preact@3.13.0` | 2450 |
433
599
  | `react-router@8.4.0` | 60994 |
434
600
  <!-- size-comparison:end -->
435
601
 
436
- The table is generated by `pnpm size` from all exports of each listed entry,
602
+ The common-export rows measure the same named API set: `createDataRouter`,
603
+ `defineRoute`, `RouterProvider`, `Routes`, `Link`, `Form`, `useRouter`,
604
+ `useLoaderData`, `useActionData`, `useParams`, `useLocation`,
605
+ `useRevalidator` and `useFetcher`. Preact’s link and submission APIs currently
606
+ have additional behavior; equal names do not imply identical implementations.
607
+ The routing-only rows retain `createRouter`, `defineRoute`, `RouterProvider`,
608
+ `Routes`, `Link`, `useParams` and `useLocation`. Full Preact also exposes richer
609
+ application APIs. These tiers overlap: do not add the rows together.
610
+
611
+ The table is generated by `pnpm size` from the named subsets above or all exports of each other listed entry,
437
612
  using production ESM bundles, esbuild, Terser, and gzip level 9. React, React DOM,
438
613
  and Preact are external in every bundle. Transitive library dependencies are
439
614
  included. React Router provides a broader API; this compares complete entry
440
615
  sizes, not equivalent feature sets or the minimum code for one route.
441
- `@kasperrt/smolter/client` adds browser transport for server loaders/actions; server-only
616
+ `@kasperrt/smolter/react/client` adds browser transport for server loaders/actions; server-only
442
617
  rendering code and the Vite plugin are not shipped to the browser.
443
618
 
619
+ ### Routing without data hooks
620
+
621
+ ```tsx
622
+ import { render } from "preact";
623
+ import {
624
+ createRouter,
625
+ defineRoute,
626
+ Link,
627
+ RouterProvider,
628
+ Routes,
629
+ } from "@kasperrt/smolter/preact";
630
+ import Home from "./routes/home";
631
+ import About from "./routes/about";
632
+
633
+ const router = createRouter([
634
+ defineRoute("/", { default: Home }),
635
+ defineRoute("/about", { default: About }),
636
+ ], { browser: true });
637
+
638
+ render(
639
+ <RouterProvider router={router}>
640
+ <nav>
641
+ <Link href="/">Home</Link>
642
+ <Link href="/about">About</Link>
643
+ </nav>
644
+ <Routes />
645
+ </RouterProvider>,
646
+ document.getElementById("app")!,
647
+ );
648
+ ```
649
+
650
+ Add `useParams` for dynamic paths such as `/tasks/:id` and `useLocation` for
651
+ the current URL. Both are included in the routing-only measurement, even though
652
+ this example does not need them. Switch the factory to `createDataRouter` when
653
+ adding loaders, actions or fetchers, importing it from the same entry. SSR hydration and file-routed applications use the
654
+ larger client/document/lazy-route tier; they are not represented by the routing-only number.
655
+
444
656
  Exact current measurements are generated in
445
- [`packages/ui/src/size.json`](https://github.com/kasperrt/smolter/blob/main/packages/ui/src/size.json).
657
+ [`packages/ui/src/size.json`](./packages/ui/src/size.json).
446
658
 
447
659
  ```sh
448
660
  pnpm fix # Formatting
@@ -466,6 +678,8 @@ PRs. [Release workflow](https://github.com/kasperrt/smolter/blob/main/RELEASING.
466
678
  To test a local package build in another project:
467
679
 
468
680
  ```sh
469
- pnpm --dir packages/smolter pack --pack-destination ../..
681
+ pnpm pack
470
682
  pnpm add /absolute/path/to/kasperrt-smolter-0.0.1.tgz
471
683
  ```
684
+
685
+ Workspace structure and rendering checks are documented in [CONTRIBUTING.md](./CONTRIBUTING.md).
@@ -0,0 +1,10 @@
1
+ //#region .generated/client/deserialize.ts
2
+ /** Restore a trusted snapshot produced by @kasperrt/smolter/server serialize, including its route error. */
3
+ function deserialize(json) {
4
+ const snapshot = JSON.parse(json);
5
+ const error = snapshot.error;
6
+ if (error) snapshot.error = Object.assign(new Error(error.message), { name: error.name });
7
+ return snapshot;
8
+ }
9
+ //#endregion
10
+ export { deserialize };
@@ -7,6 +7,7 @@ export type { ClientActionArgs, ClientLoaderArgs } from "../core/index.ts";
7
7
  export { deserialize } from "./deserialize.ts";
8
8
  /** Browser-safe route exports, excluding server implementation code. */
9
9
  export interface ClientRouteModule {
10
+ id?: string;
10
11
  default?: unknown;
11
12
  HydrateFallback?: unknown;
12
13
  ErrorBoundary?: unknown;
@@ -0,0 +1,46 @@
1
+ import { deserialize } from "./deserialize.js";
2
+ //#region .generated/client/index.ts
3
+ /** Browser transport for server routes. File-router builds generate this call. */
4
+ function serverRoute(path, module, handlers = {
5
+ loader: true,
6
+ action: true
7
+ }) {
8
+ const remote = async ({ request, signal }) => {
9
+ const url = new URL(request.url);
10
+ const response = await fetch(`/_smolter?url=${encodeURIComponent(url.pathname + url.search)}`, {
11
+ method: request.method,
12
+ signal,
13
+ ...request.method !== "GET" && { body: await request.formData() }
14
+ });
15
+ const location = response.headers.get("X-Smolter-Redirect");
16
+ if (location) return new Response(null, {
17
+ status: 303,
18
+ headers: { Location: location }
19
+ });
20
+ const data = await response.json();
21
+ if (!response.ok) return new Error(data.error ?? "Route request failed");
22
+ return data;
23
+ };
24
+ return {
25
+ ...module,
26
+ path,
27
+ ...handlers.loader && { loader: remote },
28
+ ...handlers.action && { action: remote },
29
+ ...module.clientLoader && { clientLoader: (args) => module.clientLoader({
30
+ ...args,
31
+ serverLoader: () => remote(args)
32
+ }) },
33
+ ...module.clientAction && { clientAction: (args) => {
34
+ const request = args.request.clone();
35
+ return module.clientAction({
36
+ ...args,
37
+ serverAction: () => remote({
38
+ ...args,
39
+ request: request.clone()
40
+ })
41
+ });
42
+ } }
43
+ };
44
+ }
45
+ //#endregion
46
+ export { deserialize, serverRoute };
@@ -0,0 +1,12 @@
1
+ export interface ApplicationEnvironment {
2
+ resolveURL?: (url: URL) => URL;
3
+ isDocumentHandoff?: (from: URL, to: URL) => boolean;
4
+ leaveDocument?: (destination: URL) => void;
5
+ entryScript?: string;
6
+ }
7
+ export declare let applicationEnvironment: ApplicationEnvironment | undefined;
8
+ /** Configure deployment-specific navigation before rendering or mounting. */
9
+ export declare function configureApplication(environment: ApplicationEnvironment): void;
10
+ export declare function resolveApplicationURL(url: URL): URL;
11
+ export declare function handoffDocument(event: MouseEvent, destination: URL): void;
12
+ export declare function leaveDocument(destination: URL): void;
@@ -0,0 +1,23 @@
1
+ //#region .generated/core/environment.ts
2
+ var applicationEnvironment;
3
+ /** Configure deployment-specific navigation before rendering or mounting. */
4
+ function configureApplication(environment) {
5
+ applicationEnvironment = environment;
6
+ }
7
+ function resolveApplicationURL(url) {
8
+ return applicationEnvironment?.resolveURL?.(url) ?? url;
9
+ }
10
+ function handoffDocument(event, destination) {
11
+ if (!applicationEnvironment?.isDocumentHandoff?.(new URL(location.href), destination)) return;
12
+ event.preventDefault();
13
+ leaveDocument(destination);
14
+ }
15
+ function leaveDocument(destination) {
16
+ if (applicationEnvironment?.leaveDocument) {
17
+ applicationEnvironment.leaveDocument(destination);
18
+ return;
19
+ }
20
+ location.assign(destination.href);
21
+ }
22
+ //#endregion
23
+ export { applicationEnvironment, configureApplication, handoffDocument, leaveDocument, resolveApplicationURL };
@@ -0,0 +1,7 @@
1
+ //#region .generated/core/errors.ts
2
+ /** Resolve returned or rejected errors into Error values without losing their cause. */
3
+ function safeWrapAsync(work) {
4
+ return Promise.resolve().then(work).then((data) => data instanceof Error ? { error: data } : { data }, (cause) => ({ error: Error(String(cause), { cause }) }));
5
+ }
6
+ //#endregion
7
+ export { safeWrapAsync };
@@ -1,6 +1,8 @@
1
1
  /** Framework-independent data routing. @module */
2
2
  export * from "./errors.ts";
3
3
  export * from "./match.ts";
4
+ export * from "./navigation-router.ts";
4
5
  export * from "./router.ts";
6
+ export * from "./serialize.ts";
5
7
  export * from "./types.ts";
6
8
  export * from "./url.ts";