@weft-js/cli 0.1.1 → 0.1.3

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 (171) hide show
  1. package/README.md +534 -54
  2. package/bin/weft.mjs +8 -1
  3. package/docs/async.md +16 -6
  4. package/docs/browser.md +22 -8
  5. package/docs/config.md +39 -9
  6. package/docs/core.md +30 -0
  7. package/docs/deploy.md +33 -8
  8. package/docs/design.md +12 -3
  9. package/docs/entrypoints.md +79 -0
  10. package/docs/fonts.md +12 -2
  11. package/docs/icons.md +13 -7
  12. package/docs/lists.md +3 -1
  13. package/docs/meta.md +13 -3
  14. package/docs/plugins.md +32 -9
  15. package/docs/props.md +13 -2
  16. package/docs/reactivity.md +26 -0
  17. package/docs/rules.md +19 -12
  18. package/docs/rust.md +47 -17
  19. package/docs/start-short.md +3 -2
  20. package/docs/start.md +226 -52
  21. package/docs/state.md +33 -7
  22. package/docs/style.md +31 -8
  23. package/docs/surface.md +61 -15
  24. package/docs/testing.md +15 -5
  25. package/docs/theme.md +182 -0
  26. package/docs/ui-state.md +19 -6
  27. package/docs/verify.md +13 -0
  28. package/package.json +13 -4
  29. package/src/add/config.mjs +93 -0
  30. package/src/add/errors.mjs +2 -0
  31. package/src/add/setup.mjs +88 -0
  32. package/src/add-rust.mjs +82 -27
  33. package/src/add.mjs +209 -181
  34. package/src/agents-md.mjs +144 -43
  35. package/src/alias.mjs +16 -5
  36. package/src/audit/page.mjs +313 -0
  37. package/src/audit/report.mjs +69 -0
  38. package/src/audit/utils.mjs +5 -0
  39. package/src/audit.mjs +159 -206
  40. package/src/browser/cli.mjs +24 -5
  41. package/src/browser/client.mjs +189 -25
  42. package/src/browser/commands.mjs +166 -51
  43. package/src/catalog/audit.mjs +129 -0
  44. package/src/catalog/auth.mjs +40 -0
  45. package/src/catalog/compiler.mjs +337 -0
  46. package/src/catalog/contracts.mjs +18 -0
  47. package/src/catalog/database.mjs +52 -0
  48. package/src/catalog/deploy.mjs +117 -0
  49. package/src/catalog/design.mjs +159 -0
  50. package/src/catalog/forms.mjs +25 -0
  51. package/src/catalog/hydration.mjs +29 -0
  52. package/src/catalog/icons.mjs +24 -0
  53. package/src/catalog/media.mjs +163 -0
  54. package/src/catalog/metadata.mjs +116 -0
  55. package/src/catalog/plugins.mjs +228 -0
  56. package/src/catalog/realtime.mjs +195 -0
  57. package/src/catalog/rust.mjs +75 -0
  58. package/src/catalog/server-functions.mjs +92 -0
  59. package/src/catalog/state.mjs +39 -0
  60. package/src/catalog/style-groups.mjs +54 -0
  61. package/src/catalog/tests.mjs +127 -0
  62. package/src/catalog/text.mjs +200 -0
  63. package/src/catalog/ui-state.mjs +42 -0
  64. package/src/catalog.mjs +67 -460
  65. package/src/check/runtime.mjs +280 -0
  66. package/src/check.mjs +198 -208
  67. package/src/cli/authoring.mjs +213 -0
  68. package/src/cli/project.mjs +302 -0
  69. package/src/cli.mjs +222 -250
  70. package/src/config.mjs +1 -1
  71. package/src/contributions.mjs +75 -25
  72. package/src/db-layer.mjs +13 -5
  73. package/src/deploy/cdn.mjs +94 -16
  74. package/src/deploy/files.mjs +100 -21
  75. package/src/deploy/fit.mjs +127 -23
  76. package/src/deploy/hosts.mjs +90 -20
  77. package/src/deploy/index/cli.mjs +20 -0
  78. package/src/deploy/index/environment.mjs +69 -0
  79. package/src/deploy/index/steps.mjs +87 -0
  80. package/src/deploy/index.mjs +228 -114
  81. package/src/deploy/needs.mjs +88 -31
  82. package/src/design-checks/accessible-names.mjs +62 -0
  83. package/src/design-checks/contrast.mjs +43 -0
  84. package/src/design-checks/csp.mjs +60 -0
  85. package/src/design-checks/files.mjs +59 -0
  86. package/src/design-checks/heading-links.mjs +61 -0
  87. package/src/design-checks/interaction.mjs +65 -0
  88. package/src/design-checks/jsx.mjs +67 -0
  89. package/src/design-checks/layout-values.mjs +68 -0
  90. package/src/design-checks/native-controls.mjs +48 -0
  91. package/src/design-checks/outline.mjs +39 -0
  92. package/src/design-checks/reporter.mjs +37 -0
  93. package/src/design-checks/rules.mjs +274 -0
  94. package/src/design-checks/values.mjs +262 -0
  95. package/src/design-checks.mjs +10 -400
  96. package/src/diag.mjs +32 -8
  97. package/src/docs.mjs +138 -43
  98. package/src/doctor.mjs +20 -8
  99. package/src/files.mjs +18 -5
  100. package/src/fix.mjs +10 -2
  101. package/src/gate/after.mjs +40 -0
  102. package/src/gate/before.mjs +54 -0
  103. package/src/gate/classify.mjs +72 -0
  104. package/src/gate/mutation.mjs +209 -0
  105. package/src/gate/resolve-cases.mjs +22 -0
  106. package/src/gate/result.mjs +63 -0
  107. package/src/gate/run.mjs +75 -0
  108. package/src/gate.mjs +104 -202
  109. package/src/infer/box-props.cjs +140 -0
  110. package/src/infer/core-boxes.cjs +46 -0
  111. package/src/infer/derived-writes.cjs +95 -0
  112. package/src/infer/engine/checks.cjs +193 -0
  113. package/src/infer/engine/flow.cjs +293 -0
  114. package/src/infer/engine/report.cjs +158 -0
  115. package/src/infer/engine/utils.cjs +15 -0
  116. package/src/infer/engine.cjs +108 -368
  117. package/src/infer/facts/sites.cjs +114 -0
  118. package/src/infer/facts.cjs +210 -117
  119. package/src/infer/hosts.cjs +69 -22
  120. package/src/infer/lsp.mjs +149 -40
  121. package/src/infer/session.cjs +73 -17
  122. package/src/infer/shadow.cjs +13 -5
  123. package/src/infer/worker.cjs +57 -9
  124. package/src/jsx-scan.mjs +63 -21
  125. package/src/load-config/schema.mjs +281 -0
  126. package/src/load-config.mjs +137 -138
  127. package/src/map.mjs +93 -26
  128. package/src/mcp/browser-tools.mjs +155 -0
  129. package/src/mcp.mjs +147 -69
  130. package/src/meta-table.mjs +43 -8
  131. package/src/mutate.mjs +120 -36
  132. package/src/plugin-checks.mjs +52 -23
  133. package/src/plugins.mjs +125 -39
  134. package/src/project.mjs +170 -79
  135. package/src/props-checks.mjs +24 -6
  136. package/src/props-listener.mjs +27 -9
  137. package/src/react-checks.mjs +35 -4
  138. package/src/server-state-checks.mjs +34 -0
  139. package/src/share-checks.mjs +121 -37
  140. package/src/site.mjs +33 -6
  141. package/src/slots.mjs +104 -19
  142. package/src/start/build.mjs +116 -0
  143. package/src/start/routes.mjs +38 -0
  144. package/src/start.mjs +193 -95
  145. package/src/state-checks/core-state.mjs +223 -0
  146. package/src/state-checks/modules.mjs +17 -0
  147. package/src/state-checks/scan.mjs +232 -0
  148. package/src/state-checks/server-graph.mjs +65 -0
  149. package/src/state-checks.mjs +109 -133
  150. package/src/style/find.mjs +121 -0
  151. package/src/style.mjs +133 -127
  152. package/src/surface-checks.mjs +212 -46
  153. package/src/tailwind.mjs +5 -4
  154. package/src/tasks.mjs +189 -27
  155. package/src/test-rules/context.mjs +109 -0
  156. package/src/test-rules/file-rules.mjs +279 -0
  157. package/src/test-rules/rule-helpers.mjs +244 -0
  158. package/src/test-rules/syntax.mjs +223 -0
  159. package/src/test-rules/test-rules.mjs +127 -0
  160. package/src/testdiff.mjs +94 -32
  161. package/src/tests.mjs +31 -483
  162. package/src/text-checks.mjs +229 -69
  163. package/src/tokens.mjs +12 -4
  164. package/src/trust/scan.mjs +95 -0
  165. package/src/trust.mjs +214 -102
  166. package/src/weft.mjs +41 -9
  167. package/src/workspace.mjs +96 -19
  168. package/ts-plugin/context.js +57 -0
  169. package/ts-plugin/index.js +4 -124
  170. package/ts-plugin/mapping.js +65 -0
  171. package/ts-plugin/proxy.js +144 -0
