toiljs 0.0.15 → 0.0.19

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 (273) hide show
  1. package/.babelrc +13 -13
  2. package/.gitattributes +2 -2
  3. package/.github/ISSUE_TEMPLATE/bug_report.md +38 -38
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +90 -90
  5. package/.github/ISSUE_TEMPLATE/config.yml +8 -8
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  7. package/.github/PULL_REQUEST_TEMPLATE.md +43 -43
  8. package/.github/changelog-config.json +45 -45
  9. package/.github/dependabot.yml +27 -27
  10. package/.github/workflows/ci.yml +191 -191
  11. package/.prettierrc.json +11 -11
  12. package/.vscode/settings.json +9 -9
  13. package/CHANGELOG.md +116 -5
  14. package/LICENSE +187 -187
  15. package/README.md +524 -315
  16. package/as-pect.asconfig.json +34 -34
  17. package/as-pect.config.js +65 -65
  18. package/assets/logo.svg +36 -36
  19. package/build/backend/.tsbuildinfo +1 -1
  20. package/build/backend/index.d.ts +1 -0
  21. package/build/backend/index.js +20 -1
  22. package/build/cli/.tsbuildinfo +1 -1
  23. package/build/cli/index.js +1320 -696
  24. package/build/client/.tsbuildinfo +1 -1
  25. package/build/client/dev/devtools.d.ts +6 -0
  26. package/build/client/dev/devtools.js +479 -0
  27. package/build/client/dev/error-overlay.d.ts +9 -0
  28. package/build/client/dev/error-overlay.js +19 -4
  29. package/build/client/errors.d.ts +1 -0
  30. package/build/client/errors.js +3 -0
  31. package/build/client/index.d.ts +2 -0
  32. package/build/client/index.js +2 -0
  33. package/build/client/navigation/prefetch.d.ts +1 -0
  34. package/build/client/navigation/prefetch.js +35 -0
  35. package/build/client/routing/Router.js +1 -1
  36. package/build/client/routing/hooks.js +6 -2
  37. package/build/client/routing/loader.d.ts +23 -0
  38. package/build/client/routing/loader.js +53 -7
  39. package/build/client/routing/mount.js +4 -3
  40. package/build/client/rpc.d.ts +1 -0
  41. package/build/client/rpc.js +37 -0
  42. package/build/compiler/.tsbuildinfo +1 -1
  43. package/build/compiler/config.d.ts +16 -0
  44. package/build/compiler/config.js +9 -0
  45. package/build/compiler/docs.js +78 -21
  46. package/build/compiler/generate.js +5 -4
  47. package/build/compiler/index.d.ts +3 -2
  48. package/build/compiler/index.js +2 -2
  49. package/build/compiler/plugin.js +228 -0
  50. package/build/compiler/prerender.d.ts +1 -0
  51. package/build/compiler/prerender.js +1 -1
  52. package/build/compiler/seo.d.ts +1 -1
  53. package/build/compiler/seo.js +20 -5
  54. package/build/compiler/ssg.js +39 -2
  55. package/build/compiler/vite.js +25 -0
  56. package/build/io/.tsbuildinfo +1 -1
  57. package/build/io/codec.d.ts +54 -0
  58. package/build/io/codec.js +143 -0
  59. package/build/io/index.d.ts +1 -2
  60. package/build/io/index.js +1 -2
  61. package/build/logger/.tsbuildinfo +1 -1
  62. package/build/shared/.tsbuildinfo +1 -1
  63. package/eslint.config.js +48 -48
  64. package/examples/basic/client/404.tsx +11 -11
  65. package/examples/basic/client/components/.gitkeep +1 -1
  66. package/examples/basic/client/global-error.tsx +13 -13
  67. package/examples/basic/client/layout.tsx +25 -25
  68. package/examples/basic/client/public/images/.gitkeep +1 -1
  69. package/examples/basic/client/public/images/logo.svg +36 -36
  70. package/examples/basic/client/public/robots.txt +2 -2
  71. package/examples/basic/client/routes/docs/[...slug].tsx +12 -12
  72. package/examples/basic/client/routes/features/error/error.tsx +16 -16
  73. package/examples/basic/client/routes/features/index.tsx +1 -1
  74. package/examples/basic/client/routes/features/template/b.tsx +14 -14
  75. package/examples/basic/client/routes/files/[[...slug]].tsx +21 -21
  76. package/examples/basic/client/routes/gallery/layout.tsx +13 -13
  77. package/examples/basic/client/routes/io.tsx +23 -24
  78. package/examples/basic/client/routes/loader-demo/loading.tsx +13 -13
  79. package/examples/basic/client/routes/rest.tsx +74 -0
  80. package/examples/basic/client/routes/rpc.tsx +43 -0
  81. package/examples/basic/client/routes/search.tsx +61 -61
  82. package/examples/basic/client/toil.tsx +5 -5
  83. package/package.json +167 -148
  84. package/presets/eslint.js +88 -88
  85. package/presets/no-uint8array-tostring.js +200 -200
  86. package/presets/prettier-plugin.js +51 -0
  87. package/presets/prettier.json +19 -18
  88. package/presets/tsconfig.json +37 -37
  89. package/server/runtime/README.md +97 -0
  90. package/server/runtime/abort/abort.ts +27 -0
  91. package/server/runtime/env/Server.ts +61 -0
  92. package/server/runtime/envelope.ts +191 -0
  93. package/server/runtime/exports/index.ts +52 -0
  94. package/server/runtime/handlers/ToilHandler.ts +34 -0
  95. package/server/runtime/index.ts +26 -0
  96. package/server/runtime/lang/Potential.ts +5 -0
  97. package/server/runtime/memory.ts +81 -0
  98. package/server/runtime/request.ts +55 -0
  99. package/server/runtime/response.ts +86 -0
  100. package/server/runtime/rest/Rest.ts +39 -0
  101. package/server/runtime/rest/RestHandler.ts +20 -0
  102. package/server/runtime/rest/RouteContext.ts +82 -0
  103. package/server/runtime/rest/match.ts +48 -0
  104. package/server/runtime/tsconfig.json +7 -0
  105. package/src/backend/index.ts +202 -160
  106. package/src/cli/create.ts +15 -5
  107. package/src/cli/diagnostics.ts +81 -0
  108. package/src/cli/doctor.ts +384 -7
  109. package/src/cli/index.ts +11 -2
  110. package/src/cli/proc.ts +50 -50
  111. package/src/cli/updates.ts +69 -69
  112. package/src/cli/validate.ts +31 -31
  113. package/src/client/channel/channel.ts +146 -146
  114. package/src/client/components/Form.tsx +65 -65
  115. package/src/client/components/Script.tsx +113 -113
  116. package/src/client/components/Slot.tsx +21 -21
  117. package/src/client/dev/devtools.tsx +1018 -0
  118. package/src/client/dev/error-overlay.tsx +30 -4
  119. package/src/client/errors.ts +11 -0
  120. package/src/client/head/head.ts +167 -167
  121. package/src/client/head/metadata.ts +112 -112
  122. package/src/client/index.ts +91 -89
  123. package/src/client/navigation/NavLink.tsx +86 -86
  124. package/src/client/navigation/navigation.ts +235 -235
  125. package/src/client/navigation/prefetch.ts +169 -130
  126. package/src/client/navigation/scroll.ts +53 -53
  127. package/src/client/routing/Router.tsx +8 -2
  128. package/src/client/routing/action.ts +122 -122
  129. package/src/client/routing/error-boundary.tsx +43 -43
  130. package/src/client/routing/hooks.ts +21 -6
  131. package/src/client/routing/loader.ts +325 -235
  132. package/src/client/routing/match.ts +47 -47
  133. package/src/client/routing/mount.tsx +54 -52
  134. package/src/client/routing/params-context.ts +10 -10
  135. package/src/client/routing/slot-context.ts +7 -7
  136. package/src/client/rpc.ts +64 -0
  137. package/src/client/search/search.ts +189 -189
  138. package/src/client/search/use-page-search.ts +73 -73
  139. package/src/client/types.ts +73 -73
  140. package/src/compiler/config.ts +221 -182
  141. package/src/compiler/docs.ts +285 -228
  142. package/src/compiler/generate.ts +395 -394
  143. package/src/compiler/index.ts +66 -57
  144. package/src/compiler/pages.ts +70 -70
  145. package/src/compiler/plugin.ts +258 -2
  146. package/src/compiler/prerender.ts +156 -156
  147. package/src/compiler/seo.ts +417 -390
  148. package/src/compiler/ssg.ts +171 -126
  149. package/src/compiler/vite.ts +34 -0
  150. package/src/io/FastMap.ts +151 -127
  151. package/src/io/FastSet.ts +15 -1
  152. package/src/io/codec.ts +217 -0
  153. package/src/io/index.ts +10 -11
  154. package/src/io/lengths.ts +14 -14
  155. package/src/io/types.ts +19 -18
  156. package/src/logger/index.ts +22 -22
  157. package/src/shared/index.ts +10 -10
  158. package/std/client/index.d.ts +15 -15
  159. package/std/client/package.json +3 -3
  160. package/test/assembly/example.spec.ts +17 -7
  161. package/test/channel.test.ts +21 -21
  162. package/test/doctor.test.ts +65 -0
  163. package/test/dom/Link.test.tsx +47 -47
  164. package/test/dom/NavLink.test.tsx +37 -37
  165. package/test/dom/error-overlay.test.tsx +44 -44
  166. package/test/dom/loader.test.tsx +121 -121
  167. package/test/dom/navigation.test.ts +59 -59
  168. package/test/dom/revalidate.test.tsx +38 -38
  169. package/test/dom/route-head.test.tsx +78 -78
  170. package/test/dom/router-loading.test.tsx +44 -44
  171. package/test/dom/scroll.test.ts +56 -56
  172. package/test/dom/use-metadata.test.tsx +58 -58
  173. package/test/errors.test.ts +21 -0
  174. package/test/io.test.ts +117 -93
  175. package/test/navlink.test.ts +28 -28
  176. package/test/placeholder.test.ts +9 -9
  177. package/test/prettier-plugin.test.ts +46 -0
  178. package/test/routes.test.ts +76 -76
  179. package/test/rpc.test.ts +50 -0
  180. package/test/seo.test.ts +175 -164
  181. package/test/slot-layouts.test.ts +69 -69
  182. package/test/ssg.test.ts +36 -36
  183. package/test/update.test.ts +44 -44
  184. package/test/validate.test.ts +42 -42
  185. package/tests/data-parity/generated-parity.ts +99 -0
  186. package/tests/data-parity/parity.ts +80 -0
  187. package/tests/data-parity/spec.ts +46 -0
  188. package/toil-routes.d.ts +7 -0
  189. package/tsconfig.backend.json +13 -13
  190. package/tsconfig.base.json +35 -35
  191. package/tsconfig.cli.json +13 -13
  192. package/tsconfig.client.json +14 -14
  193. package/tsconfig.compiler.json +13 -13
  194. package/tsconfig.io.json +12 -12
  195. package/tsconfig.json +22 -22
  196. package/tsconfig.logger.json +12 -12
  197. package/tsconfig.server.json +10 -10
  198. package/tsconfig.shared.json +12 -12
  199. package/vitest.config.ts +26 -26
  200. package/.idea/codeStyles/Project.xml +0 -54
  201. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  202. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  203. package/.idea/modules.xml +0 -8
  204. package/.idea/prettier.xml +0 -7
  205. package/.idea/toiljs.iml +0 -8
  206. package/.idea/vcs.xml +0 -6
  207. package/.toil/entry.tsx +0 -9
  208. package/.toil/index.html +0 -12
  209. package/.toil/routes.ts +0 -9
  210. package/build/cli/configure.d.ts +0 -16
  211. package/build/cli/configure.js +0 -272
  212. package/build/cli/create.d.ts +0 -16
  213. package/build/cli/create.js +0 -420
  214. package/build/cli/diagnostics.d.ts +0 -55
  215. package/build/cli/diagnostics.js +0 -333
  216. package/build/cli/doctor.d.ts +0 -6
  217. package/build/cli/doctor.js +0 -249
  218. package/build/cli/features.d.ts +0 -25
  219. package/build/cli/features.js +0 -107
  220. package/build/cli/index.d.ts +0 -2
  221. package/build/cli/proc.d.ts +0 -6
  222. package/build/cli/proc.js +0 -31
  223. package/build/cli/ui.d.ts +0 -9
  224. package/build/cli/ui.js +0 -75
  225. package/build/cli/update.d.ts +0 -7
  226. package/build/cli/update.js +0 -117
  227. package/build/cli/updates.d.ts +0 -10
  228. package/build/cli/updates.js +0 -45
  229. package/build/cli/validate.d.ts +0 -4
  230. package/build/cli/validate.js +0 -19
  231. package/build/client/Link.d.ts +0 -8
  232. package/build/client/Link.js +0 -44
  233. package/build/client/NavLink.d.ts +0 -14
  234. package/build/client/NavLink.js +0 -37
  235. package/build/client/Router.d.ts +0 -7
  236. package/build/client/Router.js +0 -55
  237. package/build/client/channel.d.ts +0 -23
  238. package/build/client/channel.js +0 -94
  239. package/build/client/error-boundary.d.ts +0 -16
  240. package/build/client/error-boundary.js +0 -19
  241. package/build/client/head.d.ts +0 -26
  242. package/build/client/head.js +0 -87
  243. package/build/client/hooks.d.ts +0 -17
  244. package/build/client/hooks.js +0 -48
  245. package/build/client/lazy.d.ts +0 -16
  246. package/build/client/lazy.js +0 -53
  247. package/build/client/match.d.ts +0 -2
  248. package/build/client/match.js +0 -32
  249. package/build/client/mount.d.ts +0 -2
  250. package/build/client/mount.js +0 -13
  251. package/build/client/navigation.d.ts +0 -13
  252. package/build/client/navigation.js +0 -97
  253. package/build/client/params-context.d.ts +0 -2
  254. package/build/client/params-context.js +0 -2
  255. package/build/client/prefetch.d.ts +0 -11
  256. package/build/client/prefetch.js +0 -100
  257. package/build/client/runtime.d.ts +0 -31
  258. package/build/client/runtime.js +0 -112
  259. package/build/client/scroll.d.ts +0 -8
  260. package/build/client/scroll.js +0 -36
  261. package/build/io/BinaryReader.d.ts +0 -44
  262. package/build/io/BinaryReader.js +0 -244
  263. package/build/io/BinaryWriter.d.ts +0 -44
  264. package/build/io/BinaryWriter.js +0 -297
  265. package/build/server/release.wasm +0 -0
  266. package/build/server/release.wat +0 -9
  267. package/src/io/BinaryReader.ts +0 -340
  268. package/src/io/BinaryWriter.ts +0 -385
  269. package/src/server/index.ts +0 -10
  270. package/src/server/main.ts +0 -13
  271. package/src/server/tsconfig.json +0 -4
  272. package/toil-env.d.ts +0 -16
  273. package/toilconfig.json +0 -30
