@revealui/setup 0.3.4 → 0.3.6

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.
@@ -0,0 +1,353 @@
1
+ // src/system-tune/detect.ts
2
+ import { execSync } from "child_process";
3
+ import { existsSync, readFileSync } from "fs";
4
+ import { arch, cpus, freemem, homedir, platform, release, totalmem } from "os";
5
+ import { join } from "path";
6
+ function detectPlatformClass() {
7
+ const p = platform();
8
+ if (p === "linux") {
9
+ try {
10
+ const procVersion = readFileSync("/proc/version", "utf8").toLowerCase();
11
+ if (procVersion.includes("microsoft") || procVersion.includes("wsl")) {
12
+ return "wsl2";
13
+ }
14
+ } catch {
15
+ }
16
+ try {
17
+ if (existsSync("/.dockerenv")) return "docker";
18
+ const cgroup = readFileSync("/proc/1/cgroup", "utf8");
19
+ if (cgroup.includes("docker") || cgroup.includes("containerd")) return "docker";
20
+ } catch {
21
+ }
22
+ try {
23
+ const dmiProduct = readFileSync("/sys/class/dmi/id/product_name", "utf8").trim().toLowerCase();
24
+ if (dmiProduct.includes("virtual") || dmiProduct.includes("kvm") || dmiProduct.includes("xen") || dmiProduct.includes("hvm")) {
25
+ return "cloud-vm";
26
+ }
27
+ } catch {
28
+ }
29
+ return "linux";
30
+ }
31
+ if (p === "darwin") return "macos";
32
+ if (p === "win32") return "windows";
33
+ return "unknown";
34
+ }
35
+ function detectDistro() {
36
+ try {
37
+ const osRelease = readFileSync("/etc/os-release", "utf8");
38
+ const match = osRelease.match(/^PRETTY_NAME="?([^"\n]+)"?/m);
39
+ return match?.[1];
40
+ } catch {
41
+ return void 0;
42
+ }
43
+ }
44
+ function detectMemory() {
45
+ const p = platform();
46
+ if (p === "linux") {
47
+ try {
48
+ const meminfo = readFileSync("/proc/meminfo", "utf8");
49
+ const parse = (key) => {
50
+ const match = meminfo.match(new RegExp(`^${key}:\\s+(\\d+)`, "m"));
51
+ return match ? Number.parseInt(match[1], 10) * 1024 : 0;
52
+ };
53
+ return {
54
+ totalBytes: parse("MemTotal"),
55
+ freeBytes: parse("MemAvailable") || parse("MemFree"),
56
+ swapTotalBytes: parse("SwapTotal"),
57
+ swapFreeBytes: parse("SwapFree")
58
+ };
59
+ } catch {
60
+ }
61
+ }
62
+ return {
63
+ totalBytes: totalmem(),
64
+ freeBytes: freemem(),
65
+ swapTotalBytes: 0,
66
+ swapFreeBytes: 0
67
+ };
68
+ }
69
+ function detectCpu() {
70
+ const cores = cpus();
71
+ const model = cores[0]?.model ?? "unknown";
72
+ const logicalCores = cores.length;
73
+ let physicalCores = logicalCores;
74
+ const p = platform();
75
+ if (p === "linux") {
76
+ try {
77
+ const output = execSync('grep "^cpu cores" /proc/cpuinfo | head -1', {
78
+ encoding: "utf8",
79
+ timeout: 2e3
80
+ });
81
+ const match = output.match(/:\s*(\d+)/);
82
+ if (match) physicalCores = Number.parseInt(match[1], 10);
83
+ } catch {
84
+ }
85
+ } else if (p === "darwin") {
86
+ try {
87
+ const output = execSync("sysctl -n hw.physicalcpu", { encoding: "utf8", timeout: 2e3 });
88
+ physicalCores = Number.parseInt(output.trim(), 10) || logicalCores;
89
+ } catch {
90
+ }
91
+ }
92
+ return { model, physicalCores, logicalCores };
93
+ }
94
+ function detectDisk() {
95
+ const p = platform();
96
+ const target = process.cwd();
97
+ if (p === "linux" || p === "darwin") {
98
+ try {
99
+ const output = execSync(`df -B1 "${target}" | tail -1`, { encoding: "utf8", timeout: 2e3 });
100
+ const parts = output.trim().split(/\s+/);
101
+ if (parts.length >= 4) {
102
+ return {
103
+ totalBytes: Number.parseInt(parts[1], 10) || 0,
104
+ freeBytes: Number.parseInt(parts[3], 10) || 0
105
+ };
106
+ }
107
+ } catch {
108
+ }
109
+ }
110
+ return { totalBytes: 0, freeBytes: 0 };
111
+ }
112
+ function detectExistingConfigs() {
113
+ const home = homedir();
114
+ let wslconfig = false;
115
+ try {
116
+ const windowsUser = execSync('cmd.exe /c "echo %USERPROFILE%" 2>/dev/null', {
117
+ encoding: "utf8",
118
+ timeout: 3e3
119
+ }).trim();
120
+ const wslPath = windowsUser.replace(/\\/g, "/").replace(/^([A-Z]):/i, (_, d) => `/mnt/${d.toLowerCase()}`);
121
+ wslconfig = existsSync(join(wslPath, ".wslconfig"));
122
+ } catch {
123
+ wslconfig = existsSync(join(home, ".wslconfig"));
124
+ }
125
+ let earlyoom = false;
126
+ try {
127
+ const result = execSync("systemctl is-enabled earlyoom 2>/dev/null", {
128
+ encoding: "utf8",
129
+ timeout: 2e3
130
+ });
131
+ earlyoom = result.trim() === "enabled";
132
+ } catch {
133
+ earlyoom = false;
134
+ }
135
+ let dockerAutostart = false;
136
+ try {
137
+ const result = execSync("systemctl is-enabled docker 2>/dev/null", {
138
+ encoding: "utf8",
139
+ timeout: 2e3
140
+ });
141
+ dockerAutostart = result.trim() === "enabled";
142
+ } catch {
143
+ dockerAutostart = false;
144
+ }
145
+ const nodeOptions = process.env.NODE_OPTIONS ?? null;
146
+ return { wslconfig, earlyoom, dockerAutostart, nodeOptions };
147
+ }
148
+ function detectSystem() {
149
+ return {
150
+ os: {
151
+ platform: platform(),
152
+ release: release(),
153
+ arch: arch(),
154
+ distro: detectDistro()
155
+ },
156
+ platformClass: detectPlatformClass(),
157
+ memory: detectMemory(),
158
+ cpu: detectCpu(),
159
+ disk: detectDisk(),
160
+ existingConfigs: detectExistingConfigs()
161
+ };
162
+ }
163
+
164
+ // src/system-tune/profiles/wsl-low-ram.json
165
+ var wsl_low_ram_default = {
166
+ $schema: "../profile-schema.json",
167
+ id: "wsl-low-ram",
168
+ name: "WSL2 Low-RAM Host",
169
+ description: "Safe defaults for WSL2 on hosts with \u22648 GB RAM. Prevents the VM from starving Windows by capping memory, disabling aggressive reclaim, and keeping Docker off by default.",
170
+ version: "0.1.0",
171
+ origin: "2026-04-13 crash postmortem: WSL on 7.3 GB host claimed ~6 GB, starving Windows. Hand-authored fix captured as seed profile.",
172
+ match: {
173
+ platform: "wsl2",
174
+ maxHostRamGb: 8
175
+ },
176
+ tune: {
177
+ wslconfig: {
178
+ memory: "4GB",
179
+ processors: 2,
180
+ swap: "2GB",
181
+ vmIdleTimeout: -1,
182
+ autoMemoryReclaim: "disabled",
183
+ networkingMode: "mirrored"
184
+ },
185
+ node: {
186
+ maxOldSpaceSize: 2048
187
+ },
188
+ pnpm: {
189
+ childConcurrency: 2
190
+ },
191
+ turbo: {
192
+ concurrency: 2
193
+ },
194
+ vitest: {
195
+ maxThreads: 2
196
+ },
197
+ earlyoom: {
198
+ enabled: true,
199
+ memThreshold: 5,
200
+ swapThreshold: 10,
201
+ prefer: "turbo|biome|vitest|tsc|esbuild"
202
+ },
203
+ docker: {
204
+ autostart: false
205
+ }
206
+ }
207
+ };
208
+
209
+ // src/system-tune/profiles.ts
210
+ var PROFILES = [wsl_low_ram_default];
211
+
212
+ // src/system-tune/plan.ts
213
+ function matchProfile(system) {
214
+ const ramGb = system.memory.totalBytes / (1024 * 1024 * 1024);
215
+ for (const profile of PROFILES) {
216
+ if (profile.match.platform !== system.platformClass) continue;
217
+ if (profile.match.maxHostRamGb !== void 0 && ramGb > profile.match.maxHostRamGb) continue;
218
+ if (profile.match.minHostRamGb !== void 0 && ramGb < profile.match.minHostRamGb) continue;
219
+ return profile;
220
+ }
221
+ return null;
222
+ }
223
+ function generateWslActions(profile, system) {
224
+ const actions = [];
225
+ const wsl = profile.tune.wslconfig;
226
+ if (!wsl) return actions;
227
+ const entries = [];
228
+ if (wsl.memory) entries.push(["memory", wsl.memory]);
229
+ if (wsl.processors !== void 0) entries.push(["processors", String(wsl.processors)]);
230
+ if (wsl.swap) entries.push(["swap", wsl.swap]);
231
+ if (wsl.vmIdleTimeout !== void 0) entries.push(["vmIdleTimeout", String(wsl.vmIdleTimeout)]);
232
+ if (wsl.autoMemoryReclaim) entries.push(["autoMemoryReclaim", wsl.autoMemoryReclaim]);
233
+ if (wsl.networkingMode) entries.push(["networkingMode", wsl.networkingMode]);
234
+ if (entries.length > 0) {
235
+ const desired = entries.map(([k, v]) => `${k}=${v}`).join(", ");
236
+ actions.push({
237
+ target: ".wslconfig [wsl2]",
238
+ current: system.existingConfigs.wslconfig ? "(exists, values unknown)" : null,
239
+ desired,
240
+ privileged: false,
241
+ description: `Set WSL2 config: ${desired}`
242
+ });
243
+ }
244
+ return actions;
245
+ }
246
+ function generateNodeActions(profile, system) {
247
+ const actions = [];
248
+ const node = profile.tune.node;
249
+ if (!node?.maxOldSpaceSize) return actions;
250
+ const desired = `--max-old-space-size=${node.maxOldSpaceSize}`;
251
+ const current = system.existingConfigs.nodeOptions;
252
+ const alreadySet = current?.includes("max-old-space-size") ?? false;
253
+ if (!alreadySet) {
254
+ actions.push({
255
+ target: "NODE_OPTIONS",
256
+ current,
257
+ desired: current ? `${current} ${desired}` : desired,
258
+ privileged: false,
259
+ description: `Add ${desired} to NODE_OPTIONS in shell profile`
260
+ });
261
+ }
262
+ return actions;
263
+ }
264
+ function generateEarlyoomActions(profile, system) {
265
+ const actions = [];
266
+ const oom = profile.tune.earlyoom;
267
+ if (!oom?.enabled) return actions;
268
+ if (!system.existingConfigs.earlyoom) {
269
+ const args = [`-m ${oom.memThreshold ?? 5}`, `-s ${oom.swapThreshold ?? 10}`];
270
+ if (oom.prefer) args.push(`--prefer '${oom.prefer}'`);
271
+ actions.push({
272
+ target: "/etc/default/earlyoom",
273
+ current: null,
274
+ desired: `EARLYOOM_ARGS="${args.join(" ")}"`,
275
+ privileged: true,
276
+ description: `Install and configure earlyoom (kill memory hogs before OOM killer)`
277
+ });
278
+ }
279
+ return actions;
280
+ }
281
+ function generateDockerActions(profile, system) {
282
+ const actions = [];
283
+ const docker = profile.tune.docker;
284
+ if (docker === void 0) return actions;
285
+ if (!docker.autostart && system.existingConfigs.dockerAutostart) {
286
+ actions.push({
287
+ target: "systemctl docker",
288
+ current: "enabled (autostart)",
289
+ desired: "disabled (on-demand via sudo systemctl start docker)",
290
+ privileged: true,
291
+ description: "Disable Docker autostart to save ~200-400 MB RAM on boot"
292
+ });
293
+ }
294
+ return actions;
295
+ }
296
+ function generateConcurrencyActions(profile) {
297
+ const actions = [];
298
+ if (profile.tune.pnpm?.childConcurrency) {
299
+ actions.push({
300
+ target: ".npmrc or pnpm config",
301
+ current: null,
302
+ desired: `child-concurrency=${profile.tune.pnpm.childConcurrency}`,
303
+ privileged: false,
304
+ description: `Limit pnpm child concurrency to ${profile.tune.pnpm.childConcurrency}`
305
+ });
306
+ }
307
+ if (profile.tune.turbo?.concurrency) {
308
+ actions.push({
309
+ target: "turbo.json or TURBO_CONCURRENCY",
310
+ current: null,
311
+ desired: `concurrency=${profile.tune.turbo.concurrency}`,
312
+ privileged: false,
313
+ description: `Limit Turbo concurrency to ${profile.tune.turbo.concurrency}`
314
+ });
315
+ }
316
+ if (profile.tune.vitest?.maxThreads) {
317
+ actions.push({
318
+ target: "vitest.config poolOptions.threads.maxThreads",
319
+ current: null,
320
+ desired: `maxThreads=${profile.tune.vitest.maxThreads}`,
321
+ privileged: false,
322
+ description: `Limit Vitest threads to ${profile.tune.vitest.maxThreads}`
323
+ });
324
+ }
325
+ return actions;
326
+ }
327
+ function generatePlan(system, profile) {
328
+ const actions = [
329
+ ...generateWslActions(profile, system),
330
+ ...generateNodeActions(profile, system),
331
+ ...generateEarlyoomActions(profile, system),
332
+ ...generateDockerActions(profile, system),
333
+ ...generateConcurrencyActions(profile)
334
+ ];
335
+ return {
336
+ profileId: profile.id,
337
+ system,
338
+ actions,
339
+ isNoop: actions.length === 0
340
+ };
341
+ }
342
+ function generateAutoplan(system) {
343
+ const profile = matchProfile(system);
344
+ if (!profile) return null;
345
+ return generatePlan(system, profile);
346
+ }
347
+ export {
348
+ PROFILES,
349
+ detectSystem,
350
+ generateAutoplan,
351
+ generatePlan,
352
+ matchProfile
353
+ };
@@ -131,4 +131,3 @@ export {
131
131
  handleASTParseError,
132
132
  logger
133
133
  };
