create-ventura 0.1.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.
Files changed (3) hide show
  1. package/README.md +24 -0
  2. package/index.mjs +146 -0
  3. package/package.json +25 -0
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # create-ventura
2
+
3
+ Crea un proyecto nuevo con el **Ventura Stack** (React Router v7 + Bun + Tailwind v4 + Cloudflare Workers) en un solo comando.
4
+
5
+ ```bash
6
+ bunx create-ventura@latest mi-app
7
+ cd mi-app
8
+ bun run dev
9
+ ```
10
+
11
+ Opciones:
12
+
13
+ ```bash
14
+ bunx create-ventura@latest mi-app --name "Mi App" # nombre visible del proyecto
15
+ ```
16
+
17
+ Qué hace:
18
+
19
+ 1. Descarga el template (sin historial de git).
20
+ 2. `git init` + `bun install` (instala los git hooks vía `prepare`).
21
+ 3. Genera secrets aleatorios en `.dev.vars` y renombra `package.json`, `wrangler.toml` y `app/config/site.ts`.
22
+ 4. Deja un commit inicial limpio.
23
+
24
+ Requisitos: [Bun](https://bun.sh) y `tar` (incluido en Windows 10+, macOS y Linux).
package/index.mjs ADDED
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * create-ventura — scaffolding del Ventura Stack desde la terminal.
4
+ *
5
+ * Uso:
6
+ * bunx create-ventura@latest mi-app
7
+ * bunx create-ventura@latest mi-app --name "Mi App"
8
+ * npx create-ventura@latest mi-app
9
+ *
10
+ * Qué hace:
11
+ * 1. Descarga el template (tarball de la rama main, sin historial de git).
12
+ * 2. `git init` + `bun install` (instala git hooks vía `prepare`).
13
+ * 3. Corre el setup del template: genera secrets en `.dev.vars` y renombra
14
+ * package.json, wrangler.toml y app/config/site.ts al nombre elegido.
15
+ * 4. Deja un commit inicial limpio.
16
+ */
17
+ import { spawnSync } from 'node:child_process'
18
+ import { existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'
19
+ import { join, resolve } from 'node:path'
20
+ import { createInterface } from 'node:readline/promises'
21
+
22
+ const TEMPLATE_TARBALL =
23
+ 'https://codeload.github.com/izaack55182/ventura-starter/tar.gz/refs/heads/main'
24
+
25
+ const c = {
26
+ reset: '\x1b[0m',
27
+ bold: '\x1b[1m',
28
+ dim: '\x1b[2m',
29
+ green: '\x1b[32m',
30
+ cyan: '\x1b[36m',
31
+ red: '\x1b[31m',
32
+ }
33
+ const ok = (m) => console.log(`${c.green}✓${c.reset} ${m}`)
34
+ const info = (m) => console.log(`${c.cyan}›${c.reset} ${m}`)
35
+ const fail = (m) => {
36
+ console.error(`${c.red}✗ ${m}${c.reset}`)
37
+ process.exit(1)
38
+ }
39
+
40
+ /** Lee un flag de la forma `--name valor` o `--name=valor`. */
41
+ function getArg(name) {
42
+ const eq = process.argv.find((a) => a.startsWith(`--${name}=`))
43
+ if (eq) return eq.slice(name.length + 3)
44
+ const i = process.argv.indexOf(`--${name}`)
45
+ const next = process.argv[i + 1]
46
+ if (i !== -1 && next && !next.startsWith('--')) return next
47
+ return undefined
48
+ }
49
+
50
+ function toSlug(name) {
51
+ return name
52
+ .trim()
53
+ .toLowerCase()
54
+ .normalize('NFD')
55
+ .replace(/[̀-ͯ]/g, '')
56
+ .replace(/[^a-z0-9]+/g, '-')
57
+ .replace(/^-+|-+$/g, '')
58
+ }
59
+
60
+ /** "mi-app" -> "Mi App" */
61
+ function toDisplay(slug) {
62
+ return slug
63
+ .split('-')
64
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
65
+ .join(' ')
66
+ }
67
+
68
+ function run(cmd, args, cwd, label) {
69
+ const r = spawnSync(cmd, args, { cwd, stdio: 'inherit' })
70
+ if (r.status !== 0) fail(`Falló: ${label ?? `${cmd} ${args.join(' ')}`}`)
71
+ }
72
+
73
+ function has(cmd) {
74
+ return spawnSync(cmd, ['--version'], { stdio: 'ignore' }).status === 0
75
+ }
76
+
77
+ async function main() {
78
+ console.log(`\n${c.bold}${c.cyan}⚡ create-ventura${c.reset} — Ventura Stack\n`)
79
+
80
+ // 1. Directorio destino
81
+ let dir = process.argv[2] && !process.argv[2].startsWith('--') ? process.argv[2] : undefined
82
+ if (!dir && process.stdin.isTTY) {
83
+ const rl = createInterface({ input: process.stdin, output: process.stdout })
84
+ dir =
85
+ (
86
+ await rl.question(`${c.bold}Nombre del directorio${c.reset} ${c.dim}(mi-app)${c.reset} `)
87
+ ).trim() || 'mi-app'
88
+ rl.close()
89
+ }
90
+ if (!dir) fail('Indica el directorio: bunx create-ventura mi-app')
91
+
92
+ const slug = toSlug(dir)
93
+ const target = resolve(process.cwd(), dir)
94
+ if (existsSync(target) && readdirSync(target).length > 0) {
95
+ fail(`El directorio "${dir}" ya existe y no está vacío.`)
96
+ }
97
+ const displayName = getArg('name') ?? toDisplay(slug)
98
+
99
+ if (!has('bun')) fail('Se requiere Bun (https://bun.sh). Instálalo y reintenta.')
100
+
101
+ // 2. Descargar y extraer el template (sin historial de git)
102
+ info(`Descargando el template…`)
103
+ const res = await fetch(TEMPLATE_TARBALL)
104
+ if (!res.ok) fail(`No se pudo descargar el template (HTTP ${res.status}).`)
105
+ const tarball = Buffer.from(await res.arrayBuffer())
106
+ mkdirSync(target, { recursive: true })
107
+ // Extrae vía stdin y con cwd en el destino: sin rutas en los argumentos,
108
+ // funciona igual con bsdtar (Windows/macOS) y GNU tar (Linux, Git Bash).
109
+ const tar = spawnSync('tar', ['-xz', '--strip-components=1'], {
110
+ cwd: target,
111
+ input: tarball,
112
+ stdio: ['pipe', 'inherit', 'inherit'],
113
+ })
114
+ if (tar.status !== 0) fail('Falló: extraer el template')
115
+ // El paquete del CLI no forma parte de un proyecto nuevo.
116
+ rmSync(join(target, 'other', 'create-ventura'), { recursive: true, force: true })
117
+ ok(`Template copiado en ${dir}/`)
118
+
119
+ // 3. git init antes de instalar (bun install corre `prepare` → lefthook)
120
+ if (has('git')) run('git', ['init', '-q'], target)
121
+
122
+ info('Instalando dependencias (bun install)…')
123
+ run('bun', ['install'], target)
124
+
125
+ // 4. Setup del template: secrets + renombrado completo
126
+ run('bun', ['run', 'setup', '--name', displayName, '--slug', slug], target)
127
+
128
+ // 5. Commit inicial limpio (ya renombrado). --no-verify: es el snapshot del
129
+ // template tal cual; los hooks de lefthook aplican a los commits siguientes.
130
+ if (has('git')) {
131
+ run('git', ['add', '-A'], target)
132
+ const commit = spawnSync(
133
+ 'git',
134
+ ['commit', '-q', '--no-verify', '-m', 'Initial commit (create-ventura)'],
135
+ { cwd: target, stdio: 'ignore' }
136
+ )
137
+ if (commit.status === 0) ok('Commit inicial creado.')
138
+ else info('No se pudo crear el commit inicial (¿falta configurar git user.name/email?).')
139
+ }
140
+
141
+ console.log(`\n${c.bold}${c.green}Listo.${c.reset} Para empezar:\n`)
142
+ console.log(` cd ${dir}`)
143
+ console.log(` bun run dev\n`)
144
+ }
145
+
146
+ main().catch((e) => fail(e?.message ?? String(e)))
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "create-ventura",
3
+ "version": "0.1.0",
4
+ "description": "Crea un proyecto nuevo con el Ventura Stack (React Router v7 + Bun + Cloudflare Workers).",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-ventura": "index.mjs"
8
+ },
9
+ "files": [
10
+ "index.mjs"
11
+ ],
12
+ "engines": {
13
+ "node": ">=18"
14
+ },
15
+ "license": "MIT",
16
+ "keywords": [
17
+ "create",
18
+ "starter",
19
+ "template",
20
+ "react-router",
21
+ "bun",
22
+ "cloudflare",
23
+ "ventura"
24
+ ]
25
+ }