@@ -1,25 +1,25 @@
1
- import { type ReactNode } from 'react';
2
- import Footer from './components/Footer';
3
- import Header from './components/Header';
4
- import HoneycombBackground from './components/HoneycombBackground';
5
-
6
- export default function Layout({ children }: { children?: ReactNode }) {
7
- return (
8
- <div className="app">
9
- <HoneycombBackground />
10
- {/* Site-wide head defaults. `titleTemplate` wraps each route's own title (a route metadata
11
- title of "About" renders as "About | ToilJS"); a route opts out by setting its own
12
- `titleTemplate: '%s'`. `title` is the fallback for routes that set none. */}
13
- <Toil.Head
14
- titleTemplate="%s | ToilJS"
15
- title="ToilJS"
16
- meta={[{ name: 'description', content: 'The most performant React framework.' }]}
17
- />
18
- <Header />
19
-
20
- <main className="content">{children}</main>
21
-
22
- <Footer />
23
- </div>
24
- );
25
- }
1
+ import { type ReactNode } from 'react';
2
+ import Footer from './components/Footer';
3
+ import Header from './components/Header';
4
+ import HoneycombBackground from './components/HoneycombBackground';
5
+
6
+ export default function Layout({ children }: { children?: ReactNode }) {
7
+ return (
8
+ <div className="app">
9
+ <HoneycombBackground />
10
+ {/* Site-wide head defaults. `titleTemplate` wraps each route's own title (a route metadata
11
+ title of "About" renders as "About | ToilJS"); a route opts out by setting its own
12
+ `titleTemplate: '%s'`. `title` is the fallback for routes that set none. */}
13
+ <Toil.Head
14
+ titleTemplate="%s | ToilJS"
15
+ title="ToilJS"
16
+ meta={[{ name: 'description', content: 'The most performant React framework.' }]}
17
+ />
18
+ <Header />
19
+
20
+ <main className="content">{children}</main>
21
+
22
+ <Footer />
23
+ </div>
24
+ );
25
+ }
@@ -1 +1 @@
1
- # Place images and other static assets here; served at /images/*.
1
+ # Place images and other static assets here; served at /images/*.
@@ -1,37 +1,37 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500">
3
- <!-- Generator: Adobe Illustrator 30.4.0, SVG Export Plug-In . SVG Version: 2.1.4 Build 226) -->
4
- <defs>
5
- <style>
6
- .st0 {
7
- fill: #fff;
8
- }
9
-
10
- .st1 {
11
- fill: url(#linear-gradient1);
12
- }
13
-
14
- .st2 {
15
- fill: url(#linear-gradient);
16
- }
17
- </style>
18
- <linearGradient id="linear-gradient" x1="43.27" y1="43.27" x2="467.12" y2="467.12" gradientUnits="userSpaceOnUse">
19
- <stop offset="0" stop-color="#6990ff"/>
20
- <stop offset=".03" stop-color="#6479f9"/>
21
- <stop offset=".08" stop-color="#5d57f0"/>
22
- <stop offset=".12" stop-color="#583de9"/>
23
- <stop offset=".17" stop-color="#542ae3"/>
24
- <stop offset=".23" stop-color="#521ee0"/>
25
- <stop offset=".28" stop-color="#521be0"/>
26
- <stop offset=".66" stop-color="#6900f4"/>
27
- <stop offset="1" stop-color="#7f00f6"/>
28
- </linearGradient>
29
- <linearGradient id="linear-gradient1" x1="149.99" y1="355.49" x2="149.99" y2="0" gradientUnits="userSpaceOnUse">
30
- <stop offset=".15" stop-color="#6990ff" stop-opacity=".6"/>
31
- <stop offset=".55" stop-color="#531ae1"/>
32
- </linearGradient>
33
- </defs>
34
- <rect class="st2" width="500" height="500" rx="130" ry="130"/>
35
- <path class="st1" d="M299.98,0L0,355.49v-225.49C0,58.2,58.2,0,130,0h169.98Z"/>
36
- <path class="st0" d="M106.17,111.11h285.24c9.9,0,16.7,9.96,13.09,19.18l-17.98,45.96c-2.11,5.39-7.31,8.94-13.09,8.94h-74.65c-7.76,0-14.06,6.29-14.06,14.06v214.94c0,7.76-6.29,14.06-14.06,14.06h-45.96c-7.76,0-14.06-6.29-14.06-14.06v-217.25c0-7.76-6.29-14.06-14.06-14.06h-73.66c-5.82,0-11.04-3.59-13.12-9.02l-16.76-43.64c-3.54-9.21,3.26-19.1,13.12-19.1Z"/>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 500 500">
3
+ <!-- Generator: Adobe Illustrator 30.4.0, SVG Export Plug-In . SVG Version: 2.1.4 Build 226) -->
4
+ <defs>
5
+ <style>
6
+ .st0 {
7
+ fill: #fff;
8
+ }
9
+
10
+ .st1 {
11
+ fill: url(#linear-gradient1);
12
+ }
13
+
14
+ .st2 {
15
+ fill: url(#linear-gradient);
16
+ }
17
+ </style>
18
+ <linearGradient id="linear-gradient" x1="43.27" y1="43.27" x2="467.12" y2="467.12" gradientUnits="userSpaceOnUse">
19
+ <stop offset="0" stop-color="#6990ff"/>
20
+ <stop offset=".03" stop-color="#6479f9"/>
21
+ <stop offset=".08" stop-color="#5d57f0"/>
22
+ <stop offset=".12" stop-color="#583de9"/>
23
+ <stop offset=".17" stop-color="#542ae3"/>
24
+ <stop offset=".23" stop-color="#521ee0"/>
25
+ <stop offset=".28" stop-color="#521be0"/>
26
+ <stop offset=".66" stop-color="#6900f4"/>
27
+ <stop offset="1" stop-color="#7f00f6"/>
28
+ </linearGradient>
29
+ <linearGradient id="linear-gradient1" x1="149.99" y1="355.49" x2="149.99" y2="0" gradientUnits="userSpaceOnUse">
30
+ <stop offset=".15" stop-color="#6990ff" stop-opacity=".6"/>
31
+ <stop offset=".55" stop-color="#531ae1"/>
32
+ </linearGradient>
33
+ </defs>
34
+ <rect class="st2" width="500" height="500" rx="130" ry="130"/>
35
+ <path class="st1" d="M299.98,0L0,355.49v-225.49C0,58.2,58.2,0,130,0h169.98Z"/>
36
+ <path class="st0" d="M106.17,111.11h285.24c9.9,0,16.7,9.96,13.09,19.18l-17.98,45.96c-2.11,5.39-7.31,8.94-13.09,8.94h-74.65c-7.76,0-14.06,6.29-14.06,14.06v214.94c0,7.76-6.29,14.06-14.06,14.06h-45.96c-7.76,0-14.06-6.29-14.06-14.06v-217.25c0-7.76-6.29-14.06-14.06-14.06h-73.66c-5.82,0-11.04-3.59-13.12-9.02l-16.76-43.64c-3.54-9.21,3.26-19.1,13.12-19.1Z"/>
37
37
  </svg>
@@ -1,2 +1,2 @@
1
- User-agent: *
2
- Allow: /
1
+ User-agent: *
2
+ Allow: /
@@ -1,12 +1,12 @@
1
- export default function Docs() {
2
- const { slug } = Toil.useParams();
3
- return (
4
- <main>
5
- <h1>Docs</h1>
6
- <p>
7
- Catch-all route <code>client/routes/docs/[...slug].tsx</code> matched: <code>{slug}</code>
8
- </p>
9
- <Toil.Link href="/">Back home</Toil.Link>
10
- </main>
11
- );
12
- }
1
+ export default function Docs() {
2
+ const { slug } = Toil.useParams();
3
+ return (
4
+ <main>
5
+ <h1>Docs</h1>
6
+ <p>
7
+ Catch-all route <code>client/routes/docs/[...slug].tsx</code> matched: <code>{slug}</code>
8
+ </p>
9
+ <Toil.Link href="/">Back home</Toil.Link>
10
+ </main>
11
+ );
12
+ }
@@ -1,16 +1,16 @@
1
- // The error boundary for this segment. It receives the thrown error and a `reset` to retry the
2
- // render. Place an `error.tsx` next to any route to contain failures there.
3
- export default function FeatureError({ error, reset }: Toil.RouteErrorProps) {
4
- return (
5
- <main>
6
- <h1>Something broke</h1>
7
- <p style={{ color: 'crimson' }}>{error instanceof Error ? error.message : String(error)}</p>
8
- <p>
9
- <button type="button" onClick={reset}>
10
- Try again
11
- </button>{' '}
12
- <Toil.Link href="/features">Back to features</Toil.Link>
13
- </p>
14
- </main>
15
- );
16
- }
1
+ // The error boundary for this segment. It receives the thrown error and a `reset` to retry the
2
+ // render. Place an `error.tsx` next to any route to contain failures there.
3
+ export default function FeatureError({ error, reset }: Toil.RouteErrorProps) {
4
+ return (
5
+ <main>
6
+ <h1>Something broke</h1>
7
+ <p style={{ color: 'crimson' }}>{error instanceof Error ? error.message : String(error)}</p>
8
+ <p>
9
+ <button type="button" onClick={reset}>
10
+ Try again
11
+ </button>{' '}
12
+ <Toil.Link href="/features">Back to features</Toil.Link>
13
+ </p>
14
+ </main>
15
+ );
16
+ }
@@ -47,7 +47,7 @@ const groups: { heading: string; items: { href: Toil.Href; label: string; note:
47
47
  items: [
48
48
  { href: '/features/script', label: 'Script', note: 'Toil.Script with a load strategy' },
49
49
  { href: '/features/realtime', label: 'WebSocket channel', note: 'Toil.useChannel against /_toil' },
50
- { href: '/io', label: 'Binary IO', note: 'BinaryWriter / BinaryReader / FastSet, no import' }
50
+ { href: '/io', label: 'Binary IO', note: 'DataWriter / DataReader / FastSet, no import' }
51
51
  ]
52
52
  }
53
53
  ];
@@ -1,14 +1,14 @@
1
- export const metadata: Toil.Metadata = { title: 'Templates, sibling' };
2
-
3
- export default function TemplateSibling() {
4
- return (
5
- <main>
6
- <h1>Sibling page</h1>
7
- <p>Same template, fresh mount. Navigate back and forth to see the counter increment.</p>
8
- <p>
9
- <Toil.Link href="/features/template">First page</Toil.Link>{' '}
10
- <Toil.Link href="/features">Back to features</Toil.Link>
11
- </p>
12
- </main>
13
- );
14
- }
1
+ export const metadata: Toil.Metadata = { title: 'Templates, sibling' };
2
+
3
+ export default function TemplateSibling() {
4
+ return (
5
+ <main>
6
+ <h1>Sibling page</h1>
7
+ <p>Same template, fresh mount. Navigate back and forth to see the counter increment.</p>
8
+ <p>
9
+ <Toil.Link href="/features/template">First page</Toil.Link>{' '}
10
+ <Toil.Link href="/features">Back to features</Toil.Link>
11
+ </p>
12
+ </main>
13
+ );
14
+ }
@@ -1,21 +1,21 @@
1
- export const metadata: Toil.Metadata = { title: 'Optional catch-all' };
2
-
3
- // Optional catch-all: `[[...slug]]` matches the bare `/files` AND any depth below it (`/files/a/b`).
4
- // `slug` is undefined at the base and a path string when segments are present.
5
- export default function Files() {
6
- const { slug } = Toil.useParams();
7
- return (
8
- <main>
9
- <h1>Optional catch-all</h1>
10
- <p>
11
- <code>files/[[...slug]].tsx</code> matched. Current slug:{' '}
12
- <code>{slug ?? '(none, this is the base /files)'}</code>
13
- </p>
14
- <p>
15
- <Toil.Link href="/files">/files</Toil.Link>{' '}
16
- <Toil.Link href="/files/images/logo">/files/images/logo</Toil.Link>{' '}
17
- <Toil.Link href="/features">Back to features</Toil.Link>
18
- </p>
19
- </main>
20
- );
21
- }
1
+ export const metadata: Toil.Metadata = { title: 'Optional catch-all' };
2
+
3
+ // Optional catch-all: `[[...slug]]` matches the bare `/files` AND any depth below it (`/files/a/b`).
4
+ // `slug` is undefined at the base and a path string when segments are present.
5
+ export default function Files() {
6
+ const { slug } = Toil.useParams();
7
+ return (
8
+ <main>
9
+ <h1>Optional catch-all</h1>
10
+ <p>
11
+ <code>files/[[...slug]].tsx</code> matched. Current slug:{' '}
12
+ <code>{slug ?? '(none, this is the base /files)'}</code>
13
+ </p>
14
+ <p>
15
+ <Toil.Link href="/files">/files</Toil.Link>{' '}
16
+ <Toil.Link href="/files/images/logo">/files/images/logo</Toil.Link>{' '}
17
+ <Toil.Link href="/features">Back to features</Toil.Link>
18
+ </p>
19
+ </main>
20
+ );
21
+ }
@@ -1,13 +1,13 @@
1
- import { type ReactNode } from 'react';
2
-
3
- // This layout renders the normal page content AND a parallel `@modal` slot. The slot stays empty
4
- // until an intercepting route fills it (see @modal/(.)photo/[id].tsx), at which point a modal appears
5
- // over the gallery without leaving the page.
6
- export default function GalleryLayout({ children }: { children?: ReactNode }) {
7
- return (
8
- <div>
9
- {children}
10
- <Toil.Slot name="modal" />
11
- </div>
12
- );
13
- }
1
+ import { type ReactNode } from 'react';
2
+
3
+ // This layout renders the normal page content AND a parallel `@modal` slot. The slot stays empty
4
+ // until an intercepting route fills it (see @modal/(.)photo/[id].tsx), at which point a modal appears
5
+ // over the gallery without leaving the page.
6
+ export default function GalleryLayout({ children }: { children?: ReactNode }) {
7
+ return (
8
+ <div>
9
+ {children}
10
+ <Toil.Slot name="modal" />
11
+ </div>
12
+ );
13
+ }
@@ -1,24 +1,23 @@
1
- export default function IoDemo() {
2
- const writer = new BinaryWriter();
3
- writer.writeU32(42);
4
- writer.writeStringWithLength('hello toil');
5
- const bytes = writer.getBuffer();
6
-
7
- const reader = new BinaryReader(bytes);
8
- const n = reader.readU32();
9
- const s = reader.readStringWithLength();
10
-
11
- const seen = new FastSet<bigint>();
12
- seen.add(1n).add(2n).add(1n);
13
-
14
- return (
15
- <main>
16
- <h1>Native IO</h1>
17
- <p>
18
- <code>new BinaryWriter()</code> with no import, round-tripped {n} and &quot;{s}&quot; through{' '}
19
- {bytes.length} bytes; FastSet size {seen.size}.
20
- </p>
21
- <Toil.Link href="/">Back home</Toil.Link>
22
- </main>
23
- );
24
- }
1
+ export default function IoDemo() {
2
+ const writer = new DataWriter();
3
+ writer.writeU32(42).writeString('hello toil');
4
+ const bytes = writer.toBytes();
5
+
6
+ const reader = new DataReader(bytes);
7
+ const n = reader.readU32();
8
+ const s = reader.readString();
9
+
10
+ const seen = new FastSet<bigint>();
11
+ seen.add(1n).add(2n).add(1n);
12
+
13
+ return (
14
+ <main>
15
+ <h1>Native IO</h1>
16
+ <p>
17
+ <code>new DataWriter()</code> with no import, round-tripped {n} and &quot;{s}&quot; through{' '}
18
+ {bytes.length} bytes; FastSet size {seen.size}.
19
+ </p>
20
+ <Toil.Link href="/">Back home</Toil.Link>
21
+ </main>
22
+ );
23
+ }
@@ -1,13 +1,13 @@
1
- // Shown as the Suspense fallback while this route's `loader` runs (and its chunk loads). Because the
2
- // loader awaits 2s, you'll see this spinner before the page renders with its data.
3
- export default function LoaderDemoLoading() {
4
- return (
5
- <main>
6
- <div className="loading-bar" />
7
- <div className="loading-center">
8
- <span className="spinner" aria-hidden="true" />
9
- <p>Loading data…</p>
10
- </div>
11
- </main>
12
- );
13
- }
1
+ // Shown as the Suspense fallback while this route's `loader` runs (and its chunk loads). Because the
2
+ // loader awaits 2s, you'll see this spinner before the page renders with its data.
3
+ export default function LoaderDemoLoading() {
4
+ return (
5
+ <main>
6
+ <div className="loading-bar" />
7
+ <div className="loading-center">
8
+ <span className="spinner" aria-hidden="true" />
9
+ <p>Loading data…</p>
10
+ </div>
11
+ </main>
12
+ );
13
+ }
@@ -0,0 +1,74 @@
1
+ // Demo of the generated REST fetch client (see ../../shared/server.ts, emitted by the
2
+ // server build from the `@rest` controllers in server/api.ts). Unlike `Server.<service>`
3
+ // RPC, this is working code: `Server.REST.<controller>.<route>(args)` is a real, typed
4
+ // `fetch`. `args` is `{ params?, body?, query?, headers? }`; a `@data` return is parsed
5
+ // into its typed class, and a route that returns a `Response` hands you the raw fetch
6
+ // `Response` to inspect (status, `.json()`, ...). Needs the server running to respond.
7
+ import { useState } from 'react';
8
+
9
+ import { NewPlayer, type Player, ScoreDelta } from 'shared/server';
10
+
11
+ export default function RestDemo() {
12
+ const [log, setLog] = useState<string[]>([]);
13
+ const note = (line: string) => setLog((prev) => [line, ...prev].slice(0, 8));
14
+
15
+ // POST /players -> typed Promise<Player>, body is a @data class.
16
+ const onCreate = async () => {
17
+ try {
18
+ const names = ['Ada', 'Linus', 'Grace', 'Dennis'];
19
+ const name = names[Math.floor(Math.random() * names.length)];
20
+ const player = await Server.REST.players.create({ body: new NewPlayer(name) });
21
+ note(`created #${player.id} ${player.name}`);
22
+ } catch (err) {
23
+ note(parseError(err));
24
+ }
25
+ };
26
+
27
+ // POST /players/:id/score -> path param + body; route returns a Response, so we get
28
+ // the raw fetch Response and parse it ourselves.
29
+ const onScore = async () => {
30
+ try {
31
+ const points = BigInt(1 + Math.floor(Math.random() * 10));
32
+ const res = await Server.REST.players.addScore({
33
+ params: { id: 1 },
34
+ body: new ScoreDelta(points)
35
+ });
36
+ if (!res.ok) {
37
+ note(`addScore -> ${res.status} (create player #1 first)`);
38
+ return;
39
+ }
40
+ const p = (await res.json()) as Player;
41
+ note(`#${p.id} ${p.name} -> ${p.score}`);
42
+ } catch (err) {
43
+ note(parseError(err));
44
+ }
45
+ };
46
+
47
+ // GET /leaderboard -> typed Promise<Standings>, a @data wrapper of Player[].
48
+ const onBoard = async () => {
49
+ try {
50
+ const board = await Server.REST.leaderboard.top();
51
+ note('leaderboard: ' + board.players.map((p) => `${p.name}(${p.score})`).join(', '));
52
+ } catch (err) {
53
+ note(parseError(err));
54
+ }
55
+ };
56
+
57
+ return (
58
+ <main>
59
+ <h1>REST</h1>
60
+ <p>
61
+ <code>Server.REST.*</code> is a real, typed <code>fetch</code> client generated from the{' '}
62
+ <code>@rest</code> controllers. It needs the server running to respond.
63
+ </p>
64
+ <button onClick={onCreate}>create player</button> <button onClick={onScore}>award points to #1</button>{' '}
65
+ <button onClick={onBoard}>leaderboard</button>
66
+ <ul>
67
+ {log.map((line, i) => (
68
+ <li key={i}>{line}</li>
69
+ ))}
70
+ </ul>
71
+ <Toil.Link href="/">Back home</Toil.Link>
72
+ </main>
73
+ );
74
+ }
@@ -0,0 +1,43 @@
1
+ // Demo of the generated, typed `Server` RPC surface (see ../../shared/server.ts, emitted
2
+ // by the server build from `@service`/`@remote`). `Server` is global (no import) and typed
3
+ // from the server: `Server.ping(n)` (free `@remote`) and `Server.admin.reset()` (a
4
+ // `@service` method). Transport is not wired yet, so a real call throws; this page shows
5
+ // the typing and reports the stub error via the global `parseError`.
6
+ import { useState } from 'react';
7
+
8
+ export default function RpcDemo() {
9
+ const [result, setResult] = useState('not called');
10
+
11
+ // Scalar in / scalar out: Server.ping is typed (n: number) => Promise<number>.
12
+ const onPing = async () => {
13
+ try {
14
+ const next = await Server.ping(10);
15
+ setResult(`ping -> ${next}`);
16
+ } catch (err) {
17
+ setResult(parseError(err));
18
+ }
19
+ };
20
+
21
+ // A @service method: namespaced under its service key.
22
+ const onReset = async () => {
23
+ try {
24
+ await Server.admin.reset();
25
+ setResult('admin.reset -> store cleared');
26
+ } catch (err) {
27
+ setResult(parseError(err));
28
+ }
29
+ };
30
+
31
+ return (
32
+ <main>
33
+ <h1>RPC</h1>
34
+ <p>
35
+ <code>Server</code> (RPC) is typed from the server build, no import. Calling throws until the transport
36
+ lands. For working server calls today, use the REST client.
37
+ </p>
38
+ <button onClick={onPing}>Server.ping(10)</button> <button onClick={onReset}>Server.admin.reset()</button>
39
+ <p>{result}</p>
40
+ <Toil.Link href="/rest">See the REST demo</Toil.Link> · <Toil.Link href="/">Back home</Toil.Link>
41
+ </main>
42
+ );
43
+ }
@@ -1,61 +1,61 @@
1
- import { useState } from 'react';
2
-
3
- export const metadata: Toil.Metadata = {
4
- title: 'Search',
5
- description: 'Search every page by its metadata and jump straight to it.',
6
- keywords: ['search', 'find', 'pages', 'metadata']
7
- };
8
-
9
- // A tiny site-wide search box. `usePageSearch` queries the compiler-built index of every page's
10
- // metadata (title/description/keywords/OpenGraph + static `searchHints` on dynamic routes), returns
11
- // ranked matches with their route `path`, and `goTo` navigates to whichever one you pick.
12
- export default function Search() {
13
- const [query, setQuery] = useState('');
14
- const { results, pages, goTo } = Toil.usePageSearch(query, { includeDynamic: true });
15
-
16
- return (
17
- <main>
18
- <h1>Search</h1>
19
- <p>
20
- Type to search across the metadata of all {pages.length} pages, title, description, keywords, and
21
- OpenGraph. Indexed at build by <code>client/routes/*</code>.
22
- </p>
23
-
24
- <input
25
- type="search"
26
- value={query}
27
- onChange={(e) => {
28
- setQuery(e.target.value);
29
- }}
30
- placeholder="Search pages… (try “blog”, “features”, “started”)"
31
- aria-label="Search pages"
32
- autoFocus
33
- style={{ width: '100%', padding: '0.6rem 0.8rem', fontSize: '1rem' }}
34
- />
35
-
36
- {query.trim() !== '' && (
37
- <ul style={{ listStyle: 'none', padding: 0, marginTop: '1rem' }}>
38
- {results.length === 0 && <li>No pages match “{query}”.</li>}
39
- {results.map((r) => (
40
- <li key={r.page.path} style={{ marginBottom: '0.75rem' }}>
41
- <button
42
- type="button"
43
- onClick={() => {
44
- goTo(r);
45
- }}
46
- disabled={r.page.dynamic}
47
- title={r.page.dynamic ? 'Dynamic route, needs params to open' : undefined}
48
- style={{ textAlign: 'left', cursor: r.page.dynamic ? 'default' : 'pointer' }}>
49
- <strong>{r.page.metadata.title ?? r.page.path}</strong> <code>{r.page.path}</code>
50
- {r.page.metadata.description !== undefined && <div>{r.page.metadata.description}</div>}
51
- <small>
52
- score {r.score.toFixed(1)} · matched {r.matches.join(', ')}
53
- </small>
54
- </button>
55
- </li>
56
- ))}
57
- </ul>
58
- )}
59
- </main>
60
- );
61
- }
1
+ import { useState } from 'react';
2
+
3
+ export const metadata: Toil.Metadata = {
4
+ title: 'Search',
5
+ description: 'Search every page by its metadata and jump straight to it.',
6
+ keywords: ['search', 'find', 'pages', 'metadata']
7
+ };
8
+
9
+ // A tiny site-wide search box. `usePageSearch` queries the compiler-built index of every page's
10
+ // metadata (title/description/keywords/OpenGraph + static `searchHints` on dynamic routes), returns
11
+ // ranked matches with their route `path`, and `goTo` navigates to whichever one you pick.
12
+ export default function Search() {
13
+ const [query, setQuery] = useState('');
14
+ const { results, pages, goTo } = Toil.usePageSearch(query, { includeDynamic: true });
15
+
16
+ return (
17
+ <main>
18
+ <h1>Search</h1>
19
+ <p>
20
+ Type to search across the metadata of all {pages.length} pages, title, description, keywords, and
21
+ OpenGraph. Indexed at build by <code>client/routes/*</code>.
22
+ </p>
23
+
24
+ <input
25
+ type="search"
26
+ value={query}
27
+ onChange={(e) => {
28
+ setQuery(e.target.value);
29
+ }}
30
+ placeholder="Search pages… (try “blog”, “features”, “started”)"
31
+ aria-label="Search pages"
32
+ autoFocus
33
+ style={{ width: '100%', padding: '0.6rem 0.8rem', fontSize: '1rem' }}
34
+ />
35
+
36
+ {query.trim() !== '' && (
37
+ <ul style={{ listStyle: 'none', padding: 0, marginTop: '1rem' }}>
38
+ {results.length === 0 && <li>No pages match “{query}”.</li>}
39
+ {results.map((r) => (
40
+ <li key={r.page.path} style={{ marginBottom: '0.75rem' }}>
41
+ <button
42
+ type="button"
43
+ onClick={() => {
44
+ goTo(r);
45
+ }}
46
+ disabled={r.page.dynamic}
47
+ title={r.page.dynamic ? 'Dynamic route, needs params to open' : undefined}
48
+ style={{ textAlign: 'left', cursor: r.page.dynamic ? 'default' : 'pointer' }}>
49
+ <strong>{r.page.metadata.title ?? r.page.path}</strong> <code>{r.page.path}</code>
50
+ {r.page.metadata.description !== undefined && <div>{r.page.metadata.description}</div>}
51
+ <small>
52
+ score {r.score.toFixed(1)} · matched {r.matches.join(', ')}
53
+ </small>
54
+ </button>
55
+ </li>
56
+ ))}
57
+ </ul>
58
+ )}
59
+ </main>
60
+ );
61
+ }
@@ -1,5 +1,5 @@
1
- import { routes, layout, notFound, globalError, slots } from 'toiljs/routes';
2
-
3
- import './styles/main.css';
4
-
5
- Toil.mount(routes, layout, notFound, globalError, slots);
1
+ import { routes, layout, notFound, globalError, slots } from 'toiljs/routes';
2
+
3
+ import './styles/main.css';
4
+
5
+ Toil.mount(routes, layout, notFound, globalError, slots);