134
- //# sourceMappingURL=index.js.map
@@ -133,4 +133,3 @@ export {
133
133
  validateEnv,
134
134
  validators
135
135
  };
136
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revealui/setup",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Setup utilities for RevealUI projects - environment, database, and configuration management",
5
5
  "keywords": [
6
6
  "cli",
@@ -18,18 +18,18 @@
18
18
  "license": "MIT",
19
19
  "author": "RevealUI Team",
20
20
  "dependencies": {
21
- "execa": "^9.0.0",
22
- "inquirer": "^13.3.2",
21
+ "execa": "^9.6.1",
22
+ "inquirer": "^13.4.1",
23
23
  "ora": "^9.3.0",
24
24
  "zod": "^4.3.6",
25
- "@revealui/config": "0.3.3"
25
+ "@revealui/config": "0.4.0"
26
26
  },
27
27
  "devDependencies": {
28
- "@types/inquirer": "^9.0.7",
29
- "@types/node": "^25.5.0",
30
- "tsup": "^8.0.0",
28
+ "@types/inquirer": "^9.0.9",
29
+ "@types/node": "^25.5.2",
30
+ "tsup": "^8.5.1",
31
31
  "typescript": "^6.0.2",
32
- "vitest": "^4.1.0"
32
+ "vitest": "^4.1.3"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=24.13.0"
@@ -50,6 +50,14 @@
50
50
  "./validators": {
51
51
  "types": "./dist/validators/index.d.ts",
52
52
  "import": "./dist/validators/index.js"
53
+ },
54
+ "./bootstrap": {
55
+ "types": "./dist/bootstrap/index.d.ts",
56
+ "import": "./dist/bootstrap/index.js"
57
+ },
58
+ "./system-tune": {
59
+ "types": "./dist/system-tune/index.d.ts",
60
+ "import": "./dist/system-tune/index.js"
53
61
  }
54
62
  },
55
63
  "files": [
@@ -63,6 +71,10 @@
63
71
  },
64
72
  "type": "module",
65
73
  "types": "./dist/index.d.ts",
74
+ "homepage": "https://revealui.com",
75
+ "bugs": {
76
+ "url": "https://github.com/RevealUIStudio/revealui/issues"
77
+ },
66
78
  "scripts": {
67
79
  "build": "tsup",
68
80
  "dev": "tsup --watch",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/environment/generators.ts","../../src/environment/setup.ts","../../src/utils/logger.ts","../../src/validators/env.ts"],"sourcesContent":["/**\n * Environment secret and password generators\n */\n\nimport { randomBytes } from 'node:crypto';\n\n/**\n * Generates a secure random secret.\n *\n * @param length - Length in bytes (default: 32 bytes = 64 hex chars)\n * @returns Hex-encoded random secret\n *\n * @example\n * ```typescript\n * const secret = generateSecret() // 64 char hex string\n * ```\n */\nexport function generateSecret(length = 32): string {\n return randomBytes(length).toString('hex');\n}\n\n/**\n * Generates a secure password with alphanumeric and special characters.\n *\n * @param length - Password length (default: 16)\n * @returns Random password\n *\n * @example\n * ```typescript\n * const password = generatePassword(16) // e.g., \"aB3!xY9@pQ5#mN7$\"\n * ```\n */\nexport function generatePassword(length = 16): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';\n let password = '';\n const randomValues = randomBytes(length);\n for (let i = 0; i < length; i++) {\n password += chars[randomValues[i] % chars.length];\n }\n return password;\n}\n\n/**\n * Updates a value in environment file content.\n *\n * @param content - Original env file content\n * @param key - Environment variable name\n * @param value - New value\n * @returns Updated env file content\n *\n * @example\n * ```typescript\n * const updated = updateEnvValue(content, 'DB_URL', 'postgresql://...')\n * ```\n */\nexport function updateEnvValue(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, 'm');\n\n if (regex.test(content)) {\n // Replace existing value\n return content.replace(regex, `${key}=${value}`);\n }\n\n // Add new line at the end\n return `${content.trimEnd()}\\n${key}=${value}\\n`;\n}\n\n/**\n * Parses environment file content into key-value pairs.\n *\n * @param content - Environment file content\n * @returns Parsed environment variables\n *\n * @example\n * ```typescript\n * const env = parseEnvContent('DB_URL=postgresql://...\\nAPI_KEY=abc123')\n * // { DB_URL: 'postgresql://...', API_KEY: 'abc123' }\n * ```\n */\nexport function parseEnvContent(content: string): Record<string, string> {\n const env: Record<string, string> = {};\n const lines = content.split('\\n');\n\n for (const line of lines) {\n // Skip comments and empty lines\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n // Parse key=value\n const match = trimmed.match(/^([^=]+)=(.*)$/);\n if (match) {\n const [, key, value] = match;\n env[key.trim()] = value.trim();\n }\n }\n\n return env;\n}\n","/**\n * Environment setup orchestration\n */\n\nimport { copyFile, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport inquirer from 'inquirer';\nimport { createLogger } from '../utils/logger.js';\nimport { type EnvVariable, REQUIRED_ENV_VARS, validateEnv } from '../validators/env.js';\nimport { generateSecret, parseEnvContent, updateEnvValue } from './generators.js';\n\nexport interface SetupEnvironmentOptions {\n projectRoot: string;\n templatePath?: string;\n outputPath?: string;\n force?: boolean;\n generateOnly?: boolean;\n interactive?: boolean;\n customVariables?: EnvVariable[];\n logger?: ReturnType<typeof createLogger>;\n}\n\nexport interface SetupEnvironmentResult {\n success: boolean;\n envPath: string;\n missing: string[];\n invalid: string[];\n}\n\n/**\n * Sets up environment variables for a project.\n *\n * @param options - Setup configuration options\n * @returns Setup result with validation info\n *\n * @example\n * ```typescript\n * const result = await setupEnvironment({\n * projectRoot: '/path/to/project',\n * interactive: true\n * })\n * ```\n */\nexport async function setupEnvironment(\n options: SetupEnvironmentOptions,\n): Promise<SetupEnvironmentResult> {\n const {\n projectRoot,\n templatePath = join(projectRoot, '.env.template'),\n outputPath = join(projectRoot, '.env.development.local'),\n force = false,\n generateOnly = false,\n interactive = true,\n customVariables,\n logger = createLogger({ prefix: 'Setup' }),\n } = options;\n\n const requiredVars = customVariables || REQUIRED_ENV_VARS;\n\n logger.header('Environment Setup');\n\n // Check if template exists\n try {\n await readFile(templatePath, 'utf-8');\n } catch {\n logger.error(`.env.template not found at: ${templatePath}`);\n logger.info('Please ensure .env.template exists in the project root.');\n return {\n success: false,\n envPath: outputPath,\n missing: requiredVars.map((v) => v.name),\n invalid: [],\n };\n }\n\n // Check if output file already exists\n let outputExists = false;\n try {\n await readFile(outputPath, 'utf-8');\n outputExists = true;\n } catch {\n // File doesn't exist, which is fine\n }\n\n if (outputExists && !force) {\n if (interactive) {\n logger.warn('.env.development.local already exists');\n const { overwrite } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'overwrite',\n message: 'Overwrite existing file?',\n default: false,\n },\n ]);\n if (!overwrite) {\n logger.info('Setup cancelled. Use force: true to overwrite.');\n return {\n success: false,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n } else {\n // Non-interactive mode without force, don't overwrite\n logger.info('Output file exists. Set force: true to overwrite.');\n return {\n success: false,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n }\n\n // Copy template\n logger.info('Copying .env.template to .env.development.local...');\n await copyFile(templatePath, outputPath);\n logger.success('Template copied');\n\n if (generateOnly) {\n // Just generate secrets and update the file\n await generateSecrets(outputPath, logger);\n logger.success('Secrets generated');\n return {\n success: true,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n\n // Parse the template to get current values\n let envContent = await readFile(outputPath, 'utf-8');\n const currentEnv = parseEnvContent(envContent);\n\n // Check for missing required values\n const validation = validateEnv(requiredVars, currentEnv);\n\n if (interactive && (validation.missing.length > 0 || validation.invalid.length > 0)) {\n logger.info('Some required values need to be configured:');\n logger.divider();\n\n for (const varName of validation.missing) {\n const variable = requiredVars.find((v) => v.name === varName);\n if (!variable) continue;\n\n logger.info(`${varName}: ${variable.description}`);\n\n if (varName === 'REVEALUI_SECRET') {\n // Auto-generate secret\n const secret = generateSecret(32);\n envContent = updateEnvValue(envContent, varName, secret);\n logger.success(`Generated ${varName}`);\n } else {\n // Prompt for value\n const { value } = await inquirer.prompt([\n {\n type: 'input',\n name: 'value',\n message: `Enter value for ${varName}:`,\n validate: (input: string) => {\n if (!input.trim()) {\n return 'Value cannot be empty (press Ctrl+C to skip)';\n }\n if (variable.validator && !variable.validator(input.trim())) {\n return `Invalid format for ${varName}`;\n }\n return true;\n },\n },\n ]);\n\n if (value.trim()) {\n envContent = updateEnvValue(envContent, varName, value.trim());\n logger.success(`Set ${varName}`);\n }\n }\n }\n\n // Save updated content\n await writeFile(outputPath, envContent);\n logger.success('Environment file updated');\n } else if (!interactive && validation.missing.length > 0) {\n // Non-interactive mode with missing values - just generate secrets\n for (const varName of validation.missing) {\n if (varName === 'REVEALUI_SECRET') {\n const secret = generateSecret(32);\n envContent = updateEnvValue(envContent, varName, secret);\n logger.success(`Generated ${varName}`);\n }\n }\n await writeFile(outputPath, envContent);\n }\n\n // Final validation\n const finalContent = await readFile(outputPath, 'utf-8');\n const finalEnv = parseEnvContent(finalContent);\n const finalValidation = validateEnv(requiredVars, finalEnv);\n\n logger.divider();\n\n if (finalValidation.valid) {\n logger.success('Environment setup complete!');\n return {\n success: true,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n\n logger.warn('Setup incomplete - some variables still need to be configured:');\n for (const varName of finalValidation.missing) {\n logger.warn(` - ${varName}`);\n }\n logger.info('Edit .env.development.local to add missing values.');\n\n return {\n success: false,\n envPath: outputPath,\n missing: finalValidation.missing,\n invalid: finalValidation.invalid,\n };\n}\n\n/**\n * Generates secrets and updates the env file.\n */\nasync function generateSecrets(\n envPath: string,\n logger: ReturnType<typeof createLogger>,\n): Promise<void> {\n let content = await readFile(envPath, 'utf-8');\n\n // Generate REVEALUI_SECRET\n const secret = generateSecret(32);\n content = updateEnvValue(content, 'REVEALUI_SECRET', secret);\n\n await writeFile(envPath, content);\n logger.success('Generated REVEALUI_SECRET');\n}\n","/**\n * Unified Logger for RevealUI Scripts\n *\n * Provides consistent logging across all scripts with color support,\n * structured output, and log level filtering.\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nexport interface LoggerOptions {\n level?: LogLevel;\n prefix?: string;\n colors?: boolean;\n timestamps?: boolean;\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\ninterface ColorMap {\n reset: string;\n red: string;\n green: string;\n yellow: string;\n blue: string;\n cyan: string;\n magenta: string;\n dim: string;\n bold: string;\n}\n\nfunction getColors(enabled: boolean): ColorMap {\n if (!enabled) {\n return {\n reset: '',\n red: '',\n green: '',\n yellow: '',\n blue: '',\n cyan: '',\n magenta: '',\n dim: '',\n bold: '',\n };\n }\n return {\n reset: '\\x1b[0m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n magenta: '\\x1b[35m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n };\n}\n\nexport interface Logger {\n debug: (msg: string, ...args: unknown[]) => void;\n info: (msg: string, ...args: unknown[]) => void;\n warn: (msg: string, ...args: unknown[]) => void;\n error: (msg: string, ...args: unknown[]) => void;\n success: (msg: string, ...args: unknown[]) => void;\n warning: (msg: string, ...args: unknown[]) => void;\n header: (msg: string) => void;\n divider: () => void;\n table: (data: Record<string, unknown>[]) => void;\n group: (label: string) => void;\n groupEnd: () => void;\n progress: (current: number, total: number, label?: string) => void;\n}\n\n/**\n * Creates a logger instance with configurable options.\n *\n * @example\n * ```typescript\n * const logger = createLogger({ level: 'info', prefix: 'MyScript' })\n * logger.info('Starting process')\n * logger.success('Completed!')\n * ```\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const {\n level = (process.env.LOG_LEVEL as LogLevel) || 'info',\n prefix = '',\n colors = process.env.FORCE_COLOR !== '0' && process.stdout.isTTY !== false,\n timestamps = false,\n } = options;\n\n const currentLevel = LOG_LEVELS[level] ?? LOG_LEVELS.info;\n const c = getColors(colors);\n\n function shouldLog(msgLevel: LogLevel): boolean {\n return LOG_LEVELS[msgLevel] >= currentLevel;\n }\n\n function formatPrefix(): string {\n const parts: string[] = [];\n if (timestamps) {\n parts.push(`${c.dim}[${new Date().toISOString()}]${c.reset}`);\n }\n if (prefix) {\n parts.push(`${c.cyan}[${prefix}]${c.reset}`);\n }\n return parts.length > 0 ? `${parts.join(' ')} ` : '';\n }\n\n function formatArgs(args: unknown[]): string {\n if (args.length === 0) return '';\n return (\n ' ' +\n args.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg))).join(' ')\n );\n }\n\n return {\n debug(msg: string, ...args: unknown[]) {\n if (!shouldLog('debug')) return;\n console.log(`${formatPrefix()}${c.dim}[DEBUG]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n info(msg: string, ...args: unknown[]) {\n if (!shouldLog('info')) return;\n console.log(`${formatPrefix()}${c.blue}[INFO]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n warn(msg: string, ...args: unknown[]) {\n if (!shouldLog('warn')) return;\n console.warn(`${formatPrefix()}${c.yellow}[WARN]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n error(msg: string, ...args: unknown[]) {\n if (!shouldLog('error')) return;\n console.error(`${formatPrefix()}${c.red}[ERROR]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n success(msg: string, ...args: unknown[]) {\n if (!shouldLog('info')) return;\n console.log(`${formatPrefix()}${c.green}[OK]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n warning(msg: string, ...args: unknown[]) {\n this.warn(msg, ...args);\n },\n\n header(msg: string) {\n if (!shouldLog('info')) return;\n const line = '='.repeat(msg.length + 4);\n console.log(`\\n${c.cyan}${line}`);\n console.log(`| ${msg} |`);\n console.log(`${line}${c.reset}\\n`);\n },\n\n divider() {\n if (!shouldLog('info')) return;\n console.log(`${c.dim}${'─'.repeat(60)}${c.reset}`);\n },\n\n table(data: Record<string, unknown>[]) {\n if (!shouldLog('info')) return;\n console.table(data);\n },\n\n group(label: string) {\n if (!shouldLog('info')) return;\n console.group(`${c.bold}${label}${c.reset}`);\n },\n\n groupEnd() {\n if (!shouldLog('info')) return;\n console.groupEnd();\n },\n\n progress(current: number, total: number, label = '') {\n if (!shouldLog('info')) return;\n const percent = Math.round((current / total) * 100);\n const filled = Math.round(percent / 5);\n const empty = 20 - filled;\n const bar = `${'█'.repeat(filled)}${'░'.repeat(empty)}`;\n const labelText = label ? ` ${label}` : '';\n process.stdout.write(`\\r${c.cyan}${bar}${c.reset} ${percent}%${labelText}`);\n if (current === total) {\n console.log(); // New line when complete\n }\n },\n };\n}\n\n/**\n * Standardized error handler for AST parsing errors\n */\nexport function handleASTParseError(filePath: string, error: unknown, logger: Logger): void {\n const message = error instanceof Error ? error.message : String(error);\n logger.warning(`AST Parse Error in ${filePath}: ${message}`);\n}\n\n/**\n * Default logger instance for quick usage\n */\nexport const logger = createLogger();\n","/**\n * Environment variable validation\n */\n\nexport interface EnvVariable {\n name: string;\n description: string;\n required: boolean;\n validator?: (value: string) => boolean;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n missing: string[];\n invalid: string[];\n}\n\n/**\n * Validates environment variables against required schema.\n *\n * @param required - Array of required environment variable definitions\n * @param env - Environment variable object to validate\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const result = validateEnv([\n * { name: 'DB_URL', description: 'Database URL', required: true }\n * ], process.env)\n * ```\n */\nexport function validateEnv(\n required: EnvVariable[],\n env: Record<string, string | undefined>,\n): ValidationResult {\n const missing: string[] = [];\n const invalid: string[] = [];\n\n for (const variable of required) {\n const value = env[variable.name];\n\n // Check if required variable is missing\n if (variable.required && (!value || value.trim() === '')) {\n missing.push(variable.name);\n continue;\n }\n\n // Check if value passes custom validator\n if (value && variable.validator && !variable.validator(value)) {\n invalid.push(variable.name);\n }\n }\n\n return {\n valid: missing.length === 0 && invalid.length === 0,\n missing,\n invalid,\n };\n}\n\n/**\n * Common environment variable validators\n */\nexport const validators = {\n /**\n * Validates PostgreSQL connection string format\n */\n postgresUrl: (value: string): boolean => {\n try {\n const url = new URL(value);\n return url.protocol === 'postgresql:' || url.protocol === 'postgres:';\n } catch {\n return false;\n }\n },\n\n /**\n * Validates Stripe secret key format\n */\n stripeSecretKey: (value: string): boolean => {\n return value.startsWith('sk_test_') || value.startsWith('sk_live_');\n },\n\n /**\n * Validates Stripe publishable key format\n */\n stripePublishableKey: (value: string): boolean => {\n return value.startsWith('pk_test_') || value.startsWith('pk_live_');\n },\n\n /**\n * Validates URL format\n */\n url: (value: string): boolean => {\n try {\n new URL(value);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Validates minimum length\n */\n minLength:\n (min: number) =>\n (value: string): boolean => {\n return value.length >= min;\n },\n\n /**\n * Validates email format\n */\n email: (value: string): boolean => {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n },\n};\n\n/**\n * Common required environment variables for RevealUI\n */\nexport const REQUIRED_ENV_VARS: EnvVariable[] = [\n {\n name: 'REVEALUI_SECRET',\n description: 'Secret key for JWT tokens and session encryption (min 32 chars)',\n required: true,\n validator: validators.minLength(32),\n },\n {\n name: 'POSTGRES_URL',\n description: 'PostgreSQL connection string',\n required: true,\n validator: validators.postgresUrl,\n },\n {\n name: 'BLOB_READ_WRITE_TOKEN',\n description: 'Vercel Blob storage token',\n required: true,\n },\n {\n name: 'STRIPE_SECRET_KEY',\n description: 'Stripe secret key (sk_test_... or sk_live_...)',\n required: true,\n validator: validators.stripeSecretKey,\n },\n {\n name: 'NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY',\n description: 'Stripe publishable key (pk_test_... or pk_live_...)',\n required: true,\n validator: validators.stripePublishableKey,\n },\n];\n\n/**\n * Optional environment variables\n */\nexport const OPTIONAL_ENV_VARS: EnvVariable[] = [\n {\n name: 'STRIPE_WEBHOOK_SECRET',\n description: 'Stripe webhook secret (whsec_...)',\n required: false,\n },\n {\n name: 'NEXT_PUBLIC_SUPABASE_URL',\n description: 'Supabase project URL',\n required: false,\n validator: validators.url,\n },\n {\n name: 'NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY',\n description: 'Supabase publishable key (sb_publishable_...)',\n required: false,\n },\n {\n name: 'REVEALUI_ADMIN_EMAIL',\n description: 'Initial admin email',\n required: false,\n validator: validators.email,\n },\n {\n name: 'REVEALUI_ADMIN_PASSWORD',\n description: 'Initial admin password (min 12 chars)',\n required: false,\n validator: validators.minLength(12),\n },\n];\n"],"mappings":";AAIA,SAAS,mBAAmB;AAarB,SAAS,eAAe,SAAS,IAAY;AAClD,SAAO,YAAY,MAAM,EAAE,SAAS,KAAK;AAC3C;AAaO,SAAS,iBAAiB,SAAS,IAAY;AACpD,QAAM,QAAQ;AACd,MAAI,WAAW;AACf,QAAM,eAAe,YAAY,MAAM;AACvC,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,gBAAY,MAAM,aAAa,CAAC,IAAI,MAAM,MAAM;AAAA,EAClD;AACA,SAAO;AACT;AAeO,SAAS,eAAe,SAAiB,KAAa,OAAuB;AAClF,QAAM,QAAQ,IAAI,OAAO,IAAI,GAAG,QAAQ,GAAG;AAE3C,MAAI,MAAM,KAAK,OAAO,GAAG;AAEvB,WAAO,QAAQ,QAAQ,OAAO,GAAG,GAAG,IAAI,KAAK,EAAE;AAAA,EACjD;AAGA,SAAO,GAAG,QAAQ,QAAQ,CAAC;AAAA,EAAK,GAAG,IAAI,KAAK;AAAA;AAC9C;AAcO,SAAS,gBAAgB,SAAyC;AACvE,QAAM,MAA8B,CAAC;AACrC,QAAM,QAAQ,QAAQ,MAAM,IAAI;AAEhC,aAAW,QAAQ,OAAO;AAExB,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,EAAG;AAGzC,UAAM,QAAQ,QAAQ,MAAM,gBAAgB;AAC5C,QAAI,OAAO;AACT,YAAM,CAAC,EAAE,KAAK,KAAK,IAAI;AACvB,UAAI,IAAI,KAAK,CAAC,IAAI,MAAM,KAAK;AAAA,IAC/B;AAAA,EACF;AAEA,SAAO;AACT;;;AC7FA,SAAS,UAAU,UAAU,iBAAiB;AAC9C,SAAS,YAAY;AACrB,OAAO,cAAc;;;ACUrB,IAAM,aAAuC;AAAA,EAC3C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AACV;AAcA,SAAS,UAAU,SAA4B;AAC7C,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,MACL,OAAO;AAAA,MACP,KAAK;AAAA,MACL,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,MAAM;AAAA,MACN,SAAS;AAAA,MACT,KAAK;AAAA,MACL,MAAM;AAAA,IACR;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO;AAAA,IACP,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,MAAM;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,MAAM;AAAA,EACR;AACF;AA2BO,SAAS,aAAa,UAAyB,CAAC,GAAW;AAChE,QAAM;AAAA,IACJ,QAAS,QAAQ,IAAI,aAA0B;AAAA,IAC/C,SAAS;AAAA,IACT,SAAS,QAAQ,IAAI,gBAAgB,OAAO,QAAQ,OAAO,UAAU;AAAA,IACrE,aAAa;AAAA,EACf,IAAI;AAEJ,QAAM,eAAe,WAAW,KAAK,KAAK,WAAW;AACrD,QAAM,IAAI,UAAU,MAAM;AAE1B,WAAS,UAAU,UAA6B;AAC9C,WAAO,WAAW,QAAQ,KAAK;AAAA,EACjC;AAEA,WAAS,eAAuB;AAC9B,UAAM,QAAkB,CAAC;AACzB,QAAI,YAAY;AACd,YAAM,KAAK,GAAG,EAAE,GAAG,KAAI,oBAAI,KAAK,GAAE,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE;AAAA,IAC9D;AACA,QAAI,QAAQ;AACV,YAAM,KAAK,GAAG,EAAE,IAAI,IAAI,MAAM,IAAI,EAAE,KAAK,EAAE;AAAA,IAC7C;AACA,WAAO,MAAM,SAAS,IAAI,GAAG,MAAM,KAAK,GAAG,CAAC,MAAM;AAAA,EACpD;AAEA,WAAS,WAAW,MAAyB;AAC3C,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,WACE,MACA,KAAK,IAAI,CAAC,QAAS,OAAO,QAAQ,WAAW,KAAK,UAAU,GAAG,IAAI,OAAO,GAAG,CAAE,EAAE,KAAK,GAAG;AAAA,EAE7F;AAEA,SAAO;AAAA,IACL,MAAM,QAAgB,MAAiB;AACrC,UAAI,CAAC,UAAU,OAAO,EAAG;AACzB,cAAQ,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,UAAU,EAAE,KAAK,IAAI,GAAG,GAAG,WAAW,IAAI,CAAC,EAAE;AAAA,IACpF;AAAA,IAEA,KAAK,QAAgB,MAAiB;AACpC,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,IAAI,SAAS,EAAE,KAAK,IAAI,GAAG,GAAG,WAAW,IAAI,CAAC,EAAE;AAAA,IACpF;AAAA,IAEA,KAAK,QAAgB,MAAiB;AACpC,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,KAAK,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,SAAS,EAAE,KAAK,IAAI,GAAG,GAAG,WAAW,IAAI,CAAC,EAAE;AAAA,IACvF;AAAA,IAEA,MAAM,QAAgB,MAAiB;AACrC,UAAI,CAAC,UAAU,OAAO,EAAG;AACzB,cAAQ,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,UAAU,EAAE,KAAK,IAAI,GAAG,GAAG,WAAW,IAAI,CAAC,EAAE;AAAA,IACtF;AAAA,IAEA,QAAQ,QAAgB,MAAiB;AACvC,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,GAAG,GAAG,WAAW,IAAI,CAAC,EAAE;AAAA,IACnF;AAAA,IAEA,QAAQ,QAAgB,MAAiB;AACvC,WAAK,KAAK,KAAK,GAAG,IAAI;AAAA,IACxB;AAAA,IAEA,OAAO,KAAa;AAClB,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,YAAM,OAAO,IAAI,OAAO,IAAI,SAAS,CAAC;AACtC,cAAQ,IAAI;AAAA,EAAK,EAAE,IAAI,GAAG,IAAI,EAAE;AAChC,cAAQ,IAAI,KAAK,GAAG,IAAI;AACxB,cAAQ,IAAI,GAAG,IAAI,GAAG,EAAE,KAAK;AAAA,CAAI;AAAA,IACnC;AAAA,IAEA,UAAU;AACR,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,IAAI,GAAG,EAAE,GAAG,GAAG,SAAI,OAAO,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE;AAAA,IACnD;AAAA,IAEA,MAAM,MAAiC;AACrC,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,MAAM,IAAI;AAAA,IACpB;AAAA,IAEA,MAAM,OAAe;AACnB,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,MAAM,GAAG,EAAE,IAAI,GAAG,KAAK,GAAG,EAAE,KAAK,EAAE;AAAA,IAC7C;AAAA,IAEA,WAAW;AACT,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,cAAQ,SAAS;AAAA,IACnB;AAAA,IAEA,SAAS,SAAiB,OAAe,QAAQ,IAAI;AACnD,UAAI,CAAC,UAAU,MAAM,EAAG;AACxB,YAAM,UAAU,KAAK,MAAO,UAAU,QAAS,GAAG;AAClD,YAAM,SAAS,KAAK,MAAM,UAAU,CAAC;AACrC,YAAM,QAAQ,KAAK;AACnB,YAAM,MAAM,GAAG,SAAI,OAAO,MAAM,CAAC,GAAG,SAAI,OAAO,KAAK,CAAC;AACrD,YAAM,YAAY,QAAQ,IAAI,KAAK,KAAK;AACxC,cAAQ,OAAO,MAAM,KAAK,EAAE,IAAI,GAAG,GAAG,GAAG,EAAE,KAAK,IAAI,OAAO,IAAI,SAAS,EAAE;AAC1E,UAAI,YAAY,OAAO;AACrB,gBAAQ,IAAI;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACF;AAaO,IAAM,SAAS,aAAa;;;AC/K5B,SAAS,YACd,UACA,KACkB;AAClB,QAAM,UAAoB,CAAC;AAC3B,QAAM,UAAoB,CAAC;AAE3B,aAAW,YAAY,UAAU;AAC/B,UAAM,QAAQ,IAAI,SAAS,IAAI;AAG/B,QAAI,SAAS,aAAa,CAAC,SAAS,MAAM,KAAK,MAAM,KAAK;AACxD,cAAQ,KAAK,SAAS,IAAI;AAC1B;AAAA,IACF;AAGA,QAAI,SAAS,SAAS,aAAa,CAAC,SAAS,UAAU,KAAK,GAAG;AAC7D,cAAQ,KAAK,SAAS,IAAI;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,WAAW,KAAK,QAAQ,WAAW;AAAA,IAClD;AAAA,IACA;AAAA,EACF;AACF;AAKO,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA,EAIxB,aAAa,CAAC,UAA2B;AACvC,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,KAAK;AACzB,aAAO,IAAI,aAAa,iBAAiB,IAAI,aAAa;AAAA,IAC5D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,CAAC,UAA2B;AAC3C,WAAO,MAAM,WAAW,UAAU,KAAK,MAAM,WAAW,UAAU;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,CAAC,UAA2B;AAChD,WAAO,MAAM,WAAW,UAAU,KAAK,MAAM,WAAW,UAAU;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,CAAC,UAA2B;AAC/B,QAAI;AACF,UAAI,IAAI,KAAK;AACb,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WACE,CAAC,QACD,CAAC,UAA2B;AAC1B,WAAO,MAAM,UAAU;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKF,OAAO,CAAC,UAA2B;AACjC,WAAO,6BAA6B,KAAK,KAAK;AAAA,EAChD;AACF;AAKO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW,UAAU,EAAE;AAAA,EACpC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AACF;AAKO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW,UAAU,EAAE;AAAA,EACpC;AACF;;;AF/IA,eAAsB,iBACpB,SACiC;AACjC,QAAM;AAAA,IACJ;AAAA,IACA,eAAe,KAAK,aAAa,eAAe;AAAA,IAChD,aAAa,KAAK,aAAa,wBAAwB;AAAA,IACvD,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,cAAc;AAAA,IACd;AAAA,IACA,QAAAA,UAAS,aAAa,EAAE,QAAQ,QAAQ,CAAC;AAAA,EAC3C,IAAI;AAEJ,QAAM,eAAe,mBAAmB;AAExC,EAAAA,QAAO,OAAO,mBAAmB;AAGjC,MAAI;AACF,UAAM,SAAS,cAAc,OAAO;AAAA,EACtC,QAAQ;AACN,IAAAA,QAAO,MAAM,+BAA+B,YAAY,EAAE;AAC1D,IAAAA,QAAO,KAAK,yDAAyD;AACrE,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS,aAAa,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,MACvC,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,eAAe;AACnB,MAAI;AACF,UAAM,SAAS,YAAY,OAAO;AAClC,mBAAe;AAAA,EACjB,QAAQ;AAAA,EAER;AAEA,MAAI,gBAAgB,CAAC,OAAO;AAC1B,QAAI,aAAa;AACf,MAAAA,QAAO,KAAK,uCAAuC;AACnD,YAAM,EAAE,UAAU,IAAI,MAAM,SAAS,OAAO;AAAA,QAC1C;AAAA,UACE,MAAM;AAAA,UACN,MAAM;AAAA,UACN,SAAS;AAAA,UACT,SAAS;AAAA,QACX;AAAA,MACF,CAAC;AACD,UAAI,CAAC,WAAW;AACd,QAAAA,QAAO,KAAK,gDAAgD;AAC5D,eAAO;AAAA,UACL,SAAS;AAAA,UACT,SAAS;AAAA,UACT,SAAS,CAAC;AAAA,UACV,SAAS,CAAC;AAAA,QACZ;AAAA,MACF;AAAA,IACF,OAAO;AAEL,MAAAA,QAAO,KAAK,mDAAmD;AAC/D,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS,CAAC;AAAA,QACV,SAAS,CAAC;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAGA,EAAAA,QAAO,KAAK,oDAAoD;AAChE,QAAM,SAAS,cAAc,UAAU;AACvC,EAAAA,QAAO,QAAQ,iBAAiB;AAEhC,MAAI,cAAc;AAEhB,UAAM,gBAAgB,YAAYA,OAAM;AACxC,IAAAA,QAAO,QAAQ,mBAAmB;AAClC,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS,CAAC;AAAA,MACV,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AAGA,MAAI,aAAa,MAAM,SAAS,YAAY,OAAO;AACnD,QAAM,aAAa,gBAAgB,UAAU;AAG7C,QAAM,aAAa,YAAY,cAAc,UAAU;AAEvD,MAAI,gBAAgB,WAAW,QAAQ,SAAS,KAAK,WAAW,QAAQ,SAAS,IAAI;AACnF,IAAAA,QAAO,KAAK,6CAA6C;AACzD,IAAAA,QAAO,QAAQ;AAEf,eAAW,WAAW,WAAW,SAAS;AACxC,YAAM,WAAW,aAAa,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO;AAC5D,UAAI,CAAC,SAAU;AAEf,MAAAA,QAAO,KAAK,GAAG,OAAO,KAAK,SAAS,WAAW,EAAE;AAEjD,UAAI,YAAY,mBAAmB;AAEjC,cAAM,SAAS,eAAe,EAAE;AAChC,qBAAa,eAAe,YAAY,SAAS,MAAM;AACvD,QAAAA,QAAO,QAAQ,aAAa,OAAO,EAAE;AAAA,MACvC,OAAO;AAEL,cAAM,EAAE,MAAM,IAAI,MAAM,SAAS,OAAO;AAAA,UACtC;AAAA,YACE,MAAM;AAAA,YACN,MAAM;AAAA,YACN,SAAS,mBAAmB,OAAO;AAAA,YACnC,UAAU,CAAC,UAAkB;AAC3B,kBAAI,CAAC,MAAM,KAAK,GAAG;AACjB,uBAAO;AAAA,cACT;AACA,kBAAI,SAAS,aAAa,CAAC,SAAS,UAAU,MAAM,KAAK,CAAC,GAAG;AAC3D,uBAAO,sBAAsB,OAAO;AAAA,cACtC;AACA,qBAAO;AAAA,YACT;AAAA,UACF;AAAA,QACF,CAAC;AAED,YAAI,MAAM,KAAK,GAAG;AAChB,uBAAa,eAAe,YAAY,SAAS,MAAM,KAAK,CAAC;AAC7D,UAAAA,QAAO,QAAQ,OAAO,OAAO,EAAE;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAGA,UAAM,UAAU,YAAY,UAAU;AACtC,IAAAA,QAAO,QAAQ,0BAA0B;AAAA,EAC3C,WAAW,CAAC,eAAe,WAAW,QAAQ,SAAS,GAAG;AAExD,eAAW,WAAW,WAAW,SAAS;AACxC,UAAI,YAAY,mBAAmB;AACjC,cAAM,SAAS,eAAe,EAAE;AAChC,qBAAa,eAAe,YAAY,SAAS,MAAM;AACvD,QAAAA,QAAO,QAAQ,aAAa,OAAO,EAAE;AAAA,MACvC;AAAA,IACF;AACA,UAAM,UAAU,YAAY,UAAU;AAAA,EACxC;AAGA,QAAM,eAAe,MAAM,SAAS,YAAY,OAAO;AACvD,QAAM,WAAW,gBAAgB,YAAY;AAC7C,QAAM,kBAAkB,YAAY,cAAc,QAAQ;AAE1D,EAAAA,QAAO,QAAQ;AAEf,MAAI,gBAAgB,OAAO;AACzB,IAAAA,QAAO,QAAQ,6BAA6B;AAC5C,WAAO;AAAA,MACL,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS,CAAC;AAAA,MACV,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AAEA,EAAAA,QAAO,KAAK,gEAAgE;AAC5E,aAAW,WAAW,gBAAgB,SAAS;AAC7C,IAAAA,QAAO,KAAK,OAAO,OAAO,EAAE;AAAA,EAC9B;AACA,EAAAA,QAAO,KAAK,oDAAoD;AAEhE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS,gBAAgB;AAAA,IACzB,SAAS,gBAAgB;AAAA,EAC3B;AACF;AAKA,eAAe,gBACb,SACAA,SACe;AACf,MAAI,UAAU,MAAM,SAAS,SAAS,OAAO;AAG7C,QAAM,SAAS,eAAe,EAAE;AAChC,YAAU,eAAe,SAAS,mBAAmB,MAAM;AAE3D,QAAM,UAAU,SAAS,OAAO;AAChC,EAAAA,QAAO,QAAQ,2BAA2B;AAC5C;","names":["logger"]}
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/environment/generators.ts","../src/environment/setup.ts","../src/utils/logger.ts","../src/validators/env.ts"],"sourcesContent":["/**\n * Environment secret and password generators\n */\n\nimport { randomBytes } from 'node:crypto';\n\n/**\n * Generates a secure random secret.\n *\n * @param length - Length in bytes (default: 32 bytes = 64 hex chars)\n * @returns Hex-encoded random secret\n *\n * @example\n * ```typescript\n * const secret = generateSecret() // 64 char hex string\n * ```\n */\nexport function generateSecret(length = 32): string {\n return randomBytes(length).toString('hex');\n}\n\n/**\n * Generates a secure password with alphanumeric and special characters.\n *\n * @param length - Password length (default: 16)\n * @returns Random password\n *\n * @example\n * ```typescript\n * const password = generatePassword(16) // e.g., \"aB3!xY9@pQ5#mN7$\"\n * ```\n */\nexport function generatePassword(length = 16): string {\n const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';\n let password = '';\n const randomValues = randomBytes(length);\n for (let i = 0; i < length; i++) {\n password += chars[randomValues[i] % chars.length];\n }\n return password;\n}\n\n/**\n * Updates a value in environment file content.\n *\n * @param content - Original env file content\n * @param key - Environment variable name\n * @param value - New value\n * @returns Updated env file content\n *\n * @example\n * ```typescript\n * const updated = updateEnvValue(content, 'DB_URL', 'postgresql://...')\n * ```\n */\nexport function updateEnvValue(content: string, key: string, value: string): string {\n const regex = new RegExp(`^${key}=.*$`, 'm');\n\n if (regex.test(content)) {\n // Replace existing value\n return content.replace(regex, `${key}=${value}`);\n }\n\n // Add new line at the end\n return `${content.trimEnd()}\\n${key}=${value}\\n`;\n}\n\n/**\n * Parses environment file content into key-value pairs.\n *\n * @param content - Environment file content\n * @returns Parsed environment variables\n *\n * @example\n * ```typescript\n * const env = parseEnvContent('DB_URL=postgresql://...\\nAPI_KEY=abc123')\n * // { DB_URL: 'postgresql://...', API_KEY: 'abc123' }\n * ```\n */\nexport function parseEnvContent(content: string): Record<string, string> {\n const env: Record<string, string> = {};\n const lines = content.split('\\n');\n\n for (const line of lines) {\n // Skip comments and empty lines\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n // Parse key=value\n const match = trimmed.match(/^([^=]+)=(.*)$/);\n if (match) {\n const [, key, value] = match;\n env[key.trim()] = value.trim();\n }\n }\n\n return env;\n}\n","/**\n * Environment setup orchestration\n */\n\nimport { copyFile, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport inquirer from 'inquirer';\nimport { createLogger } from '../utils/logger.js';\nimport { type EnvVariable, REQUIRED_ENV_VARS, validateEnv } from '../validators/env.js';\nimport { generateSecret, parseEnvContent, updateEnvValue } from './generators.js';\n\nexport interface SetupEnvironmentOptions {\n projectRoot: string;\n templatePath?: string;\n outputPath?: string;\n force?: boolean;\n generateOnly?: boolean;\n interactive?: boolean;\n customVariables?: EnvVariable[];\n logger?: ReturnType<typeof createLogger>;\n}\n\nexport interface SetupEnvironmentResult {\n success: boolean;\n envPath: string;\n missing: string[];\n invalid: string[];\n}\n\n/**\n * Sets up environment variables for a project.\n *\n * @param options - Setup configuration options\n * @returns Setup result with validation info\n *\n * @example\n * ```typescript\n * const result = await setupEnvironment({\n * projectRoot: '/path/to/project',\n * interactive: true\n * })\n * ```\n */\nexport async function setupEnvironment(\n options: SetupEnvironmentOptions,\n): Promise<SetupEnvironmentResult> {\n const {\n projectRoot,\n templatePath = join(projectRoot, '.env.template'),\n outputPath = join(projectRoot, '.env.development.local'),\n force = false,\n generateOnly = false,\n interactive = true,\n customVariables,\n logger = createLogger({ prefix: 'Setup' }),\n } = options;\n\n const requiredVars = customVariables || REQUIRED_ENV_VARS;\n\n logger.header('Environment Setup');\n\n // Check if template exists\n try {\n await readFile(templatePath, 'utf-8');\n } catch {\n logger.error(`.env.template not found at: ${templatePath}`);\n logger.info('Please ensure .env.template exists in the project root.');\n return {\n success: false,\n envPath: outputPath,\n missing: requiredVars.map((v) => v.name),\n invalid: [],\n };\n }\n\n // Check if output file already exists\n let outputExists = false;\n try {\n await readFile(outputPath, 'utf-8');\n outputExists = true;\n } catch {\n // File doesn't exist, which is fine\n }\n\n if (outputExists && !force) {\n if (interactive) {\n logger.warn('.env.development.local already exists');\n const { overwrite } = await inquirer.prompt([\n {\n type: 'confirm',\n name: 'overwrite',\n message: 'Overwrite existing file?',\n default: false,\n },\n ]);\n if (!overwrite) {\n logger.info('Setup cancelled. Use force: true to overwrite.');\n return {\n success: false,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n } else {\n // Non-interactive mode without force, don't overwrite\n logger.info('Output file exists. Set force: true to overwrite.');\n return {\n success: false,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n }\n\n // Copy template\n logger.info('Copying .env.template to .env.development.local...');\n await copyFile(templatePath, outputPath);\n logger.success('Template copied');\n\n if (generateOnly) {\n // Just generate secrets and update the file\n await generateSecrets(outputPath, logger);\n logger.success('Secrets generated');\n return {\n success: true,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n\n // Parse the template to get current values\n let envContent = await readFile(outputPath, 'utf-8');\n const currentEnv = parseEnvContent(envContent);\n\n // Check for missing required values\n const validation = validateEnv(requiredVars, currentEnv);\n\n if (interactive && (validation.missing.length > 0 || validation.invalid.length > 0)) {\n logger.info('Some required values need to be configured:');\n logger.divider();\n\n for (const varName of validation.missing) {\n const variable = requiredVars.find((v) => v.name === varName);\n if (!variable) continue;\n\n logger.info(`${varName}: ${variable.description}`);\n\n if (varName === 'REVEALUI_SECRET') {\n // Auto-generate secret\n const secret = generateSecret(32);\n envContent = updateEnvValue(envContent, varName, secret);\n logger.success(`Generated ${varName}`);\n } else {\n // Prompt for value\n const { value } = await inquirer.prompt([\n {\n type: 'input',\n name: 'value',\n message: `Enter value for ${varName}:`,\n validate: (input: string) => {\n if (!input.trim()) {\n return 'Value cannot be empty (press Ctrl+C to skip)';\n }\n if (variable.validator && !variable.validator(input.trim())) {\n return `Invalid format for ${varName}`;\n }\n return true;\n },\n },\n ]);\n\n if (value.trim()) {\n envContent = updateEnvValue(envContent, varName, value.trim());\n logger.success(`Set ${varName}`);\n }\n }\n }\n\n // Save updated content\n await writeFile(outputPath, envContent);\n logger.success('Environment file updated');\n } else if (!interactive && validation.missing.length > 0) {\n // Non-interactive mode with missing values - just generate secrets\n for (const varName of validation.missing) {\n if (varName === 'REVEALUI_SECRET') {\n const secret = generateSecret(32);\n envContent = updateEnvValue(envContent, varName, secret);\n logger.success(`Generated ${varName}`);\n }\n }\n await writeFile(outputPath, envContent);\n }\n\n // Final validation\n const finalContent = await readFile(outputPath, 'utf-8');\n const finalEnv = parseEnvContent(finalContent);\n const finalValidation = validateEnv(requiredVars, finalEnv);\n\n logger.divider();\n\n if (finalValidation.valid) {\n logger.success('Environment setup complete!');\n return {\n success: true,\n envPath: outputPath,\n missing: [],\n invalid: [],\n };\n }\n\n logger.warn('Setup incomplete - some variables still need to be configured:');\n for (const varName of finalValidation.missing) {\n logger.warn(` - ${varName}`);\n }\n logger.info('Edit .env.development.local to add missing values.');\n\n return {\n success: false,\n envPath: outputPath,\n missing: finalValidation.missing,\n invalid: finalValidation.invalid,\n };\n}\n\n/**\n * Generates secrets and updates the env file.\n */\nasync function generateSecrets(\n envPath: string,\n logger: ReturnType<typeof createLogger>,\n): Promise<void> {\n let content = await readFile(envPath, 'utf-8');\n\n // Generate REVEALUI_SECRET\n const secret = generateSecret(32);\n content = updateEnvValue(content, 'REVEALUI_SECRET', secret);\n\n await writeFile(envPath, content);\n logger.success('Generated REVEALUI_SECRET');\n}\n","/**\n * Unified Logger for RevealUI Scripts\n *\n * Provides consistent logging across all scripts with color support,\n * structured output, and log level filtering.\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nexport interface LoggerOptions {\n level?: LogLevel;\n prefix?: string;\n colors?: boolean;\n timestamps?: boolean;\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\ninterface ColorMap {\n reset: string;\n red: string;\n green: string;\n yellow: string;\n blue: string;\n cyan: string;\n magenta: string;\n dim: string;\n bold: string;\n}\n\nfunction getColors(enabled: boolean): ColorMap {\n if (!enabled) {\n return {\n reset: '',\n red: '',\n green: '',\n yellow: '',\n blue: '',\n cyan: '',\n magenta: '',\n dim: '',\n bold: '',\n };\n }\n return {\n reset: '\\x1b[0m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n magenta: '\\x1b[35m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n };\n}\n\nexport interface Logger {\n debug: (msg: string, ...args: unknown[]) => void;\n info: (msg: string, ...args: unknown[]) => void;\n warn: (msg: string, ...args: unknown[]) => void;\n error: (msg: string, ...args: unknown[]) => void;\n success: (msg: string, ...args: unknown[]) => void;\n warning: (msg: string, ...args: unknown[]) => void;\n header: (msg: string) => void;\n divider: () => void;\n table: (data: Record<string, unknown>[]) => void;\n group: (label: string) => void;\n groupEnd: () => void;\n progress: (current: number, total: number, label?: string) => void;\n}\n\n/**\n * Creates a logger instance with configurable options.\n *\n * @example\n * ```typescript\n * const logger = createLogger({ level: 'info', prefix: 'MyScript' })\n * logger.info('Starting process')\n * logger.success('Completed!')\n * ```\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const {\n level = (process.env.LOG_LEVEL as LogLevel) || 'info',\n prefix = '',\n colors = process.env.FORCE_COLOR !== '0' && process.stdout.isTTY !== false,\n timestamps = false,\n } = options;\n\n const currentLevel = LOG_LEVELS[level] ?? LOG_LEVELS.info;\n const c = getColors(colors);\n\n function shouldLog(msgLevel: LogLevel): boolean {\n return LOG_LEVELS[msgLevel] >= currentLevel;\n }\n\n function formatPrefix(): string {\n const parts: string[] = [];\n if (timestamps) {\n parts.push(`${c.dim}[${new Date().toISOString()}]${c.reset}`);\n }\n if (prefix) {\n parts.push(`${c.cyan}[${prefix}]${c.reset}`);\n }\n return parts.length > 0 ? `${parts.join(' ')} ` : '';\n }\n\n function formatArgs(args: unknown[]): string {\n if (args.length === 0) return '';\n return (\n ' ' +\n args.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg))).join(' ')\n );\n }\n\n return {\n debug(msg: string, ...args: unknown[]) {\n if (!shouldLog('debug')) return;\n console.log(`${formatPrefix()}${c.dim}[DEBUG]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n info(msg: string, ...args: unknown[]) {\n if (!shouldLog('info')) return;\n console.log(`${formatPrefix()}${c.blue}[INFO]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n warn(msg: string, ...args: unknown[]) {\n if (!shouldLog('warn')) return;\n console.warn(`${formatPrefix()}${c.yellow}[WARN]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n error(msg: string, ...args: unknown[]) {\n if (!shouldLog('error')) return;\n console.error(`${formatPrefix()}${c.red}[ERROR]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n success(msg: string, ...args: unknown[]) {\n if (!shouldLog('info')) return;\n console.log(`${formatPrefix()}${c.green}[OK]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n warning(msg: string, ...args: unknown[]) {\n this.warn(msg, ...args);\n },\n\n header(msg: string) {\n if (!shouldLog('info')) return;\n const line = '='.repeat(msg.length + 4);\n console.log(`\\n${c.cyan}${line}`);\n console.log(`| ${msg} |`);\n console.log(`${line}${c.reset}\\n`);\n },\n\n divider() {\n if (!shouldLog('info')) return;\n console.log(`${c.dim}${'─'.repeat(60)}${c.reset}`);\n },\n\n table(data: Record<string, unknown>[]) {\n if (!shouldLog('info')) return;\n console.table(data);\n },\n\n group(label: string) {\n if (!shouldLog('info')) return;\n console.group(`${c.bold}${label}${c.reset}`);\n },\n\n groupEnd() {\n if (!shouldLog('info')) return;\n console.groupEnd();\n },\n\n progress(current: number, total: number, label = '') {\n if (!shouldLog('info')) return;\n const percent = Math.round((current / total) * 100);\n const filled = Math.round(percent / 5);\n const empty = 20 - filled;\n const bar = `${'█'.repeat(filled)}${'░'.repeat(empty)}`;\n const labelText = label ? ` ${label}` : '';\n process.stdout.write(`\\r${c.cyan}${bar}${c.reset} ${percent}%${labelText}`);\n if (current === total) {\n console.log(); // New line when complete\n }\n },\n };\n}\n\n/**\n * Standardized error handler for AST parsing errors\n */\nexport function handleASTParseError(filePath: string, error: unknown, logger: Logger): void {\n const message = error instanceof Error ? error.message : String(error);\n logger.warning(`AST Parse Error in ${filePath}: ${message}`);\n}\n\n/**\n * Default logger instance for quick usage\n */\nexport const logger = createLogger();\n","/**\n * Environment variable validation\n */\n\nexport interface EnvVariable {\n name: string;\n description: string;\n required: boolean;\n validator?: (value: string) => boolean;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n missing: string[];\n invalid: string[];\n}\n\n/**\n * Validates environment variables against required schema.\n *\n * @param required - Array of required environment variable definitions\n * @param env - Environment variable object to validate\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const result = validateEnv([\n * { name: 'DB_URL', description: 'Database URL', required: true }\n * ], process.env)\n * ```\n */\nexport function validateEnv(\n required: EnvVariable[],\n env: Record<string, string | undefined>,\n): ValidationResult {\n const missing: string[] = [];\n const invalid: string[] = [];\n\n for (const variable of required) {\n const value = env[variable.name];\n\n // Check if required variable is missing\n if (variable.required && (!value || value.trim() === '')) {\n missing.push(variable.name);\n continue;\n }\n\n // Check if value passes custom validator\n if (value && variable.validator && !variable.validator(value)) {\n invalid.push(variable.name);\n }\n }\n\n return {\n valid: missing.length === 0 && invalid.length === 0,\n missing,\n invalid,\n };\n}\n\n/**\n * Common environment variable validators\n */\nexport const validators = {\n /**\n * Validates PostgreSQL connection string format\n */\n postgresUrl: (value: string): boolean => {\n try {\n const url = new URL(value);\n return url.protocol === 'postgresql:' || url.protocol === 'postgres:';\n } catch {\n return false;\n }\n },\n\n /**\n * Validates Stripe secret key format\n */\n stripeSecretKey: (value: string): boolean => {\n return value.startsWith('sk_test_') || value.startsWith('sk_live_');\n },\n\n /**\n * Validates Stripe publishable key format\n */\n stripePublishableKey: (value: string): boolean => {\n return value.startsWith('pk_test_') || value.startsWith('pk_live_');\n },\n\n /**\n * Validates URL format\n */\n url: (value: string): boolean => {\n try {\n new URL(value);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Validates minimum length\n */\n minLength:\n (min: number) =>\n (value: string): boolean => {\n return value.length >= min;\n },\n\n /**\n * Validates email format\n */\n email: (value: string): boolean => {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n },\n};\n\n/**\n * Common required environment variables for RevealUI\n */\nexport const REQUIRED_ENV_VARS: EnvVariable[] = [\n {\n name: 'REVEALUI_SECRET',\n description: 'Secret key for JWT tokens and session encryption (min 32 chars)',\n required: true,\n validator: validators.minLength(32),\n },\n {\n name: 'POSTGRES_URL',\n description: 'PostgreSQL connection string',\n required: true,\n validator: validators.postgresUrl,\n },\n {\n name: 'BLOB_READ_WRITE_TOKEN',\n description: 'Vercel Blob storage token',\n required: true,\n },\n {\n name: 'STRIPE_SECRET_KEY',\n description: 'Stripe secret key (sk_test_... or sk_live_...)',\n required: true,\n validator: validators.stripeSecretKey,\n },\n {\n name: 'NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY',\n description: 'Stripe publishable key (pk_test_... or pk_live_...)',\n required: true,\n validator: validators.stripePublishableKey,\n },\n];\n\n/**\n * Optional environment variables\n */\nexport const OPTIONAL_ENV_VARS: EnvVariable[] = [\n {\n name: 'STRIPE_WEBHOOK_SECRET',\n description: 'Stripe webhook secret (whsec_...)',\n required: false,\n },\n {\n name: 'NEXT_PUBLIC_SUPABASE_URL',\n description: 'Supabase project URL',\n required: false,\n validator: validators.url,\n },\n {\n name: 'NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY',\n description: 'Supabase publishable key (sb_publishable_...)',\n required: false,\n },\n {\n name: 'REVEALUI_ADMIN_EMAIL',\n description: 'Initial admin email',\n required: false,\n validator: validators.email,\n },\n {\n name: 'REVEALUI_ADMIN_PASSWORD',\n description: 'Initial admin password (min 12 chars)',\n required: false,\n validator: validators.minLength(12),\n },\n];\n"],"mappings":"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","names":["logger","logger"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utils/logger.ts"],"sourcesContent":["/**\n * Unified Logger for RevealUI Scripts\n *\n * Provides consistent logging across all scripts with color support,\n * structured output, and log level filtering.\n */\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\nexport interface LoggerOptions {\n level?: LogLevel;\n prefix?: string;\n colors?: boolean;\n timestamps?: boolean;\n}\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n};\n\ninterface ColorMap {\n reset: string;\n red: string;\n green: string;\n yellow: string;\n blue: string;\n cyan: string;\n magenta: string;\n dim: string;\n bold: string;\n}\n\nfunction getColors(enabled: boolean): ColorMap {\n if (!enabled) {\n return {\n reset: '',\n red: '',\n green: '',\n yellow: '',\n blue: '',\n cyan: '',\n magenta: '',\n dim: '',\n bold: '',\n };\n }\n return {\n reset: '\\x1b[0m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n cyan: '\\x1b[36m',\n magenta: '\\x1b[35m',\n dim: '\\x1b[2m',\n bold: '\\x1b[1m',\n };\n}\n\nexport interface Logger {\n debug: (msg: string, ...args: unknown[]) => void;\n info: (msg: string, ...args: unknown[]) => void;\n warn: (msg: string, ...args: unknown[]) => void;\n error: (msg: string, ...args: unknown[]) => void;\n success: (msg: string, ...args: unknown[]) => void;\n warning: (msg: string, ...args: unknown[]) => void;\n header: (msg: string) => void;\n divider: () => void;\n table: (data: Record<string, unknown>[]) => void;\n group: (label: string) => void;\n groupEnd: () => void;\n progress: (current: number, total: number, label?: string) => void;\n}\n\n/**\n * Creates a logger instance with configurable options.\n *\n * @example\n * ```typescript\n * const logger = createLogger({ level: 'info', prefix: 'MyScript' })\n * logger.info('Starting process')\n * logger.success('Completed!')\n * ```\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const {\n level = (process.env.LOG_LEVEL as LogLevel) || 'info',\n prefix = '',\n colors = process.env.FORCE_COLOR !== '0' && process.stdout.isTTY !== false,\n timestamps = false,\n } = options;\n\n const currentLevel = LOG_LEVELS[level] ?? LOG_LEVELS.info;\n const c = getColors(colors);\n\n function shouldLog(msgLevel: LogLevel): boolean {\n return LOG_LEVELS[msgLevel] >= currentLevel;\n }\n\n function formatPrefix(): string {\n const parts: string[] = [];\n if (timestamps) {\n parts.push(`${c.dim}[${new Date().toISOString()}]${c.reset}`);\n }\n if (prefix) {\n parts.push(`${c.cyan}[${prefix}]${c.reset}`);\n }\n return parts.length > 0 ? `${parts.join(' ')} ` : '';\n }\n\n function formatArgs(args: unknown[]): string {\n if (args.length === 0) return '';\n return (\n ' ' +\n args.map((arg) => (typeof arg === 'object' ? JSON.stringify(arg) : String(arg))).join(' ')\n );\n }\n\n return {\n debug(msg: string, ...args: unknown[]) {\n if (!shouldLog('debug')) return;\n console.log(`${formatPrefix()}${c.dim}[DEBUG]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n info(msg: string, ...args: unknown[]) {\n if (!shouldLog('info')) return;\n console.log(`${formatPrefix()}${c.blue}[INFO]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n warn(msg: string, ...args: unknown[]) {\n if (!shouldLog('warn')) return;\n console.warn(`${formatPrefix()}${c.yellow}[WARN]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n error(msg: string, ...args: unknown[]) {\n if (!shouldLog('error')) return;\n console.error(`${formatPrefix()}${c.red}[ERROR]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n success(msg: string, ...args: unknown[]) {\n if (!shouldLog('info')) return;\n console.log(`${formatPrefix()}${c.green}[OK]${c.reset} ${msg}${formatArgs(args)}`);\n },\n\n warning(msg: string, ...args: unknown[]) {\n this.warn(msg, ...args);\n },\n\n header(msg: string) {\n if (!shouldLog('info')) return;\n const line = '='.repeat(msg.length + 4);\n console.log(`\\n${c.cyan}${line}`);\n console.log(`| ${msg} |`);\n console.log(`${line}${c.reset}\\n`);\n },\n\n divider() {\n if (!shouldLog('info')) return;\n console.log(`${c.dim}${'─'.repeat(60)}${c.reset}`);\n },\n\n table(data: Record<string, unknown>[]) {\n if (!shouldLog('info')) return;\n console.table(data);\n },\n\n group(label: string) {\n if (!shouldLog('info')) return;\n console.group(`${c.bold}${label}${c.reset}`);\n },\n\n groupEnd() {\n if (!shouldLog('info')) return;\n console.groupEnd();\n },\n\n progress(current: number, total: number, label = '') {\n if (!shouldLog('info')) return;\n const percent = Math.round((current / total) * 100);\n const filled = Math.round(percent / 5);\n const empty = 20 - filled;\n const bar = `${'█'.repeat(filled)}${'░'.repeat(empty)}`;\n const labelText = label ? ` ${label}` : '';\n process.stdout.write(`\\r${c.cyan}${bar}${c.reset} ${percent}%${labelText}`);\n if (current === total) {\n console.log(); // New line when complete\n }\n },\n };\n}\n\n/**\n * Standardized error handler for AST parsing errors\n */\nexport function handleASTParseError(filePath: string, error: unknown, logger: Logger): void {\n const message = error instanceof Error ? error.message : String(error);\n logger.warning(`AST Parse Error in ${filePath}: ${message}`);\n}\n\n/**\n * Default logger instance for quick usage\n */\nexport const logger = createLogger();\n"],"mappings":"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","names":["logger"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/validators/env.ts"],"sourcesContent":["/**\n * Environment variable validation\n */\n\nexport interface EnvVariable {\n name: string;\n description: string;\n required: boolean;\n validator?: (value: string) => boolean;\n}\n\nexport interface ValidationResult {\n valid: boolean;\n missing: string[];\n invalid: string[];\n}\n\n/**\n * Validates environment variables against required schema.\n *\n * @param required - Array of required environment variable definitions\n * @param env - Environment variable object to validate\n * @returns Validation result\n *\n * @example\n * ```typescript\n * const result = validateEnv([\n * { name: 'DB_URL', description: 'Database URL', required: true }\n * ], process.env)\n * ```\n */\nexport function validateEnv(\n required: EnvVariable[],\n env: Record<string, string | undefined>,\n): ValidationResult {\n const missing: string[] = [];\n const invalid: string[] = [];\n\n for (const variable of required) {\n const value = env[variable.name];\n\n // Check if required variable is missing\n if (variable.required && (!value || value.trim() === '')) {\n missing.push(variable.name);\n continue;\n }\n\n // Check if value passes custom validator\n if (value && variable.validator && !variable.validator(value)) {\n invalid.push(variable.name);\n }\n }\n\n return {\n valid: missing.length === 0 && invalid.length === 0,\n missing,\n invalid,\n };\n}\n\n/**\n * Common environment variable validators\n */\nexport const validators = {\n /**\n * Validates PostgreSQL connection string format\n */\n postgresUrl: (value: string): boolean => {\n try {\n const url = new URL(value);\n return url.protocol === 'postgresql:' || url.protocol === 'postgres:';\n } catch {\n return false;\n }\n },\n\n /**\n * Validates Stripe secret key format\n */\n stripeSecretKey: (value: string): boolean => {\n return value.startsWith('sk_test_') || value.startsWith('sk_live_');\n },\n\n /**\n * Validates Stripe publishable key format\n */\n stripePublishableKey: (value: string): boolean => {\n return value.startsWith('pk_test_') || value.startsWith('pk_live_');\n },\n\n /**\n * Validates URL format\n */\n url: (value: string): boolean => {\n try {\n new URL(value);\n return true;\n } catch {\n return false;\n }\n },\n\n /**\n * Validates minimum length\n */\n minLength:\n (min: number) =>\n (value: string): boolean => {\n return value.length >= min;\n },\n\n /**\n * Validates email format\n */\n email: (value: string): boolean => {\n return /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value);\n },\n};\n\n/**\n * Common required environment variables for RevealUI\n */\nexport const REQUIRED_ENV_VARS: EnvVariable[] = [\n {\n name: 'REVEALUI_SECRET',\n description: 'Secret key for JWT tokens and session encryption (min 32 chars)',\n required: true,\n validator: validators.minLength(32),\n },\n {\n name: 'POSTGRES_URL',\n description: 'PostgreSQL connection string',\n required: true,\n validator: validators.postgresUrl,\n },\n {\n name: 'BLOB_READ_WRITE_TOKEN',\n description: 'Vercel Blob storage token',\n required: true,\n },\n {\n name: 'STRIPE_SECRET_KEY',\n description: 'Stripe secret key (sk_test_... or sk_live_...)',\n required: true,\n validator: validators.stripeSecretKey,\n },\n {\n name: 'NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY',\n description: 'Stripe publishable key (pk_test_... or pk_live_...)',\n required: true,\n validator: validators.stripePublishableKey,\n },\n];\n\n/**\n * Optional environment variables\n */\nexport const OPTIONAL_ENV_VARS: EnvVariable[] = [\n {\n name: 'STRIPE_WEBHOOK_SECRET',\n description: 'Stripe webhook secret (whsec_...)',\n required: false,\n },\n {\n name: 'NEXT_PUBLIC_SUPABASE_URL',\n description: 'Supabase project URL',\n required: false,\n validator: validators.url,\n },\n {\n name: 'NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY',\n description: 'Supabase publishable key (sb_publishable_...)',\n required: false,\n },\n {\n name: 'REVEALUI_ADMIN_EMAIL',\n description: 'Initial admin email',\n required: false,\n validator: validators.email,\n },\n {\n name: 'REVEALUI_ADMIN_PASSWORD',\n description: 'Initial admin password (min 12 chars)',\n required: false,\n validator: validators.minLength(12),\n },\n];\n"],"mappings":";AA+BO,SAAS,YACd,UACA,KACkB;AAClB,QAAM,UAAoB,CAAC;AAC3B,QAAM,UAAoB,CAAC;AAE3B,aAAW,YAAY,UAAU;AAC/B,UAAM,QAAQ,IAAI,SAAS,IAAI;AAG/B,QAAI,SAAS,aAAa,CAAC,SAAS,MAAM,KAAK,MAAM,KAAK;AACxD,cAAQ,KAAK,SAAS,IAAI;AAC1B;AAAA,IACF;AAGA,QAAI,SAAS,SAAS,aAAa,CAAC,SAAS,UAAU,KAAK,GAAG;AAC7D,cAAQ,KAAK,SAAS,IAAI;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,WAAW,KAAK,QAAQ,WAAW;AAAA,IAClD;AAAA,IACA;AAAA,EACF;AACF;AAKO,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA,EAIxB,aAAa,CAAC,UAA2B;AACvC,QAAI;AACF,YAAM,MAAM,IAAI,IAAI,KAAK;AACzB,aAAO,IAAI,aAAa,iBAAiB,IAAI,aAAa;AAAA,IAC5D,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,CAAC,UAA2B;AAC3C,WAAO,MAAM,WAAW,UAAU,KAAK,MAAM,WAAW,UAAU;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,CAAC,UAA2B;AAChD,WAAO,MAAM,WAAW,UAAU,KAAK,MAAM,WAAW,UAAU;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,CAAC,UAA2B;AAC/B,QAAI;AACF,UAAI,IAAI,KAAK;AACb,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WACE,CAAC,QACD,CAAC,UAA2B;AAC1B,WAAO,MAAM,UAAU;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKF,OAAO,CAAC,UAA2B;AACjC,WAAO,6BAA6B,KAAK,KAAK;AAAA,EAChD;AACF;AAKO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW,UAAU,EAAE;AAAA,EACpC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AACF;AAKO,IAAM,oBAAmC;AAAA,EAC9C;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW;AAAA,EACxB;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,UAAU;AAAA,IACV,WAAW,WAAW,UAAU,EAAE;AAAA,EACpC;AACF;","names":[]}