create-nowaki 0.14.0 → 0.15.0
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/index.js +3 -0
- package/package.json +1 -1
- package/templates/_shared/AGENTS.md +23 -3
- package/templates/_shared/README.md +2 -0
- package/templates/_shared/env.example +7 -0
- package/templates/_shared/package.json +2 -2
- package/templates/basics/actions/echo.ts +22 -0
- package/templates/basics/routes/_404.tsx +13 -0
- package/templates/basics/routes/api/health.ts +6 -0
package/index.js
CHANGED
|
@@ -141,6 +141,9 @@ await cp(path.join(templatesDir, template), dest, { recursive: true });
|
|
|
141
141
|
try {
|
|
142
142
|
await rename(path.join(dest, "_gitignore"), path.join(dest, ".gitignore"));
|
|
143
143
|
} catch {}
|
|
144
|
+
try {
|
|
145
|
+
await rename(path.join(dest, "env.example"), path.join(dest, ".env.example"));
|
|
146
|
+
} catch {}
|
|
144
147
|
|
|
145
148
|
try {
|
|
146
149
|
const pkgPath = path.join(dest, "package.json");
|
package/package.json
CHANGED
|
@@ -84,13 +84,22 @@ nowaki.config.mjs plugins (optional)
|
|
|
84
84
|
islands to cut work on first load. The directives are typed (no prop leaks).
|
|
85
85
|
7. **Server functions** — a module with a top-of-file `"use server"` directive
|
|
86
86
|
becomes RPC; the client gets a tiny fetch proxy, the implementation stays on
|
|
87
|
-
the server. Validate
|
|
87
|
+
the server. Validate the input with `serverFn(schema, impl)` (any Standard
|
|
88
|
+
Schema library: zod, valibot, arktype); `nowaki build` warns about exports that
|
|
89
|
+
take arguments without it. Read auth via `getContext()`, and throw
|
|
90
|
+
`ServerFnError` for messages the client may see (other errors are a generic
|
|
91
|
+
500 in production):
|
|
88
92
|
```ts
|
|
89
93
|
// actions/todos.ts
|
|
90
94
|
"use server";
|
|
91
|
-
import {
|
|
92
|
-
|
|
95
|
+
import { z } from "zod";
|
|
96
|
+
import { getContext, serverFn, ServerFnError } from "@nowaki-dev/runtime";
|
|
97
|
+
export const addTodo = serverFn(z.string().min(1).max(200), async (text) => {
|
|
98
|
+
if (!getContext()?.cookies?.user) throw new ServerFnError("Sign in first", { status: 401 });
|
|
99
|
+
/* runs on the server with a validated string */
|
|
100
|
+
});
|
|
93
101
|
```
|
|
102
|
+
The **basics** template includes `actions/echo.ts` as a minimal validated example.
|
|
94
103
|
Call it from an island like a normal async function:
|
|
95
104
|
`import { addTodo } from "../actions/todos.ts";`
|
|
96
105
|
8. **Jetstream islands** (server-reactive, zero client JS) — give an island
|
|
@@ -112,6 +121,17 @@ nowaki.config.mjs plugins (optional)
|
|
|
112
121
|
```
|
|
113
122
|
Unknown paths, missing params, and wrong param keys are compile errors.
|
|
114
123
|
|
|
124
|
+
## Security
|
|
125
|
+
|
|
126
|
+
- **`nowaki dev` is for local development.** Do not expose it to untrusted networks.
|
|
127
|
+
Use `nowaki start` or a deploy adapter output in production.
|
|
128
|
+
- **Secrets stay server-side.** Only `PUBLIC_*` (and `MODE`) reach the browser. Copy
|
|
129
|
+
`.env.example` to `.env` and keep database URLs, API keys, and tokens unprefixed.
|
|
130
|
+
- **Server functions and API routes are public endpoints.** Validate and bound every
|
|
131
|
+
argument; authorize with `getContext()` (cookies/headers) before mutating data.
|
|
132
|
+
- **Do not embed secrets** in client islands, loaders returned to the page, or static
|
|
133
|
+
prerender output. ISR pages must not include per-user secrets.
|
|
134
|
+
|
|
115
135
|
## Don't
|
|
116
136
|
|
|
117
137
|
- Don't add a build tool (Vite/webpack/Babel) or a `tsconfig` paths setup — the
|
|
@@ -8,6 +8,7 @@ components under `islands/` ship JavaScript and hydrate.
|
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npm install
|
|
11
|
+
cp .env.example .env # optional — only PUBLIC_* vars belong in client bundles
|
|
11
12
|
npm run dev # http://localhost:3000
|
|
12
13
|
```
|
|
13
14
|
|
|
@@ -43,6 +44,7 @@ actions/ "use server" RPC modules (optional)
|
|
|
43
44
|
`preact/compat`, so many React libraries work.)
|
|
44
45
|
- Use **explicit file extensions** in relative imports: `../islands/Counter.tsx`.
|
|
45
46
|
- A route's `loader` runs only on the server; `action` handles non-GET requests.
|
|
47
|
+
- `routes/api/health.ts` is a minimal JSON API example; `routes/_404.tsx` handles unknown paths.
|
|
46
48
|
- `AGENTS.md` documents the conventions for AI coding agents.
|
|
47
49
|
|
|
48
50
|
Docs: <https://nowaki.dev/docs>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Copy to `.env` for local development. Never commit `.env` (see `.gitignore`).
|
|
2
|
+
#
|
|
3
|
+
# Only variables prefixed with PUBLIC_ are inlined into client bundles.
|
|
4
|
+
# Everything else stays on the server (loaders, actions, server functions).
|
|
5
|
+
#
|
|
6
|
+
# PUBLIC_SITE_NAME=My App
|
|
7
|
+
# DATABASE_URL=postgres://... # server-only — do not prefix with PUBLIC_
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"prerender": "nowaki prerender"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@nowaki-dev/runtime": "^0.
|
|
12
|
+
"@nowaki-dev/runtime": "^0.13.0",
|
|
13
13
|
"preact": "^10.25.4",
|
|
14
14
|
"preact-render-to-string": "^6.8.2"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
17
|
-
"nowaki": "^0.
|
|
17
|
+
"nowaki": "^0.14.0"
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use server";
|
|
2
|
+
|
|
3
|
+
import { getContext, serverFn } from "@nowaki-dev/runtime";
|
|
4
|
+
|
|
5
|
+
// Hand-written Standard Schema (no zod/valibot) — same pattern as examples/hello/actions/todos.ts.
|
|
6
|
+
const message = {
|
|
7
|
+
"~standard": {
|
|
8
|
+
version: 1 as const,
|
|
9
|
+
vendor: "example",
|
|
10
|
+
validate: (v: unknown) =>
|
|
11
|
+
typeof v === "string" && v.length <= 120
|
|
12
|
+
? { value: v.trim() }
|
|
13
|
+
: { issues: [{ message: "message must be a string of at most 120 characters" }] },
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/** Example server function — validated input and getContext() for auth in real apps. */
|
|
18
|
+
export const echo = serverFn(message, async (text) => ({
|
|
19
|
+
ok: true,
|
|
20
|
+
echo: text,
|
|
21
|
+
hasRequest: getContext() != null,
|
|
22
|
+
}));
|