@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.
- package/README.md +534 -54
- package/bin/weft.mjs +8 -1
- package/docs/async.md +16 -6
- package/docs/browser.md +22 -8
- package/docs/config.md +39 -9
- package/docs/core.md +30 -0
- package/docs/deploy.md +33 -8
- package/docs/design.md +12 -3
- package/docs/entrypoints.md +79 -0
- package/docs/fonts.md +12 -2
- package/docs/icons.md +13 -7
- package/docs/lists.md +3 -1
- package/docs/meta.md +13 -3
- package/docs/plugins.md +32 -9
- package/docs/props.md +13 -2
- package/docs/reactivity.md +26 -0
- package/docs/rules.md +19 -12
- package/docs/rust.md +47 -17
- package/docs/start-short.md +3 -2
- package/docs/start.md +226 -52
- package/docs/state.md +33 -7
- package/docs/style.md +31 -8
- package/docs/surface.md +61 -15
- package/docs/testing.md +15 -5
- package/docs/theme.md +182 -0
- package/docs/ui-state.md +19 -6
- package/docs/verify.md +13 -0
- package/package.json +13 -4
- package/src/add/config.mjs +93 -0
- package/src/add/errors.mjs +2 -0
- package/src/add/setup.mjs +88 -0
- package/src/add-rust.mjs +82 -27
- package/src/add.mjs +209 -181
- package/src/agents-md.mjs +144 -43
- package/src/alias.mjs +16 -5
- package/src/audit/page.mjs +313 -0
- package/src/audit/report.mjs +69 -0
- package/src/audit/utils.mjs +5 -0
- package/src/audit.mjs +159 -206
- package/src/browser/cli.mjs +24 -5
- package/src/browser/client.mjs +189 -25
- package/src/browser/commands.mjs +166 -51
- package/src/catalog/audit.mjs +129 -0
- package/src/catalog/auth.mjs +40 -0
- package/src/catalog/compiler.mjs +337 -0
- package/src/catalog/contracts.mjs +18 -0
- package/src/catalog/database.mjs +52 -0
- package/src/catalog/deploy.mjs +117 -0
- package/src/catalog/design.mjs +159 -0
- package/src/catalog/forms.mjs +25 -0
- package/src/catalog/hydration.mjs +29 -0
- package/src/catalog/icons.mjs +24 -0
- package/src/catalog/media.mjs +163 -0
- package/src/catalog/metadata.mjs +116 -0
- package/src/catalog/plugins.mjs +228 -0
- package/src/catalog/realtime.mjs +195 -0
- package/src/catalog/rust.mjs +75 -0
- package/src/catalog/server-functions.mjs +92 -0
- package/src/catalog/state.mjs +39 -0
- package/src/catalog/style-groups.mjs +54 -0
- package/src/catalog/tests.mjs +127 -0
- package/src/catalog/text.mjs +200 -0
- package/src/catalog/ui-state.mjs +42 -0
- package/src/catalog.mjs +67 -460
- package/src/check/runtime.mjs +280 -0
- package/src/check.mjs +198 -208
- package/src/cli/authoring.mjs +213 -0
- package/src/cli/project.mjs +302 -0
- package/src/cli.mjs +222 -250
- package/src/config.mjs +1 -1
- package/src/contributions.mjs +75 -25
- package/src/db-layer.mjs +13 -5
- package/src/deploy/cdn.mjs +94 -16
- package/src/deploy/files.mjs +100 -21
- package/src/deploy/fit.mjs +127 -23
- package/src/deploy/hosts.mjs +90 -20
- package/src/deploy/index/cli.mjs +20 -0
- package/src/deploy/index/environment.mjs +69 -0
- package/src/deploy/index/steps.mjs +87 -0
- package/src/deploy/index.mjs +228 -114
- package/src/deploy/needs.mjs +88 -31
- package/src/design-checks/accessible-names.mjs +62 -0
- package/src/design-checks/contrast.mjs +43 -0
- package/src/design-checks/csp.mjs +60 -0
- package/src/design-checks/files.mjs +59 -0
- package/src/design-checks/heading-links.mjs +61 -0
- package/src/design-checks/interaction.mjs +65 -0
- package/src/design-checks/jsx.mjs +67 -0
- package/src/design-checks/layout-values.mjs +68 -0
- package/src/design-checks/native-controls.mjs +48 -0
- package/src/design-checks/outline.mjs +39 -0
- package/src/design-checks/reporter.mjs +37 -0
- package/src/design-checks/rules.mjs +274 -0
- package/src/design-checks/values.mjs +262 -0
- package/src/design-checks.mjs +10 -400
- package/src/diag.mjs +32 -8
- package/src/docs.mjs +138 -43
- package/src/doctor.mjs +20 -8
- package/src/files.mjs +18 -5
- package/src/fix.mjs +10 -2
- package/src/gate/after.mjs +40 -0
- package/src/gate/before.mjs +54 -0
- package/src/gate/classify.mjs +72 -0
- package/src/gate/mutation.mjs +209 -0
- package/src/gate/resolve-cases.mjs +22 -0
- package/src/gate/result.mjs +63 -0
- package/src/gate/run.mjs +75 -0
- package/src/gate.mjs +104 -202
- package/src/infer/box-props.cjs +140 -0
- package/src/infer/core-boxes.cjs +46 -0
- package/src/infer/derived-writes.cjs +95 -0
- package/src/infer/engine/checks.cjs +193 -0
- package/src/infer/engine/flow.cjs +293 -0
- package/src/infer/engine/report.cjs +158 -0
- package/src/infer/engine/utils.cjs +15 -0
- package/src/infer/engine.cjs +108 -368
- package/src/infer/facts/sites.cjs +114 -0
- package/src/infer/facts.cjs +210 -117
- package/src/infer/hosts.cjs +69 -22
- package/src/infer/lsp.mjs +149 -40
- package/src/infer/session.cjs +73 -17
- package/src/infer/shadow.cjs +13 -5
- package/src/infer/worker.cjs +57 -9
- package/src/jsx-scan.mjs +63 -21
- package/src/load-config/schema.mjs +281 -0
- package/src/load-config.mjs +137 -138
- package/src/map.mjs +93 -26
- package/src/mcp/browser-tools.mjs +155 -0
- package/src/mcp.mjs +147 -69
- package/src/meta-table.mjs +43 -8
- package/src/mutate.mjs +120 -36
- package/src/plugin-checks.mjs +52 -23
- package/src/plugins.mjs +125 -39
- package/src/project.mjs +170 -79
- package/src/props-checks.mjs +24 -6
- package/src/props-listener.mjs +27 -9
- package/src/react-checks.mjs +35 -4
- package/src/server-state-checks.mjs +34 -0
- package/src/share-checks.mjs +121 -37
- package/src/site.mjs +33 -6
- package/src/slots.mjs +104 -19
- package/src/start/build.mjs +116 -0
- package/src/start/routes.mjs +38 -0
- package/src/start.mjs +193 -95
- package/src/state-checks/core-state.mjs +223 -0
- package/src/state-checks/modules.mjs +17 -0
- package/src/state-checks/scan.mjs +232 -0
- package/src/state-checks/server-graph.mjs +65 -0
- package/src/state-checks.mjs +109 -133
- package/src/style/find.mjs +121 -0
- package/src/style.mjs +133 -127
- package/src/surface-checks.mjs +212 -46
- package/src/tailwind.mjs +5 -4
- package/src/tasks.mjs +189 -27
- package/src/test-rules/context.mjs +109 -0
- package/src/test-rules/file-rules.mjs +279 -0
- package/src/test-rules/rule-helpers.mjs +244 -0
- package/src/test-rules/syntax.mjs +223 -0
- package/src/test-rules/test-rules.mjs +127 -0
- package/src/testdiff.mjs +94 -32
- package/src/tests.mjs +31 -483
- package/src/text-checks.mjs +229 -69
- package/src/tokens.mjs +12 -4
- package/src/trust/scan.mjs +95 -0
- package/src/trust.mjs +214 -102
- package/src/weft.mjs +41 -9
- package/src/workspace.mjs +96 -19
- package/ts-plugin/context.js +57 -0
- package/ts-plugin/index.js +4 -124
- package/ts-plugin/mapping.js +65 -0
- 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
|
-
//
|
|
10
|
-
const user = resource(signal =>
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
//
|
|
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
|
|
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 {
|
|
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()
|
|
9
|
-
const shown = visible()
|
|
10
|
-
|
|
11
|
-
const
|
|
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 => {
|
|
15
|
-
|
|
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'}
|
|
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: {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
32
|
-
|
|
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
|
-
|
|
8
|
-
weft deploy
|
|
9
|
-
|
|
10
|
-
weft deploy
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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: {
|
|
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 {
|
|
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
|
|
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: {
|
|
14
|
-
|
|
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
|
-
|
|
15
|
+
// Or: import * as Icons
|
|
16
|
+
import Icons from '@weft-js/warp-icons'
|
|
16
17
|
<Icons.Check />
|
|
17
18
|
|
|
18
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 =>
|
|
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 = {
|
|
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]'>) =>
|
|
26
|
-
|
|
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
|
|
12
|
-
src/index.ts client-safe src/index.ts
|
|
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',
|
|
28
|
-
|
|
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(
|
|
46
|
-
{
|
|
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: {
|
|
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
|
-
|
|
129
|
+
// Refused without changes until these are present.
|
|
130
|
+
needs: ['db', 'auth'],
|
|
112
131
|
run({ engine, layer, read }) {
|
|
113
|
-
return {
|
|
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
|
-
|
|
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
|
|
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.
|