@revealui/cli 0.0.1-pre.1 → 0.2.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/LICENSE +22 -202
- package/README.md +86 -0
- package/bin/create-revealui.js +6 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +1075 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.js +1071 -123
- package/dist/index.js.map +1 -0
- package/package.json +42 -44
- package/templates/minimal/.env.example +36 -0
- package/templates/minimal/_gitignore +26 -0
- package/templates/minimal/next.config.mjs +10 -0
- package/templates/minimal/package.json +34 -0
- package/templates/minimal/revealui.config.ts +18 -0
- package/templates/minimal/src/app/globals.css +15 -0
- package/templates/minimal/src/app/layout.tsx +15 -0
- package/templates/minimal/src/app/page.tsx +20 -0
- package/templates/minimal/tsconfig.json +11 -0
- package/dist/commands/add.d.ts +0 -28
- package/dist/commands/add.d.ts.map +0 -1
- package/dist/commands/add.js +0 -115
- package/dist/commands/check.d.ts +0 -7
- package/dist/commands/check.d.ts.map +0 -1
- package/dist/commands/check.js +0 -34
- package/dist/commands/doctor/checks/build.d.ts +0 -10
- package/dist/commands/doctor/checks/build.d.ts.map +0 -1
- package/dist/commands/doctor/checks/build.js +0 -74
- package/dist/commands/doctor/checks/config.d.ts +0 -14
- package/dist/commands/doctor/checks/config.d.ts.map +0 -1
- package/dist/commands/doctor/checks/config.js +0 -116
- package/dist/commands/doctor/checks/dependencies.d.ts +0 -14
- package/dist/commands/doctor/checks/dependencies.d.ts.map +0 -1
- package/dist/commands/doctor/checks/dependencies.js +0 -126
- package/dist/commands/doctor/checks/practices.d.ts +0 -14
- package/dist/commands/doctor/checks/practices.d.ts.map +0 -1
- package/dist/commands/doctor/checks/practices.js +0 -142
- package/dist/commands/doctor/checks/structure.d.ts +0 -14
- package/dist/commands/doctor/checks/structure.d.ts.map +0 -1
- package/dist/commands/doctor/checks/structure.js +0 -107
- package/dist/commands/doctor/fixes/index.d.ts +0 -26
- package/dist/commands/doctor/fixes/index.d.ts.map +0 -1
- package/dist/commands/doctor/fixes/index.js +0 -108
- package/dist/commands/doctor/index.d.ts +0 -11
- package/dist/commands/doctor/index.d.ts.map +0 -1
- package/dist/commands/doctor/index.js +0 -37
- package/dist/commands/doctor/print.d.ts +0 -6
- package/dist/commands/doctor/print.d.ts.map +0 -1
- package/dist/commands/doctor/print.js +0 -31
- package/dist/commands/doctor/types.d.ts +0 -16
- package/dist/commands/doctor/types.d.ts.map +0 -1
- package/dist/commands/doctor/types.js +0 -1
- package/dist/commands/fix.d.ts +0 -5
- package/dist/commands/fix.d.ts.map +0 -1
- package/dist/commands/fix.js +0 -129
- package/dist/commands/init.d.ts +0 -35
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -104
- package/dist/commands/upgrade.d.ts +0 -9
- package/dist/commands/upgrade.d.ts.map +0 -1
- package/dist/commands/upgrade.js +0 -85
- package/dist/index.d.ts.map +0 -1
- package/dist/onLoad.d.ts +0 -3
- package/dist/onLoad.d.ts.map +0 -1
- package/dist/onLoad.js +0 -5
- package/dist/utils.d.ts +0 -3
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -6
package/dist/cli.js
ADDED
|
@@ -0,0 +1,1075 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __esm = (fn, res) => function __init() {
|
|
4
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
5
|
+
};
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.56.2_@types+node@25.3.0__@swc+core@1.15.11_@swc+h_406b258ea3c313c6308725a34065a5eb/node_modules/tsup/assets/esm_shims.js
|
|
12
|
+
import path from "path";
|
|
13
|
+
import { fileURLToPath } from "url";
|
|
14
|
+
var init_esm_shims = __esm({
|
|
15
|
+
"../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.56.2_@types+node@25.3.0__@swc+core@1.15.11_@swc+h_406b258ea3c313c6308725a34065a5eb/node_modules/tsup/assets/esm_shims.js"() {
|
|
16
|
+
"use strict";
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// src/validators/node-version.ts
|
|
21
|
+
import { createLogger } from "@revealui/setup/utils";
|
|
22
|
+
function validateNodeVersion() {
|
|
23
|
+
const currentVersion = process.version.slice(1);
|
|
24
|
+
const [currentMajor, currentMinor] = currentVersion.split(".").map(Number);
|
|
25
|
+
const [requiredMajor, requiredMinor] = REQUIRED_NODE_VERSION.split(".").map(Number);
|
|
26
|
+
if (currentMajor < requiredMajor || currentMajor === requiredMajor && currentMinor < requiredMinor) {
|
|
27
|
+
logger.error(
|
|
28
|
+
`Node.js ${REQUIRED_NODE_VERSION} or higher is required. You have ${currentVersion}.`
|
|
29
|
+
);
|
|
30
|
+
logger.info("Please upgrade Node.js: https://nodejs.org/");
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
var logger, REQUIRED_NODE_VERSION;
|
|
36
|
+
var init_node_version = __esm({
|
|
37
|
+
"src/validators/node-version.ts"() {
|
|
38
|
+
"use strict";
|
|
39
|
+
init_esm_shims();
|
|
40
|
+
logger = createLogger({ prefix: "Setup" });
|
|
41
|
+
REQUIRED_NODE_VERSION = "24.12.0";
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// src/generators/devbox.ts
|
|
46
|
+
import fs from "fs/promises";
|
|
47
|
+
import path2 from "path";
|
|
48
|
+
async function generateDevbox(projectPath) {
|
|
49
|
+
const devboxConfig = {
|
|
50
|
+
packages: ["nodejs@24.12.0", "pnpm@10.28.2", "postgresql@16", "stripe-cli@latest"],
|
|
51
|
+
shell: {
|
|
52
|
+
init_hook: [
|
|
53
|
+
"corepack enable",
|
|
54
|
+
'echo "\u{1F680} RevealUI Devbox shell ready!"',
|
|
55
|
+
'echo "Run: pnpm dev to start development"'
|
|
56
|
+
],
|
|
57
|
+
scripts: {
|
|
58
|
+
dev: "pnpm dev",
|
|
59
|
+
setup: "pnpm install && pnpm db:init",
|
|
60
|
+
test: "pnpm test"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
env: {
|
|
64
|
+
NODE_ENV: "development"
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
await fs.writeFile(
|
|
68
|
+
path2.join(projectPath, "devbox.json"),
|
|
69
|
+
JSON.stringify(devboxConfig, null, 2),
|
|
70
|
+
"utf-8"
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
var init_devbox = __esm({
|
|
74
|
+
"src/generators/devbox.ts"() {
|
|
75
|
+
"use strict";
|
|
76
|
+
init_esm_shims();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// src/generators/devcontainer.ts
|
|
81
|
+
import fs2 from "fs/promises";
|
|
82
|
+
import path3 from "path";
|
|
83
|
+
async function generateDevContainer(projectPath) {
|
|
84
|
+
const devcontainerDir = path3.join(projectPath, ".devcontainer");
|
|
85
|
+
await fs2.mkdir(devcontainerDir, { recursive: true });
|
|
86
|
+
const devcontainerConfig = {
|
|
87
|
+
name: "RevealUI Development",
|
|
88
|
+
image: "mcr.microsoft.com/devcontainers/typescript-node:24",
|
|
89
|
+
features: {
|
|
90
|
+
"ghcr.io/devcontainers/features/common-utils:2": {
|
|
91
|
+
installZsh: true,
|
|
92
|
+
installOhMyZsh: true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
forwardPorts: [3e3, 4e3, 5432],
|
|
96
|
+
portsAttributes: {
|
|
97
|
+
"3000": {
|
|
98
|
+
label: "Web App",
|
|
99
|
+
onAutoForward: "notify"
|
|
100
|
+
},
|
|
101
|
+
"4000": {
|
|
102
|
+
label: "CMS",
|
|
103
|
+
onAutoForward: "notify"
|
|
104
|
+
},
|
|
105
|
+
"5432": {
|
|
106
|
+
label: "PostgreSQL",
|
|
107
|
+
onAutoForward: "silent"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
postCreateCommand: "corepack enable && pnpm install",
|
|
111
|
+
customizations: {
|
|
112
|
+
vscode: {
|
|
113
|
+
extensions: [
|
|
114
|
+
"dbaeumer.vscode-eslint",
|
|
115
|
+
"biomejs.biome",
|
|
116
|
+
"bradlc.vscode-tailwindcss",
|
|
117
|
+
"Prisma.prisma",
|
|
118
|
+
"ms-azuretools.vscode-docker",
|
|
119
|
+
"streetsidesoftware.code-spell-checker"
|
|
120
|
+
],
|
|
121
|
+
settings: {
|
|
122
|
+
"editor.defaultFormatter": "biomejs.biome",
|
|
123
|
+
"editor.formatOnSave": true,
|
|
124
|
+
"editor.codeActionsOnSave": {
|
|
125
|
+
"quickfix.biome": "explicit",
|
|
126
|
+
"source.organizeImports.biome": "explicit"
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
remoteUser: "node"
|
|
132
|
+
};
|
|
133
|
+
await fs2.writeFile(
|
|
134
|
+
path3.join(devcontainerDir, "devcontainer.json"),
|
|
135
|
+
JSON.stringify(devcontainerConfig, null, 2),
|
|
136
|
+
"utf-8"
|
|
137
|
+
);
|
|
138
|
+
const dockerCompose = `version: '3.8'
|
|
139
|
+
|
|
140
|
+
services:
|
|
141
|
+
app:
|
|
142
|
+
build:
|
|
143
|
+
context: ..
|
|
144
|
+
dockerfile: .devcontainer/Dockerfile
|
|
145
|
+
volumes:
|
|
146
|
+
- ..:/workspace:cached
|
|
147
|
+
command: sleep infinity
|
|
148
|
+
network_mode: service:db
|
|
149
|
+
|
|
150
|
+
db:
|
|
151
|
+
image: pgvector/pgvector:pg16
|
|
152
|
+
restart: unless-stopped
|
|
153
|
+
environment:
|
|
154
|
+
POSTGRES_USER: postgres
|
|
155
|
+
POSTGRES_PASSWORD: postgres
|
|
156
|
+
POSTGRES_DB: revealui
|
|
157
|
+
volumes:
|
|
158
|
+
- postgres-data:/var/lib/postgresql/data
|
|
159
|
+
|
|
160
|
+
volumes:
|
|
161
|
+
postgres-data:
|
|
162
|
+
`;
|
|
163
|
+
await fs2.writeFile(path3.join(devcontainerDir, "docker-compose.yml"), dockerCompose, "utf-8");
|
|
164
|
+
const dockerfile = `FROM mcr.microsoft.com/devcontainers/typescript-node:24
|
|
165
|
+
|
|
166
|
+
# Install additional tools
|
|
167
|
+
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \\
|
|
168
|
+
&& apt-get -y install --no-install-recommends postgresql-client
|
|
169
|
+
|
|
170
|
+
# Enable pnpm
|
|
171
|
+
RUN corepack enable
|
|
172
|
+
`;
|
|
173
|
+
await fs2.writeFile(path3.join(devcontainerDir, "Dockerfile"), dockerfile, "utf-8");
|
|
174
|
+
const readme = `# Dev Container Setup
|
|
175
|
+
|
|
176
|
+
This directory contains the Dev Container configuration for RevealUI.
|
|
177
|
+
|
|
178
|
+
## Usage
|
|
179
|
+
|
|
180
|
+
### VS Code
|
|
181
|
+
|
|
182
|
+
1. Install the "Dev Containers" extension
|
|
183
|
+
2. Open this folder in VS Code
|
|
184
|
+
3. Press F1 and select "Dev Containers: Reopen in Container"
|
|
185
|
+
|
|
186
|
+
### GitHub Codespaces
|
|
187
|
+
|
|
188
|
+
1. Click the green "Code" button on GitHub
|
|
189
|
+
2. Select "Codespaces" tab
|
|
190
|
+
3. Click "Create codespace on main"
|
|
191
|
+
|
|
192
|
+
## What's Included
|
|
193
|
+
|
|
194
|
+
- Node.js 24.12.0
|
|
195
|
+
- pnpm package manager
|
|
196
|
+
- PostgreSQL 16 with pgvector
|
|
197
|
+
- VS Code extensions:
|
|
198
|
+
- ESLint
|
|
199
|
+
- Biome
|
|
200
|
+
- Tailwind CSS
|
|
201
|
+
- Prisma
|
|
202
|
+
- Docker
|
|
203
|
+
- Code Spell Checker
|
|
204
|
+
|
|
205
|
+
## Environment Variables
|
|
206
|
+
|
|
207
|
+
Environment variables are loaded from \`.env.development.local\`.
|
|
208
|
+
For GitHub Codespaces, set secrets in your repository settings.
|
|
209
|
+
|
|
210
|
+
## Ports
|
|
211
|
+
|
|
212
|
+
- 3000: Web application
|
|
213
|
+
- 4000: CMS
|
|
214
|
+
- 5432: PostgreSQL database
|
|
215
|
+
`;
|
|
216
|
+
await fs2.writeFile(path3.join(devcontainerDir, "README.md"), readme, "utf-8");
|
|
217
|
+
}
|
|
218
|
+
var init_devcontainer = __esm({
|
|
219
|
+
"src/generators/devcontainer.ts"() {
|
|
220
|
+
"use strict";
|
|
221
|
+
init_esm_shims();
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// src/generators/readme.ts
|
|
226
|
+
import fs3 from "fs/promises";
|
|
227
|
+
import path4 from "path";
|
|
228
|
+
async function generateReadme(projectPath, projectConfig) {
|
|
229
|
+
const readme = `# ${projectConfig.projectName}
|
|
230
|
+
|
|
231
|
+
A RevealUI project created with @revealui/cli.
|
|
232
|
+
|
|
233
|
+
## Getting Started
|
|
234
|
+
|
|
235
|
+
First, install dependencies:
|
|
236
|
+
|
|
237
|
+
\`\`\`bash
|
|
238
|
+
pnpm install
|
|
239
|
+
\`\`\`
|
|
240
|
+
|
|
241
|
+
Then, initialize the database:
|
|
242
|
+
|
|
243
|
+
\`\`\`bash
|
|
244
|
+
pnpm db:init
|
|
245
|
+
pnpm db:migrate
|
|
246
|
+
\`\`\`
|
|
247
|
+
|
|
248
|
+
Run the development server:
|
|
249
|
+
|
|
250
|
+
\`\`\`bash
|
|
251
|
+
pnpm dev
|
|
252
|
+
\`\`\`
|
|
253
|
+
|
|
254
|
+
Open [http://localhost:4000](http://localhost:4000) with your browser to access the CMS.
|
|
255
|
+
|
|
256
|
+
The web application runs on [http://localhost:3000](http://localhost:3000).
|
|
257
|
+
|
|
258
|
+
## Development Environments
|
|
259
|
+
|
|
260
|
+
### Standard Setup
|
|
261
|
+
|
|
262
|
+
Requirements:
|
|
263
|
+
- Node.js 24.12.0 or higher
|
|
264
|
+
- pnpm 10.28.2 or higher
|
|
265
|
+
- PostgreSQL 16
|
|
266
|
+
|
|
267
|
+
### Dev Containers
|
|
268
|
+
|
|
269
|
+
Open in VS Code and select "Reopen in Container", or use GitHub Codespaces.
|
|
270
|
+
|
|
271
|
+
### Devbox
|
|
272
|
+
|
|
273
|
+
Install Devbox:
|
|
274
|
+
|
|
275
|
+
\`\`\`bash
|
|
276
|
+
curl -fsSL https://get.jetpack.io/devbox | bash
|
|
277
|
+
\`\`\`
|
|
278
|
+
|
|
279
|
+
Then start the Devbox shell:
|
|
280
|
+
|
|
281
|
+
\`\`\`bash
|
|
282
|
+
devbox shell
|
|
283
|
+
pnpm dev
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
286
|
+
## Project Structure
|
|
287
|
+
|
|
288
|
+
\`\`\`
|
|
289
|
+
${projectConfig.projectName}/
|
|
290
|
+
\u251C\u2500\u2500 apps/
|
|
291
|
+
\u2502 \u251C\u2500\u2500 cms/ # CMS application
|
|
292
|
+
\u2502 \u2514\u2500\u2500 web/ # Frontend application
|
|
293
|
+
\u251C\u2500\u2500 packages/
|
|
294
|
+
\u2502 \u251C\u2500\u2500 auth/ # Authentication
|
|
295
|
+
\u2502 \u251C\u2500\u2500 db/ # Database
|
|
296
|
+
\u2502 \u2514\u2500\u2500 ... # Other shared packages
|
|
297
|
+
\u251C\u2500\u2500 .devcontainer/ # Dev Container configuration
|
|
298
|
+
\u251C\u2500\u2500 devbox.json # Devbox configuration
|
|
299
|
+
\u2514\u2500\u2500 .env.development.local # Environment variables
|
|
300
|
+
\`\`\`
|
|
301
|
+
|
|
302
|
+
## Available Scripts
|
|
303
|
+
|
|
304
|
+
- \`pnpm dev\` - Start development servers
|
|
305
|
+
- \`pnpm build\` - Build for production
|
|
306
|
+
- \`pnpm test\` - Run tests
|
|
307
|
+
- \`pnpm lint\` - Run linters
|
|
308
|
+
- \`pnpm typecheck\` - Type check
|
|
309
|
+
- \`pnpm db:init\` - Initialize database
|
|
310
|
+
- \`pnpm db:migrate\` - Run migrations
|
|
311
|
+
- \`pnpm db:seed\` - Seed database
|
|
312
|
+
|
|
313
|
+
## Learn More
|
|
314
|
+
|
|
315
|
+
- [RevealUI Documentation](https://github.com/your-org/RevealUI)
|
|
316
|
+
- [Next.js Documentation](https://nextjs.org/docs)
|
|
317
|
+
- [Hono Documentation](https://hono.dev)
|
|
318
|
+
|
|
319
|
+
## Template
|
|
320
|
+
|
|
321
|
+
This project was created using the **${projectConfig.template}** template.
|
|
322
|
+
|
|
323
|
+
## License
|
|
324
|
+
|
|
325
|
+
MIT
|
|
326
|
+
`;
|
|
327
|
+
await fs3.writeFile(path4.join(projectPath, "README.md"), readme, "utf-8");
|
|
328
|
+
}
|
|
329
|
+
var init_readme = __esm({
|
|
330
|
+
"src/generators/readme.ts"() {
|
|
331
|
+
"use strict";
|
|
332
|
+
init_esm_shims();
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// src/installers/dependencies.ts
|
|
337
|
+
import { createLogger as createLogger2 } from "@revealui/setup/utils";
|
|
338
|
+
import { execa } from "execa";
|
|
339
|
+
import ora from "ora";
|
|
340
|
+
async function installDependencies(projectPath) {
|
|
341
|
+
const spinner = ora("Installing dependencies with pnpm...").start();
|
|
342
|
+
try {
|
|
343
|
+
await execa("pnpm", ["install"], {
|
|
344
|
+
cwd: projectPath,
|
|
345
|
+
stdio: "pipe"
|
|
346
|
+
});
|
|
347
|
+
spinner.succeed("Dependencies installed successfully");
|
|
348
|
+
} catch (error) {
|
|
349
|
+
spinner.fail("Failed to install dependencies");
|
|
350
|
+
logger2.error('Please run "pnpm install" manually');
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async function isPnpmInstalled() {
|
|
355
|
+
try {
|
|
356
|
+
await execa("pnpm", ["--version"]);
|
|
357
|
+
return true;
|
|
358
|
+
} catch {
|
|
359
|
+
return false;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
var logger2;
|
|
363
|
+
var init_dependencies = __esm({
|
|
364
|
+
"src/installers/dependencies.ts"() {
|
|
365
|
+
"use strict";
|
|
366
|
+
init_esm_shims();
|
|
367
|
+
logger2 = createLogger2({ prefix: "Install" });
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
// src/utils/git.ts
|
|
372
|
+
import { createLogger as createLogger3 } from "@revealui/setup/utils";
|
|
373
|
+
import { execa as execa2 } from "execa";
|
|
374
|
+
async function initializeGitRepo(projectPath) {
|
|
375
|
+
try {
|
|
376
|
+
await execa2("git", ["init"], { cwd: projectPath });
|
|
377
|
+
logger3.success("Initialized git repository");
|
|
378
|
+
} catch (error) {
|
|
379
|
+
logger3.warn("Failed to initialize git repository");
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async function createInitialCommit(projectPath) {
|
|
384
|
+
try {
|
|
385
|
+
await execa2("git", ["add", "."], { cwd: projectPath });
|
|
386
|
+
await execa2("git", ["commit", "-m", "Initial commit from @revealui/cli"], { cwd: projectPath });
|
|
387
|
+
logger3.success("Created initial commit");
|
|
388
|
+
} catch (error) {
|
|
389
|
+
logger3.warn("Failed to create initial commit");
|
|
390
|
+
throw error;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function isGitInstalled() {
|
|
394
|
+
try {
|
|
395
|
+
await execa2("git", ["--version"]);
|
|
396
|
+
return true;
|
|
397
|
+
} catch {
|
|
398
|
+
return false;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
var logger3;
|
|
402
|
+
var init_git = __esm({
|
|
403
|
+
"src/utils/git.ts"() {
|
|
404
|
+
"use strict";
|
|
405
|
+
init_esm_shims();
|
|
406
|
+
logger3 = createLogger3({ prefix: "Git" });
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// src/commands/create.ts
|
|
411
|
+
import crypto from "crypto";
|
|
412
|
+
import fs4 from "fs/promises";
|
|
413
|
+
import path5 from "path";
|
|
414
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
415
|
+
import { createLogger as createLogger4 } from "@revealui/setup/utils";
|
|
416
|
+
import ora2 from "ora";
|
|
417
|
+
function buildEnvLocal(cfg) {
|
|
418
|
+
const lines = [
|
|
419
|
+
"# Generated by @revealui/cli \u2014 fill in the remaining placeholders before running `pnpm dev`",
|
|
420
|
+
"",
|
|
421
|
+
"# Core",
|
|
422
|
+
`REVEALUI_SECRET=${generateSecret()}`,
|
|
423
|
+
`REVEALUI_PUBLIC_SERVER_URL=http://localhost:4000`,
|
|
424
|
+
`NEXT_PUBLIC_SERVER_URL=http://localhost:4000`,
|
|
425
|
+
"",
|
|
426
|
+
"# Database"
|
|
427
|
+
];
|
|
428
|
+
if (cfg.database.postgresUrl) {
|
|
429
|
+
lines.push(`POSTGRES_URL=${cfg.database.postgresUrl}`);
|
|
430
|
+
} else {
|
|
431
|
+
lines.push("POSTGRES_URL=postgresql://postgres:postgres@localhost:5432/revealui");
|
|
432
|
+
}
|
|
433
|
+
lines.push("", "# Storage (Vercel Blob)");
|
|
434
|
+
if (cfg.storage.provider === "vercel-blob" && cfg.storage.blobToken) {
|
|
435
|
+
lines.push(`BLOB_READ_WRITE_TOKEN=${cfg.storage.blobToken}`);
|
|
436
|
+
} else {
|
|
437
|
+
lines.push("BLOB_READ_WRITE_TOKEN=vercel_blob_rw_placeholder");
|
|
438
|
+
}
|
|
439
|
+
lines.push("", "# Stripe");
|
|
440
|
+
if (cfg.payment.enabled && cfg.payment.stripeSecretKey) {
|
|
441
|
+
lines.push(`STRIPE_SECRET_KEY=${cfg.payment.stripeSecretKey}`);
|
|
442
|
+
lines.push(`STRIPE_WEBHOOK_SECRET=${cfg.payment.stripeWebhookSecret || "whsec_placeholder"}`);
|
|
443
|
+
lines.push(
|
|
444
|
+
`NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${cfg.payment.stripePublishableKey || "pk_test_placeholder"}`
|
|
445
|
+
);
|
|
446
|
+
} else {
|
|
447
|
+
lines.push("STRIPE_SECRET_KEY=sk_test_placeholder");
|
|
448
|
+
lines.push("STRIPE_WEBHOOK_SECRET=whsec_placeholder");
|
|
449
|
+
lines.push("NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_placeholder");
|
|
450
|
+
}
|
|
451
|
+
lines.push("", "# Admin bootstrap (used on first run only)");
|
|
452
|
+
lines.push("REVEALUI_ADMIN_EMAIL=admin@example.com");
|
|
453
|
+
lines.push("REVEALUI_ADMIN_PASSWORD=changeme-min-12-chars");
|
|
454
|
+
return `${lines.join("\n")}
|
|
455
|
+
`;
|
|
456
|
+
}
|
|
457
|
+
function generateSecret() {
|
|
458
|
+
return crypto.randomBytes(24).toString("hex");
|
|
459
|
+
}
|
|
460
|
+
async function copyTemplate(templateName, targetPath) {
|
|
461
|
+
const templatePath = path5.join(TEMPLATES_DIR, templateName);
|
|
462
|
+
try {
|
|
463
|
+
await fs4.access(templatePath);
|
|
464
|
+
} catch {
|
|
465
|
+
throw new Error(
|
|
466
|
+
`Template "${templateName}" not found at ${templatePath}. Available templates: minimal, basic-blog, e-commerce, portfolio`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
await copyDir(templatePath, targetPath);
|
|
470
|
+
}
|
|
471
|
+
async function copyDir(src, dest) {
|
|
472
|
+
await fs4.mkdir(dest, { recursive: true });
|
|
473
|
+
const entries = await fs4.readdir(src, { withFileTypes: true });
|
|
474
|
+
for (const entry of entries) {
|
|
475
|
+
const srcPath = path5.join(src, entry.name);
|
|
476
|
+
const destName = entry.name === "_gitignore" ? ".gitignore" : entry.name;
|
|
477
|
+
const destPath = path5.join(dest, destName);
|
|
478
|
+
if (entry.isDirectory()) {
|
|
479
|
+
await copyDir(srcPath, destPath);
|
|
480
|
+
} else {
|
|
481
|
+
await fs4.copyFile(srcPath, destPath);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
function resolveTemplateName(template) {
|
|
486
|
+
const map = {
|
|
487
|
+
"basic-blog": "minimal",
|
|
488
|
+
"e-commerce": "minimal",
|
|
489
|
+
portfolio: "minimal"
|
|
490
|
+
};
|
|
491
|
+
return map[template] ?? "minimal";
|
|
492
|
+
}
|
|
493
|
+
async function createProject(cfg) {
|
|
494
|
+
const { project, skipGit = false, skipInstall = false } = cfg;
|
|
495
|
+
const { projectPath, projectName, template } = project;
|
|
496
|
+
const spinner = ora2(`Copying template "${template}"...`).start();
|
|
497
|
+
try {
|
|
498
|
+
await copyTemplate(resolveTemplateName(template), projectPath);
|
|
499
|
+
spinner.succeed("Template files copied");
|
|
500
|
+
} catch (err) {
|
|
501
|
+
spinner.fail("Failed to copy template files");
|
|
502
|
+
throw err;
|
|
503
|
+
}
|
|
504
|
+
const pkgJsonPath = path5.join(projectPath, "package.json");
|
|
505
|
+
try {
|
|
506
|
+
const raw = await fs4.readFile(pkgJsonPath, "utf-8");
|
|
507
|
+
await fs4.writeFile(pkgJsonPath, raw.replaceAll("{{PROJECT_NAME}}", projectName), "utf-8");
|
|
508
|
+
} catch {
|
|
509
|
+
}
|
|
510
|
+
const envSpinner = ora2("Writing .env.local...").start();
|
|
511
|
+
try {
|
|
512
|
+
await fs4.writeFile(path5.join(projectPath, ".env.local"), buildEnvLocal(cfg), "utf-8");
|
|
513
|
+
envSpinner.succeed(".env.local written");
|
|
514
|
+
} catch (err) {
|
|
515
|
+
envSpinner.fail("Failed to write .env.local");
|
|
516
|
+
throw err;
|
|
517
|
+
}
|
|
518
|
+
await generateReadme(projectPath, project);
|
|
519
|
+
logger4.success("README.md generated");
|
|
520
|
+
if (cfg.devenv.createDevContainer) {
|
|
521
|
+
await generateDevContainer(projectPath);
|
|
522
|
+
logger4.success(".devcontainer/ generated");
|
|
523
|
+
}
|
|
524
|
+
if (cfg.devenv.createDevbox) {
|
|
525
|
+
await generateDevbox(projectPath);
|
|
526
|
+
logger4.success("devbox.json generated");
|
|
527
|
+
}
|
|
528
|
+
if (!skipInstall) {
|
|
529
|
+
const pnpmOk = await isPnpmInstalled();
|
|
530
|
+
if (!pnpmOk) {
|
|
531
|
+
logger4.warn("pnpm not found \u2014 skipping dependency installation. Run `pnpm install` manually.");
|
|
532
|
+
} else {
|
|
533
|
+
await installDependencies(projectPath);
|
|
534
|
+
}
|
|
535
|
+
} else {
|
|
536
|
+
logger4.info("Skipping dependency installation (--skip-install)");
|
|
537
|
+
}
|
|
538
|
+
if (!skipGit) {
|
|
539
|
+
const gitOk = await isGitInstalled();
|
|
540
|
+
if (!gitOk) {
|
|
541
|
+
logger4.warn("git not found \u2014 skipping repository initialisation.");
|
|
542
|
+
} else {
|
|
543
|
+
await initializeGitRepo(projectPath);
|
|
544
|
+
await createInitialCommit(projectPath);
|
|
545
|
+
}
|
|
546
|
+
} else {
|
|
547
|
+
logger4.info("Skipping git initialisation (--skip-git)");
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
var logger4, __filename2, __dirname2, TEMPLATES_DIR;
|
|
551
|
+
var init_create = __esm({
|
|
552
|
+
"src/commands/create.ts"() {
|
|
553
|
+
"use strict";
|
|
554
|
+
init_esm_shims();
|
|
555
|
+
init_devbox();
|
|
556
|
+
init_devcontainer();
|
|
557
|
+
init_readme();
|
|
558
|
+
init_dependencies();
|
|
559
|
+
init_git();
|
|
560
|
+
logger4 = createLogger4({ prefix: "Create" });
|
|
561
|
+
__filename2 = fileURLToPath2(import.meta.url);
|
|
562
|
+
__dirname2 = path5.dirname(__filename2);
|
|
563
|
+
TEMPLATES_DIR = path5.resolve(__dirname2, "../../templates");
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// src/validators/credentials.ts
|
|
568
|
+
import { createLogger as createLogger5 } from "@revealui/setup/utils";
|
|
569
|
+
async function validateStripeKey(key) {
|
|
570
|
+
if (!(key.startsWith("sk_test_") || key.startsWith("sk_live_"))) {
|
|
571
|
+
return {
|
|
572
|
+
valid: false,
|
|
573
|
+
message: "Stripe key must start with sk_test_ or sk_live_"
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
return { valid: true };
|
|
577
|
+
}
|
|
578
|
+
async function validateNeonUrl(url) {
|
|
579
|
+
try {
|
|
580
|
+
const parsed = new URL(url);
|
|
581
|
+
if (!parsed.protocol.startsWith("postgres")) {
|
|
582
|
+
return {
|
|
583
|
+
valid: false,
|
|
584
|
+
message: "Database URL must use postgres:// or postgresql:// protocol"
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
return { valid: true };
|
|
588
|
+
} catch {
|
|
589
|
+
return {
|
|
590
|
+
valid: false,
|
|
591
|
+
message: "Invalid database URL format"
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
async function validateVercelToken(token) {
|
|
596
|
+
if (!token || token.length < 20) {
|
|
597
|
+
return {
|
|
598
|
+
valid: false,
|
|
599
|
+
message: "Vercel token appears invalid (too short)"
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
return { valid: true };
|
|
603
|
+
}
|
|
604
|
+
async function validateSupabaseUrl(url) {
|
|
605
|
+
try {
|
|
606
|
+
const parsed = new URL(url);
|
|
607
|
+
if (!parsed.hostname.includes("supabase")) {
|
|
608
|
+
logger5.warn("URL does not appear to be a Supabase URL");
|
|
609
|
+
}
|
|
610
|
+
return { valid: true };
|
|
611
|
+
} catch {
|
|
612
|
+
return {
|
|
613
|
+
valid: false,
|
|
614
|
+
message: "Invalid Supabase URL format"
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
var logger5;
|
|
619
|
+
var init_credentials = __esm({
|
|
620
|
+
"src/validators/credentials.ts"() {
|
|
621
|
+
"use strict";
|
|
622
|
+
init_esm_shims();
|
|
623
|
+
logger5 = createLogger5({ prefix: "Validator" });
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
// src/prompts/database.ts
|
|
628
|
+
import inquirer from "inquirer";
|
|
629
|
+
async function promptDatabaseConfig() {
|
|
630
|
+
const { provider } = await inquirer.prompt([
|
|
631
|
+
{
|
|
632
|
+
type: "list",
|
|
633
|
+
name: "provider",
|
|
634
|
+
message: "Which database provider would you like to use?",
|
|
635
|
+
choices: [
|
|
636
|
+
{
|
|
637
|
+
name: "NeonDB - Serverless PostgreSQL (recommended)",
|
|
638
|
+
value: "neon"
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
name: "Supabase - PostgreSQL with built-in features",
|
|
642
|
+
value: "supabase"
|
|
643
|
+
},
|
|
644
|
+
{
|
|
645
|
+
name: "Local PostgreSQL - Use existing local database",
|
|
646
|
+
value: "local"
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
name: "Skip - Configure later",
|
|
650
|
+
value: "skip"
|
|
651
|
+
}
|
|
652
|
+
],
|
|
653
|
+
default: "neon"
|
|
654
|
+
}
|
|
655
|
+
]);
|
|
656
|
+
if (provider === "skip") {
|
|
657
|
+
return { provider: "skip" };
|
|
658
|
+
}
|
|
659
|
+
if (provider === "local") {
|
|
660
|
+
const { postgresUrl: postgresUrl2 } = await inquirer.prompt([
|
|
661
|
+
{
|
|
662
|
+
type: "input",
|
|
663
|
+
name: "postgresUrl",
|
|
664
|
+
message: "Enter your PostgreSQL connection string:",
|
|
665
|
+
default: "postgresql://postgres:postgres@localhost:5432/revealui",
|
|
666
|
+
validate: async (input) => {
|
|
667
|
+
const result = await validateNeonUrl(input);
|
|
668
|
+
return result.valid ? true : result.message || "Invalid database URL";
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
]);
|
|
672
|
+
return { provider: "local", postgresUrl: postgresUrl2 };
|
|
673
|
+
}
|
|
674
|
+
const { postgresUrl } = await inquirer.prompt([
|
|
675
|
+
{
|
|
676
|
+
type: "input",
|
|
677
|
+
name: "postgresUrl",
|
|
678
|
+
message: `Enter your ${provider === "neon" ? "Neon" : "Supabase"} database connection string:`,
|
|
679
|
+
validate: async (input) => {
|
|
680
|
+
if (!input || input.trim() === "") {
|
|
681
|
+
return "Database URL is required";
|
|
682
|
+
}
|
|
683
|
+
const result = await validateNeonUrl(input);
|
|
684
|
+
return result.valid ? true : result.message || "Invalid database URL";
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
]);
|
|
688
|
+
return { provider, postgresUrl };
|
|
689
|
+
}
|
|
690
|
+
var init_database = __esm({
|
|
691
|
+
"src/prompts/database.ts"() {
|
|
692
|
+
"use strict";
|
|
693
|
+
init_esm_shims();
|
|
694
|
+
init_credentials();
|
|
695
|
+
}
|
|
696
|
+
});
|
|
697
|
+
|
|
698
|
+
// src/prompts/devenv.ts
|
|
699
|
+
import inquirer2 from "inquirer";
|
|
700
|
+
async function promptDevEnvConfig() {
|
|
701
|
+
const answers = await inquirer2.prompt([
|
|
702
|
+
{
|
|
703
|
+
type: "confirm",
|
|
704
|
+
name: "createDevContainer",
|
|
705
|
+
message: "Create Dev Container configuration for VS Code / GitHub Codespaces?",
|
|
706
|
+
default: true
|
|
707
|
+
},
|
|
708
|
+
{
|
|
709
|
+
type: "confirm",
|
|
710
|
+
name: "createDevbox",
|
|
711
|
+
message: "Create Devbox configuration for Nix-powered development?",
|
|
712
|
+
default: true
|
|
713
|
+
}
|
|
714
|
+
]);
|
|
715
|
+
return answers;
|
|
716
|
+
}
|
|
717
|
+
var init_devenv = __esm({
|
|
718
|
+
"src/prompts/devenv.ts"() {
|
|
719
|
+
"use strict";
|
|
720
|
+
init_esm_shims();
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
// src/prompts/payments.ts
|
|
725
|
+
import inquirer3 from "inquirer";
|
|
726
|
+
async function promptPaymentConfig() {
|
|
727
|
+
const { enabled } = await inquirer3.prompt([
|
|
728
|
+
{
|
|
729
|
+
type: "confirm",
|
|
730
|
+
name: "enabled",
|
|
731
|
+
message: "Do you want to configure Stripe payments?",
|
|
732
|
+
default: true
|
|
733
|
+
}
|
|
734
|
+
]);
|
|
735
|
+
if (!enabled) {
|
|
736
|
+
return { enabled: false };
|
|
737
|
+
}
|
|
738
|
+
const answers = await inquirer3.prompt([
|
|
739
|
+
{
|
|
740
|
+
type: "input",
|
|
741
|
+
name: "stripeSecretKey",
|
|
742
|
+
message: "Enter your Stripe secret key (sk_test_... or sk_live_...):",
|
|
743
|
+
validate: async (input) => {
|
|
744
|
+
if (!input || input.trim() === "") {
|
|
745
|
+
return "Stripe secret key is required";
|
|
746
|
+
}
|
|
747
|
+
const result = await validateStripeKey(input);
|
|
748
|
+
return result.valid ? true : result.message || "Invalid Stripe key";
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
{
|
|
752
|
+
type: "input",
|
|
753
|
+
name: "stripePublishableKey",
|
|
754
|
+
message: "Enter your Stripe publishable key (pk_test_... or pk_live_...):",
|
|
755
|
+
validate: (input) => {
|
|
756
|
+
if (!input || input.trim() === "") {
|
|
757
|
+
return "Stripe publishable key is required";
|
|
758
|
+
}
|
|
759
|
+
if (!(input.startsWith("pk_test_") || input.startsWith("pk_live_"))) {
|
|
760
|
+
return "Stripe publishable key must start with pk_test_ or pk_live_";
|
|
761
|
+
}
|
|
762
|
+
return true;
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
type: "input",
|
|
767
|
+
name: "stripeWebhookSecret",
|
|
768
|
+
message: "Enter your Stripe webhook secret (whsec_..., optional - press Enter to skip):",
|
|
769
|
+
default: ""
|
|
770
|
+
}
|
|
771
|
+
]);
|
|
772
|
+
return {
|
|
773
|
+
enabled: true,
|
|
774
|
+
stripeSecretKey: answers.stripeSecretKey,
|
|
775
|
+
stripePublishableKey: answers.stripePublishableKey,
|
|
776
|
+
stripeWebhookSecret: answers.stripeWebhookSecret || void 0
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
var init_payments = __esm({
|
|
780
|
+
"src/prompts/payments.ts"() {
|
|
781
|
+
"use strict";
|
|
782
|
+
init_esm_shims();
|
|
783
|
+
init_credentials();
|
|
784
|
+
}
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
// src/prompts/project.ts
|
|
788
|
+
import fs5 from "fs";
|
|
789
|
+
import path6 from "path";
|
|
790
|
+
import inquirer4 from "inquirer";
|
|
791
|
+
async function promptProjectConfig(defaultName) {
|
|
792
|
+
const answers = await inquirer4.prompt([
|
|
793
|
+
{
|
|
794
|
+
type: "input",
|
|
795
|
+
name: "projectName",
|
|
796
|
+
message: "What is your project name?",
|
|
797
|
+
default: defaultName || "my-revealui-project",
|
|
798
|
+
validate: (input) => {
|
|
799
|
+
if (!/^[a-z0-9-]+$/.test(input)) {
|
|
800
|
+
return "Project name must contain only lowercase letters, numbers, and hyphens";
|
|
801
|
+
}
|
|
802
|
+
const projectPath = path6.resolve(process.cwd(), input);
|
|
803
|
+
if (fs5.existsSync(projectPath)) {
|
|
804
|
+
return `Directory "${input}" already exists`;
|
|
805
|
+
}
|
|
806
|
+
return true;
|
|
807
|
+
}
|
|
808
|
+
},
|
|
809
|
+
{
|
|
810
|
+
type: "list",
|
|
811
|
+
name: "template",
|
|
812
|
+
message: "Which template would you like to use?",
|
|
813
|
+
choices: [
|
|
814
|
+
{
|
|
815
|
+
name: "Basic Blog - A simple blog with posts and pages",
|
|
816
|
+
value: "basic-blog"
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
name: "E-commerce - Product catalog with checkout",
|
|
820
|
+
value: "e-commerce"
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: "Portfolio - Personal portfolio site",
|
|
824
|
+
value: "portfolio"
|
|
825
|
+
}
|
|
826
|
+
],
|
|
827
|
+
default: "basic-blog"
|
|
828
|
+
}
|
|
829
|
+
]);
|
|
830
|
+
return {
|
|
831
|
+
projectName: answers.projectName,
|
|
832
|
+
projectPath: path6.resolve(process.cwd(), answers.projectName),
|
|
833
|
+
template: answers.template
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
var init_project = __esm({
|
|
837
|
+
"src/prompts/project.ts"() {
|
|
838
|
+
"use strict";
|
|
839
|
+
init_esm_shims();
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
|
|
843
|
+
// src/prompts/storage.ts
|
|
844
|
+
import inquirer5 from "inquirer";
|
|
845
|
+
async function promptStorageConfig() {
|
|
846
|
+
const { provider } = await inquirer5.prompt([
|
|
847
|
+
{
|
|
848
|
+
type: "list",
|
|
849
|
+
name: "provider",
|
|
850
|
+
message: "Which storage provider would you like to use?",
|
|
851
|
+
choices: [
|
|
852
|
+
{
|
|
853
|
+
name: "Vercel Blob - Simple object storage (recommended)",
|
|
854
|
+
value: "vercel-blob"
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
name: "Supabase Storage - Integrated with Supabase",
|
|
858
|
+
value: "supabase"
|
|
859
|
+
},
|
|
860
|
+
{
|
|
861
|
+
name: "Skip - Configure later",
|
|
862
|
+
value: "skip"
|
|
863
|
+
}
|
|
864
|
+
],
|
|
865
|
+
default: "vercel-blob"
|
|
866
|
+
}
|
|
867
|
+
]);
|
|
868
|
+
if (provider === "skip") {
|
|
869
|
+
return { provider: "skip" };
|
|
870
|
+
}
|
|
871
|
+
if (provider === "vercel-blob") {
|
|
872
|
+
const { blobToken } = await inquirer5.prompt([
|
|
873
|
+
{
|
|
874
|
+
type: "input",
|
|
875
|
+
name: "blobToken",
|
|
876
|
+
message: "Enter your Vercel Blob read/write token:",
|
|
877
|
+
validate: async (input) => {
|
|
878
|
+
if (!input || input.trim() === "") {
|
|
879
|
+
return "Blob token is required";
|
|
880
|
+
}
|
|
881
|
+
const result = await validateVercelToken(input);
|
|
882
|
+
return result.valid ? true : result.message || "Invalid token";
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
]);
|
|
886
|
+
return { provider: "vercel-blob", blobToken };
|
|
887
|
+
}
|
|
888
|
+
const answers = await inquirer5.prompt([
|
|
889
|
+
{
|
|
890
|
+
type: "input",
|
|
891
|
+
name: "supabaseUrl",
|
|
892
|
+
message: "Enter your Supabase project URL:",
|
|
893
|
+
validate: async (input) => {
|
|
894
|
+
if (!input || input.trim() === "") {
|
|
895
|
+
return "Supabase URL is required";
|
|
896
|
+
}
|
|
897
|
+
const result = await validateSupabaseUrl(input);
|
|
898
|
+
return result.valid ? true : result.message || "Invalid URL";
|
|
899
|
+
}
|
|
900
|
+
},
|
|
901
|
+
{
|
|
902
|
+
type: "input",
|
|
903
|
+
name: "supabaseAnonKey",
|
|
904
|
+
message: "Enter your Supabase anonymous key:",
|
|
905
|
+
validate: (input) => {
|
|
906
|
+
if (!input || input.trim() === "") {
|
|
907
|
+
return "Supabase anonymous key is required";
|
|
908
|
+
}
|
|
909
|
+
return true;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
]);
|
|
913
|
+
return {
|
|
914
|
+
provider: "supabase",
|
|
915
|
+
supabaseUrl: answers.supabaseUrl,
|
|
916
|
+
supabaseAnonKey: answers.supabaseAnonKey
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
var init_storage = __esm({
|
|
920
|
+
"src/prompts/storage.ts"() {
|
|
921
|
+
"use strict";
|
|
922
|
+
init_esm_shims();
|
|
923
|
+
init_credentials();
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
// src/index.ts
|
|
928
|
+
var index_exports = {};
|
|
929
|
+
__export(index_exports, {
|
|
930
|
+
run: () => run
|
|
931
|
+
});
|
|
932
|
+
import { readFileSync } from "fs";
|
|
933
|
+
import { homedir } from "os";
|
|
934
|
+
import { join } from "path";
|
|
935
|
+
import { createLogger as createLogger6 } from "@revealui/setup/utils";
|
|
936
|
+
function checkProLicense() {
|
|
937
|
+
let key = process.env.REVEALUI_LICENSE_KEY;
|
|
938
|
+
if (!key) {
|
|
939
|
+
try {
|
|
940
|
+
const licenseFile = join(homedir(), ".revealui", "license.json");
|
|
941
|
+
const parsed = JSON.parse(readFileSync(licenseFile, "utf8"));
|
|
942
|
+
key = parsed.key;
|
|
943
|
+
} catch {
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (!key) return false;
|
|
947
|
+
try {
|
|
948
|
+
const parts = key.split(".");
|
|
949
|
+
if (parts.length < 2) return false;
|
|
950
|
+
const payload = JSON.parse(Buffer.from(parts[1] ?? "", "base64").toString("utf8"));
|
|
951
|
+
const tier = payload.tier ?? "free";
|
|
952
|
+
return tier === "pro" || tier === "enterprise";
|
|
953
|
+
} catch {
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
async function run(projectName, _options) {
|
|
958
|
+
try {
|
|
959
|
+
logger6.info("[1/8] Validating Node.js version...");
|
|
960
|
+
if (!validateNodeVersion()) {
|
|
961
|
+
process.exit(1);
|
|
962
|
+
}
|
|
963
|
+
logger6.success(`Node.js version: ${process.version}`);
|
|
964
|
+
logger6.info("[2/8] Configure your project");
|
|
965
|
+
const projectConfig = await promptProjectConfig(projectName);
|
|
966
|
+
logger6.success(`Project: ${projectConfig.projectName}`);
|
|
967
|
+
logger6.success(`Template: ${projectConfig.template}`);
|
|
968
|
+
if (PRO_TEMPLATES.has(projectConfig.template)) {
|
|
969
|
+
if (!checkProLicense()) {
|
|
970
|
+
logger6.error(`The "${projectConfig.template}" template requires a RevealUI Pro license.`);
|
|
971
|
+
logger6.info("Get Pro at https://revealui.com/pricing");
|
|
972
|
+
logger6.info("Set your license key: export REVEALUI_LICENSE_KEY=<your-key>");
|
|
973
|
+
process.exit(2);
|
|
974
|
+
}
|
|
975
|
+
logger6.success("Pro license verified");
|
|
976
|
+
}
|
|
977
|
+
logger6.info("[3/8] Configure database");
|
|
978
|
+
const databaseConfig = await promptDatabaseConfig();
|
|
979
|
+
if (databaseConfig.provider !== "skip") {
|
|
980
|
+
logger6.success(`Database: ${databaseConfig.provider}`);
|
|
981
|
+
} else {
|
|
982
|
+
logger6.info("Database configuration skipped");
|
|
983
|
+
}
|
|
984
|
+
logger6.info("[4/8] Configure storage");
|
|
985
|
+
const storageConfig = await promptStorageConfig();
|
|
986
|
+
if (storageConfig.provider !== "skip") {
|
|
987
|
+
logger6.success(`Storage: ${storageConfig.provider}`);
|
|
988
|
+
} else {
|
|
989
|
+
logger6.info("Storage configuration skipped");
|
|
990
|
+
}
|
|
991
|
+
logger6.info("[5/8] Configure payments");
|
|
992
|
+
const paymentConfig = await promptPaymentConfig();
|
|
993
|
+
if (paymentConfig.enabled) {
|
|
994
|
+
logger6.success("Stripe configured");
|
|
995
|
+
} else {
|
|
996
|
+
logger6.info("Payments disabled");
|
|
997
|
+
}
|
|
998
|
+
logger6.info("[6/8] Configure development environment");
|
|
999
|
+
const devEnvConfig = await promptDevEnvConfig();
|
|
1000
|
+
logger6.success(
|
|
1001
|
+
`Dev Container: ${devEnvConfig.createDevContainer ? "Yes" : "No"}, Devbox: ${devEnvConfig.createDevbox ? "Yes" : "No"}`
|
|
1002
|
+
);
|
|
1003
|
+
logger6.info("[7/8] Creating project...");
|
|
1004
|
+
await createProject({
|
|
1005
|
+
project: projectConfig,
|
|
1006
|
+
database: databaseConfig,
|
|
1007
|
+
storage: storageConfig,
|
|
1008
|
+
payment: paymentConfig,
|
|
1009
|
+
devenv: devEnvConfig,
|
|
1010
|
+
skipGit: _options.skipGit,
|
|
1011
|
+
skipInstall: _options.skipInstall
|
|
1012
|
+
});
|
|
1013
|
+
logger6.success("Project created successfully");
|
|
1014
|
+
logger6.info("[8/8] Next steps");
|
|
1015
|
+
logger6.divider();
|
|
1016
|
+
logger6.info(`cd ${projectConfig.projectName}`);
|
|
1017
|
+
logger6.info("pnpm install");
|
|
1018
|
+
logger6.info("pnpm dev");
|
|
1019
|
+
logger6.divider();
|
|
1020
|
+
logger6.success(`\u{1F389} Project ${projectConfig.projectName} created successfully!`);
|
|
1021
|
+
} catch (error) {
|
|
1022
|
+
if (error instanceof Error) {
|
|
1023
|
+
logger6.error(`Failed to create project: ${error.message}`);
|
|
1024
|
+
} else {
|
|
1025
|
+
logger6.error("An unexpected error occurred");
|
|
1026
|
+
}
|
|
1027
|
+
process.exit(1);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
var logger6, PRO_TEMPLATES;
|
|
1031
|
+
var init_index = __esm({
|
|
1032
|
+
"src/index.ts"() {
|
|
1033
|
+
"use strict";
|
|
1034
|
+
init_esm_shims();
|
|
1035
|
+
init_cli();
|
|
1036
|
+
init_node_version();
|
|
1037
|
+
init_create();
|
|
1038
|
+
init_database();
|
|
1039
|
+
init_devenv();
|
|
1040
|
+
init_payments();
|
|
1041
|
+
init_project();
|
|
1042
|
+
init_storage();
|
|
1043
|
+
logger6 = createLogger6({ prefix: "@revealui/cli" });
|
|
1044
|
+
PRO_TEMPLATES = /* @__PURE__ */ new Set(["e-commerce", "portfolio"]);
|
|
1045
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
1046
|
+
const cli = createCli();
|
|
1047
|
+
cli.parse(process.argv);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
// src/cli.ts
|
|
1053
|
+
import { createLogger as createLogger7 } from "@revealui/setup/utils";
|
|
1054
|
+
import { Command } from "commander";
|
|
1055
|
+
function createCli() {
|
|
1056
|
+
const program = new Command();
|
|
1057
|
+
program.name("create-revealui").description("Create a new RevealUI project").version("0.1.0").argument("[project-name]", "Name of the project").option("-t, --template <name>", "Template to use (basic-blog, e-commerce, portfolio)").option("--skip-git", "Skip git initialization", false).option("--skip-install", "Skip dependency installation", false).action(async (projectName, options) => {
|
|
1058
|
+
logger7.header("\u{1F680} Create RevealUI Project");
|
|
1059
|
+
const { run: run2 } = await Promise.resolve().then(() => (init_index(), index_exports));
|
|
1060
|
+
await run2(projectName, options);
|
|
1061
|
+
});
|
|
1062
|
+
return program;
|
|
1063
|
+
}
|
|
1064
|
+
var logger7;
|
|
1065
|
+
var init_cli = __esm({
|
|
1066
|
+
"src/cli.ts"() {
|
|
1067
|
+
init_esm_shims();
|
|
1068
|
+
logger7 = createLogger7({ prefix: "CLI" });
|
|
1069
|
+
}
|
|
1070
|
+
});
|
|
1071
|
+
init_cli();
|
|
1072
|
+
export {
|
|
1073
|
+
createCli
|
|
1074
|
+
};
|
|
1075
|
+
//# sourceMappingURL=cli.js.map
|