create-pracht 0.6.3 → 0.7.1
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 +9 -7
- package/package.json +4 -1
- package/skills/add-auth/SKILL.md +173 -121
- package/skills/add-capabilities/SKILL.md +108 -96
- package/skills/add-observability/SKILL.md +12 -39
- package/skills/audit-agent-surface/SKILL.md +23 -17
- package/skills/audit-auth/SKILL.md +68 -12
- package/skills/audit-bundles/SKILL.md +11 -1
- package/skills/audit-shells/SKILL.md +12 -5
- package/skills/migrate-nextjs/SKILL.md +30 -10
- package/skills/pracht-debug/SKILL.md +17 -1
- package/skills/pracht-scaffold/SKILL.md +11 -1
- package/skills/pre-deploy/SKILL.md +15 -1
- package/skills/tune-render-mode/SKILL.md +36 -0
- package/skills/typed-routes/SKILL.md +3 -2
- package/skills/upgrade-pracht/SKILL.md +18 -8
- package/src/index.js +221 -59
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: audit-shells
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.3.0
|
|
4
4
|
description: |
|
|
5
5
|
Audit pracht shells: missing `Loading()` on SPA routes, `<html>`/`<head>`/
|
|
6
6
|
`<body>` rendered inside a shell, shells that never render `children`, unused
|
|
@@ -103,10 +103,17 @@ JSON first:
|
|
|
103
103
|
JSON has no shell registry of its own, so "unused" means "registered in
|
|
104
104
|
`defineApp` but referenced by no route or group".
|
|
105
105
|
- **Pages apps** (`mode: "pages"`): there is no `defineApp` shell registry.
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
Each `_app` file is auto-registered — `src/pages/_app.tsx` as `"pages"`,
|
|
107
|
+
`src/pages/blog/_app.tsx` as `"pages:blog"` — and owns the routes in its
|
|
108
|
+
directory subtree (see docs/ROUTING.md). Shells **replace**, they do not
|
|
109
|
+
nest: the nearest `_app` above a route is the only one that renders it, so a
|
|
110
|
+
directory shell must carry its own `head()`/`headers()` rather than inherit
|
|
111
|
+
the parent's. "Unused shells" analysis does not apply; instead check
|
|
112
|
+
`pracht inspect routes --json` and confirm each route's `shell` is the
|
|
113
|
+
nearest `_app` you expect, and that no directory you meant to scope is
|
|
114
|
+
silently falling back to `"pages"`. An `_app` inside an underscore-reserved
|
|
115
|
+
tree (`src/pages/_components/_app.tsx`) is a plain helper, and two `_app`
|
|
116
|
+
files in one directory are a build, `doctor`, and `verify` error.
|
|
110
117
|
|
|
111
118
|
Then report:
|
|
112
119
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: migrate-nextjs
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.7.0
|
|
4
4
|
description: |
|
|
5
5
|
Migrate a Next.js app to pracht: App or Pages Router pages, layouts, middleware,
|
|
6
6
|
API routes, data fetching, and metadata — plus React→Preact, `className`→`class`,
|
|
@@ -25,11 +25,8 @@ before converting it; never infer from the filename. Prefer the simplest
|
|
|
25
25
|
pracht equivalent, and when a Next.js feature has no equivalent, say so and
|
|
26
26
|
propose an alternative instead of inventing one.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
`
|
|
30
|
-
scaffold and `inspect_routes`/`inspect_api`/`doctor`/`verify` to check
|
|
31
|
-
progress, instead of Bash. `pracht inspect` needs the pracht plugin in the
|
|
32
|
-
vite config; `inspect_build` needs a prior `pracht build`.
|
|
28
|
+
With the Pracht MCP server, prefer its generate/inspect/doctor/verify tools;
|
|
29
|
+
`inspect_build` needs a prior `pracht build`.
|
|
33
30
|
|
|
34
31
|
## Step 0: Assess the source
|
|
35
32
|
|
|
@@ -40,6 +37,9 @@ the tree: `app/` (App Router), `pages/` (Pages Router), `middleware.ts`,
|
|
|
40
37
|
`"use server"` actions — and the third-party integrations (auth, CMS, DB,
|
|
41
38
|
analytics). Confirm scope with the user if the app has more than ~20 routes.
|
|
42
39
|
|
|
40
|
+
Agent tools alone do not require a router migration; use the standalone host:
|
|
41
|
+
<https://pracht.resynapse.dev/docs/standalone-capabilities>.
|
|
42
|
+
|
|
43
43
|
## Fast path: Pages Router
|
|
44
44
|
|
|
45
45
|
`pagesDir` makes a pages-router source near-drop-in — **Phase 7 is then
|
|
@@ -47,13 +47,25 @@ automatic**:
|
|
|
47
47
|
|
|
48
48
|
1. `pracht({ pagesDir: "/src/pages" })` in `vite.config.ts`; copy `pages/` to
|
|
49
49
|
`src/pages/`.
|
|
50
|
-
2. `_app.tsx` → pracht shell shape (`Shell` export taking `children`).
|
|
50
|
+
2. `_app.tsx` → pracht shell shape (`Shell` export taking `children`). A
|
|
51
|
+
subdirectory `_app` scopes a shell to that subtree (`blog/_app.tsx` →
|
|
52
|
+
`"pages:blog"`), where App Router `layout.tsx` lands — but shells replace
|
|
53
|
+
rather than nest, so it repeats the chrome, `head()`, and `headers()` it
|
|
54
|
+
needs.
|
|
51
55
|
3. `getServerSideProps`/`getStaticProps` → `loader` export.
|
|
52
56
|
4. `export const RENDER_MODE = "ssg"` on static pages (`"ssr"` is the
|
|
53
57
|
default). For time-revalidated pages export `RENDER_MODE = "isg"` plus a
|
|
54
58
|
positive integer `REVALIDATE` in seconds; webhook policies require ejecting
|
|
55
59
|
to a manifest.
|
|
56
|
-
5.
|
|
60
|
+
5. `middleware.ts` → a root-level `src/pages/_middleware.ts` exporting a
|
|
61
|
+
`MiddlewareFn` (Phase 6). It runs on every page route; API routes are not
|
|
62
|
+
wrapped. Move `config.matcher` checks into the body and compare
|
|
63
|
+
`stripBase(url.pathname)`. A nested `_middleware`, a `_middleware/`
|
|
64
|
+
directory, and a missing export are build/doctor/verify errors.
|
|
65
|
+
6. Other `_`-prefixed files and directories are reserved: pracht ignores the
|
|
66
|
+
subtree. Capabilities live in `src/capabilities/` (auto-discovered,
|
|
67
|
+
self-named); `agents` / `constraints` in `src/pages/_app.config.ts`.
|
|
68
|
+
7. Run the dev server, iterate, and optionally eject later with
|
|
57
69
|
`generateRoutesFile`.
|
|
58
70
|
|
|
59
71
|
## Concept mapping
|
|
@@ -62,11 +74,11 @@ automatic**:
|
|
|
62
74
|
| ------------------------------- | --------------------------------------------------------------- | --------------------------------------------------------------------- |
|
|
63
75
|
| `pages/` directory | `pagesDir` plugin option | Auto-discovers routes from the file system |
|
|
64
76
|
| `app/page.tsx` | `src/routes/*.tsx` + `route()` in manifest | File is a module; wiring is explicit |
|
|
65
|
-
| `app/layout.tsx` | `src/shells/*.tsx` + `shells` in `defineApp`
|
|
77
|
+
| `app/layout.tsx` | `src/shells/*.tsx` + `shells` in `defineApp` (pages: `_app.tsx` per directory) | Named shells; a directory `_app` replaces its parent instead of nesting |
|
|
66
78
|
| `app/loading.tsx` | `Loading` export on the shell | SSR placeholder for SPA routes until the client router takes over |
|
|
67
79
|
| `app/error.tsx` | `ErrorBoundary` export in route module | Same concept, different wiring |
|
|
68
80
|
| `app/not-found.tsx` | `notFound:` in `defineApp` (or `pages/404.tsx` in pagesDir mode) | Not a route — never matches a URL, so it cannot shadow static assets |
|
|
69
|
-
| `middleware.ts` | `src/middleware/*.ts` + `middleware` in `defineApp`
|
|
81
|
+
| `middleware.ts` | `src/middleware/*.ts` + `middleware` in `defineApp` (or `src/pages/_middleware.ts` in pagesDir mode) | Named, applied per route/group; the pages-mode file runs on every page route |
|
|
70
82
|
| `app/api/*/route.ts` | `src/api/*.ts` with `GET`/`POST` exports | Auto-discovered, no manifest entry |
|
|
71
83
|
| `generateStaticParams` | `getStaticPaths()` export | Returns `RouteParams[]` of param objects |
|
|
72
84
|
| `generateMetadata` | `head()` export | Returns `{ title, meta }` |
|
|
@@ -204,6 +216,14 @@ export const middleware: MiddlewareFn = async ({ request }, next) => {
|
|
|
204
216
|
is wrap-around (Hono/Koa/Astro shape), so you can `await next()` and observe
|
|
205
217
|
the response — useful for tracing.
|
|
206
218
|
|
|
219
|
+
In `pagesDir` mode the same `MiddlewareFn` goes in a root-level
|
|
220
|
+
`src/pages/_middleware.ts`, applied to every page route (API routes stay
|
|
221
|
+
unwrapped). Do not migrate a per-request auth matcher onto an `ssg`/`isg` page
|
|
222
|
+
and call it protected: that document runs middleware only at
|
|
223
|
+
build/revalidation, with a sanitized request. Keep such pages `ssr`/`spa`, or
|
|
224
|
+
keep a separately verified edge gate. Pure static exports have no request
|
|
225
|
+
runtime.
|
|
226
|
+
|
|
207
227
|
## Phase 7: Route manifest
|
|
208
228
|
|
|
209
229
|
Skip this phase for `pagesDir` projects. Prefer
|
|
@@ -36,6 +36,7 @@ Reach for these before deep manual inspection:
|
|
|
36
36
|
| `pracht inspect routes\|api\|build --json` | The resolved graph — never reconstruct it from source |
|
|
37
37
|
| `GET /_pracht` (JSON at `/_pracht.json`) | Same graph from a running dev server, no CLI needed |
|
|
38
38
|
| `Server-Timing` on dev SSR responses | `mw` / `loader` / `render` durations in ms — which phase is slow |
|
|
39
|
+
| `pracht_*` WebMCP page tools in the open tab | Tab-scoped view from an agent-driven browser: `pracht_route`, `pracht_loader_data`, `pracht_islands`, `pracht_last_error`, `pracht_page_tools` |
|
|
39
40
|
|
|
40
41
|
`pracht inspect` needs the pracht plugin in the vite config; `inspect build`
|
|
41
42
|
needs a prior `pracht build`. Under a Vite deploy base, prefix `/_pracht` with
|
|
@@ -44,6 +45,18 @@ pracht MCP server is registered (docs/MCP.md), prefer the
|
|
|
44
45
|
`inspect_routes`/`inspect_api`/`doctor`/`verify` MCP tools — same payloads,
|
|
45
46
|
structured results.
|
|
46
47
|
|
|
48
|
+
When you are driving a browser against `pracht dev` with a WebMCP-compatible
|
|
49
|
+
test harness or host, ask the tab before reading logs: every dev document registers read-only
|
|
50
|
+
`pracht_*` page tools with `document.modelContext`. `pracht_route` gives the
|
|
51
|
+
matched route, files, render/hydration mode, and middleware; `pracht_loader_data`
|
|
52
|
+
the data the page holds now (`{ path: "a.0.b" }` narrows it; islands/none routes
|
|
53
|
+
answer with the route-state request to make instead); `pracht_islands` each
|
|
54
|
+
island's file, strategy, props, and hydration status; `pracht_last_error` the
|
|
55
|
+
structured server error behind an overlay or `ErrorBoundary` plus recent client
|
|
56
|
+
errors; `pracht_page_tools` the app's active WebMCP tools on the route. All
|
|
57
|
+
resolve to `{ ok, data }` / `{ ok: false, error }` envelopes and follow client
|
|
58
|
+
navigation.
|
|
59
|
+
|
|
47
60
|
## Checklist
|
|
48
61
|
|
|
49
62
|
Work in order; stop at the root cause.
|
|
@@ -94,7 +107,10 @@ Work in order; stop at the root cause.
|
|
|
94
107
|
component (via Preact's `options.__m` hook). Compare server HTML against
|
|
95
108
|
client output. Usual causes: date/time differences, browser-only APIs during
|
|
96
109
|
SSR (`window`, `document`, `localStorage`), conditional rendering on client
|
|
97
|
-
state — or
|
|
110
|
+
state — or, on Preact 10, a suspending boundary resolving to zero or multiple
|
|
111
|
+
DOM nodes. Preact 11 supports those boundary shapes, so Pracht skips that
|
|
112
|
+
legacy diagnostic there. Another cause is two copies of `@pracht/core` in
|
|
113
|
+
the SSR module graph. The tell for
|
|
98
114
|
that last one: in the server-rendered HTML of *every* page, `useLocation()`
|
|
99
115
|
returns `/`, `useParams()` returns `{}`, and `useRouteData()` returns
|
|
100
116
|
`undefined`, while the hydrated client is correct — provider and hooks hold
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pracht-scaffold
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.4.0
|
|
4
4
|
description: |
|
|
5
5
|
Scaffold pracht code with the native generators (`pracht generate
|
|
6
6
|
route|shell|middleware|api`), falling back to manual edits only when the CLI
|
|
@@ -57,6 +57,16 @@ agent or tool consumes the output. When the pracht MCP server is registered
|
|
|
57
57
|
|
|
58
58
|
- `--shell`/`--middleware` names must already be registered or the CLI errors.
|
|
59
59
|
Generate the shell or middleware first, then the route referencing it.
|
|
60
|
+
- Pages-router apps have one middleware seam: `pracht generate middleware
|
|
61
|
+
--name _middleware` scaffolds the root `src/pages/_middleware.ts`, which runs
|
|
62
|
+
on every page route (API routes are not wrapped). Other names error in pages
|
|
63
|
+
mode, pure static exports cannot use request middleware, and `generate shell`
|
|
64
|
+
stays manifest-only — pages apps add an `_app.tsx` to the directory they want
|
|
65
|
+
it to wrap (`src/pages/blog/_app.tsx` registers `pages:blog`).
|
|
66
|
+
- `generate capability` works in both modes. Manifest apps get a `capabilities`
|
|
67
|
+
registry entry; pages apps auto-discover `src/capabilities/`, so the module
|
|
68
|
+
declares its own `name` and no manifest is written. Pages `agents` and
|
|
69
|
+
`constraints` are named exports in `src/pages/_app.config.ts`.
|
|
60
70
|
- `generate route` also emits a Playwright smoke test in `e2e/` when the app
|
|
61
71
|
has a Playwright setup (`playwright.config.*` or an `e2e/` directory);
|
|
62
72
|
`--no-test` skips it, `--test` forces it. The test imports
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pre-deploy
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.5.0
|
|
4
4
|
description: |
|
|
5
5
|
Adapter-aware pre-deployment checklist (Node, Cloudflare Workers, Vercel, static)
|
|
6
6
|
for the failures that only surface in production: missing env vars, Node-only
|
|
@@ -55,6 +55,20 @@ reports errors, stop here**; the remaining checks will be noisy false
|
|
|
55
55
|
positives. Stale generated typed-route files block deployment; if the app does
|
|
56
56
|
not use them yet, note that `typegen --check` is optional.
|
|
57
57
|
|
|
58
|
+
If `pracht inspect agents --json` reports any WebMCP exposure, run the live
|
|
59
|
+
browser boundary too. Point it at the already-started preview, or let it own the
|
|
60
|
+
server lifecycle:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pracht verify webmcp --start "pracht preview" --json
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
CI must install a pinned Chrome 150+ build and pass its executable with
|
|
67
|
+
`--browser`; the verifier never silently downloads one. Treat unsupported API,
|
|
68
|
+
startup/registration failure, and graph drift as deployment errors. Do not add
|
|
69
|
+
`--scenario` unless the repository already supplies an explicitly safe WebMCP
|
|
70
|
+
eval scenario.
|
|
71
|
+
|
|
58
72
|
For a PR deploy, `pracht report --base origin/main` produces a markdown summary
|
|
59
73
|
(graph diff + verify + budgets) worth attaching.
|
|
60
74
|
|
|
@@ -127,6 +127,42 @@ field (absent from the JSON), grep the manifest for `hydration:` (pages apps:
|
|
|
127
127
|
router), island props must be JSON-serializable, and `render: "spa"` cannot
|
|
128
128
|
combine with `"islands"`/`"none"`.
|
|
129
129
|
|
|
130
|
+
## Step 3c: Consider streaming for slow SSR routes
|
|
131
|
+
|
|
132
|
+
An `ssr` route whose loader has one slow call and several fast ones is a
|
|
133
|
+
candidate for `defer()` plus `streaming: true`. Flag it when the loader awaits
|
|
134
|
+
more than one independent source and at least one is materially slower — the
|
|
135
|
+
whole document currently waits on the slowest.
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// before: TTFB waits on getReviews()
|
|
139
|
+
return { product: await getProduct(id), reviews: await getReviews(id) };
|
|
140
|
+
|
|
141
|
+
// after: shell flushes without reviews, which stream in
|
|
142
|
+
return { product: await getProduct(id), reviews: defer(getReviews(id)) };
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Pages routes use `export const STREAMING = true` with SSR and full hydration.
|
|
146
|
+
|
|
147
|
+
Recommend `streaming: true` only alongside a `<Suspense>` boundary reading the
|
|
148
|
+
deferred value with `use()`; without a boundary there is nothing to flush
|
|
149
|
+
early. Do not recommend it for:
|
|
150
|
+
|
|
151
|
+
- `ssg` / `isg` routes — they write files and the manifest rejects the
|
|
152
|
+
combination
|
|
153
|
+
- routes with `hydration` other than `"full"` — no client runtime resumes a
|
|
154
|
+
boundary, and the manifest rejects it
|
|
155
|
+
- routes whose loader is a single slow call with nothing else to show — the
|
|
156
|
+
shell would be empty and the user sees a skeleton rather than content
|
|
157
|
+
|
|
158
|
+
Also mention the tradeoffs when proposing it: a deferred rejection surfaces at
|
|
159
|
+
the read site rather than as an error document (the response is already
|
|
160
|
+
committed at `200`), and streaming needs a `script-src` that allows the
|
|
161
|
+
renderer's inline bootstrap script. Route `head()` and `headers()` hooks run
|
|
162
|
+
before deferred work settles, so any data they need must stay awaited. Confirm
|
|
163
|
+
the app uses
|
|
164
|
+
`preact-render-to-string` 6.7 or newer before enabling streaming.
|
|
165
|
+
|
|
130
166
|
## Step 4: Propose diffs, then apply on confirmation
|
|
131
167
|
|
|
132
168
|
Present the exact edits and wait for approval. Where the edit lands depends
|
|
@@ -145,8 +145,9 @@ export function Component() {
|
|
|
145
145
|
|
|
146
146
|
Prefer this over `useRouteData<typeof loader>()` when typegen runs; keep the
|
|
147
147
|
generic form for projects that do not generate route types. Routes without a
|
|
148
|
-
loader type their data as `undefined`. The id must be the active route
|
|
149
|
-
|
|
148
|
+
loader type their data as `undefined`. The id must be the active route: a
|
|
149
|
+
mismatch throws (with a descriptive message in dev), so a shell or island that
|
|
150
|
+
needs another route's data must receive it as props instead.
|
|
150
151
|
|
|
151
152
|
### API routes
|
|
152
153
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: upgrade-pracht
|
|
3
|
-
version: 1.0
|
|
3
|
+
version: 1.1.0
|
|
4
4
|
description: |
|
|
5
5
|
Upgrade the `@pracht/*` packages safely: inventory installed versions, read the
|
|
6
6
|
changelogs between installed and target, map breaking changes to real usage,
|
|
@@ -30,11 +30,15 @@ List every installed pracht package and its resolved version:
|
|
|
30
30
|
pnpm list --depth 1 --json | grep -A2 '@pracht/' # or read package.json + lockfile
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
The family: `@pracht/core`, `@pracht/cli`, `@pracht/vite-plugin`,
|
|
34
|
-
`@pracht/adapter-node`, `@pracht/adapter-cloudflare`,
|
|
35
|
-
`@pracht/
|
|
36
|
-
`@pracht/
|
|
37
|
-
|
|
33
|
+
The family, in full: `@pracht/core`, `@pracht/cli`, `@pracht/vite-plugin`,
|
|
34
|
+
`@pracht/adapter-node`, `@pracht/adapter-cloudflare`,
|
|
35
|
+
`@pracht/adapter-netlify`, `@pracht/adapter-vercel`,
|
|
36
|
+
`@pracht/adapter-static`, `@pracht/preact-ssr-precompile`,
|
|
37
|
+
`@pracht/capabilities`, `@pracht/content`, `@pracht/markdown`,
|
|
38
|
+
`@pracht/openapi`, `@pracht/image`, `@pracht/i18n`, `@pracht/session`,
|
|
39
|
+
`@pracht/test`, plus the `create-pracht` scaffolder (which is not a runtime
|
|
40
|
+
dependency and does not need to move with the rest). Get the latest published
|
|
41
|
+
versions with `npm view <pkg> version`.
|
|
38
42
|
|
|
39
43
|
## Step 2: Understand the versioning model
|
|
40
44
|
|
|
@@ -73,11 +77,17 @@ https://raw.githubusercontent.com/JoviDeCroock/pracht/main/packages/<dir>/CHANGE
|
|
|
73
77
|
| `@pracht/core` | `packages/framework` |
|
|
74
78
|
| `@pracht/cli` | `packages/cli` |
|
|
75
79
|
| `@pracht/vite-plugin` | `packages/vite-plugin` |
|
|
76
|
-
| `@pracht/adapter-node` / `-cloudflare` / `-vercel` | `packages/adapter-*` |
|
|
80
|
+
| `@pracht/adapter-node` / `-cloudflare` / `-netlify` / `-vercel` / `-static` | `packages/adapter-*` |
|
|
77
81
|
| `@pracht/preact-ssr-precompile` | `packages/preact-ssr-precompile` |
|
|
82
|
+
| `@pracht/capabilities` | `packages/capabilities` |
|
|
78
83
|
| `@pracht/content` | `packages/content` |
|
|
79
84
|
| `@pracht/markdown` | `packages/markdown` |
|
|
85
|
+
| `@pracht/openapi` | `packages/openapi` |
|
|
80
86
|
| `@pracht/image` | `packages/image` |
|
|
87
|
+
| `@pracht/i18n` | `packages/i18n` |
|
|
88
|
+
| `@pracht/session` | `packages/session` |
|
|
89
|
+
| `@pracht/test` | `packages/test` |
|
|
90
|
+
| `create-pracht` | `packages/start` |
|
|
81
91
|
|
|
82
92
|
Changelogs are changesets-generated: `## X.Y.Z` sections containing
|
|
83
93
|
`### Major Changes` / `### Minor Changes` / `### Patch Changes`. Read every
|
|
@@ -92,7 +102,7 @@ changelog prescribes, and whether it can be applied mechanically. Also
|
|
|
92
102
|
re-check peer ranges after a major target bump — `@pracht/vite-plugin`
|
|
93
103
|
requires `vite` (^8), `@pracht/adapter-cloudflare` requires `vite` and
|
|
94
104
|
`wrangler` (^4.81), `@pracht/core` requires `preact` (^10) and
|
|
95
|
-
`preact-render-to-string` (^6).
|
|
105
|
+
`preact-render-to-string` (^6.7).
|
|
96
106
|
|
|
97
107
|
Present the plan as a table:
|
|
98
108
|
|