create-rivet 0.0.0-stage → 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +45 -2
- package/cli.d.ts +2 -0
- package/cli.js +10 -0
- package/deploy.d.ts +32 -0
- package/deploy.js +99 -0
- package/index.d.ts +118 -0
- package/index.js +184 -0
- package/main.d.ts +9 -0
- package/main.js +169 -0
- package/package.json +57 -4
- package/prompt.d.ts +24 -0
- package/prompt.js +127 -0
- package/templates/starter-minimal/.agents/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-minimal/.agents/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-minimal/.agents/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-minimal/.agents/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-minimal/.agents/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-minimal/.agents/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-minimal/.agents/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-minimal/.agents/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-minimal/.agents/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-minimal/.agents/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-minimal/.agents/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-minimal/.claude/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-minimal/.claude/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-minimal/.claude/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-minimal/.claude/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-minimal/.claude/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-minimal/.claude/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-minimal/.claude/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-minimal/.claude/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-minimal/.claude/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-minimal/.claude/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-minimal/.claude/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-minimal/.cursor/rules/rivet-add-route.mdc +37 -0
- package/templates/starter-minimal/.cursor/rules/rivet-add-ui-page.mdc +43 -0
- package/templates/starter-minimal/.cursor/rules/rivet-fix-resumability-error.mdc +27 -0
- package/templates/starter-minimal/.cursor/rules/rivet-form-in-drawer.mdc +64 -0
- package/templates/starter-minimal/.cursor/rules/rivet-port-react-component.mdc +37 -0
- package/templates/starter-minimal/.cursor/rules/rivet-ui-design.mdc +42 -0
- package/templates/starter-minimal/.cursor/rules/rivet.mdc +27 -0
- package/templates/starter-minimal/.github/copilot-instructions.md +21 -0
- package/templates/starter-minimal/AGENTS.md +461 -0
- package/templates/starter-minimal/CLAUDE.md +461 -0
- package/templates/starter-minimal/README.md +26 -0
- package/templates/starter-minimal/_gitignore +3 -0
- package/templates/starter-minimal/package.json +28 -0
- package/templates/starter-minimal/prerender.js +5 -0
- package/templates/starter-minimal/src/document.ts +14 -0
- package/templates/starter-minimal/src/routes/index.tsx +16 -0
- package/templates/starter-minimal/tsconfig.json +21 -0
- package/templates/starter-minimal/vite.config.ts +4 -0
- package/templates/starter-server/.agents/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-server/.agents/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-server/.agents/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-server/.agents/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-server/.agents/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-server/.agents/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-server/.agents/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-server/.agents/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-server/.agents/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-server/.agents/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-server/.agents/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-server/.claude/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-server/.claude/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-server/.claude/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-server/.claude/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-server/.claude/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-server/.claude/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-server/.claude/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-server/.claude/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-server/.claude/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-server/.claude/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-server/.claude/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-server/.cursor/rules/rivet-add-route.mdc +37 -0
- package/templates/starter-server/.cursor/rules/rivet-add-ui-page.mdc +43 -0
- package/templates/starter-server/.cursor/rules/rivet-fix-resumability-error.mdc +27 -0
- package/templates/starter-server/.cursor/rules/rivet-form-in-drawer.mdc +64 -0
- package/templates/starter-server/.cursor/rules/rivet-port-react-component.mdc +37 -0
- package/templates/starter-server/.cursor/rules/rivet-ui-design.mdc +42 -0
- package/templates/starter-server/.cursor/rules/rivet.mdc +27 -0
- package/templates/starter-server/.dockerignore +7 -0
- package/templates/starter-server/.github/copilot-instructions.md +21 -0
- package/templates/starter-server/AGENTS.md +461 -0
- package/templates/starter-server/CLAUDE.md +461 -0
- package/templates/starter-server/Dockerfile +18 -0
- package/templates/starter-server/README.md +30 -0
- package/templates/starter-server/_gitignore +3 -0
- package/templates/starter-server/package.json +31 -0
- package/templates/starter-server/serve.js +6 -0
- package/templates/starter-server/src/document.ts +14 -0
- package/templates/starter-server/src/routes/index.tsx +41 -0
- package/templates/starter-server/src/styles.css +9 -0
- package/templates/starter-server/tsconfig.json +21 -0
- package/templates/starter-server/vite.config.ts +8 -0
- package/templates/starter-static/.agents/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-static/.agents/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-static/.agents/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-static/.agents/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-static/.agents/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-static/.agents/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-static/.agents/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-static/.agents/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-static/.agents/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-static/.agents/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-static/.agents/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-static/.claude/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-static/.claude/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-static/.claude/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-static/.claude/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-static/.claude/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-static/.claude/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-static/.claude/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-static/.claude/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-static/.claude/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-static/.claude/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-static/.claude/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-static/.cursor/rules/rivet-add-route.mdc +37 -0
- package/templates/starter-static/.cursor/rules/rivet-add-ui-page.mdc +43 -0
- package/templates/starter-static/.cursor/rules/rivet-fix-resumability-error.mdc +27 -0
- package/templates/starter-static/.cursor/rules/rivet-form-in-drawer.mdc +64 -0
- package/templates/starter-static/.cursor/rules/rivet-port-react-component.mdc +37 -0
- package/templates/starter-static/.cursor/rules/rivet-ui-design.mdc +42 -0
- package/templates/starter-static/.cursor/rules/rivet.mdc +27 -0
- package/templates/starter-static/.github/copilot-instructions.md +21 -0
- package/templates/starter-static/AGENTS.md +461 -0
- package/templates/starter-static/CLAUDE.md +461 -0
- package/templates/starter-static/README.md +30 -0
- package/templates/starter-static/_gitignore +3 -0
- package/templates/starter-static/package.json +31 -0
- package/templates/starter-static/prerender.js +5 -0
- package/templates/starter-static/serve.js +21 -0
- package/templates/starter-static/src/components/Counter.tsx +15 -0
- package/templates/starter-static/src/document.ts +14 -0
- package/templates/starter-static/src/routes/_layout.tsx +18 -0
- package/templates/starter-static/src/routes/about.tsx +11 -0
- package/templates/starter-static/src/routes/index.tsx +14 -0
- package/templates/starter-static/src/styles.css +9 -0
- package/templates/starter-static/tsconfig.json +21 -0
- package/templates/starter-static/vite.config.ts +9 -0
- package/templates/starter-ui/.agents/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-ui/.agents/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-ui/.agents/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-ui/.agents/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-ui/.agents/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-ui/.agents/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-ui/.agents/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-ui/.agents/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-ui/.agents/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-ui/.agents/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-ui/.agents/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-ui/.claude/skills/rivet-add-route/LICENSE.txt +21 -0
- package/templates/starter-ui/.claude/skills/rivet-add-route/SKILL.md +36 -0
- package/templates/starter-ui/.claude/skills/rivet-add-ui-page/LICENSE.txt +21 -0
- package/templates/starter-ui/.claude/skills/rivet-add-ui-page/SKILL.md +42 -0
- package/templates/starter-ui/.claude/skills/rivet-fix-resumability-error/LICENSE.txt +21 -0
- package/templates/starter-ui/.claude/skills/rivet-fix-resumability-error/SKILL.md +26 -0
- package/templates/starter-ui/.claude/skills/rivet-form-in-drawer/LICENSE.txt +21 -0
- package/templates/starter-ui/.claude/skills/rivet-form-in-drawer/SKILL.md +63 -0
- package/templates/starter-ui/.claude/skills/rivet-port-react-component/LICENSE.txt +21 -0
- package/templates/starter-ui/.claude/skills/rivet-port-react-component/SKILL.md +36 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/LICENSE.txt +21 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/SKILL.md +41 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/references/component-composition.md +55 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/references/interactions.md +49 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/references/rivet-implementation.md +66 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/references/structure-and-layout.md +51 -0
- package/templates/starter-ui/.claude/skills/rivet-ui-design/references/visual-foundations.md +64 -0
- package/templates/starter-ui/.cursor/rules/rivet-add-route.mdc +37 -0
- package/templates/starter-ui/.cursor/rules/rivet-add-ui-page.mdc +43 -0
- package/templates/starter-ui/.cursor/rules/rivet-fix-resumability-error.mdc +27 -0
- package/templates/starter-ui/.cursor/rules/rivet-form-in-drawer.mdc +64 -0
- package/templates/starter-ui/.cursor/rules/rivet-port-react-component.mdc +37 -0
- package/templates/starter-ui/.cursor/rules/rivet-ui-design.mdc +42 -0
- package/templates/starter-ui/.cursor/rules/rivet.mdc +27 -0
- package/templates/starter-ui/.github/copilot-instructions.md +21 -0
- package/templates/starter-ui/AGENTS.md +461 -0
- package/templates/starter-ui/CLAUDE.md +461 -0
- package/templates/starter-ui/README.md +32 -0
- package/templates/starter-ui/_gitignore +3 -0
- package/templates/starter-ui/package.json +34 -0
- package/templates/starter-ui/prerender.js +5 -0
- package/templates/starter-ui/serve.js +21 -0
- package/templates/starter-ui/src/components/LikeButton.tsx +12 -0
- package/templates/starter-ui/src/document.ts +14 -0
- package/templates/starter-ui/src/routes/index.tsx +39 -0
- package/templates/starter-ui/src/styles.css +11 -0
- package/templates/starter-ui/tsconfig.json +21 -0
- package/templates/starter-ui/vite.config.ts +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Denys Severyn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# create-rivet
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Create a [Rivet](https://github.com/N1XUS/rivetjs) app.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
npm create rivet@latest my-app
|
|
7
|
+
cd my-app
|
|
8
|
+
npm run dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
It asks for a project name, a template, whether to install dependencies and whether to create a git repository. Other package managers: `pnpm create rivet`, `yarn create rivet`, `bun create rivet`.
|
|
12
|
+
|
|
13
|
+
## Templates
|
|
14
|
+
|
|
15
|
+
| `--template` | What you get |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `static` (default) | Static site: pages prerendered to HTML, Tailwind CSS, two routes, an interactive counter. |
|
|
18
|
+
| `server` | Node.js server: a loader and a form action per request, Tailwind CSS, a Dockerfile. |
|
|
19
|
+
| `ui` | Static site with `@rivetjs/ui` components and Tailwind CSS v4. |
|
|
20
|
+
| `minimal` | One page, one signal, no Tailwind. |
|
|
21
|
+
|
|
22
|
+
All templates use TypeScript and need Node.js 24 or newer.
|
|
23
|
+
|
|
24
|
+
## Options
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm create rivet@latest my-app -- --template server --yes --no-git
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
| Option | |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| `-t`, `--template <id>` | `static`, `server`, `ui` or `minimal` |
|
|
33
|
+
| `-d`, `--deploy <target>` | `vercel`, `netlify`, `cloudflare` (any template), `bun`, `deno` (`server` template): sets the router adapter and the platform files |
|
|
34
|
+
| `-n`, `--name <name>` | `package.json` name (default: the folder name) |
|
|
35
|
+
| `-y`, `--yes` | ask nothing, take the defaults |
|
|
36
|
+
| `--no-install` | skip installing dependencies |
|
|
37
|
+
| `--no-git` | skip `git init` |
|
|
38
|
+
| `--pm <name>` | `npm`, `pnpm`, `yarn` or `bun` (default: the one running the command) |
|
|
39
|
+
| `-f`, `--force` | write into a folder that is not empty |
|
|
40
|
+
| `-h`, `--help` | all options |
|
|
41
|
+
|
|
42
|
+
With npm, options go after `--`.
|
|
43
|
+
|
|
44
|
+
## Nx monorepos
|
|
45
|
+
|
|
46
|
+
The same templates as Nx projects, with cached `build` / `test` / `check` targets: [`@rivetjs/nx`](https://github.com/N1XUS/rivetjs/tree/main/libs/nx) (`npx create-nx-workspace@latest my-org --preset=@rivetjs/nx`, or `npx nx add @rivetjs/nx` in an existing workspace).
|
package/cli.d.ts
ADDED
package/cli.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `create-rivet` bin (`npm create rivet@latest`): see ./main.ts.
|
|
3
|
+
import { main } from "./main.js";
|
|
4
|
+
process.exitCode = await main(process.argv.slice(2), {
|
|
5
|
+
input: process.stdin,
|
|
6
|
+
output: process.stdout,
|
|
7
|
+
error: process.stderr,
|
|
8
|
+
cwd: process.cwd(),
|
|
9
|
+
env: process.env,
|
|
10
|
+
});
|
package/deploy.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Overlay, type PackageManager, type TemplateId } from "./index.js";
|
|
2
|
+
export declare const DEPLOY_TARGETS: readonly [{
|
|
3
|
+
readonly id: "vercel";
|
|
4
|
+
readonly label: "Vercel";
|
|
5
|
+
readonly hint: "Build Output API (.vercel/output), `vercel deploy --prebuilt`";
|
|
6
|
+
}, {
|
|
7
|
+
readonly id: "netlify";
|
|
8
|
+
readonly label: "Netlify";
|
|
9
|
+
readonly hint: "netlify.toml + Netlify Functions (dist/netlify)";
|
|
10
|
+
}, {
|
|
11
|
+
readonly id: "cloudflare";
|
|
12
|
+
readonly label: "Cloudflare Workers";
|
|
13
|
+
readonly hint: "Workers + static assets, `wrangler deploy`";
|
|
14
|
+
}, {
|
|
15
|
+
readonly id: "bun";
|
|
16
|
+
readonly label: "Bun";
|
|
17
|
+
readonly hint: "`bun dist/server/bun.js` (server template)";
|
|
18
|
+
}, {
|
|
19
|
+
readonly id: "deno";
|
|
20
|
+
readonly label: "Deno";
|
|
21
|
+
readonly hint: "`deno run dist/server/deno.js` (server template)";
|
|
22
|
+
}];
|
|
23
|
+
export type DeployTarget = (typeof DEPLOY_TARGETS)[number]["id"];
|
|
24
|
+
/** Wrangler major the cloudflare target was verified with (`wrangler dev --local`, 4.x). */
|
|
25
|
+
export declare const WRANGLER_RANGE = "^4.0.0";
|
|
26
|
+
export declare function findDeployTarget(id: string): (typeof DEPLOY_TARGETS)[number] | undefined;
|
|
27
|
+
/** Why `target` cannot be used with `template`, or `undefined`. */
|
|
28
|
+
export declare function deployProblem(target: DeployTarget, template: TemplateId): string | undefined;
|
|
29
|
+
/** `rivetRouter({ … })` / `rivetRouter()` → with `adapter: "<target>"` first. Throws when the call is missing. */
|
|
30
|
+
export declare function addAdapter(config: string, target: DeployTarget): string;
|
|
31
|
+
/** The overlay for `target` (package manager: the build command written into netlify.toml). */
|
|
32
|
+
export declare function deployOverlay(target: DeployTarget, pm?: PackageManager): Overlay;
|
package/deploy.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// `--deploy <target>`: the per-platform edits over a starter, as a create-rivet `Overlay`. The router builds the
|
|
2
|
+
// platform output itself (`rivetRouter({ adapter })`, libs/router/adapters/CLAUDE.md); here only the project files:
|
|
3
|
+
// - every target: `adapter: "<target>"` in vite.config.ts' `rivetRouter({ … })`, `.vercel/` `.netlify/` `.wrangler/`
|
|
4
|
+
// in .gitignore;
|
|
5
|
+
// - vercel: `deploy` = `vercel deploy --prebuilt` (deploys `.vercel/output` from `npm run build`);
|
|
6
|
+
// - netlify: netlify.toml (build command, `publish = "dist/netlify"`: the Frameworks API has no publish setting);
|
|
7
|
+
// - cloudflare: `wrangler` dev dependency, `preview` = `wrangler dev`, `deploy` = `wrangler deploy` (the build writes
|
|
8
|
+
// dist/cloudflare/wrangler.json and points Wrangler at it). No `nodejs_compat` flag: the build sets the flags;
|
|
9
|
+
// - bun / deno (server starter only): `start` runs the generated server entry; the Node-only serve.js + Dockerfile go.
|
|
10
|
+
import { existsSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { commands } from "./index.js";
|
|
13
|
+
export const DEPLOY_TARGETS = [
|
|
14
|
+
{ id: "vercel", label: "Vercel", hint: "Build Output API (.vercel/output), `vercel deploy --prebuilt`" },
|
|
15
|
+
{ id: "netlify", label: "Netlify", hint: "netlify.toml + Netlify Functions (dist/netlify)" },
|
|
16
|
+
{ id: "cloudflare", label: "Cloudflare Workers", hint: "Workers + static assets, `wrangler deploy`" },
|
|
17
|
+
{ id: "bun", label: "Bun", hint: "`bun dist/server/bun.js` (server template)" },
|
|
18
|
+
{ id: "deno", label: "Deno", hint: "`deno run dist/server/deno.js` (server template)" },
|
|
19
|
+
];
|
|
20
|
+
/** Wrangler major the cloudflare target was verified with (`wrangler dev --local`, 4.x). */
|
|
21
|
+
export const WRANGLER_RANGE = "^4.0.0";
|
|
22
|
+
const SERVER_ONLY = new Set(["bun", "deno"]);
|
|
23
|
+
const IGNORED = [".vercel/", ".netlify/", ".wrangler/"];
|
|
24
|
+
export function findDeployTarget(id) {
|
|
25
|
+
return DEPLOY_TARGETS.find((target) => target.id === id);
|
|
26
|
+
}
|
|
27
|
+
/** Why `target` cannot be used with `template`, or `undefined`. */
|
|
28
|
+
export function deployProblem(target, template) {
|
|
29
|
+
if (SERVER_ONLY.has(target) && template !== "server")
|
|
30
|
+
return `--deploy ${target} runs a server: use --template server`;
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
/** `rivetRouter({ … })` / `rivetRouter()` → with `adapter: "<target>"` first. Throws when the call is missing. */
|
|
34
|
+
export function addAdapter(config, target) {
|
|
35
|
+
if (/rivetRouter\(\s*\{[^}]*\badapter\s*:/.test(config))
|
|
36
|
+
throw new Error("vite.config.ts already sets an adapter");
|
|
37
|
+
if (/rivetRouter\(\s*\)/.test(config))
|
|
38
|
+
return config.replace(/rivetRouter\(\s*\)/, `rivetRouter({ adapter: "${target}" })`);
|
|
39
|
+
if (/rivetRouter\(\s*\{/.test(config))
|
|
40
|
+
return config.replace(/rivetRouter\(\s*\{\s*/, `rivetRouter({ adapter: "${target}", `);
|
|
41
|
+
throw new Error("vite.config.ts has no rivetRouter() call to add the adapter to");
|
|
42
|
+
}
|
|
43
|
+
/** The overlay for `target` (package manager: the build command written into netlify.toml). */
|
|
44
|
+
export function deployOverlay(target, pm = "npm") {
|
|
45
|
+
return {
|
|
46
|
+
name: "deploy-" + target,
|
|
47
|
+
manifest: (pkg) => {
|
|
48
|
+
const scripts = { ...(pkg["scripts"] ?? {}) };
|
|
49
|
+
const out = { ...pkg, scripts };
|
|
50
|
+
if (target === "vercel")
|
|
51
|
+
scripts["deploy"] = "vercel deploy --prebuilt";
|
|
52
|
+
if (target === "cloudflare") {
|
|
53
|
+
scripts["preview"] = "wrangler dev";
|
|
54
|
+
scripts["deploy"] = "wrangler deploy";
|
|
55
|
+
out.devDependencies = { ...pkg.devDependencies, wrangler: WRANGLER_RANGE };
|
|
56
|
+
}
|
|
57
|
+
if (target === "bun")
|
|
58
|
+
scripts["start"] = "bun dist/server/bun.js";
|
|
59
|
+
if (target === "deno")
|
|
60
|
+
scripts["start"] = "deno run --allow-net --allow-read --allow-env dist/server/deno.js";
|
|
61
|
+
return out;
|
|
62
|
+
},
|
|
63
|
+
edit: (dir) => {
|
|
64
|
+
const written = ["vite.config.ts", ".gitignore"];
|
|
65
|
+
const removed = [];
|
|
66
|
+
const config = join(dir, "vite.config.ts");
|
|
67
|
+
writeFileSync(config, addAdapter(readFileSync(config, "utf8"), target));
|
|
68
|
+
const gitignore = join(dir, ".gitignore");
|
|
69
|
+
const lines = existsSync(gitignore) ? readFileSync(gitignore, "utf8").split("\n").filter(Boolean) : [];
|
|
70
|
+
writeFileSync(gitignore, [...lines, ...IGNORED.filter((entry) => !lines.includes(entry))].join("\n") + "\n");
|
|
71
|
+
if (target === "netlify") {
|
|
72
|
+
writeFileSync(join(dir, "netlify.toml"), `[build]\n command = "${commands(pm).run("build")}"\n publish = "dist/netlify"\n`);
|
|
73
|
+
written.push("netlify.toml");
|
|
74
|
+
}
|
|
75
|
+
const readme = join(dir, "README.md");
|
|
76
|
+
if (existsSync(readme)) {
|
|
77
|
+
const run = commands(pm).run;
|
|
78
|
+
const label = findDeployTarget(target).label;
|
|
79
|
+
const how = {
|
|
80
|
+
vercel: `\`${run("build")}\` also writes \`.vercel/output\` (Build Output API). Deploy it with the Vercel CLI: \`${run("deploy")}\` (\`vercel deploy --prebuilt\`).`,
|
|
81
|
+
netlify: `\`netlify.toml\` makes Netlify run \`${run("build")}\` and publish \`dist/netlify\`; the server function goes to \`.netlify/v1\`. Connect the repository in Netlify, or deploy with the Netlify CLI after a build.`,
|
|
82
|
+
cloudflare: `\`${run("build")}\` writes \`dist/cloudflare\` (worker + static assets + \`wrangler.json\`). \`${run("preview")}\` runs it in the local Workers runtime, \`${run("deploy")}\` uploads it. Keep \`nodejs_compat\` off (the build sets the compatibility flags).`,
|
|
83
|
+
bun: `\`${run("build")}\` writes \`dist/server/bun.js\`; \`${run("start")}\` serves the app with Bun (\`PORT\`, \`HOST\`). Bun must be installed.`,
|
|
84
|
+
deno: `\`${run("build")}\` writes \`dist/server/deno.js\`; \`${run("start")}\` serves the app with Deno (\`PORT\`, \`HOST\`). Deno must be installed.`,
|
|
85
|
+
};
|
|
86
|
+
writeFileSync(readme, readFileSync(readme, "utf8").trimEnd() +
|
|
87
|
+
`\n\n## Deploy: ${label}\n\n- \`vite.config.ts\` sets \`rivetRouter({ adapter: "${target}" })\`.\n- ${how[target]}\n`);
|
|
88
|
+
written.push("README.md");
|
|
89
|
+
}
|
|
90
|
+
if (SERVER_ONLY.has(target))
|
|
91
|
+
for (const file of ["serve.js", "Dockerfile", ".dockerignore"])
|
|
92
|
+
if (existsSync(join(dir, file))) {
|
|
93
|
+
rmSync(join(dir, file));
|
|
94
|
+
removed.push(file);
|
|
95
|
+
}
|
|
96
|
+
return { written, removed };
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/** Starter templates offered by the CLI (`--template <id>`); `dir` is the folder under `templates/`. */
|
|
2
|
+
export declare const TEMPLATES: readonly [{
|
|
3
|
+
readonly id: "static";
|
|
4
|
+
readonly dir: "starter-static";
|
|
5
|
+
readonly label: "Static site";
|
|
6
|
+
readonly hint: "pages prerendered to HTML, Tailwind, two routes, a counter";
|
|
7
|
+
}, {
|
|
8
|
+
readonly id: "server";
|
|
9
|
+
readonly dir: "starter-server";
|
|
10
|
+
readonly label: "Node server";
|
|
11
|
+
readonly hint: "loader + form action per request, Tailwind, Dockerfile";
|
|
12
|
+
}, {
|
|
13
|
+
readonly id: "ui";
|
|
14
|
+
readonly dir: "starter-ui";
|
|
15
|
+
readonly label: "UI components";
|
|
16
|
+
readonly hint: "@rivetjs/ui components + Tailwind v4, static";
|
|
17
|
+
}, {
|
|
18
|
+
readonly id: "minimal";
|
|
19
|
+
readonly dir: "starter-minimal";
|
|
20
|
+
readonly label: "Minimal";
|
|
21
|
+
readonly hint: "one page, one signal, no Tailwind";
|
|
22
|
+
}];
|
|
23
|
+
export type TemplateId = (typeof TEMPLATES)[number]["id"];
|
|
24
|
+
export declare const PACKAGE_MANAGERS: readonly ["npm", "pnpm", "yarn", "bun"];
|
|
25
|
+
export type PackageManager = (typeof PACKAGE_MANAGERS)[number];
|
|
26
|
+
/** This package's own manifest version: every `@rivetjs/*` package is released with the same version. */
|
|
27
|
+
export declare function ownVersion(): string;
|
|
28
|
+
/** The dependency range written for `@rivetjs/*`: exact for a prerelease (`0.1.0-alpha.1`), `^x.y.z` otherwise. */
|
|
29
|
+
export declare function versionRange(version: string): string;
|
|
30
|
+
/** Where the templates are: bundled next to the code (published package) or the repository's `templates/`. */
|
|
31
|
+
export declare function templatesRoot(): string;
|
|
32
|
+
/** `templates/_<name>` (an overlay's files), bundled or in the repository. */
|
|
33
|
+
export declare function overlayDir(name: string): string;
|
|
34
|
+
export declare function findTemplate(name: string): (typeof TEMPLATES)[number] | undefined;
|
|
35
|
+
/** The package manager that runs us (`npm create` / `pnpm create` / `yarn create` / `bun create` set the user agent). */
|
|
36
|
+
export declare function detectPackageManager(userAgent?: string): PackageManager;
|
|
37
|
+
/** Commands shown after creation for a package manager. */
|
|
38
|
+
export declare function commands(pm: PackageManager): {
|
|
39
|
+
install: string;
|
|
40
|
+
run: (script: string) => string;
|
|
41
|
+
};
|
|
42
|
+
/** An npm package name from a folder name (`My App` → `my-app`). */
|
|
43
|
+
export declare function toPackageName(name: string): string;
|
|
44
|
+
/** `undefined` when `name` is a valid npm package name, else why not. */
|
|
45
|
+
export declare function validatePackageName(name: string): string | undefined;
|
|
46
|
+
/** True when `dir` is missing or holds nothing but `.git` / `.DS_Store`. */
|
|
47
|
+
export declare function isEmptyDir(dir: string): boolean;
|
|
48
|
+
/** Template paths never copied: build output, installs, generated route types, StackBlitz config. */
|
|
49
|
+
export declare const SKIP: RegExp;
|
|
50
|
+
/** npm never packs `.gitignore` files: the bundled templates carry them as `_gitignore`. */
|
|
51
|
+
export declare const RENAMES: Readonly<Record<string, string>>;
|
|
52
|
+
/** One file of a template (or overlay) folder: `path` relative to the folder (posix, {@link RENAMES} applied). */
|
|
53
|
+
export interface TemplateFile {
|
|
54
|
+
path: string;
|
|
55
|
+
/** Absolute source path. */
|
|
56
|
+
source: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The files of a template (or overlay) folder, sorted: skips {@link SKIP}, applies {@link RENAMES}. Shared by
|
|
60
|
+
* {@link copyTemplateDir} and `@rivetjs/nx` (which writes them into an Nx `Tree` instead of the file system).
|
|
61
|
+
*/
|
|
62
|
+
export declare function templateFiles(from: string): TemplateFile[];
|
|
63
|
+
/** Copies a template (or an overlay) folder onto `to`: skips {@link SKIP}, applies {@link RENAMES}. */
|
|
64
|
+
export declare function copyTemplateDir(from: string, to: string): string[];
|
|
65
|
+
export interface PackageJson {
|
|
66
|
+
name?: string;
|
|
67
|
+
version?: string;
|
|
68
|
+
dependencies?: Record<string, string>;
|
|
69
|
+
devDependencies?: Record<string, string>;
|
|
70
|
+
[field: string]: unknown;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The template's `package.json` for the new project: `name`, `version` 0.1.0, every `@rivetjs/*` (and `create-rivet`)
|
|
74
|
+
* dependency → `range` (templates name `experimental` / `workspace:` / `file:` / `link:` specs that only resolve in the repo).
|
|
75
|
+
*/
|
|
76
|
+
export declare function rewriteManifest(pkg: PackageJson, name: string, range: string): PackageJson;
|
|
77
|
+
/**
|
|
78
|
+
* Extension point for options layered over a template (e.g. a deploy target, `--deploy`): files copied over the
|
|
79
|
+
* template (`dir`, same skip / rename rules; keep them in `templates/_<name>/`, which `bundle.ts` ships and
|
|
80
|
+
* {@link overlayDir} finds), then `manifest` edits the new `package.json` (scripts, dependencies), then `edit`
|
|
81
|
+
* changes other files in place (`deploy.ts`: vite.config.ts, .gitignore, netlify.toml).
|
|
82
|
+
*/
|
|
83
|
+
export interface Overlay {
|
|
84
|
+
name: string;
|
|
85
|
+
dir?: string;
|
|
86
|
+
manifest?: (pkg: PackageJson) => PackageJson;
|
|
87
|
+
/** Edits files of the new project (after `dir`); returns the paths it wrote (relative) and removed. */
|
|
88
|
+
edit?: (dir: string) => {
|
|
89
|
+
written?: string[];
|
|
90
|
+
removed?: string[];
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export interface CreateOptions {
|
|
94
|
+
/** Target folder (created). */
|
|
95
|
+
dir: string;
|
|
96
|
+
template: TemplateId;
|
|
97
|
+
/** `package.json` name (default: from the folder name). */
|
|
98
|
+
name?: string;
|
|
99
|
+
/** `@rivetjs/*` dependency spec (default: {@link versionRange} of this package's version). */
|
|
100
|
+
rivetVersion?: string;
|
|
101
|
+
overlays?: Overlay[];
|
|
102
|
+
/** Templates folder (default {@link templatesRoot}). */
|
|
103
|
+
templates?: string;
|
|
104
|
+
}
|
|
105
|
+
/** Writes the project. Throws when the template is unknown. Does not install or run git. */
|
|
106
|
+
export declare function createProject(options: CreateOptions): {
|
|
107
|
+
dir: string;
|
|
108
|
+
name: string;
|
|
109
|
+
files: string[];
|
|
110
|
+
};
|
|
111
|
+
/** `<pm> install` in `dir` (inherits the terminal). Returns whether it succeeded. */
|
|
112
|
+
export declare function installDependencies(dir: string, pm: PackageManager, { stdio }?: {
|
|
113
|
+
stdio?: "inherit" | "pipe" | undefined;
|
|
114
|
+
}): boolean;
|
|
115
|
+
/** `git init` + first commit, unless git is missing or `dir` is already inside a work tree. */
|
|
116
|
+
export declare function initGit(dir: string): "created" | "committed" | "inside-repo" | "no-git" | "failed";
|
|
117
|
+
/** `dir` exists and is a file (not a folder). */
|
|
118
|
+
export declare function isFile(path: string): boolean;
|
package/index.js
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// create-rivet: copies a Rivet starter template into a new folder, rewrites its `@rivetjs/*` dependencies to
|
|
2
|
+
// the published version, writes the package name, then optionally installs dependencies and runs `git init`.
|
|
3
|
+
// `cli.ts` parses the command line and asks the questions; everything here is plain functions (tests call them).
|
|
4
|
+
//
|
|
5
|
+
// Templates: the published package ships them in `templates/` (copied from the repository's `templates/` at
|
|
6
|
+
// package time by `bundle.ts`); inside the repository they are read from `templates/` directly.
|
|
7
|
+
import { spawnSync } from "node:child_process";
|
|
8
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
11
|
+
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
/** Starter templates offered by the CLI (`--template <id>`); `dir` is the folder under `templates/`. */
|
|
13
|
+
export const TEMPLATES = [
|
|
14
|
+
{ id: "static", dir: "starter-static", label: "Static site", hint: "pages prerendered to HTML, Tailwind, two routes, a counter" },
|
|
15
|
+
{ id: "server", dir: "starter-server", label: "Node server", hint: "loader + form action per request, Tailwind, Dockerfile" },
|
|
16
|
+
{ id: "ui", dir: "starter-ui", label: "UI components", hint: "@rivetjs/ui components + Tailwind v4, static" },
|
|
17
|
+
{ id: "minimal", dir: "starter-minimal", label: "Minimal", hint: "one page, one signal, no Tailwind" },
|
|
18
|
+
];
|
|
19
|
+
export const PACKAGE_MANAGERS = ["npm", "pnpm", "yarn", "bun"];
|
|
20
|
+
/** This package's own manifest version: every `@rivetjs/*` package is released with the same version. */
|
|
21
|
+
export function ownVersion() {
|
|
22
|
+
return JSON.parse(readFileSync(join(HERE, "package.json"), "utf8")).version;
|
|
23
|
+
}
|
|
24
|
+
/** The dependency range written for `@rivetjs/*`: exact for a prerelease (`0.1.0-alpha.1`), `^x.y.z` otherwise. */
|
|
25
|
+
export function versionRange(version) {
|
|
26
|
+
return version.includes("-") ? version : "^" + version;
|
|
27
|
+
}
|
|
28
|
+
/** Where the templates are: bundled next to the code (published package) or the repository's `templates/`. */
|
|
29
|
+
export function templatesRoot() {
|
|
30
|
+
const bundled = join(HERE, "templates");
|
|
31
|
+
return existsSync(bundled) ? bundled : resolve(HERE, "../../templates");
|
|
32
|
+
}
|
|
33
|
+
/** `templates/_<name>` (an overlay's files), bundled or in the repository. */
|
|
34
|
+
export function overlayDir(name) {
|
|
35
|
+
return join(templatesRoot(), "_" + name);
|
|
36
|
+
}
|
|
37
|
+
export function findTemplate(name) {
|
|
38
|
+
return TEMPLATES.find((template) => template.id === name || template.dir === name);
|
|
39
|
+
}
|
|
40
|
+
/** The package manager that runs us (`npm create` / `pnpm create` / `yarn create` / `bun create` set the user agent). */
|
|
41
|
+
export function detectPackageManager(userAgent = process.env["npm_config_user_agent"] ?? "") {
|
|
42
|
+
const name = userAgent.split("/")[0];
|
|
43
|
+
return PACKAGE_MANAGERS.includes(name ?? "") ? name : "npm";
|
|
44
|
+
}
|
|
45
|
+
/** Commands shown after creation for a package manager. */
|
|
46
|
+
export function commands(pm) {
|
|
47
|
+
return {
|
|
48
|
+
install: pm === "yarn" ? "yarn" : `${pm} install`,
|
|
49
|
+
run: (script) => (pm === "npm" || pm === "bun" ? `${pm} run ${script}` : `${pm} ${script}`),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** An npm package name from a folder name (`My App` → `my-app`). */
|
|
53
|
+
export function toPackageName(name) {
|
|
54
|
+
return (name
|
|
55
|
+
.trim()
|
|
56
|
+
.toLowerCase()
|
|
57
|
+
.replace(/\s+/g, "-")
|
|
58
|
+
.replace(/^[._]+/, "")
|
|
59
|
+
.replace(/[^a-z0-9~._-]+/g, "-")
|
|
60
|
+
.replace(/^-+|-+$/g, "") || "rivet-app");
|
|
61
|
+
}
|
|
62
|
+
/** `undefined` when `name` is a valid npm package name, else why not. */
|
|
63
|
+
export function validatePackageName(name) {
|
|
64
|
+
if (!name)
|
|
65
|
+
return "Name is empty";
|
|
66
|
+
if (name.length > 214)
|
|
67
|
+
return "Name is longer than 214 characters";
|
|
68
|
+
if (!/^(?:@[a-z0-9~-][a-z0-9._~-]*\/)?[a-z0-9~-][a-z0-9._~-]*$/.test(name))
|
|
69
|
+
return "Use lowercase letters, digits, '-', '.', '_' (npm package name rules)";
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
/** True when `dir` is missing or holds nothing but `.git` / `.DS_Store`. */
|
|
73
|
+
export function isEmptyDir(dir) {
|
|
74
|
+
if (!existsSync(dir))
|
|
75
|
+
return true;
|
|
76
|
+
return readdirSync(dir).every((entry) => entry === ".git" || entry === ".DS_Store");
|
|
77
|
+
}
|
|
78
|
+
/** Template paths never copied: build output, installs, generated route types, StackBlitz config. */
|
|
79
|
+
export const SKIP = /(^|[/\\])(node_modules|dist|\.rivet|\.stackblitzrc)([/\\]|$)/;
|
|
80
|
+
/** npm never packs `.gitignore` files: the bundled templates carry them as `_gitignore`. */
|
|
81
|
+
export const RENAMES = { _gitignore: ".gitignore" };
|
|
82
|
+
/**
|
|
83
|
+
* The files of a template (or overlay) folder, sorted: skips {@link SKIP}, applies {@link RENAMES}. Shared by
|
|
84
|
+
* {@link copyTemplateDir} and `@rivetjs/nx` (which writes them into an Nx `Tree` instead of the file system).
|
|
85
|
+
*/
|
|
86
|
+
export function templateFiles(from) {
|
|
87
|
+
const files = [];
|
|
88
|
+
const walk = (at) => {
|
|
89
|
+
for (const entry of readdirSync(at, { withFileTypes: true })) {
|
|
90
|
+
const path = join(at, entry.name);
|
|
91
|
+
const rel = relative(from, path);
|
|
92
|
+
if (SKIP.test(rel))
|
|
93
|
+
continue;
|
|
94
|
+
if (entry.isDirectory()) {
|
|
95
|
+
walk(path);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
files.push({
|
|
99
|
+
path: join(dirname(rel), RENAMES[entry.name] ?? entry.name)
|
|
100
|
+
.split(sep)
|
|
101
|
+
.join("/"),
|
|
102
|
+
source: path,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
walk(from);
|
|
107
|
+
return files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
108
|
+
}
|
|
109
|
+
/** Copies a template (or an overlay) folder onto `to`: skips {@link SKIP}, applies {@link RENAMES}. */
|
|
110
|
+
export function copyTemplateDir(from, to) {
|
|
111
|
+
const copied = [];
|
|
112
|
+
for (const file of templateFiles(from)) {
|
|
113
|
+
const target = join(to, file.path);
|
|
114
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
115
|
+
cpSync(file.source, target);
|
|
116
|
+
copied.push(relative(to, target).split(sep).join("/"));
|
|
117
|
+
}
|
|
118
|
+
return copied.sort();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* The template's `package.json` for the new project: `name`, `version` 0.1.0, every `@rivetjs/*` (and `create-rivet`)
|
|
122
|
+
* dependency → `range` (templates name `experimental` / `workspace:` / `file:` / `link:` specs that only resolve in the repo).
|
|
123
|
+
*/
|
|
124
|
+
export function rewriteManifest(pkg, name, range) {
|
|
125
|
+
const out = { ...pkg, name, version: "0.1.0" };
|
|
126
|
+
for (const field of ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"]) {
|
|
127
|
+
const deps = pkg[field];
|
|
128
|
+
if (!deps)
|
|
129
|
+
continue;
|
|
130
|
+
out[field] = Object.fromEntries(Object.entries(deps).map(([dep, spec]) => [dep, dep.startsWith("@rivetjs/") || dep === "create-rivet" ? range : spec]));
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
/** Writes the project. Throws when the template is unknown. Does not install or run git. */
|
|
135
|
+
export function createProject(options) {
|
|
136
|
+
const template = findTemplate(options.template);
|
|
137
|
+
if (!template)
|
|
138
|
+
throw new Error(`Unknown template "${options.template}" (${TEMPLATES.map((t) => t.id).join(", ")})`);
|
|
139
|
+
const source = join(options.templates ?? templatesRoot(), template.dir);
|
|
140
|
+
if (!existsSync(join(source, "package.json")))
|
|
141
|
+
throw new Error(`Template files missing: ${source}`);
|
|
142
|
+
const dir = resolve(options.dir);
|
|
143
|
+
const name = options.name ?? toPackageName(basename(dir));
|
|
144
|
+
mkdirSync(dir, { recursive: true });
|
|
145
|
+
const files = new Set(copyTemplateDir(source, dir));
|
|
146
|
+
let pkg = rewriteManifest(JSON.parse(readFileSync(join(dir, "package.json"), "utf8")), name, options.rivetVersion ?? versionRange(ownVersion()));
|
|
147
|
+
for (const overlay of options.overlays ?? []) {
|
|
148
|
+
if (overlay.dir)
|
|
149
|
+
for (const file of copyTemplateDir(overlay.dir, dir))
|
|
150
|
+
files.add(file);
|
|
151
|
+
if (overlay.manifest)
|
|
152
|
+
pkg = overlay.manifest(pkg);
|
|
153
|
+
const edited = overlay.edit?.(dir);
|
|
154
|
+
for (const file of edited?.written ?? [])
|
|
155
|
+
files.add(file);
|
|
156
|
+
for (const file of edited?.removed ?? [])
|
|
157
|
+
files.delete(file);
|
|
158
|
+
}
|
|
159
|
+
writeFileSync(join(dir, "package.json"), JSON.stringify(pkg, null, 2) + "\n");
|
|
160
|
+
return { dir, name, files: [...files].sort() };
|
|
161
|
+
}
|
|
162
|
+
/** `<pm> install` in `dir` (inherits the terminal). Returns whether it succeeded. */
|
|
163
|
+
export function installDependencies(dir, pm, { stdio = "inherit" } = {}) {
|
|
164
|
+
const run = spawnSync(pm, pm === "yarn" ? [] : ["install"], { cwd: dir, stdio, shell: process.platform === "win32" });
|
|
165
|
+
return run.status === 0;
|
|
166
|
+
}
|
|
167
|
+
/** `git init` + first commit, unless git is missing or `dir` is already inside a work tree. */
|
|
168
|
+
export function initGit(dir) {
|
|
169
|
+
const git = (...args) => spawnSync("git", args, { cwd: dir, stdio: "pipe", encoding: "utf8" });
|
|
170
|
+
if (git("--version").status !== 0)
|
|
171
|
+
return "no-git";
|
|
172
|
+
if (git("rev-parse", "--is-inside-work-tree").stdout?.trim() === "true")
|
|
173
|
+
return "inside-repo";
|
|
174
|
+
if (git("init", "-q").status !== 0)
|
|
175
|
+
return "failed";
|
|
176
|
+
if (git("add", "-A").status !== 0)
|
|
177
|
+
return "failed";
|
|
178
|
+
// No identity configured: the repository stays initialised with the files staged.
|
|
179
|
+
return git("commit", "-q", "-m", "Initial commit from create-rivet").status === 0 ? "committed" : "created";
|
|
180
|
+
}
|
|
181
|
+
/** `dir` exists and is a file (not a folder). */
|
|
182
|
+
export function isFile(path) {
|
|
183
|
+
return existsSync(path) && !statSync(path).isDirectory();
|
|
184
|
+
}
|
package/main.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type PromptIO } from "./prompt.js";
|
|
2
|
+
export declare const HELP: string;
|
|
3
|
+
export interface MainIO extends PromptIO {
|
|
4
|
+
error: NodeJS.WritableStream;
|
|
5
|
+
cwd: string;
|
|
6
|
+
env: Record<string, string | undefined>;
|
|
7
|
+
}
|
|
8
|
+
/** Runs the command; resolves with the exit code (0 ok, 1 error, 130 cancelled). */
|
|
9
|
+
export declare function main(argv: string[], io: MainIO): Promise<number>;
|