@weft-js/cli 0.1.1 → 0.1.2
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 +38 -14
- 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/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @weft-js/cli
|
|
2
2
|
|
|
3
|
-
> **Early release (0.1.
|
|
3
|
+
> **Early release (0.1.x).** APIs can change between minor versions.
|
|
4
4
|
|
|
5
|
-
The `weft` command. It runs an app (`dev`, `build`, `start`), checks it (`check`, `tsc`, `fix`),
|
|
6
|
-
and agents (`docs`, `agents-md`, `mcp`) and manages plugins (`add`, `plugins`). An app made with `npm create @weft-js`
|
|
5
|
+
The `weft` command. It runs an app (`dev`, `build`, `start`), checks it (`check`, `tsc`, `fix`, `audit`), ships it
|
|
6
|
+
(`deploy`), serves its docs to people and agents (`docs`, `agents-md`, `mcp`) and manages plugins (`add`, `plugins`). An app made with `npm create @weft-js`
|
|
7
7
|
already has it.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
@@ -25,22 +25,28 @@ files, errors and warnings.
|
|
|
25
25
|
| `fix [files…]` | Applies the safe autofixes |
|
|
26
26
|
| `doctor` | Which compiler this install uses, whether Rust is around (it's optional), and what live data does on the target |
|
|
27
27
|
| `dev [--port <n>]` | The dev server, for an app with `src/routes` |
|
|
28
|
-
| `build [--runtime node\|bun\|deno] [--preset <p>]` | The production build, into `.output
|
|
28
|
+
| `build [--runtime node\|bun\|deno] [--preset <p>]` | The production build, into `.output/`. The built pages are then audited (L-codes), and an error fails the build |
|
|
29
29
|
| `start [--runtime <r>]` | Runs the build |
|
|
30
|
+
| `audit [routes…] [--url <u>]` | The built pages, or a running site, in a clean Chrome at phone and desktop widths: axe-core's WCAG rules, console errors, the head, sideways scroll and layout shift |
|
|
31
|
+
| `deploy hosts` | Which hosts can run this app, why not, what each costs, and the one Weft suggests |
|
|
32
|
+
| `deploy init [target]` | The host's files (`netlify.toml`, `fly.toml` and a Dockerfile…) and a GitHub workflow that checks and deploys on push |
|
|
33
|
+
| `deploy [--prod] [--yes]` | Checks the fit, builds for the target and runs the host's own CLI: Netlify, Vercel, Cloudflare, Fly or Render. Without `--yes` it's a dry run |
|
|
30
34
|
| `db generate [name]`, `db live`, `db listen` | A migration for schema changes; one with change triggers; the change feed as its own process |
|
|
31
35
|
| `routes [--meta]` | The route table; `--meta` adds each route's metadata and H-diagnostics |
|
|
36
|
+
| `surfaces` | The canvas and WebGL surfaces the project already defines |
|
|
32
37
|
| `test --gate` | The test gate on the diff: fail-before, mutants on changed lines and no weakened tests |
|
|
33
38
|
| `browser <cmd>` | Drives the running app: open, snapshot, act, assert and more (`weft browser help`) |
|
|
34
39
|
| `docs [topic\|code]` | Prints a docs page or a diagnostic (`weft docs props`, `weft docs W014`) |
|
|
35
|
-
| `agents-md [--check]` | Writes AGENTS.md from the installed
|
|
40
|
+
| `agents-md [--check]` | Writes AGENTS.md from the installed Weft; `--check` exits 1 when it's stale |
|
|
36
41
|
| `map [--stdout]` | Writes `.weft/map.md`: what to call in this app |
|
|
42
|
+
| `icons publish <dir>` | Every icon and variant as static `.svg` files with a `manifest.json`, for a CDN |
|
|
37
43
|
| `tasks`, `run <task>` | Lists commands and project tasks; runs a task from `weft.config.ts` |
|
|
38
44
|
| `add <feature>` | Installs a plugin and wires it into the config; also `tailwind`, `auth`, `db` and `rust` |
|
|
39
45
|
| `plugins [list\|explain\|sync\|audit\|approve]` | Plugins, their slots and permissions |
|
|
40
46
|
| `style find\|explain\|matrix` | Style groups |
|
|
41
|
-
| `tokens` |
|
|
47
|
+
| `tokens` | Warp's resolved tokens as DTCG, in `.weft/tokens/` |
|
|
42
48
|
| `lsp` | A language server for editors, with inferred props |
|
|
43
|
-
| `mcp` |
|
|
49
|
+
| `mcp` | An MCP server on stdio: `docs`, `check`, `audit`, `routes_meta`, `map`, `tasks`, `surfaces`, `style_find`, `style_explain`, `test_gate` and the `browser_*` tools |
|
|
44
50
|
|
|
45
51
|
Every command takes `--root <dir>` (the working directory by default) and `--json`. JSON goes to stdout and text for
|
|
46
52
|
people to stderr. Exit codes: 0 ok, 1 errors found (or a stale AGENTS.md under `--check`), 2 a usage or internal error.
|
|
@@ -48,8 +54,9 @@ people to stderr. Exit codes: 0 ok, 1 errors found (or a stale AGENTS.md under `
|
|
|
48
54
|
## Docs
|
|
49
55
|
|
|
50
56
|
- `weft docs config`: `weft.config.ts` and every key in it.
|
|
51
|
-
- `weft docs diagnostics`: every code, and which ones the installed
|
|
57
|
+
- `weft docs diagnostics`: every code, and which ones the installed Weft reports.
|
|
52
58
|
- `weft docs verify`: `weft browser` and the test gate.
|
|
59
|
+
- `weft docs deploy`: hosts, `weft deploy` and the E-codes.
|
|
53
60
|
- `weft docs plugins`: writing a plugin.
|
|
54
61
|
|
|
55
62
|
The source of each page is in [docs/](docs). Adding a diagnostic is in [CONTRIBUTING.md](../../CONTRIBUTING.md).
|
|
@@ -59,13 +66,23 @@ The source of each page is in [docs/](docs). Adding a diagnostic is in [CONTRIBU
|
|
|
59
66
|
`check`, `tasks` and the MCP tools report the same shape:
|
|
60
67
|
|
|
61
68
|
```json
|
|
62
|
-
{
|
|
63
|
-
"
|
|
64
|
-
"
|
|
65
|
-
"
|
|
69
|
+
{
|
|
70
|
+
"code": "W014",
|
|
71
|
+
"severity": "error",
|
|
72
|
+
"owner": "core",
|
|
73
|
+
"file": "src/App.tsx",
|
|
74
|
+
"span": [21, 44, 21, 117],
|
|
75
|
+
"offset": [867, 940],
|
|
76
|
+
"why": "Copying every item gives each a new identity.",
|
|
77
|
+
"fix": { "text": "Keep unchanged items stable." },
|
|
66
78
|
"project": true,
|
|
67
|
-
"related": [{
|
|
68
|
-
|
|
79
|
+
"related": [{
|
|
80
|
+
"file": "src/components/ProductList.tsx",
|
|
81
|
+
"span": [29, 10, 29, 10],
|
|
82
|
+
"why": "rendered here as a keyed list"
|
|
83
|
+
}],
|
|
84
|
+
"docs": "weft docs W014"
|
|
85
|
+
}
|
|
69
86
|
```
|
|
70
87
|
|
|
71
88
|
- `span` is 1-based `[line, col, endLine, endCol]`, with columns in UTF-16 units. `offset` is UTF-16 indices into the
|
|
@@ -73,3 +90,10 @@ The source of each page is in [docs/](docs). Adding a diagnostic is in [CONTRIBU
|
|
|
73
90
|
- `fix.edits` (`{ file, span, offset, text }`) is there when there's a mechanical change, and `fix.safe` says whether
|
|
74
91
|
`weft fix` applies it without asking.
|
|
75
92
|
- `project: true` marks a result that needed more than one file to find.
|
|
93
|
+
|
|
94
|
+
## Links
|
|
95
|
+
|
|
96
|
+
- [Source](https://github.com/Ravonus/weft/tree/main/packages/cli)
|
|
97
|
+
- [Weft on GitHub](https://github.com/Ravonus/weft): the framework, the docs and every package
|
|
98
|
+
- [Changelog](https://github.com/Ravonus/weft/blob/main/CHANGELOG.md)
|
|
99
|
+
- [Issues](https://github.com/Ravonus/weft/issues)
|
package/bin/weft.mjs
CHANGED
|
@@ -4,5 +4,12 @@ import { main } from '../src/cli.mjs'
|
|
|
4
4
|
// Not `exitCode`: an app's module can leave a pool open, and a finished command must still end.
|
|
5
5
|
const code = await main(process.argv.slice(2))
|
|
6
6
|
// A pipe holds about 64 KB: exiting first would cut off long --json output.
|
|
7
|
-
await Promise.all(
|
|
7
|
+
await Promise.all(
|
|
8
|
+
[process.stdout, process.stderr].map(
|
|
9
|
+
(out) =>
|
|
10
|
+
new Promise((done) => {
|
|
11
|
+
out.write('', done)
|
|
12
|
+
}),
|
|
13
|
+
),
|
|
14
|
+
)
|
|
8
15
|
process.exit(code)
|
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)
|