toiljs 0.0.115 → 0.0.117

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 (326) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +16 -7
  3. package/TYPESCRIPT_LAW.md +1946 -2073
  4. package/build/backend/.tsbuildinfo +1 -1
  5. package/build/cli/.tsbuildinfo +1 -1
  6. package/build/cli/index.js +2375 -258
  7. package/build/client/.tsbuildinfo +1 -1
  8. package/build/client/dev/devtools.js +1 -1
  9. package/build/client/dev/error-overlay.js +1 -1
  10. package/build/client/routing/mount.js +1 -1
  11. package/build/compiler/.tsbuildinfo +1 -1
  12. package/build/compiler/auth-emails.js +7 -3
  13. package/build/compiler/emails.js +1 -1
  14. package/build/compiler/index.d.ts +1 -0
  15. package/build/compiler/index.js +25 -4
  16. package/build/compiler/pages.js +2 -3
  17. package/build/compiler/prerender.d.ts +3 -8
  18. package/build/compiler/prerender.js +88 -127
  19. package/build/compiler/ssg.js +3 -4
  20. package/build/compiler/template-build.js +3 -4
  21. package/build/compiler/toil-docs.generated.js +6 -5
  22. package/build/compiler/vite.js +3 -6
  23. package/build/devserver/.tsbuildinfo +1 -1
  24. package/build/devserver/db/database.js +7 -3
  25. package/build/devserver/db/types.js +1 -1
  26. package/build/devserver/production.js +4 -3
  27. package/build/devserver/runtime/crypto.d.ts +1 -1
  28. package/build/io/.tsbuildinfo +1 -1
  29. package/build/logger/.tsbuildinfo +1 -1
  30. package/build/shared/.tsbuildinfo +1 -1
  31. package/examples/basic/client/routes/analytics.tsx +7 -5
  32. package/examples/basic/server/tsconfig.json +1 -3
  33. package/package.json +45 -44
  34. package/presets/no-uint8array-tostring.js +120 -153
  35. package/presets/oxlint.d.ts +5 -0
  36. package/presets/oxlint.js +224 -0
  37. package/server/runtime/tsconfig.json +1 -3
  38. package/tsconfig.json +2 -11
  39. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -38
  40. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -90
  41. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  42. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -20
  43. package/.github/PULL_REQUEST_TEMPLATE.md +0 -43
  44. package/.github/changelog-config.json +0 -45
  45. package/.github/dependabot.yml +0 -27
  46. package/.github/workflows/ci.yml +0 -222
  47. package/.vscode/settings.json +0 -10
  48. package/docs/README.md +0 -107
  49. package/docs/auth/README.md +0 -104
  50. package/docs/auth/configuration.md +0 -105
  51. package/docs/auth/emails.md +0 -92
  52. package/docs/auth/extending.md +0 -202
  53. package/docs/auth/how-it-works.md +0 -138
  54. package/docs/auth/usage.md +0 -188
  55. package/docs/backend/README.md +0 -143
  56. package/docs/backend/data.md +0 -351
  57. package/docs/backend/rest.md +0 -402
  58. package/docs/backend/rpc.md +0 -226
  59. package/docs/background/README.md +0 -114
  60. package/docs/background/daemons.md +0 -276
  61. package/docs/background/derive.md +0 -179
  62. package/docs/cli/README.md +0 -379
  63. package/docs/concepts/ai-guide.md +0 -132
  64. package/docs/concepts/config.md +0 -416
  65. package/docs/concepts/decorators.md +0 -127
  66. package/docs/concepts/security.md +0 -108
  67. package/docs/concepts/tiers.md +0 -166
  68. package/docs/concepts/types.md +0 -216
  69. package/docs/database/README.md +0 -143
  70. package/docs/database/capacity.md +0 -350
  71. package/docs/database/counters.md +0 -174
  72. package/docs/database/documents.md +0 -277
  73. package/docs/database/events.md +0 -307
  74. package/docs/database/membership.md +0 -246
  75. package/docs/database/setup.md +0 -155
  76. package/docs/database/unique.md +0 -216
  77. package/docs/database/views.md +0 -246
  78. package/docs/frontend/README.md +0 -104
  79. package/docs/frontend/components.md +0 -286
  80. package/docs/frontend/data-fetching.md +0 -260
  81. package/docs/frontend/images.md +0 -148
  82. package/docs/frontend/metadata.md +0 -344
  83. package/docs/frontend/navigation.md +0 -296
  84. package/docs/frontend/rendering.md +0 -236
  85. package/docs/frontend/routing.md +0 -346
  86. package/docs/frontend/scripts.md +0 -118
  87. package/docs/frontend/search.md +0 -191
  88. package/docs/frontend/styling.md +0 -147
  89. package/docs/frontend/toil-global.md +0 -216
  90. package/docs/getting-started/README.md +0 -81
  91. package/docs/getting-started/create-project.md +0 -131
  92. package/docs/getting-started/deploy.md +0 -101
  93. package/docs/getting-started/first-app.md +0 -215
  94. package/docs/getting-started/installation.md +0 -124
  95. package/docs/getting-started/migrating.md +0 -125
  96. package/docs/getting-started/project-structure.md +0 -163
  97. package/docs/introduction/README.md +0 -66
  98. package/docs/introduction/design-principles.md +0 -81
  99. package/docs/introduction/distributed.md +0 -91
  100. package/docs/introduction/how-it-works.md +0 -121
  101. package/docs/introduction/hyperscale.md +0 -70
  102. package/docs/introduction/modern-stack.md +0 -85
  103. package/docs/introduction/vs-other-frameworks.md +0 -64
  104. package/docs/introduction/why-toil.md +0 -99
  105. package/docs/llms.txt +0 -95
  106. package/docs/realtime/README.md +0 -102
  107. package/docs/realtime/channels.md +0 -211
  108. package/docs/realtime/streams.md +0 -369
  109. package/docs/services/README.md +0 -60
  110. package/docs/services/analytics.md +0 -279
  111. package/docs/services/caching.md +0 -175
  112. package/docs/services/cookies.md +0 -235
  113. package/docs/services/crypto.md +0 -209
  114. package/docs/services/email.md +0 -289
  115. package/docs/services/environment.md +0 -141
  116. package/docs/services/ratelimit.md +0 -174
  117. package/docs/services/time.md +0 -85
  118. package/eslint.config.js +0 -57
  119. package/examples/basic/client/routes/docs/[...slug].tsx +0 -12
  120. package/presets/eslint.js +0 -88
  121. package/src/backend/index.ts +0 -204
  122. package/src/cli/configure.ts +0 -363
  123. package/src/cli/create.ts +0 -924
  124. package/src/cli/db.ts +0 -158
  125. package/src/cli/diagnostics.ts +0 -665
  126. package/src/cli/doctor.ts +0 -982
  127. package/src/cli/features.ts +0 -170
  128. package/src/cli/index.ts +0 -326
  129. package/src/cli/notify.ts +0 -120
  130. package/src/cli/proc.ts +0 -56
  131. package/src/cli/ui.ts +0 -169
  132. package/src/cli/update.ts +0 -248
  133. package/src/cli/updates.ts +0 -92
  134. package/src/cli/validate.ts +0 -31
  135. package/src/cli/version-check.ts +0 -125
  136. package/src/client/auth.ts +0 -869
  137. package/src/client/channel/channel.ts +0 -146
  138. package/src/client/components/Form.tsx +0 -65
  139. package/src/client/components/Image.tsx +0 -160
  140. package/src/client/components/Script.tsx +0 -113
  141. package/src/client/components/Slot.tsx +0 -21
  142. package/src/client/dev/devtools.tsx +0 -1089
  143. package/src/client/dev/error-overlay.tsx +0 -225
  144. package/src/client/errors.ts +0 -11
  145. package/src/client/head/head.ts +0 -182
  146. package/src/client/head/metadata.ts +0 -110
  147. package/src/client/index.ts +0 -130
  148. package/src/client/navigation/Link.tsx +0 -108
  149. package/src/client/navigation/NavLink.tsx +0 -86
  150. package/src/client/navigation/navigation.ts +0 -235
  151. package/src/client/navigation/prefetch.ts +0 -169
  152. package/src/client/navigation/scroll.ts +0 -53
  153. package/src/client/routing/Router.tsx +0 -216
  154. package/src/client/routing/action.ts +0 -122
  155. package/src/client/routing/error-boundary.tsx +0 -43
  156. package/src/client/routing/hooks.ts +0 -140
  157. package/src/client/routing/lazy.ts +0 -77
  158. package/src/client/routing/loader.ts +0 -381
  159. package/src/client/routing/match.ts +0 -47
  160. package/src/client/routing/mount.tsx +0 -90
  161. package/src/client/routing/params-context.ts +0 -10
  162. package/src/client/routing/slot-context.ts +0 -7
  163. package/src/client/rpc.ts +0 -97
  164. package/src/client/search/search.ts +0 -189
  165. package/src/client/search/use-page-search.ts +0 -73
  166. package/src/client/ssr/markers.tsx +0 -172
  167. package/src/client/stream/client.ts +0 -237
  168. package/src/client/types.ts +0 -73
  169. package/src/compiler/auth-emails.ts +0 -312
  170. package/src/compiler/config.ts +0 -369
  171. package/src/compiler/docs.ts +0 -127
  172. package/src/compiler/email-preview.ts +0 -314
  173. package/src/compiler/emails.ts +0 -404
  174. package/src/compiler/fonts.ts +0 -89
  175. package/src/compiler/generate.ts +0 -471
  176. package/src/compiler/image-blur.ts +0 -42
  177. package/src/compiler/image-report.ts +0 -88
  178. package/src/compiler/index.ts +0 -1362
  179. package/src/compiler/pages.ts +0 -49
  180. package/src/compiler/plugin.ts +0 -391
  181. package/src/compiler/prerender.ts +0 -263
  182. package/src/compiler/routes.ts +0 -170
  183. package/src/compiler/seo.ts +0 -415
  184. package/src/compiler/sri.ts +0 -144
  185. package/src/compiler/ssg.ts +0 -177
  186. package/src/compiler/ssr-codegen.ts +0 -85
  187. package/src/compiler/template-build.ts +0 -676
  188. package/src/compiler/template.ts +0 -262
  189. package/src/compiler/toil-docs.generated.ts +0 -77
  190. package/src/compiler/vite.ts +0 -245
  191. package/src/devserver/analytics/index.ts +0 -317
  192. package/src/devserver/config/dotenv.ts +0 -102
  193. package/src/devserver/config/env.ts +0 -30
  194. package/src/devserver/config/ratelimit.ts +0 -123
  195. package/src/devserver/daemon/catalog.ts +0 -120
  196. package/src/devserver/daemon/cron.ts +0 -87
  197. package/src/devserver/daemon/host.ts +0 -134
  198. package/src/devserver/daemon/index.ts +0 -369
  199. package/src/devserver/daemon/runtime.ts +0 -48
  200. package/src/devserver/db/catalog.ts +0 -109
  201. package/src/devserver/db/database.ts +0 -1834
  202. package/src/devserver/db/derives.ts +0 -121
  203. package/src/devserver/db/index.ts +0 -20
  204. package/src/devserver/db/routeKinds.ts +0 -191
  205. package/src/devserver/db/types.ts +0 -168
  206. package/src/devserver/email/caps.ts +0 -0
  207. package/src/devserver/email/config.ts +0 -141
  208. package/src/devserver/email/console.ts +0 -348
  209. package/src/devserver/email/index.ts +0 -155
  210. package/src/devserver/email/providers.ts +0 -131
  211. package/src/devserver/email/status.ts +0 -23
  212. package/src/devserver/email/validate.ts +0 -37
  213. package/src/devserver/email/wire.ts +0 -55
  214. package/src/devserver/http/cache.ts +0 -0
  215. package/src/devserver/http/envelope.ts +0 -157
  216. package/src/devserver/http/proxy.ts +0 -172
  217. package/src/devserver/http/runtime.ts +0 -387
  218. package/src/devserver/index.ts +0 -43
  219. package/src/devserver/production-ipc.ts +0 -63
  220. package/src/devserver/production-worker.ts +0 -83
  221. package/src/devserver/production.ts +0 -718
  222. package/src/devserver/runtime/crypto.ts +0 -587
  223. package/src/devserver/runtime/host.ts +0 -427
  224. package/src/devserver/runtime/module.ts +0 -442
  225. package/src/devserver/server.ts +0 -251
  226. package/src/devserver/ssr.ts +0 -208
  227. package/src/devserver/stream/catalog.ts +0 -106
  228. package/src/devserver/stream/host.ts +0 -42
  229. package/src/devserver/stream/index.ts +0 -301
  230. package/src/devserver/stream/manager.ts +0 -167
  231. package/src/devserver/stream/router.ts +0 -101
  232. package/src/devserver/stream/wire.ts +0 -58
  233. package/src/devserver/stream/ws.ts +0 -78
  234. package/src/devserver/wasm/sections.ts +0 -59
  235. package/src/devserver/wasm/surface.ts +0 -115
  236. package/src/io/FastMap.ts +0 -151
  237. package/src/io/FastSet.ts +0 -113
  238. package/src/io/codec.ts +0 -362
  239. package/src/io/index.ts +0 -10
  240. package/src/io/lengths.ts +0 -14
  241. package/src/io/types.ts +0 -19
  242. package/src/logger/index.ts +0 -22
  243. package/src/shared/index.ts +0 -46
  244. package/test/analytics-dev.test.ts +0 -113
  245. package/test/assembly/aspect-shim.ts +0 -33
  246. package/test/assembly/cookie.spec.ts +0 -303
  247. package/test/assembly/example.spec.ts +0 -22
  248. package/test/assembly/ssr.spec.ts +0 -95
  249. package/test/assembly.test.ts +0 -59
  250. package/test/auth-emails.test.ts +0 -118
  251. package/test/built-ssr.test.ts +0 -148
  252. package/test/channel.test.ts +0 -21
  253. package/test/config-host-port.test.ts +0 -59
  254. package/test/configure.test.ts +0 -94
  255. package/test/daemon-build.test.ts +0 -278
  256. package/test/daemon-catalog.test.ts +0 -349
  257. package/test/daemon-emulation.test.ts +0 -256
  258. package/test/db.test.ts +0 -0
  259. package/test/devserver-database.test.ts +0 -1102
  260. package/test/devserver-email.test.ts +0 -306
  261. package/test/devserver-pqauth.test.ts +0 -93
  262. package/test/devserver-secrets.test.ts +0 -63
  263. package/test/devserver.test.ts +0 -259
  264. package/test/doctor.test.ts +0 -298
  265. package/test/dom/Image.test.tsx +0 -144
  266. package/test/dom/Link.test.tsx +0 -67
  267. package/test/dom/NavLink.test.tsx +0 -37
  268. package/test/dom/Script.test.tsx +0 -48
  269. package/test/dom/action.test.tsx +0 -146
  270. package/test/dom/error-overlay.test.tsx +0 -44
  271. package/test/dom/loader.test.tsx +0 -121
  272. package/test/dom/navigation.test.ts +0 -59
  273. package/test/dom/revalidate.test.tsx +0 -38
  274. package/test/dom/route-head.test.tsx +0 -56
  275. package/test/dom/router-loading.test.tsx +0 -44
  276. package/test/dom/scroll.test.ts +0 -56
  277. package/test/dom/slot.test.tsx +0 -131
  278. package/test/dom/use-metadata.test.tsx +0 -58
  279. package/test/dom/view-transitions.test.tsx +0 -53
  280. package/test/dynamic-routing.test.ts +0 -132
  281. package/test/email-console.test.ts +0 -86
  282. package/test/email-preview.test.ts +0 -73
  283. package/test/emails.test.ts +0 -58
  284. package/test/errors.test.ts +0 -21
  285. package/test/example-guestbook.test.ts +0 -123
  286. package/test/features.test.ts +0 -149
  287. package/test/fixtures/bignum-wire/spec.ts +0 -25
  288. package/test/fixtures/daemon-app.ts +0 -65
  289. package/test/fixtures/stream-echo.ts +0 -26
  290. package/test/fixtures/stream-gate.ts +0 -28
  291. package/test/fixtures/stream-trap.ts +0 -18
  292. package/test/fixtures/stream-typed.ts +0 -41
  293. package/test/fonts.test.ts +0 -28
  294. package/test/global-setup.ts +0 -17
  295. package/test/head.test.ts +0 -42
  296. package/test/image-blur.test.ts +0 -50
  297. package/test/io.test.ts +0 -117
  298. package/test/metadata.test.ts +0 -40
  299. package/test/navlink.test.ts +0 -28
  300. package/test/pages.test.ts +0 -105
  301. package/test/placeholder.test.ts +0 -9
  302. package/test/pqauth-e2e.test.ts +0 -216
  303. package/test/pqauth-email.test.ts +0 -801
  304. package/test/prerender.test.ts +0 -116
  305. package/test/prettier-plugin.test.ts +0 -46
  306. package/test/routes.test.ts +0 -76
  307. package/test/rpc-bignum-wire.test.ts +0 -164
  308. package/test/rpc-dispatch.test.ts +0 -132
  309. package/test/rpc-kinds.test.ts +0 -18
  310. package/test/rpc.test.ts +0 -66
  311. package/test/search.test.ts +0 -114
  312. package/test/seo.test.ts +0 -175
  313. package/test/slot-layouts.test.ts +0 -69
  314. package/test/sri.test.ts +0 -129
  315. package/test/ssg.test.ts +0 -36
  316. package/test/ssr-hydration.test.tsx +0 -122
  317. package/test/ssr-render.test.ts +0 -197
  318. package/test/ssr-template.test.tsx +0 -482
  319. package/test/stream-emulation.test.ts +0 -479
  320. package/test/ui.test.ts +0 -40
  321. package/test/update.test.ts +0 -58
  322. package/test/validate.test.ts +0 -42
  323. package/test/version-check.test.ts +0 -130
  324. package/tests/data-parity/generated-parity.ts +0 -99
  325. package/tests/data-parity/parity.ts +0 -80
  326. package/tests/data-parity/spec.ts +0 -46
