nivii 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/README.md +142 -215
  2. package/dist/cli.js +1 -1
  3. package/dist/dist/cli.d.ts +3 -0
  4. package/dist/dist/cli.d.ts.map +1 -0
  5. package/dist/dist/cli.js +144 -0
  6. package/dist/dist/cli.js.map +1 -0
  7. package/dist/dist/commands/config.d.ts +2 -0
  8. package/dist/dist/commands/config.d.ts.map +1 -0
  9. package/dist/dist/commands/config.js +32 -0
  10. package/dist/dist/commands/config.js.map +1 -0
  11. package/dist/dist/commands/fullstack.d.ts +12 -0
  12. package/dist/dist/commands/fullstack.d.ts.map +1 -0
  13. package/dist/dist/commands/fullstack.js +173 -0
  14. package/dist/dist/commands/fullstack.js.map +1 -0
  15. package/dist/dist/commands/share.d.ts +18 -0
  16. package/dist/dist/commands/share.d.ts.map +1 -0
  17. package/dist/dist/commands/share.js +125 -0
  18. package/dist/dist/commands/share.js.map +1 -0
  19. package/dist/dist/commands/whoami.d.ts +2 -0
  20. package/dist/dist/commands/whoami.d.ts.map +1 -0
  21. package/dist/dist/commands/whoami.js +17 -0
  22. package/dist/dist/commands/whoami.js.map +1 -0
  23. package/dist/dist/core/analytics.d.ts +11 -0
  24. package/dist/dist/core/analytics.d.ts.map +1 -0
  25. package/dist/dist/core/analytics.js +47 -0
  26. package/dist/dist/core/analytics.js.map +1 -0
  27. package/dist/dist/core/backend.d.ts +26 -0
  28. package/dist/dist/core/backend.d.ts.map +1 -0
  29. package/dist/dist/core/backend.js +185 -0
  30. package/dist/dist/core/backend.js.map +1 -0
  31. package/dist/dist/core/build.d.ts +11 -0
  32. package/dist/dist/core/build.d.ts.map +1 -0
  33. package/dist/dist/core/build.js +34 -0
  34. package/dist/dist/core/build.js.map +1 -0
  35. package/dist/dist/core/detect.d.ts +12 -0
  36. package/dist/dist/core/detect.d.ts.map +1 -0
  37. package/dist/dist/core/detect.js +122 -0
  38. package/dist/dist/core/detect.js.map +1 -0
  39. package/dist/dist/core/env.d.ts +27 -0
  40. package/dist/dist/core/env.d.ts.map +1 -0
  41. package/dist/dist/core/env.js +164 -0
  42. package/dist/dist/core/env.js.map +1 -0
  43. package/dist/dist/core/fullstack.d.ts +29 -0
  44. package/dist/dist/core/fullstack.d.ts.map +1 -0
  45. package/dist/dist/core/fullstack.js +126 -0
  46. package/dist/dist/core/fullstack.js.map +1 -0
  47. package/dist/dist/core/qr.d.ts +4 -0
  48. package/dist/dist/core/qr.d.ts.map +1 -0
  49. package/dist/dist/core/qr.js +29 -0
  50. package/dist/dist/core/qr.js.map +1 -0
  51. package/dist/dist/core/tunnel.d.ts +9 -0
  52. package/dist/dist/core/tunnel.d.ts.map +1 -0
  53. package/dist/dist/core/tunnel.js +55 -0
  54. package/dist/dist/core/tunnel.js.map +1 -0
  55. package/dist/dist/core/upload.d.ts +22 -0
  56. package/dist/dist/core/upload.d.ts.map +1 -0
  57. package/dist/dist/core/upload.js +73 -0
  58. package/dist/dist/core/upload.js.map +1 -0
  59. package/dist/dist/ui/spinner.d.ts +8 -0
  60. package/dist/dist/ui/spinner.d.ts.map +1 -0
  61. package/dist/dist/ui/spinner.js +35 -0
  62. package/dist/dist/ui/spinner.js.map +1 -0
  63. package/dist/dist/ui/theme.d.ts +14 -0
  64. package/dist/dist/ui/theme.d.ts.map +1 -0
  65. package/dist/dist/ui/theme.js +32 -0
  66. package/dist/dist/ui/theme.js.map +1 -0
  67. package/dist/dist/ui/welcome.d.ts +4 -0
  68. package/dist/dist/ui/welcome.d.ts.map +1 -0
  69. package/dist/dist/ui/welcome.js +95 -0
  70. package/dist/dist/ui/welcome.js.map +1 -0
  71. package/dist/dist/utils/config.d.ts +19 -0
  72. package/dist/dist/utils/config.d.ts.map +1 -0
  73. package/dist/dist/utils/config.js +31 -0
  74. package/dist/dist/utils/config.js.map +1 -0
  75. package/dist/dist/utils/hash.d.ts +3 -0
  76. package/dist/dist/utils/hash.d.ts.map +1 -0
  77. package/dist/dist/utils/hash.js +10 -0
  78. package/dist/dist/utils/hash.js.map +1 -0
  79. package/dist/dist/utils/zip.d.ts +2 -0
  80. package/dist/dist/utils/zip.d.ts.map +1 -0
  81. package/dist/dist/utils/zip.js +19 -0
  82. package/dist/dist/utils/zip.js.map +1 -0
  83. package/package.json +8 -3
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Nivii Analytics — View deployment analytics
3
+ */
4
+ import { loadConfig } from '../utils/config.js';
5
+ import { theme } from '../ui/theme.js';
6
+ import chalk from 'chalk';
7
+ export async function runAnalytics(slug) {
8
+ const config = loadConfig();
9
+ const apiBase = config.apiBase || 'https://api.nivii.app';
10
+ if (!slug) {
11
+ const deployments = config.deployments || [];
12
+ if (!deployments.length) {
13
+ console.log(theme.muted('\n No deployments found. Run: nivii share\n'));
14
+ return;
15
+ }
16
+ slug = deployments[0].slug;
17
+ }
18
+ console.log('');
19
+ console.log(theme.primary(' Analytics') + theme.muted(` for ${slug}.nivii.app`));
20
+ console.log('');
21
+ try {
22
+ const { default: fetch } = await import('node-fetch');
23
+ const res = await fetch(`${apiBase}/analytics/${slug}`, {
24
+ headers: config.token ? { Authorization: `Bearer ${config.token}` } : {},
25
+ });
26
+ if (!res.ok) {
27
+ console.log(theme.error(' Failed to fetch analytics: ' + res.status));
28
+ return;
29
+ }
30
+ const data = await res.json();
31
+ console.log(' ' + chalk.cyan('Total views:') + ' ' + chalk.white(String(data.views)));
32
+ console.log('');
33
+ if (data.sessions && data.sessions.length > 0) {
34
+ console.log(' ' + theme.muted('Recent visitors:'));
35
+ console.log('');
36
+ data.sessions.slice(-10).reverse().forEach(s => {
37
+ const time = new Date(s.timestamp).toLocaleString();
38
+ console.log(` ${chalk.hex('#6B7280')(time)} ${chalk.cyan(s.country)}/${chalk.white(s.city)}`);
39
+ });
40
+ }
41
+ console.log('');
42
+ }
43
+ catch (err) {
44
+ console.log(theme.error(' ' + err.message));
45
+ }
46
+ }
47
+ //# sourceMappingURL=analytics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analytics.js","sourceRoot":"","sources":["../../src/core/analytics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import { EnvVar } from './env.js';
2
+ export interface BackendDeployOptions {
3
+ projectDir: string;
4
+ slug: string;
5
+ envVars: EnvVar[];
6
+ flyToken: string;
7
+ port?: number;
8
+ framework: string;
9
+ expiresIn?: number;
10
+ }
11
+ export interface BackendDeployResult {
12
+ url: string;
13
+ appName: string;
14
+ machineId: string;
15
+ }
16
+ /** Generate a minimal Dockerfile for the backend */
17
+ export declare function generateDockerfile(framework: string, port: number): string;
18
+ /** Generate fly.toml for the app */
19
+ export declare function generateFlyToml(appName: string, port: number): string;
20
+ /** Deploy backend to Fly.io using flyctl via CLI subprocess */
21
+ export declare function deployBackend(opts: BackendDeployOptions): Promise<BackendDeployResult>;
22
+ /** Schedule auto-destruction of a Fly.io app after N hours */
23
+ export declare function scheduleBackendDestroy(appName: string, flyToken: string, afterHours?: number): Promise<void>;
24
+ /** Destroy a Fly.io app */
25
+ export declare function destroyBackend(appName: string, flyToken: string): Promise<void>;
26
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/core/backend.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAKlC,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,oDAAoD;AACpD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAuB1E;AAED,oCAAoC;AACpC,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBrE;AAoCD,+DAA+D;AAC/D,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAqE5F;AAED,8DAA8D;AAC9D,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,GAAE,MAAW,GACtB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,2BAA2B;AAC3B,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMrF"}
@@ -0,0 +1,185 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import fetch from 'node-fetch';
4
+ import { createSpinner } from '../ui/spinner.js';
5
+ import chalk from 'chalk';
6
+ const FLY_API = 'https://api.machines.dev/v1';
7
+ const FLY_DEPLOY_API = 'https://fly.io/api/v1';
8
+ /** Generate a minimal Dockerfile for the backend */
9
+ export function generateDockerfile(framework, port) {
10
+ const portStr = String(port);
11
+ if (framework === 'hono') {
12
+ return `FROM node:20-alpine
13
+ WORKDIR /app
14
+ COPY package*.json ./
15
+ RUN npm ci --production
16
+ COPY . .
17
+ EXPOSE ${portStr}
18
+ CMD ["node", "src/index.js"]
19
+ `;
20
+ }
21
+ // Express / Fastify / generic Node
22
+ return `FROM node:20-alpine
23
+ WORKDIR /app
24
+ COPY package*.json ./
25
+ RUN npm ci --production
26
+ COPY . .
27
+ EXPOSE ${portStr}
28
+ CMD ["node", "index.js"]
29
+ `;
30
+ }
31
+ /** Generate fly.toml for the app */
32
+ export function generateFlyToml(appName, port) {
33
+ return `app = "${appName}"
34
+ primary_region = "sin"
35
+
36
+ [build]
37
+
38
+ [http_service]
39
+ internal_port = ${port}
40
+ force_https = true
41
+ auto_stop_machines = true
42
+ auto_start_machines = true
43
+ min_machines_running = 0
44
+
45
+ [env]
46
+ PORT = "${port}"
47
+ `;
48
+ }
49
+ /** Create a Fly.io app via API */
50
+ async function createFlyApp(name, token) {
51
+ const res = await fetch('https://api.fly.io/graphql', {
52
+ method: 'POST',
53
+ headers: {
54
+ 'Authorization': `Bearer ${token}`,
55
+ 'Content-Type': 'application/json',
56
+ },
57
+ body: JSON.stringify({
58
+ query: `
59
+ mutation CreateApp($input: CreateAppInput!) {
60
+ createApp(input: $input) {
61
+ app { name }
62
+ }
63
+ }
64
+ `,
65
+ variables: {
66
+ input: {
67
+ name,
68
+ organizationSlug: 'personal',
69
+ },
70
+ },
71
+ }),
72
+ });
73
+ const json = await res.json();
74
+ if (json.errors && json.errors.length > 0) {
75
+ // App might already exist — that's OK
76
+ if (!json.errors[0].message.includes('already exists')) {
77
+ throw new Error(`Fly app creation failed: ${json.errors[0].message}`);
78
+ }
79
+ }
80
+ }
81
+ /** Deploy backend to Fly.io using flyctl via CLI subprocess */
82
+ export async function deployBackend(opts) {
83
+ const spinner = createSpinner('Deploying backend to Fly.io…');
84
+ spinner.start();
85
+ const appName = `nivii-${opts.slug}-api`;
86
+ const port = opts.port || 3000;
87
+ const tmpDir = path.join('/tmp', `nivii-backend-${opts.slug}`);
88
+ try {
89
+ // Copy project to temp dir
90
+ if (fs.existsSync(tmpDir))
91
+ fs.rmSync(tmpDir, { recursive: true });
92
+ fs.mkdirSync(tmpDir, { recursive: true });
93
+ copyDir(opts.projectDir, tmpDir, ['node_modules', '.git', '.next', 'dist', 'build']);
94
+ // Generate Dockerfile if missing
95
+ const dockerfilePath = path.join(tmpDir, 'Dockerfile');
96
+ if (!fs.existsSync(dockerfilePath)) {
97
+ fs.writeFileSync(dockerfilePath, generateDockerfile(opts.framework, port));
98
+ }
99
+ // Generate fly.toml
100
+ fs.writeFileSync(path.join(tmpDir, 'fly.toml'), generateFlyToml(appName, port));
101
+ // Write .env file for the deployment
102
+ if (opts.envVars.length > 0) {
103
+ const envContent = opts.envVars
104
+ .map(v => `${v.key}=${v.value}`)
105
+ .join('\n');
106
+ fs.writeFileSync(path.join(tmpDir, '.env'), envContent);
107
+ }
108
+ // Use flyctl to deploy (must be installed)
109
+ const { execSync } = await import('child_process');
110
+ // Check flyctl available
111
+ try {
112
+ execSync('flyctl version', { stdio: 'ignore' });
113
+ }
114
+ catch {
115
+ throw new Error('flyctl not found. Install it: curl -L https://fly.io/install.sh | sh');
116
+ }
117
+ // Set env vars as args
118
+ const envArgs = opts.envVars
119
+ .map(v => `--env ${v.key}="${v.value}"`)
120
+ .join(' ');
121
+ // Deploy
122
+ execSync(`flyctl deploy --app ${appName} --remote-only --yes ${envArgs}`, {
123
+ cwd: tmpDir,
124
+ stdio: 'pipe',
125
+ env: { ...process.env, FLY_API_TOKEN: opts.flyToken },
126
+ });
127
+ const url = `https://${appName}.fly.dev`;
128
+ spinner.succeed(chalk.hex('#10B981')('Backend deployed ') + chalk.hex('#6B7280')(`(${appName})`));
129
+ return { url, appName, machineId: '' };
130
+ }
131
+ catch (err) {
132
+ spinner.fail(chalk.hex('#EF4444')('Backend deploy failed'));
133
+ throw err;
134
+ }
135
+ finally {
136
+ // Cleanup temp dir
137
+ try {
138
+ fs.rmSync(tmpDir, { recursive: true });
139
+ }
140
+ catch { }
141
+ }
142
+ }
143
+ /** Schedule auto-destruction of a Fly.io app after N hours */
144
+ export async function scheduleBackendDestroy(appName, flyToken, afterHours = 48) {
145
+ // We store this intent locally — a cron/timeout will handle it
146
+ // In production this would be a CF Worker scheduled task
147
+ const destroyAt = Date.now() + afterHours * 60 * 60 * 1000;
148
+ const record = { appName, flyToken: '[redacted]', destroyAt };
149
+ // Write to ~/.nivii/pending-destroys.json
150
+ const home = process.env.HOME || '/tmp';
151
+ const file = path.join(home, '.nivii', 'pending-destroys.json');
152
+ let existing = [];
153
+ try {
154
+ existing = JSON.parse(fs.readFileSync(file, 'utf-8'));
155
+ }
156
+ catch { }
157
+ existing.push(record);
158
+ fs.mkdirSync(path.dirname(file), { recursive: true });
159
+ fs.writeFileSync(file, JSON.stringify(existing, null, 2));
160
+ }
161
+ /** Destroy a Fly.io app */
162
+ export async function destroyBackend(appName, flyToken) {
163
+ const { execSync } = await import('child_process');
164
+ execSync(`flyctl apps destroy ${appName} --yes`, {
165
+ stdio: 'pipe',
166
+ env: { ...process.env, FLY_API_TOKEN: flyToken },
167
+ });
168
+ }
169
+ function copyDir(src, dest, skip = []) {
170
+ const entries = fs.readdirSync(src, { withFileTypes: true });
171
+ for (const entry of entries) {
172
+ if (skip.includes(entry.name))
173
+ continue;
174
+ const srcPath = path.join(src, entry.name);
175
+ const destPath = path.join(dest, entry.name);
176
+ if (entry.isDirectory()) {
177
+ fs.mkdirSync(destPath, { recursive: true });
178
+ copyDir(srcPath, destPath, skip);
179
+ }
180
+ else {
181
+ fs.copyFileSync(srcPath, destPath);
182
+ }
183
+ }
184
+ }
185
+ //# sourceMappingURL=backend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/core/backend.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { DetectResult } from './detect.js';
2
+ export interface BuildOptions {
3
+ cwd: string;
4
+ detect: DetectResult;
5
+ customCmd?: string;
6
+ noBuild?: boolean;
7
+ }
8
+ export declare function runBuild(opts: BuildOptions): Promise<{
9
+ outputDir: string;
10
+ }>;
11
+ //# sourceMappingURL=build.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIhD,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,YAAY,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCjF"}
@@ -0,0 +1,34 @@
1
+ import { spawn } from 'child_process';
2
+ import { createSpinner, step } from '../ui/spinner.js';
3
+ import chalk from 'chalk';
4
+ export async function runBuild(opts) {
5
+ const { cwd, detect, customCmd, noBuild } = opts;
6
+ if (noBuild || detect.buildCommand === null) {
7
+ step('📁', 'Skipping build', detect.outputDir);
8
+ return { outputDir: detect.outputDir };
9
+ }
10
+ const cmd = customCmd || detect.buildCommand;
11
+ const spinner = createSpinner(`Building with ${chalk.cyan(detect.framework)}…`);
12
+ spinner.start();
13
+ return new Promise((resolve, reject) => {
14
+ const proc = spawn(cmd, [], {
15
+ cwd,
16
+ shell: true,
17
+ env: { ...process.env, NODE_ENV: 'production', CI: '1' },
18
+ });
19
+ let stderr = '';
20
+ proc.stderr.on('data', d => { stderr += d.toString(); });
21
+ proc.on('close', code => {
22
+ if (code === 0) {
23
+ spinner.succeed(chalk.hex('#10B981')(`Build complete `) + chalk.hex('#6B7280')(`(${detect.framework})`));
24
+ resolve({ outputDir: detect.outputDir });
25
+ }
26
+ else {
27
+ spinner.fail(chalk.hex('#EF4444')('Build failed'));
28
+ console.log(chalk.hex('#6B7280')(stderr.slice(-800)));
29
+ reject(new Error(`Build exited with code ${code}`));
30
+ }
31
+ });
32
+ });
33
+ }
34
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/core/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,IAAkB;IAC/C,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAEjD,IAAI,OAAO,IAAI,MAAM,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;QAC5C,IAAI,CAAC,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;IACzC,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,IAAI,MAAM,CAAC,YAAY,CAAC;IAC7C,MAAM,OAAO,GAAG,aAAa,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAChF,OAAO,CAAC,KAAK,EAAE,CAAC;IAEhB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE;YAC1B,GAAG;YACH,KAAK,EAAE,IAAI;YACX,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,GAAG,EAAE;SACzD,CAAC,CAAC;QAEH,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,GAAG,MAAM,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAEzD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,IAAI,CAAC,EAAE;YACtB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC;gBACzG,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC;gBACnD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACtD,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC,CAAC;YACtD,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type Framework = 'nextjs' | 'vite' | 'react-cra' | 'vue' | 'svelte' | 'sveltekit' | 'astro' | 'remix' | 'nuxt' | 'solid' | 'express' | 'fastify' | 'hono' | 'static' | 'unknown';
2
+ export interface DetectResult {
3
+ framework: Framework;
4
+ buildCommand: string | null;
5
+ outputDir: string;
6
+ isServer: boolean;
7
+ port?: number;
8
+ packageManager: 'npm' | 'pnpm' | 'yarn' | 'bun';
9
+ confidence: number;
10
+ }
11
+ export declare function detectFramework(cwd: string): DetectResult;
12
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/core/detect.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,SAAS,GACjB,QAAQ,GACR,MAAM,GACN,WAAW,GACX,KAAK,GACL,QAAQ,GACR,WAAW,GACX,OAAO,GACP,OAAO,GACP,MAAM,GACN,OAAO,GACP,SAAS,GACT,SAAS,GACT,MAAM,GACN,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,SAAS,CAAC;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAiHzD"}
@@ -0,0 +1,122 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ export function detectFramework(cwd) {
4
+ const pkg = readJson(path.join(cwd, 'package.json'));
5
+ const deps = {
6
+ ...(pkg?.dependencies || {}),
7
+ ...(pkg?.devDependencies || {}),
8
+ };
9
+ const has = (name) => name in deps;
10
+ const hasFile = (...files) => files.some(f => fs.existsSync(path.join(cwd, f)));
11
+ const pm = detectPackageManager(cwd);
12
+ // Next.js
13
+ if (has('next')) {
14
+ const outputDir = fs.existsSync(path.join(cwd, 'out')) ? 'out' :
15
+ fs.existsSync(path.join(cwd, '.next')) ? '.next' : 'out';
16
+ return {
17
+ framework: 'nextjs',
18
+ buildCommand: `${pm} run build`,
19
+ outputDir,
20
+ isServer: false,
21
+ packageManager: pm,
22
+ confidence: 99,
23
+ };
24
+ }
25
+ // SvelteKit
26
+ if (has('@sveltejs/kit')) {
27
+ return {
28
+ framework: 'sveltekit',
29
+ buildCommand: `${pm} run build`,
30
+ outputDir: 'build',
31
+ isServer: false,
32
+ packageManager: pm,
33
+ confidence: 95,
34
+ };
35
+ }
36
+ // Astro
37
+ if (has('astro')) {
38
+ return {
39
+ framework: 'astro',
40
+ buildCommand: `${pm} run build`,
41
+ outputDir: 'dist',
42
+ isServer: false,
43
+ packageManager: pm,
44
+ confidence: 95,
45
+ };
46
+ }
47
+ // Remix
48
+ if (has('@remix-run/react') || has('@remix-run/node')) {
49
+ return {
50
+ framework: 'remix',
51
+ buildCommand: `${pm} run build`,
52
+ outputDir: 'public',
53
+ isServer: true,
54
+ packageManager: pm,
55
+ confidence: 90,
56
+ };
57
+ }
58
+ // Nuxt
59
+ if (has('nuxt') || has('nuxt3') || has('nuxt-edge')) {
60
+ return {
61
+ framework: 'nuxt',
62
+ buildCommand: `${pm} run generate`,
63
+ outputDir: '.output/public',
64
+ isServer: false,
65
+ packageManager: pm,
66
+ confidence: 90,
67
+ };
68
+ }
69
+ // Vite (React/Vue/Svelte/Solid)
70
+ if (has('vite')) {
71
+ const outputDir = 'dist';
72
+ if (has('react') || has('react-dom')) {
73
+ return { framework: 'react-cra', buildCommand: `${pm} run build`, outputDir, isServer: false, packageManager: pm, confidence: 88 };
74
+ }
75
+ if (has('vue')) {
76
+ return { framework: 'vue', buildCommand: `${pm} run build`, outputDir, isServer: false, packageManager: pm, confidence: 88 };
77
+ }
78
+ if (has('svelte')) {
79
+ return { framework: 'svelte', buildCommand: `${pm} run build`, outputDir, isServer: false, packageManager: pm, confidence: 88 };
80
+ }
81
+ if (has('solid-js')) {
82
+ return { framework: 'solid', buildCommand: `${pm} run build`, outputDir, isServer: false, packageManager: pm, confidence: 88 };
83
+ }
84
+ return { framework: 'vite', buildCommand: `${pm} run build`, outputDir, isServer: false, packageManager: pm, confidence: 85 };
85
+ }
86
+ // Express/Fastify/Hono server
87
+ if (has('express')) {
88
+ return { framework: 'express', buildCommand: null, outputDir: '.', isServer: true, port: 3000, packageManager: pm, confidence: 80 };
89
+ }
90
+ if (has('fastify')) {
91
+ return { framework: 'fastify', buildCommand: null, outputDir: '.', isServer: true, port: 3000, packageManager: pm, confidence: 80 };
92
+ }
93
+ if (has('hono')) {
94
+ return { framework: 'hono', buildCommand: null, outputDir: '.', isServer: true, port: 3000, packageManager: pm, confidence: 80 };
95
+ }
96
+ // Static HTML/dist/build
97
+ if (hasFile('index.html') || hasFile('dist/index.html') || hasFile('build/index.html') || hasFile('out/index.html')) {
98
+ const outputDir = fs.existsSync(path.join(cwd, 'dist/index.html')) ? 'dist' :
99
+ fs.existsSync(path.join(cwd, 'build/index.html')) ? 'build' :
100
+ fs.existsSync(path.join(cwd, 'out/index.html')) ? 'out' : '.';
101
+ return { framework: 'static', buildCommand: null, outputDir, isServer: false, packageManager: pm, confidence: 70 };
102
+ }
103
+ return { framework: 'unknown', buildCommand: null, outputDir: '.', isServer: false, packageManager: pm, confidence: 10 };
104
+ }
105
+ function detectPackageManager(cwd) {
106
+ if (fs.existsSync(path.join(cwd, 'bun.lockb')))
107
+ return 'bun';
108
+ if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml')))
109
+ return 'pnpm';
110
+ if (fs.existsSync(path.join(cwd, 'yarn.lock')))
111
+ return 'yarn';
112
+ return 'npm';
113
+ }
114
+ function readJson(filePath) {
115
+ try {
116
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
117
+ }
118
+ catch {
119
+ return null;
120
+ }
121
+ }
122
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../src/core/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export interface EnvVar {
2
+ key: string;
3
+ value: string;
4
+ isFrontendSafe: boolean;
5
+ source: string;
6
+ }
7
+ export interface EnvScanResult {
8
+ vars: EnvVar[];
9
+ files: string[];
10
+ localhostRefs: LocalhostRef[];
11
+ }
12
+ export interface LocalhostRef {
13
+ file: string;
14
+ line: number;
15
+ original: string;
16
+ envKey: string;
17
+ }
18
+ export declare function scanEnvFiles(cwd: string): EnvScanResult;
19
+ /** Scan source files for hardcoded localhost references */
20
+ export declare function scanLocalhostRefs(cwd: string): LocalhostRef[];
21
+ /** Filter which env vars to send to backend deployment */
22
+ export declare function filterBackendVars(vars: EnvVar[]): EnvVar[];
23
+ /** Replace localhost URLs in source code with env var references */
24
+ export declare function injectEnvIntoSource(cwd: string, frontendDir: string, backendUrl: string, frontendUrl: string): void;
25
+ /** Print a formatted summary of found env vars */
26
+ export declare function formatEnvSummary(result: EnvScanResult): string;
27
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/core/env.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;CAChB;AA+CD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CAiCvD;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,EAAE,CAiC7D;AAED,0DAA0D;AAC1D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAQ1D;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GAClB,IAAI,CA2BN;AAED,kDAAkD;AAClD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAS9D"}