package/docs/async.md CHANGED
@@ -6,16 +6,26 @@ import { resource, Boundary } from '@weft-js/core'
6
6
  type User = { name: string }
7
7
 
8
8
  function Name({ id }: { id: string }) {
9
- // `id` is read before the first `await`, so a new id fetches again and aborts the old request.
10
- const user = resource(signal => fetch(`/api/users/${id}`, { signal }).then(r => r.json() as Promise<User>))
11
- // `pending` is also true on a refetch, while the old value is still here: dim it rather than replace it (X033).
12
- return <h1 aria-busy={user.pending ? 'true' : 'false'}>{user.value?.name}</h1>
9
+ // A new id refetches and aborts the old request.
10
+ const user = resource(signal =>
11
+ fetch(`/api/users/${id}`, { signal })
12
+ .then(r => r.json() as Promise<User>),
13
+ )
14
+ // On a refetch, dim the old value rather than replace it (X033).
15
+ return (
16
+ <h1 aria-busy={user.pending ? 'true' : 'false'}>
17
+ {user.value?.name}
18
+ </h1>
19
+ )
13
20
  }
14
21
 
15
- // The resource is made inside the Boundary (in Name), so the Boundary waits for it.
22
+ // Name makes the resource inside the Boundary, which waits for it.
16
23
  export function Profile({ id }: { id: string }) {
17
24
  return (
18
- <Boundary pending={<p>Loading…</p>} error={(e, retry) => <button onClick={retry}>Retry</button>}>
25
+ <Boundary
26
+ pending={<p>Loading…</p>}
27
+ error={(e, retry) => <button onClick={retry}>Retry</button>}
28
+ >
19
29
  <Name id={id} />
20
30
  </Boundary>
21
31
  )
package/docs/browser.md CHANGED
@@ -2,20 +2,34 @@
2
2
 
3
3
  ```tsx
4
4
  import { state } from '@weft-js/core'
5
- import { online, visible, lifecycle, media, on, interval } from '@weft-js/core/browser'
5
+ import {
6
+ online,
7
+ visible,
8
+ lifecycle,
9
+ media,
10
+ on,
11
+ interval,
12
+ } from '@weft-js/core/browser'
6
13
 
7
14
  export function Toolbar() {
8
- const isOnline = online() // Derived<boolean>; server: true
9
- const shown = visible() // Derived<boolean>; server: true
10
- const page = lifecycle() // 'active' | 'passive' | 'hidden' | 'frozen' | 'terminated'
11
- const dark = media('(prefers-color-scheme: dark)', { ssr: false }) // server renders `ssr`
15
+ const isOnline = online() // Derived<boolean>; server: true
16
+ const shown = visible() // Derived<boolean>; server: true
17
+ // 'active' | 'passive' | 'hidden' | 'frozen' | 'terminated'
18
+ const page = lifecycle()
19
+ // Server renders `ssr`.
20
+ const dark = media('(prefers-color-scheme: dark)', { ssr: false })
12
21
  const open = state(true)
13
22
  const now = state(Date.now())
14
- on(window, 'keydown', e => { if (e.key === 'Escape') open.value = false }) // e: KeyboardEvent
15
- interval('1s', () => { now.value = Date.now() }) // also '500ms', '5m', '1h', or a number of ms
23
+ on(window, 'keydown', e => { // e: KeyboardEvent
24
+ if (e.key === 'Escape') open.value = false
25
+ })
26
+ // Also '500ms', '5m', '1h', or a number of ms.
27
+ interval('1s', () => { now.value = Date.now() })
16
28
  return (
17
29
  <p hidden={!open.value}>
18
- {isOnline.value ? 'online' : 'offline'}, {dark.value ? 'dark' : 'light'}, {shown.value ? page.value : 'hidden'},
30
+ {isOnline.value ? 'online' : 'offline'}{', '}
31
+ {dark.value ? 'dark' : 'light'}{', '}
32
+ {shown.value ? page.value : 'hidden'},
19
33
  {new Date(now.value).toLocaleTimeString()}
20
34
  </p>
21
35
  )
package/docs/config.md CHANGED
@@ -12,24 +12,41 @@ import { dialScript, warp } from '@weft-js/warp/plugin'
12
12
  export default defineConfig({
13
13
  scope: { write: ['src/**', 'test/**'], forbid: ['.env*'] },
14
14
  tasks: {
15
- seed: { run: 'node scripts/seed.mjs', description: 'Load demo products into the dev db', sideEffects: ['db'], env: ['dev'] },
15
+ seed: {
16
+ run: 'node scripts/seed.mjs',
17
+ description: 'Load demo products into the dev db',
18
+ sideEffects: ['db'], env: ['dev'],
19
+ },
16
20
  },
17
21
  environments: { dev: { url: 'http://localhost:5173' } },
18
- site: { // page metadata defaults: static tags in the server's first response (weft docs meta)
22
+ // Metadata defaults: static tags in the first response.
23
+ // See weft docs meta.
24
+ site: {
19
25
  name: 'Acme',
20
26
  url: 'https://acme.dev',
21
27
  title: '%s · Acme',
22
28
  description: 'Tools for builders.',
23
29
  locale: 'en_US',
24
- image: { url: '/og.png', width: 1200, height: 630 }, // default 'auto': a generated card (weft docs meta); false: none
30
+ // Default 'auto': generated card; false: none (weft docs meta).
31
+ image: { url: '/og.png', width: 1200, height: 630 },
25
32
  twitter: { card: 'summary_large_image', site: '@acme' },
26
- inlineCss: false, // default true: each page carries what its first paint needs; false keeps plain links
27
- criticalCss: false, // default true: one hashed sheet plus a first-paint part; false splits by chunk and inlines up to 48 KB
28
- criticalKeep: ['theme-x'], // words of selectors a first paint keeps, for classes a head script sets
29
- head: dialScript, // raw HTML in every page's head, before the stylesheets: dialScript from @weft-js/warp/plugin restores `setDial(…, { persist: true })` before the first paint
33
+ // Default true: first-paint CSS. False keeps plain links,
34
+ // as a strict CSP needs (D012).
35
+ inlineCss: false,
36
+ // Default true: one hashed sheet and first-paint CSS.
37
+ // False splits by chunk and inlines up to 48 KB.
38
+ criticalCss: false,
39
+ // Selector words to keep for classes set by a head script.
40
+ criticalKeep: ['theme-x'],
41
+ // Raw HTML before stylesheets on every page. dialScript from
42
+ // @weft-js/warp/plugin restores setDial(…, { persist: true })
43
+ // before the first paint.
44
+ head: dialScript,
30
45
  },
31
- plugins: [warp()], // plugin factories (@weft-js/core/plugin); a plain `{ name, provides }` entry is data only
32
- slots: {}, // names the winner when two plugins provide one slot
46
+ // Plugin factories; plain { name, provides } entries are data.
47
+ plugins: [warp()],
48
+ // Names the winner when two plugins provide one slot.
49
+ slots: {},
33
50
  })
34
51
  ```
35
52
 
@@ -91,3 +108,16 @@ that hides itself or code in dependencies (your package manager's lockfile pins
91
108
  fixed code to hash, so it's audited on every check instead. A plugin defined in the config file is your own code:
92
109
  only its permissions are compared. A plugin is matched to its package by name, so one that claims another's name is
93
110
  hashed as that package.
111
+
112
+
113
+ ## Indexing intent
114
+
115
+ For a site intended for public search, declare
116
+ `build: { audit: { indexing: 'public' } }`. L024 then fails the build or audit if
117
+ robots metadata or an HTTP X-Robots-Tag header says noindex. `private` or the
118
+ backward-compatible `auto` leaves this a warning; neither removes a directive.
119
+ After deployment, run `weft audit --url https://your-site.example --indexing public`:
120
+ a host or proxy may add a header that a local build cannot see. Preserve intentional
121
+ preview/private exclusions. A noindex finding is an indexing policy issue, not
122
+ chat-agent traffic; use a clean profile before attributing other audit failures
123
+ to application or framework code.
package/docs/core.md ADDED
@@ -0,0 +1,30 @@
1
+ # Core entrypoints
2
+
3
+ Import application APIs such as `state`, `derived`, `watch`, `context` and `createRoot`
4
+ from `@weft-js/core`. Use the `State<T>` and `Derived<T>` types for boxes.
5
+
6
+ `memo(fn)` returns a cached accessor, `() => T`. Call it to read the current value.
7
+ It tracks the same dependencies as `derived(fn)` and recomputes when they change.
8
+
9
+ ```ts
10
+ import { memo, state } from '@weft-js/core'
11
+
12
+ const count = state(1)
13
+ const twice = memo(() => count.value * 2)
14
+ console.log(twice()) // 2
15
+ ```
16
+
17
+ Compiler output and framework integrations use `@weft-js/core/internal`. This
18
+ entrypoint re-exports the runtime's existing implementations and shares its graph,
19
+ box constructors and server state. It does not create another runtime instance.
20
+
21
+ The root no longer exports `DIRTY`, `rt`, `listener`, `read`, `reach`, `clean`,
22
+ `setFlat`, `flat`, `collecting`, `runMounts`, `setKeyed`, `NONE`, `stats`,
23
+ `devComponent` or `Box`. Integrations that require these use the internal entrypoint.
24
+ Applications create boxes with `state` rather than constructing `Box`.
25
+
26
+ `hole`, `localProps` and `restOf` also live under the internal entrypoint. `hole`
27
+ tracks a renderer's child binding. `localProps` implements writable prop locals.
28
+ `restOf` takes the prop snapshot used by a compiled native-element spread. These
29
+ are compiler and renderer contracts, rather than application APIs. The `hole`
30
+ export of `@weft-js/core/ssr` is a separate server-rendering helper.
package/docs/deploy.md CHANGED
@@ -4,10 +4,14 @@ weft reads what the app uses and says which hosts can run it, before a build and
4
4
  writes the host's files and a workflow, and `weft deploy` runs the host's own CLI and reports the URL.
5
5
 
6
6
  ```bash
7
- weft deploy hosts # which hosts fit, why not, what each costs, and the suggestion
8
- weft deploy init # the suggested host's files, a GitHub workflow, and `deploy` in weft.config.ts
9
- weft deploy # a dry run: the build and the exact commands --yes would run
10
- weft deploy --yes # a preview deploy; add --prod for production
7
+ # Host fit, cost and suggestion
8
+ weft deploy hosts
9
+ # Host files, GitHub workflow and deploy config
10
+ weft deploy init
11
+ # Dry run: build and commands that --yes would run
12
+ weft deploy
13
+ # Preview; add --prod for production
14
+ weft deploy --yes
11
15
  ```
12
16
 
13
17
  `weft deploy` without `--yes` runs nothing. An agent runs the dry run on its own, and asks before `--yes`: a deploy
@@ -34,11 +38,19 @@ It needs a second origin and a cookie both can read, and is designed (research 4
34
38
 
35
39
  ```ts
36
40
  deploy: {
37
- target: 'fly', // netlify | vercel | cloudflare | fly | render
38
- fly: { app: 'shop', region: 'iad', volume: { name: 'data', sizeGb: 1 } },
39
- ci: 'github', // the workflow; false for none
41
+ // netlify | vercel | cloudflare | fly | render
42
+ target: 'fly',
43
+ fly: {
44
+ app: 'shop',
45
+ region: 'iad',
46
+ volume: { name: 'data', sizeGb: 1 },
47
+ },
48
+ ci: 'github', // the workflow; false for none
40
49
  branch: 'main',
41
- cdn: { proxy: 'cloudflare', images: { provider: 'cloudinary', cloud: 'shop' } },
50
+ cdn: {
51
+ proxy: 'cloudflare',
52
+ images: { provider: 'cloudinary', cloud: 'shop' },
53
+ },
42
54
  }
43
55
  ```
44
56
 
@@ -81,3 +93,16 @@ file as stale (**E006**); `init` rewrites it. A file you edited keeps its old ha
81
93
  E001 sockets on a function host, E002 a held process or a sidecar, E003 data on a disk that doesn't last, E004 a native
82
94
  addon deployed from another OS, E005 no target (with the suggestion), E006 a stale host file, E007 an unset variable,
83
95
  E008 a written credential, E009 the memory bus on many instances, E010–E014 CDN and media. `weft docs E003` explains one.
96
+
97
+
98
+ ## Indexing intent
99
+
100
+ For a site intended for public search, declare
101
+ `build: { audit: { indexing: 'public' } }`. L024 then fails the build or audit if
102
+ robots metadata or an HTTP X-Robots-Tag header says noindex. `private` or the
103
+ backward-compatible `auto` leaves this a warning; neither removes a directive.
104
+ After deployment, run `weft audit --url https://your-site.example --indexing public`:
105
+ a host or proxy may add a header that a local build cannot see. Preserve intentional
106
+ preview/private exclusions. A noindex finding is an indexing policy issue, not
107
+ chat-agent traffic; use a clean profile before attributing other audit failures
108
+ to application or framework code.
package/docs/design.md CHANGED
@@ -4,7 +4,15 @@ An app with warp has one design language: `@weft-js/warp`'s primitives and compo
4
4
  is, and the look follows the theme, the dials and the density.
5
5
 
6
6
  ```tsx
7
- import { Button, Card, Heading, Input, Row, Stack, Text } from '@weft-js/warp'
7
+ import {
8
+ Button,
9
+ Card,
10
+ Heading,
11
+ Input,
12
+ Row,
13
+ Stack,
14
+ Text,
15
+ } from '@weft-js/warp'
8
16
 
9
17
  export function Billing() {
10
18
  return (
@@ -85,13 +93,14 @@ In every app:
85
93
  | D038 | Two solid Buttons side by side | One primary action per region |
86
94
  | D039 | `<html>` with no `lang` | Set it |
87
95
 
88
- D010 is warp's contrast gate on the seed and tokens. D020–D025 are style groups.
96
+ D010 is warp's contrast gate on the seed and tokens: `weft build` stops on it. D012 is a CSP that blocks the inlined CSS. D020–D025 are style groups.
89
97
 
90
98
  `// weft-allow D001: <reason>` on the line above keeps one site; the reason is required. `check: { design: false }` in
91
99
  the config turns these off.
92
100
 
93
101
  ## Tokens
94
102
 
95
- The theme is `warp({ seed, dials, radius, fonts, tokens })`: every value goes through the contrast check. `weft tokens`
103
+ The theme is `warp({ seed, dials, fields, radius, fonts, tokens })`: every value goes through the contrast check. `weft docs theme`
104
+ has worked looks and the button channels. `weft tokens`
96
105
  writes the resolved tokens to `.weft/tokens/` as DTCG 2025.10, one file per theme × expression plus a resolver, for
97
106
  Figma, Style Dictionary or Terrazzo.
@@ -0,0 +1,79 @@
1
+ # Core and Start entrypoints
2
+
3
+ These paths are retained package exports. Node tooling must not enter a browser bundle.
4
+ The snapshots cover export paths, targets and conditions, not names or signatures.
5
+
6
+ ## @weft-js/core
7
+
8
+ - `@weft-js/core`: Application reactive runtime and components.
9
+ - `@weft-js/core/internal`: Compiler and renderer contract; shares the runtime graph, not an app API.
10
+ - `@weft-js/core/keyed`: Keyed state helpers.
11
+ - `@weft-js/core/jsx-runtime`: JSX types for compiler output; types only.
12
+ - `@weft-js/core/dom`: Browser DOM rendering and hydration; other helpers serve compiler output.
13
+ - `@weft-js/core/ssr`: Server rendering and compiler helpers.
14
+ - `@weft-js/core/head`: Browser route metadata updates.
15
+ - `@weft-js/core/test`: Test utilities; requires the test peers.
16
+ - `@weft-js/core/test/plugins`: Plugin conformance test suites; browser layout tests need a browser.
17
+ - `@weft-js/core/persist`: State persistence.
18
+ - `@weft-js/core/history`: State history.
19
+ - `@weft-js/core/sync`: State synchronization.
20
+ - `@weft-js/core/interaction`: Interaction state.
21
+ - `@weft-js/core/browser`: Browser APIs and browser state.
22
+ - `@weft-js/core/style`: Style groups and styling helpers.
23
+ - `@weft-js/core/ds`: Design system primitives.
24
+ - `@weft-js/core/media`: Media components and helpers.
25
+ - `@weft-js/core/shape`: Shape components and helpers.
26
+ - `@weft-js/core/text`: Text components and helpers.
27
+ - `@weft-js/core/surface`: Surface components and helpers.
28
+ - `@weft-js/core/media-probe`: Media probing for tooling; Node entry.
29
+ - `@weft-js/core/client`: Client type declarations only; no runtime condition.
30
+ - `@weft-js/core/style/matrix`: Style matrix tooling; Node entry.
31
+ - `@weft-js/core/hydration`: Hydration tooling; Node entry.
32
+ - `@weft-js/core/markup`: Shared markup helpers and types.
33
+ - `@weft-js/core/node-purge`: Node cache purge tooling.
34
+ - `@weft-js/core/hmr`: Compiler-generated development hot updates.
35
+ - `@weft-js/core/plugin`: Plugin declarations and runtime helpers.
36
+ - `@weft-js/core/devtools`: Development tools.
37
+ - `@weft-js/core/agent`: In-page development agent; requires testing peers.
38
+ - `@weft-js/core/config`: Configuration declarations and runtime helpers.
39
+ - `@weft-js/core/vite`: Vite plugin; Node tooling.
40
+ - `@weft-js/core/compiler`: Compiler binding; Node tooling and native or WASM compiler.
41
+
42
+ ## @weft-js/start
43
+
44
+ - `@weft-js/start`: Application server functions, forms and routing APIs.
45
+ - `@weft-js/start/data`: Server function and data primitives.
46
+ - `@weft-js/start/derive`: Server-side page metadata derivation.
47
+ - `@weft-js/start/media`: Media schema and asset types.
48
+ - `@weft-js/start/hub`: Realtime hub and topics; server.
49
+ - `@weft-js/start/live`: Streams and live queries.
50
+ - `@weft-js/start/bus`: Realtime bus interfaces.
51
+ - `@weft-js/start/changes`: Database change feeds; server.
52
+ - `@weft-js/start/changes-sql`: SQL for database change triggers; server tooling.
53
+ - `@weft-js/start/live-target`: Live target capability checks; Node tooling.
54
+ - `@weft-js/start/listen`: Database change listener; server.
55
+ - `@weft-js/start/verify`: Live verification; server tooling.
56
+ - `@weft-js/start/bus/postgres`: Postgres realtime bus; server, requires Postgres.
57
+ - `@weft-js/start/list`: List queries and helpers.
58
+ - `@weft-js/start/list/drizzle`: Drizzle list integration; requires Drizzle.
59
+ - `@weft-js/start/channel`: Realtime channels.
60
+ - `@weft-js/start/share`: Shared state.
61
+ - `@weft-js/start/db`: Drizzle schema helpers; requires Drizzle.
62
+ - `@weft-js/start/db/core`: Database interfaces and core helpers.
63
+ - `@weft-js/start/db/sqlite`: SQLite database adapter.
64
+ - `@weft-js/start/db/postgres`: Postgres database adapter; requires Postgres driver.
65
+ - `@weft-js/start/db/mysql`: MySQL database adapter; requires MySQL driver.
66
+ - `@weft-js/start/auth`: Authentication provider interface.
67
+ - `@weft-js/start/auth/better-auth`: Better Auth integration; requires Better Auth.
68
+ - `@weft-js/start/auth/drizzle`: Drizzle authentication integration; requires Drizzle.
69
+ - `@weft-js/start/extension`: Server extension contract.
70
+ - `@weft-js/start/client`: Client application bootstrap; browser.
71
+ - `@weft-js/start/server`: Server application rendering and request handling.
72
+ - `@weft-js/start/vite`: Start Vite plugin; Node tooling.
73
+ - `@weft-js/start/routes`: Route manifest tooling.
74
+ - `@weft-js/start/og`: Open Graph image tooling; server.
75
+ - `@weft-js/start/app`: Development and build application tooling; Node.
76
+ - `@weft-js/start/inspect`: Route metadata inspection; Node tooling.
77
+ - `@weft-js/start/contract`: Server function contract generation; Node tooling.
78
+ - `@weft-js/start/rust`: Rust remote function support.
79
+ - `@weft-js/start/sidecar`: Rust sidecar supervisor; Node tooling.
package/docs/fonts.md CHANGED
@@ -10,8 +10,18 @@ export default defineConfig({
10
10
  plugins: [
11
11
  text({
12
12
  fonts: {
13
- body: { family: 'Inter', src: 'assets/fonts/inter.woff2', fallback: 'Arial', axes: { wght: [100, 900] } },
14
- display: { family: 'Fraunces', src: 'assets/fonts/fraunces.woff2', fallback: 'Georgia', weight: 700 },
13
+ body: {
14
+ family: 'Inter',
15
+ src: 'assets/fonts/inter.woff2',
16
+ fallback: 'Arial',
17
+ axes: { wght: [100, 900] },
18
+ },
19
+ display: {
20
+ family: 'Fraunces',
21
+ src: 'assets/fonts/fraunces.woff2',
22
+ fallback: 'Georgia',
23
+ weight: 700,
24
+ },
15
25
  },
16
26
  }),
17
27
  ],
package/docs/icons.md CHANGED
@@ -12,20 +12,24 @@ Three forms, and all three build to the same bytes:
12
12
  import { CheckIcon } from '@weft-js/warp-icons'
13
13
  <CheckIcon />
14
14
 
15
- import Icons from '@weft-js/warp-icons' // or: import * as Icons
15
+ // Or: import * as Icons
16
+ import Icons from '@weft-js/warp-icons'
16
17
  <Icons.Check />
17
18
 
18
- import { Icon } from '@weft-js/warp' // or: '@weft-js/warp-icons/icon'
19
+ // Or import from '@weft-js/warp-icons/icon'.
20
+ import { Icon } from '@weft-js/warp'
19
21
  <Icon name="check" />
20
22
  ```
21
23
 
22
24
  Props on any of them:
23
25
 
24
26
  ```tsx
25
- <CheckIcon /> // decorative: aria-hidden, focusable="false"
27
+ // Decorative: aria-hidden, focusable="false"
28
+ <CheckIcon />
26
29
  <CheckIcon label="Saved" /> // role="img" with that name
27
30
  <CheckIcon size={24} /> // otherwise warp's icon sizes apply
28
- <CheckIcon tier="vivid" /> // this tier whatever the page's expression is
31
+ // This tier regardless of the page's expression.
32
+ <CheckIcon tier="vivid" />
29
33
  ```
30
34
 
31
35
  An icon you don't use costs nothing. One adds about 164 B of brotli with all tiers in. `sideEffects` lists only CSS, so a named import ships that icon.
@@ -41,7 +45,7 @@ One scheme, generated from the art with its types:
41
45
  | `BellIconSolid` | `Icons.BellSolid` | `solid` | the solid form |
42
46
  | `BellIconAction` | `Icons.BellAction` | `action` | has a built-in animation |
43
47
 
44
- The tier is a prop, never a name. An open mark, like an arrow, has a notched badge as its solid, with the mark cut out. Pick it on the sheet: `npm run sheet` in the package writes `contact-sheet.html`, with tier, variant, size, theme and search. `dither-sheet.html` compares the treatments.
48
+ The tier is a prop, never a name. Hollow and solid describe the object: an open mark like an arrow is an outlined arrow in hollow and a filled one in solid, never a badge. Pick it on the sheet: `npm run sheet` in the package writes `contact-sheet.html`, with tier, variant, size, theme and search. `dither-sheet.html` compares the treatments.
45
49
 
46
50
  ## A wrong name
47
51
 
@@ -69,9 +73,11 @@ A remote icon renders an empty `<svg data-icon data-loading>` of the right size
69
73
  Five icons have a built-in animation: `trash` (the lid lifts), `bell` (it rings), `check` (it draws on), `refresh` (it spins), `copy` (the sheet stacks).
70
74
 
71
75
  ```tsx
72
- <Icon name="trash" action /> // hover, focus and press, on the icon or its parent
76
+ // Hover, focus and press on the icon or its parent.
77
+ <Icon name="trash" action />
73
78
  <Icon name="refresh" action="on" /> // now; refresh keeps spinning
74
- <TrashIconAction action="press" /> // 'hover' | 'focus' | 'press' | 'on'
79
+ // 'hover' | 'focus' | 'press' | 'on'
80
+ <TrashIconAction action="press" />
75
81
  ```
76
82
 
77
83
  It's CSS alone, and each one's stylesheet ships only if that icon is used (about 230 B of CSS and 50 B of JS, brotli). Outlines ease; pixels move in whole cells, in frames. warp's motion dial and `prefers-reduced-motion` turn it off. An action on another icon is I001.
package/docs/lists.md CHANGED
@@ -11,7 +11,9 @@
11
11
  every row re-runs on every change (1 DOM write, hundreds of re-runs). Replace only what changed:
12
12
 
13
13
  ```ts
14
- products.value = products.value.map(p => (p.id === id ? { ...p, price } : p))
14
+ products.value = products.value.map(p =>
15
+ p.id === id ? { ...p, price } : p,
16
+ )
15
17
  ```
16
18
 
17
19
  The compiler sees this inside one file; `weft check` follows the box through props into other files.
package/docs/meta.md CHANGED
@@ -11,7 +11,11 @@ on what the reader gets, from what is on the page:
11
11
  ```tsx
12
12
  import type { Meta } from '@weft-js/start'
13
13
 
14
- export const meta: Meta = { title: 'Pricing', description: 'Three plans, billed monthly, and what each one includes.' }
14
+ export const meta: Meta = {
15
+ title: 'Pricing',
16
+ description: 'Three plans, billed monthly, ' +
17
+ 'and what each one includes.',
18
+ }
15
19
  ```
16
20
 
17
21
  On a param route, build it from `data` and `params`, so each page says what it is:
@@ -22,8 +26,14 @@ On a param route, build it from `data` and `params`, so each page says what it i
22
26
  import { notFound, type LoadArgs, type Meta } from '@weft-js/start'
23
27
  import { getUser } from '#/server/users'
24
28
 
25
- export const load = async ({ params }: LoadArgs<'/users/[id]'>) => (await getUser.fetch({ id: params.id })) ?? notFound()
26
- export const meta: Meta<typeof load> = ({ data }) => ({ title: data.name, description: data.bio })
29
+ export const load = async ({ params }: LoadArgs<'/users/[id]'>) => {
30
+ const user = await getUser.fetch({ id: params.id })
31
+ return user ?? notFound()
32
+ }
33
+ export const meta: Meta<typeof load> = ({ data }) => ({
34
+ title: data.name,
35
+ description: data.bio,
36
+ })
27
37
  ```
28
38
 
29
39
  `meta` is plain data: it runs once per request after the loaders and before the first byte. It can't read a box (H006)
package/docs/plugins.md CHANGED
@@ -8,8 +8,8 @@ own diagnostics and `weft add` steps. It uses only what any plugin can use, and
8
8
 
9
9
  ```
10
10
  packages/pay/ packages/pay/ (`src/stripe.ts`)
11
- plugin.mjs the manifest plugin.mjs a `pay.rail` provider
12
- src/index.ts client-safe src/index.ts stripeRail(options)
11
+ plugin.mjs the manifest plugin.mjs `pay.rail` provider
12
+ src/index.ts client-safe src/index.ts stripeRail(options)
13
13
  src/server.ts the ledger
14
14
  src/test.ts fakePay, payRailSuite
15
15
  src/checks.mjs PAY-codes
@@ -24,8 +24,12 @@ A rail is how a payment happens. `fakePay` is a second rail, which is how you kn
24
24
 
25
25
  ```js
26
26
  export const pay = definePlugin({
27
- name: '@weft-js/pay', version: '0.1.0', weft: '*', namespace: 'PAY', permissions: {},
28
- contribute: () => ({ provides: [...], diagnostics, check, docs, setup, agents, catalog, map }),
27
+ name: '@weft-js/pay',
28
+ version: '0.1.0', weft: '*', namespace: 'PAY', permissions: {},
29
+ contribute: () => ({
30
+ provides: [...], diagnostics, check, docs, setup,
31
+ agents, catalog, map,
32
+ }),
29
33
  })
30
34
  ```
31
35
 
@@ -42,8 +46,18 @@ imports lazily, on that side only. That's why an app that doesn't use a plugin c
42
46
  Pay provides `server.extension`, the slot for anything that needs a server presence:
43
47
 
44
48
  ```js
45
- provide(defineSlot({ id: 'server.extension', version: 1, cardinality: 'keyed', sides: ['server'] }),
46
- { key: 'pay', sides: { server: { module: '@weft-js/pay/server', export: 'extension' } } })
49
+ provide(
50
+ defineSlot({
51
+ id: 'server.extension', version: 1,
52
+ cardinality: 'keyed', sides: ['server'],
53
+ }),
54
+ {
55
+ key: 'pay',
56
+ sides: { server: {
57
+ module: '@weft-js/pay/server', export: 'extension',
58
+ } },
59
+ },
60
+ )
47
61
  ```
48
62
 
49
63
  The key is the mount: `/_weft/x/pay/...`. A keyed provider also needs `src/<key>.server.ts`, the app's own configuration, and
@@ -82,7 +96,11 @@ and a good template for a provider.
82
96
  `diagnostics` declares each code: severity, what it catches, the fix. `check` finds them:
83
97
 
84
98
  ```js
85
- check: { include: ['src/**/*.{ts,tsx}'], run: ctx => import('./src/checks.mjs').then(c => c.run(ctx)) }
99
+ check: {
100
+ include: ['src/**/*.{ts,tsx}'],
101
+ run: ctx => import('./src/checks.mjs')
102
+ .then(c => c.run(ctx)),
103
+ }
86
104
  ```
87
105
 
88
106
  `run(ctx)` gets `files`, `read`, `exists`, `jsx`, `slots`, and returns findings: `{ code, file, start, end, why, help?, fix? }`.
@@ -108,9 +126,14 @@ sees what a user sees. It's imported from `@weft-js/pay/test`, since core can't
108
126
  ```js
109
127
  export const setup = {
110
128
  with: ['@weft-js/pay/stripe'], // added too
111
- needs: ['db', 'auth'], // refused, with nothing changed, until they're there
129
+ // Refused without changes until these are present.
130
+ needs: ['db', 'auth'],
112
131
  run({ engine, layer, read }) {
113
- return { files: {...}, edits: {...}, env: { STRIPE_SECRET_KEY: 'sk_test_placeholder' }, next: ['...'] }
132
+ return {
133
+ files: {...}, edits: {...},
134
+ env: { STRIPE_SECRET_KEY: 'sk_test_placeholder' },
135
+ next: ['...'],
136
+ }
114
137
  },
115
138
  }
116
139
  ```
package/docs/props.md CHANGED
@@ -7,10 +7,21 @@ Leave a component's props unannotated. weft infers them from its callers and its
7
7
 
8
8
  ```tsx
9
9
  function Row(props) {
10
- return <li><button type="button" onClick={props.onPick}>{props.label.toUpperCase()}</button></li>
10
+ const { label, onPick } = props
11
+ return (
12
+ <li>
13
+ <button type="button" onClick={onPick}>
14
+ {label.toUpperCase()}
15
+ </button>
16
+ </li>
17
+ )
11
18
  }
12
19
  export default function List() {
13
- return <ul><Row label="One" onPick={() => console.log('picked one')} /></ul>
20
+ return (
21
+ <ul>
22
+ <Row label="One" onPick={() => console.log('picked one')} />
23
+ </ul>
24
+ )
14
25
  }
15
26
  ```
16
27
 
@@ -0,0 +1,26 @@
1
+ # Reading reactive values
2
+
3
+ `state(initial)` returns a writable `State<T>`. Read or assign its `.value`.
4
+ `derived(fn)` returns a read-only `Derived<T>`. Read `.value` to evaluate it and
5
+ track its dependencies.
6
+
7
+ Use `memo(fn)` when a caller needs an accessor instead of a box:
8
+
9
+ ```ts
10
+ import { derived, memo, state } from '@weft-js/core'
11
+
12
+ const count = state(1)
13
+ const doubled = derived(() => count.value * 2)
14
+ const readDoubled = memo(() => count.value * 2)
15
+
16
+ console.log(doubled.value, readDoubled()) // 2, 2
17
+ ```
18
+
19
+ Both forms cache their result and refresh it when a dependency changes. `memo`
20
+ returns a function, so call it; it has no `.value` property. The compiler also uses
21
+ this accessor form to cache component children.
22
+
23
+ For side effects, `watch(source, callback)` tracks reads in `source`. Keep the
24
+ source pure and give reactive work an owner with a component or `createRoot`.
25
+ Graph tracking, mount queues and renderer helpers belong to
26
+ `@weft-js/core/internal`; application code uses the public lifecycle APIs.