@@ -1,170 +0,0 @@
1
- /**
2
- * Pure description of toiljs's optional client styling features, a CSS preprocessor and Tailwind ,
3
- * shared by `create` (scaffold) and `configure` (toggle on existing projects). Dependency-light
4
- * (no node IO) so it can be unit-tested; the file writes and package-manager calls live in the
5
- * commands. Preprocessor and Tailwind are independent: Tailwind lives in its own `.css` entry so
6
- * it never passes through (and breaks on) a preprocessor's `@import` resolution.
7
- */
8
-
9
- /** Supported CSS preprocessor (`css` = none). */
10
- export type Preprocessor = 'css' | 'sass' | 'less' | 'stylus';
11
-
12
- /** The two independently-toggleable styling features of a project. */
13
- export interface StyleFeatures {
14
- readonly preprocessor: Preprocessor;
15
- readonly tailwind: boolean;
16
- }
17
-
18
- export const PREPROCESSORS: readonly Preprocessor[] = ['css', 'sass', 'less', 'stylus'];
19
-
20
- /** Main stylesheet extension for each preprocessor. */
21
- export const STYLE_EXT: Record<Preprocessor, string> = {
22
- css: 'css',
23
- sass: 'scss',
24
- less: 'less',
25
- stylus: 'styl',
26
- };
27
-
28
- /** npm package that enables each preprocessor in Vite (plain CSS needs none). */
29
- export const PREPROCESSOR_PKG: Record<Preprocessor, string | null> = {
30
- css: null,
31
- sass: 'sass',
32
- less: 'less',
33
- stylus: 'stylus',
34
- };
35
-
36
- /** Tailwind v4 packages. The framework auto-wires the Vite plugin when `@tailwindcss/vite` resolves. */
37
- export const TAILWIND_PKGS: readonly string[] = ['tailwindcss', '@tailwindcss/vite'];
38
-
39
- /**
40
- * Pinned versions for every package these features may install. `@tailwindcss/vite` must be
41
- * `>= 4.3.0`: earlier 4.x releases cap their `vite` peer at `^7`, so they ERESOLVE against the
42
- * Vite 8 toiljs ships (the "Tailwind broken on install" error). Keep both Tailwind pins in lockstep.
43
- */
44
- export const PKG_VERSION: Record<string, string> = {
45
- sass: '^1.83.0',
46
- less: '^4.2.1',
47
- stylus: '^0.64.0',
48
- tailwindcss: '^4.3.0',
49
- '@tailwindcss/vite': '^4.3.0',
50
- };
51
-
52
- /** Dedicated Tailwind entry (kept `.css` so no preprocessor touches its `@import`). */
53
- export const TAILWIND_ENTRY = 'styles/tailwind.css';
54
- export const TAILWIND_CSS = `@import 'tailwindcss';\n`;
55
-
56
- /** Path (relative to `client/`) of the main stylesheet for a preprocessor. */
57
- export function styleEntry(p: Preprocessor): string {
58
- return `styles/main.${STYLE_EXT[p]}`;
59
- }
60
-
61
- /** The preprocessor whose main stylesheet uses `ext` (with or without a leading dot), or null. */
62
- export function preprocessorForExt(ext: string): Preprocessor | null {
63
- const e = ext.replace(/^\./, '');
64
- if (e === 'sass') return 'sass';
65
- return PREPROCESSORS.find((p) => STYLE_EXT[p] === e) ?? null;
66
- }
67
-
68
- /** Packages required by a feature set (preprocessor package + Tailwind packages). */
69
- export function requiredPackages(f: StyleFeatures): string[] {
70
- const pkgs: string[] = [];
71
- const pp = PREPROCESSOR_PKG[f.preprocessor];
72
- if (pp) pkgs.push(pp);
73
- if (f.tailwind) pkgs.push(...TAILWIND_PKGS);
74
- return pkgs;
75
- }
76
-
77
- /** Managed packages to add and remove when moving from `from` to `to`. */
78
- export function packageDiff(
79
- from: StyleFeatures,
80
- to: StyleFeatures,
81
- ): { add: string[]; remove: string[] } {
82
- const want = new Set(requiredPackages(to));
83
- const had = new Set(requiredPackages(from));
84
- return {
85
- add: [...want].filter((p) => !had.has(p)),
86
- remove: [...had].filter((p) => !want.has(p)),
87
- };
88
- }
89
-
90
- /** The side-effect style imports for the app entry, Tailwind first so app CSS can override it. */
91
- export function styleImportLines(f: StyleFeatures): string[] {
92
- const lines: string[] = [];
93
- if (f.tailwind) lines.push(`import './${TAILWIND_ENTRY}';`);
94
- lines.push(`import './${styleEntry(f.preprocessor)}';`);
95
- return lines;
96
- }
97
-
98
- /**
99
- * Rewrites the `./styles/*` side-effect imports in an app entry (`client/toil.tsx`) to match
100
- * `features`, preserving the rest of the file. Existing style imports are removed and the new
101
- * block is placed after the `toiljs/routes` import (or the last import, or the top).
102
- */
103
- export function setStyleImports(source: string, f: StyleFeatures): string {
104
- const stripped = source.replace(
105
- /^[ \t]*import\s+['"]\.\/styles\/[^'"]+['"];?[ \t]*\r?\n/gm,
106
- '',
107
- );
108
- const block = styleImportLines(f).join('\n') + '\n';
109
-
110
- const lines = stripped.split('\n');
111
- const routesIdx = lines.findIndex((l) => /from\s+['"]toiljs\/routes['"]/.test(l));
112
- let insertAt: number;
113
- if (routesIdx !== -1) {
114
- insertAt = routesIdx + 1;
115
- } else {
116
- const lastImport = lines.reduce((acc, l, i) => (/^\s*import\s/.test(l) ? i : acc), -1);
117
- insertAt = lastImport + 1;
118
- }
119
- const head = lines.slice(0, insertAt).join('\n');
120
- const tail = lines.slice(insertAt).join('\n');
121
- return `${head}\n\n${block}\n${tail}`.replace(/\n{3,}/g, '\n\n');
122
- }
123
-
124
- /** A `toil.config` source containing `client: { images: <bool> }` (for scaffolding when none exists). */
125
- export function defaultConfigSource(images: boolean): string {
126
- return (
127
- "import { defineConfig } from 'toiljs/compiler';\n\n" +
128
- 'export default defineConfig({\n' +
129
- ' client: {\n' +
130
- ' // Optimize images at build time (resize/compress imported images).\n' +
131
- ` images: ${String(images)},\n` +
132
- ' },\n' +
133
- '});\n'
134
- );
135
- }
136
-
137
- /**
138
- * Sets the `client.images` flag in a `toil.config` source, returning the updated source, or `null`
139
- * if the file's shape isn't recognized (the caller should then fall back to a manual note). Handles
140
- * an existing `images:` value, an existing `client: {` block, or a bare `defineConfig({ … })`.
141
- */
142
- export function setConfigImages(source: string, enabled: boolean): string | null {
143
- const value = String(enabled);
144
- if (/\bimages\s*:\s*(?:true|false)/.test(source)) {
145
- return source.replace(/\bimages\s*:\s*(?:true|false)/, `images: ${value}`);
146
- }
147
- if (/\bclient\s*:\s*\{/.test(source)) {
148
- return source.replace(/\bclient\s*:\s*\{/, `client: {\n images: ${value},`);
149
- }
150
- if (/defineConfig\(\s*\{/.test(source)) {
151
- return source.replace(
152
- /defineConfig\(\s*\{/,
153
- `defineConfig({\n client: { images: ${value} },`,
154
- );
155
- }
156
- return null;
157
- }
158
-
159
- /** Detects the active preprocessor from a project's combined dependency map. */
160
- export function detectPreprocessor(deps: Record<string, string>): Preprocessor {
161
- if ('sass' in deps) return 'sass';
162
- if ('less' in deps) return 'less';
163
- if ('stylus' in deps) return 'stylus';
164
- return 'css';
165
- }
166
-
167
- /** Whether Tailwind is installed in a project's combined dependency map. */
168
- export function detectTailwind(deps: Record<string, string>): boolean {
169
- return '@tailwindcss/vite' in deps || 'tailwindcss' in deps;
170
- }
package/src/cli/index.ts DELETED
@@ -1,326 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * toiljs CLI. Routes `create` / `dev` / `build` and wraps them in the toiljs brand banner.
4
- * The compiler stays presentation-free (imported via the package's own `toiljs/compiler`
5
- * export); the epic bits, banner, the Clack scaffolding wizard, live here.
6
- */
7
- import { build, dev, start } from 'toiljs/compiler';
8
-
9
- import { runConfigure } from './configure.js';
10
- import { runCreate, type Template } from './create.js';
11
- import { runDb } from './db.js';
12
- import { runDoctor } from './doctor.js';
13
- import { notifyIfOutdated } from './notify.js';
14
- import { runUpdate } from './update.js';
15
- import { type Preprocessor, PREPROCESSORS } from './features.js';
16
- import { accent, banner, bold, danger, dim, success, version } from './ui.js';
17
-
18
- // Node 22+/26 prints an ExperimentalWarning the first time any code touches the
19
- // built-in `localStorage` global (some browser-oriented deps do when they are
20
- // evaluated server-side during the dev SSR pass). It is harmless (localStorage
21
- // works fine in the real browser) but noisy on every `toiljs dev`/`build`, so drop
22
- // exactly that one warning here, before anything runs. Every other warning still
23
- // prints. Installed on the CLI process, ahead of the compiler/dev work.
24
- const __origEmitWarning = process.emitWarning.bind(process) as (...a: unknown[]) => void;
25
- process.emitWarning = ((warning: unknown, ...rest: unknown[]): void => {
26
- const msg = typeof warning === 'string' ? warning : (warning as { message?: string })?.message;
27
- if (typeof msg === 'string' && msg.includes('localStorage is not available')) return;
28
- __origEmitWarning(warning, ...rest);
29
- }) as typeof process.emitWarning;
30
-
31
- interface Flags {
32
- root?: string;
33
- port?: number;
34
- host?: string;
35
- threads?: number;
36
- name?: string;
37
- template?: Template;
38
- preprocessor?: Preprocessor;
39
- tailwind?: boolean;
40
- ai?: boolean;
41
- images?: boolean;
42
- install?: boolean;
43
- git?: boolean;
44
- pm?: string;
45
- yes?: boolean;
46
- json?: boolean;
47
- fix?: boolean;
48
- target?: string;
49
- server?: boolean;
50
- }
51
-
52
- function parseArgs(argv: string[]): Flags {
53
- const flags: Flags = {};
54
- for (let i = 0; i < argv.length; i++) {
55
- const arg = argv[i];
56
- switch (arg) {
57
- case '--root':
58
- flags.root = argv[++i];
59
- break;
60
- case '--port': {
61
- const port = Number(argv[++i]);
62
- if (!Number.isNaN(port)) flags.port = port;
63
- break;
64
- }
65
- case '--host':
66
- flags.host = argv[++i];
67
- break;
68
- case '--threads':
69
- case '--workers': {
70
- const threads = Number(argv[++i]);
71
- if (!Number.isNaN(threads)) flags.threads = threads;
72
- break;
73
- }
74
- case '--template':
75
- case '-t': {
76
- const t = argv[++i];
77
- if (t === 'app' || t === 'minimal' || t === 'agent') flags.template = t;
78
- break;
79
- }
80
- case '--pm':
81
- flags.pm = argv[++i];
82
- break;
83
- case '--style': {
84
- const s = argv[++i];
85
- if ((PREPROCESSORS as readonly string[]).includes(s))
86
- flags.preprocessor = s as Preprocessor;
87
- break;
88
- }
89
- case '--tailwind':
90
- flags.tailwind = true;
91
- break;
92
- case '--no-tailwind':
93
- flags.tailwind = false;
94
- break;
95
- case '--ai':
96
- flags.ai = true;
97
- break;
98
- case '--no-ai':
99
- flags.ai = false;
100
- break;
101
- case '--images':
102
- flags.images = true;
103
- break;
104
- case '--no-images':
105
- flags.images = false;
106
- break;
107
- case '--install':
108
- flags.install = true;
109
- break;
110
- case '--no-install':
111
- flags.install = false;
112
- break;
113
- case '--git':
114
- flags.git = true;
115
- break;
116
- case '--no-git':
117
- flags.git = false;
118
- break;
119
- case '-y':
120
- case '--yes':
121
- flags.yes = true;
122
- break;
123
- case '--json':
124
- flags.json = true;
125
- break;
126
- case '--fix':
127
- flags.fix = true;
128
- break;
129
- case '--target':
130
- flags.target = argv[++i];
131
- break;
132
- case '--server':
133
- flags.server = true;
134
- break;
135
- default:
136
- if (!arg.startsWith('-') && flags.name === undefined) flags.name = arg;
137
- }
138
- }
139
- return flags;
140
- }
141
-
142
- function printHelp(): void {
143
- const cmd = (name: string, desc: string): string => ` ${accent(name.padEnd(15))}${dim(desc)}`;
144
- process.stdout.write(
145
- [
146
- `${bold('Usage')} ${dim('toiljs')} <command> [options]`,
147
- '',
148
- bold('Commands'),
149
- cmd('create [name]', 'scaffold a new toiljs app'),
150
- cmd('configure', 'toggle styling features (Sass/Less/Stylus, Tailwind)'),
151
- cmd('dev', 'start the dev server with HMR'),
152
- cmd('build', 'build the optimized production bundle'),
153
- cmd('start', 'self-host the built app (hyper-express / uWS)'),
154
- cmd('doctor', 'diagnose project setup and dependencies'),
155
- cmd('update', 'check for and apply dependency updates'),
156
- cmd('db <action>', 'manage dev DB data (status | reset | export | import)'),
157
- '',
158
- bold('Options'),
159
- cmd('--root <dir>', 'project root (default: current directory)'),
160
- cmd('--port <n>', 'dev/start: listen port (or PORT env / client.port; default 3000)'),
161
- cmd('--host <h>', 'dev/start: bind host, e.g. 0.0.0.0 (or HOST env / client.host; default 127.0.0.1)'),
162
- cmd('--threads <n>', 'start: production HTTP worker count'),
163
- cmd('-t, --template', 'create: app | minimal | agent'),
164
- cmd('--style <name>', 'create/configure: css | sass | less | stylus'),
165
- cmd('--tailwind', 'create/configure: enable Tailwind (--no-tailwind to remove)'),
166
- cmd('--no-ai', 'create: skip AI assistant files (CLAUDE.md, etc.)'),
167
- cmd('-y, --yes', 'create: accept defaults (non-interactive)'),
168
- cmd('--no-install', "create: don't install dependencies"),
169
- cmd('--server', 'build: build only the server (regenerate shared/server.ts + wasm)'),
170
- cmd('--json', 'doctor: machine-readable output'),
171
- cmd('--fix', 'doctor: auto-fix what it can (typed-RPC wiring)'),
172
- cmd('--target <t>', 'update: latest | minor | patch | newest | greatest'),
173
- cmd('-v, --version', 'print the toiljs version'),
174
- '',
175
- dim(' Every command checks npm for a newer toiljs and warns when outdated.'),
176
- dim(' Set TOILJS_NO_UPDATE_CHECK=1 to opt out.'),
177
- '',
178
- ].join('\n') + '\n',
179
- );
180
- }
181
-
182
- async function main(): Promise<void> {
183
- const [command, ...rest] = process.argv.slice(2);
184
-
185
- if (command === '--version' || command === '-v') {
186
- process.stdout.write(version() + '\n');
187
- return;
188
- }
189
-
190
- const flags = parseArgs(rest);
191
-
192
- // Every invocation (including `npm run dev` / `npm run build`, which call this CLI)
193
- // checks that the installed toiljs is the latest release. Warns on stderr, never blocks
194
- // the command; opt out with TOILJS_NO_UPDATE_CHECK=1.
195
- await notifyIfOutdated(flags.root);
196
-
197
- switch (command) {
198
- case 'create':
199
- banner();
200
- await runCreate({
201
- name: flags.name,
202
- template: flags.template,
203
- preprocessor: flags.preprocessor,
204
- tailwind: flags.tailwind,
205
- ai: flags.ai,
206
- images: flags.images,
207
- install: flags.install,
208
- git: flags.git,
209
- pm: flags.pm,
210
- yes: flags.yes,
211
- cwd: process.cwd(),
212
- });
213
- break;
214
-
215
- case 'configure':
216
- banner();
217
- await runConfigure({
218
- root: flags.root,
219
- preprocessor: flags.preprocessor,
220
- tailwind: flags.tailwind,
221
- images: flags.images,
222
- install: flags.install,
223
- cwd: process.cwd(),
224
- });
225
- break;
226
-
227
- case 'dev':
228
- banner();
229
- process.stdout.write(dim(' starting dev server…') + '\n\n');
230
- await dev({ root: flags.root, port: flags.port, host: flags.host });
231
- break;
232
-
233
- case 'build':
234
- banner();
235
- process.stdout.write(
236
- dim(flags.server ? ' building the server…' : ' building for production…') +
237
- '\n\n',
238
- );
239
- await build({ root: flags.root, serverOnly: flags.server });
240
- process.stdout.write(
241
- '\n' +
242
- success(' ✓ ') +
243
- bold(flags.server ? 'server build complete' : 'build complete') +
244
- '\n\n',
245
- );
246
- break;
247
-
248
- case 'start': {
249
- banner();
250
- process.stdout.write(dim(' self-hosting the built app…') + '\n\n');
251
- const server = await start({
252
- root: flags.root,
253
- port: flags.port,
254
- host: flags.host,
255
- threads: flags.threads,
256
- });
257
- // A wildcard bind (0.0.0.0/::) is not universally openable, so present a
258
- // clickable loopback URL and separately flag that it is exposed.
259
- const wildcard =
260
- server.host === '0.0.0.0' || server.host === '::' || server.host === '';
261
- const shownHost = wildcard ? 'localhost' : server.host;
262
- const exposed =
263
- server.host !== '127.0.0.1' && server.host !== 'localhost' && server.host !== '::1';
264
- process.stdout.write(
265
- accent(' ➜ ') +
266
- bold(`http://${shownHost}:${String(server.port)}`) +
267
- dim(` ws channel: ${server.wsPath}`) +
268
- (exposed
269
- ? '\n' +
270
- dim(` bound to ${server.host}:${String(server.port)} (exposed beyond loopback)`)
271
- : '') +
272
- '\n\n',
273
- );
274
- break;
275
- }
276
-
277
- case 'doctor':
278
- // Skip the banner for --json so stdout stays valid JSON.
279
- if (!flags.json) banner();
280
- await runDoctor({
281
- root: flags.root,
282
- cwd: process.cwd(),
283
- json: flags.json,
284
- fix: flags.fix,
285
- });
286
- break;
287
-
288
- case 'update':
289
- banner();
290
- await runUpdate({
291
- root: flags.root,
292
- cwd: process.cwd(),
293
- yes: flags.yes,
294
- target: flags.target,
295
- });
296
- break;
297
-
298
- case 'db': {
299
- // `toiljs db <action> [file]` — no banner so `path`/`export` pipe cleanly.
300
- const action = rest[0];
301
- const fileArg = rest[1] !== undefined && !rest[1].startsWith('-') ? rest[1] : undefined;
302
- runDb(action, fileArg, { root: flags.root });
303
- break;
304
- }
305
-
306
- case 'help':
307
- case '--help':
308
- case '-h':
309
- case undefined:
310
- banner();
311
- printHelp();
312
- break;
313
-
314
- default:
315
- banner();
316
- process.stdout.write(dim(` unknown command: ${command}`) + '\n\n');
317
- printHelp();
318
- process.exitCode = 1;
319
- }
320
- }
321
-
322
- main().catch((err: unknown) => {
323
- const message = err instanceof Error ? err.message : String(err);
324
- process.stderr.write('\n' + danger(' ✗ ') + message + '\n');
325
- process.exitCode = 1;
326
- });
package/src/cli/notify.ts DELETED
@@ -1,120 +0,0 @@
1
- /**
2
- * Automatic update check, run on every CLI invocation (so `npm run dev` / `npm run build`,
3
- * which call the toiljs CLI, are covered too). Asks the npm registry for the latest toiljs
4
- * release (answer cached for an hour in the user's cache dir, network capped at 2 seconds),
5
- * then warns on stderr when the project's installed toiljs or the running CLI is behind.
6
- * Never throws and never fails the command. Opt out with TOILJS_NO_UPDATE_CHECK=1 (also
7
- * honors NO_UPDATE_NOTIFIER and CI).
8
- */
9
- import fs from 'node:fs';
10
- import os from 'node:os';
11
- import path from 'node:path';
12
- import { fileURLToPath } from 'node:url';
13
-
14
- import { detectPackageManager } from './update.js';
15
- import { accent, bold, box, dim, version as cliVersion, warn } from './ui.js';
16
- import { findOutdated, isCacheFresh, type OutdatedRow, parseCheckCache } from './version-check.js';
17
-
18
- const REGISTRY_URL = 'https://registry.npmjs.org/toiljs/latest';
19
- const FETCH_TIMEOUT_MS = 2000;
20
-
21
- /** Where the registry answer is cached: `$XDG_CACHE_HOME`/`~/.cache` + `toiljs/`. */
22
- function cacheFile(): string {
23
- const base = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), '.cache');
24
- return path.join(base, 'toiljs', 'update-check.json');
25
- }
26
-
27
- /** Asks the npm registry for the latest published version; null on any failure. */
28
- async function fetchLatest(): Promise<string | null> {
29
- const ctrl = new AbortController();
30
- const timer = setTimeout(() => {
31
- ctrl.abort();
32
- }, FETCH_TIMEOUT_MS);
33
- try {
34
- const res = await fetch(REGISTRY_URL, {
35
- signal: ctrl.signal,
36
- headers: { accept: 'application/json' },
37
- });
38
- if (!res.ok) return null;
39
- const data: unknown = await res.json();
40
- if (typeof data !== 'object' || data === null) return null;
41
- const v = (data as Record<string, unknown>).version;
42
- return typeof v === 'string' ? v : null;
43
- } catch {
44
- return null;
45
- } finally {
46
- clearTimeout(timer);
47
- }
48
- }
49
-
50
- /**
51
- * The latest published toiljs version, from the cache when fresh, otherwise from the registry.
52
- * Failures are cached too (as null) so an offline machine backs off for the TTL instead of
53
- * paying the fetch timeout on every command.
54
- */
55
- async function resolveLatest(): Promise<string | null> {
56
- const file = cacheFile();
57
- try {
58
- const cached = parseCheckCache(fs.readFileSync(file, 'utf8'));
59
- if (cached && isCacheFresh(cached, Date.now())) return cached.latest;
60
- } catch {}
61
- const latest = await fetchLatest();
62
- try {
63
- fs.mkdirSync(path.dirname(file), { recursive: true });
64
- fs.writeFileSync(file, JSON.stringify({ latest, checkedAt: Date.now() }));
65
- } catch {}
66
- return latest;
67
- }
68
-
69
- /** Reads the version of the toiljs resolved in the project's node_modules, if any. */
70
- function projectToiljsVersion(root: string): string | null {
71
- try {
72
- const raw = fs.readFileSync(
73
- path.join(root, 'node_modules', 'toiljs', 'package.json'),
74
- 'utf8',
75
- );
76
- const parsed: unknown = JSON.parse(raw);
77
- if (typeof parsed !== 'object' || parsed === null) return null;
78
- const v = (parsed as Record<string, unknown>).version;
79
- return typeof v === 'string' ? v : null;
80
- } catch {
81
- return null;
82
- }
83
- }
84
-
85
- function noticeLines(latest: string, rows: OutdatedRow[]): string {
86
- const header = warn('⚠ ') + bold(`a newer toiljs is available: ${accent(latest)}`);
87
- const body = rows.map((row) => {
88
- const where = row.scope === 'project' ? 'this project has' : 'your global CLI is';
89
- return `${where} ${row.installed}${dim(', update with')} ${accent(row.command)}`;
90
- });
91
- return '\n' + box([header, '', ...body], warn) + '\n';
92
- }
93
-
94
- /**
95
- * Checks the project install and the running CLI against the latest release and prints a
96
- * warning to stderr when either is behind. Safe to await unconditionally: bounded by the
97
- * cache TTL + fetch timeout, and it swallows every error.
98
- */
99
- export async function notifyIfOutdated(rootArg: string | undefined): Promise<void> {
100
- try {
101
- const env = process.env;
102
- if (env.TOILJS_NO_UPDATE_CHECK || env.NO_UPDATE_NOTIFIER || env.CI) return;
103
-
104
- const latest = await resolveLatest();
105
- if (!latest) return;
106
-
107
- const root = path.resolve(rootArg ?? process.cwd());
108
- const cliDir = path.dirname(fileURLToPath(import.meta.url));
109
- const cliIsLocal = cliDir.startsWith(path.join(root, 'node_modules') + path.sep);
110
- const rows = findOutdated(
111
- latest,
112
- projectToiljsVersion(root),
113
- cliVersion(),
114
- cliIsLocal,
115
- detectPackageManager(root).name,
116
- );
117
- if (rows.length === 0) return;
118
- process.stderr.write(noticeLines(latest, rows));
119
- } catch {}
120
- }
package/src/cli/proc.ts DELETED
@@ -1,56 +0,0 @@
1
- import { spawn } from 'node:child_process';
2
-
3
- /**
4
- * Spawns `cmd args` in `cwd`, resolving on a 0 exit code and rejecting otherwise. On Windows the
5
- * `npm`/`pnpm`/`yarn` shims are `.cmd` files that need a shell; passing an args array with
6
- * `shell: true` is deprecated (DEP0190), so the whole command is passed as one string there
7
- * (args are fixed/allowlisted, never raw user input). POSIX spawns directly.
8
- */
9
- export function run(
10
- cmd: string,
11
- args: string[],
12
- cwd: string,
13
- opts: { stdio?: 'ignore' | 'inherit' } = {},
14
- ): Promise<void> {
15
- return new Promise((resolve, reject) => {
16
- const onWindows = process.platform === 'win32';
17
- const stdio = opts.stdio ?? 'ignore';
18
- const child = onWindows
19
- ? spawn([cmd, ...args].join(' '), { cwd, stdio, shell: true })
20
- : spawn(cmd, args, { cwd, stdio });
21
- child.on('error', reject);
22
- child.on('close', (code) =>
23
- code === 0 ? resolve() : reject(new Error(`${cmd} exited with code ${String(code)}`)),
24
- );
25
- });
26
- }
27
-
28
- /**
29
- * Like {@link run}, but captures stdout/stderr and resolves with them plus the exit code (it never
30
- * rejects on a non-zero exit, the caller decides). Used to read JSON from tools like
31
- * `npm-check-updates`. Same Windows shell handling as {@link run}; args are fixed/allowlisted.
32
- */
33
- export function capture(
34
- cmd: string,
35
- args: string[],
36
- cwd: string,
37
- ): Promise<{ stdout: string; stderr: string; code: number }> {
38
- return new Promise((resolve, reject) => {
39
- const onWindows = process.platform === 'win32';
40
- const child = onWindows
41
- ? spawn([cmd, ...args].join(' '), { cwd, shell: true })
42
- : spawn(cmd, args, { cwd });
43
- let stdout = '';
44
- let stderr = '';
45
- child.stdout?.on('data', (d: Buffer) => {
46
- stdout += d.toString();
47
- });
48
- child.stderr?.on('data', (d: Buffer) => {
49
- stderr += d.toString();
50
- });
51
- child.on('error', reject);
52
- child.on('close', (code) => {
53
- resolve({ stdout, stderr, code: code ?? 1 });
54
- });
55
- });
56
- }