nivii 0.3.2 → 0.3.3

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 (120) hide show
  1. package/dist/cli.js +48 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/pro.d.ts +2 -0
  4. package/dist/commands/pro.d.ts.map +1 -0
  5. package/dist/commands/pro.js +174 -0
  6. package/dist/commands/pro.js.map +1 -0
  7. package/dist/commands/share.d.ts.map +1 -1
  8. package/dist/commands/share.js +5 -4
  9. package/dist/commands/share.js.map +1 -1
  10. package/dist/core/upload.d.ts +2 -1
  11. package/dist/core/upload.d.ts.map +1 -1
  12. package/dist/core/upload.js +2 -0
  13. package/dist/core/upload.js.map +1 -1
  14. package/dist/ui/spinner.d.ts +1 -0
  15. package/dist/ui/spinner.d.ts.map +1 -1
  16. package/dist/ui/spinner.js +3 -0
  17. package/dist/ui/spinner.js.map +1 -1
  18. package/dist/ui/welcome.d.ts.map +1 -1
  19. package/dist/ui/welcome.js +6 -3
  20. package/dist/ui/welcome.js.map +1 -1
  21. package/dist/utils/config.d.ts +3 -0
  22. package/dist/utils/config.d.ts.map +1 -1
  23. package/dist/utils/config.js.map +1 -1
  24. package/package.json +1 -1
  25. package/dist/dist/cli.d.ts +0 -3
  26. package/dist/dist/cli.d.ts.map +0 -1
  27. package/dist/dist/cli.js +0 -144
  28. package/dist/dist/cli.js.map +0 -1
  29. package/dist/dist/commands/config.d.ts +0 -2
  30. package/dist/dist/commands/config.d.ts.map +0 -1
  31. package/dist/dist/commands/config.js +0 -32
  32. package/dist/dist/commands/config.js.map +0 -1
  33. package/dist/dist/commands/share.d.ts +0 -18
  34. package/dist/dist/commands/share.d.ts.map +0 -1
  35. package/dist/dist/commands/share.js +0 -125
  36. package/dist/dist/commands/share.js.map +0 -1
  37. package/dist/dist/commands/whoami.d.ts +0 -2
  38. package/dist/dist/commands/whoami.d.ts.map +0 -1
  39. package/dist/dist/commands/whoami.js +0 -17
  40. package/dist/dist/commands/whoami.js.map +0 -1
  41. package/dist/dist/core/analytics.d.ts +0 -11
  42. package/dist/dist/core/analytics.d.ts.map +0 -1
  43. package/dist/dist/core/analytics.js +0 -47
  44. package/dist/dist/core/analytics.js.map +0 -1
  45. package/dist/dist/core/build.d.ts +0 -11
  46. package/dist/dist/core/build.d.ts.map +0 -1
  47. package/dist/dist/core/build.js +0 -34
  48. package/dist/dist/core/build.js.map +0 -1
  49. package/dist/dist/core/detect.d.ts +0 -12
  50. package/dist/dist/core/detect.d.ts.map +0 -1
  51. package/dist/dist/core/detect.js +0 -122
  52. package/dist/dist/core/detect.js.map +0 -1
  53. package/dist/dist/core/qr.d.ts +0 -4
  54. package/dist/dist/core/qr.d.ts.map +0 -1
  55. package/dist/dist/core/qr.js +0 -29
  56. package/dist/dist/core/qr.js.map +0 -1
  57. package/dist/dist/core/tunnel.d.ts +0 -9
  58. package/dist/dist/core/tunnel.d.ts.map +0 -1
  59. package/dist/dist/core/tunnel.js +0 -55
  60. package/dist/dist/core/tunnel.js.map +0 -1
  61. package/dist/dist/core/upload.d.ts +0 -22
  62. package/dist/dist/core/upload.d.ts.map +0 -1
  63. package/dist/dist/core/upload.js +0 -73
  64. package/dist/dist/core/upload.js.map +0 -1
  65. package/dist/dist/ui/spinner.d.ts +0 -8
  66. package/dist/dist/ui/spinner.d.ts.map +0 -1
  67. package/dist/dist/ui/spinner.js +0 -35
  68. package/dist/dist/ui/spinner.js.map +0 -1
  69. package/dist/dist/ui/theme.d.ts +0 -14
  70. package/dist/dist/ui/theme.d.ts.map +0 -1
  71. package/dist/dist/ui/theme.js +0 -32
  72. package/dist/dist/ui/theme.js.map +0 -1
  73. package/dist/dist/ui/welcome.d.ts +0 -4
  74. package/dist/dist/ui/welcome.d.ts.map +0 -1
  75. package/dist/dist/ui/welcome.js +0 -95
  76. package/dist/dist/ui/welcome.js.map +0 -1
  77. package/dist/dist/utils/config.d.ts +0 -19
  78. package/dist/dist/utils/config.d.ts.map +0 -1
  79. package/dist/dist/utils/config.js +0 -31
  80. package/dist/dist/utils/config.js.map +0 -1
  81. package/dist/dist/utils/hash.d.ts +0 -3
  82. package/dist/dist/utils/hash.d.ts.map +0 -1
  83. package/dist/dist/utils/hash.js +0 -10
  84. package/dist/dist/utils/hash.js.map +0 -1
  85. package/dist/dist/utils/zip.d.ts +0 -2
  86. package/dist/dist/utils/zip.d.ts.map +0 -1
  87. package/dist/dist/utils/zip.js +0 -19
  88. package/dist/dist/utils/zip.js.map +0 -1
  89. package/src/cli.ts +0 -118
  90. package/src/commands/config.ts +0 -33
  91. package/src/commands/share.ts +0 -159
  92. package/src/commands/whoami.ts +0 -16
  93. package/src/core/analytics.ts +0 -64
  94. package/src/core/build.ts +0 -46
  95. package/src/core/detect.ts +0 -159
  96. package/src/core/qr.ts +0 -30
  97. package/src/core/tunnel.ts +0 -70
  98. package/src/core/upload.ts +0 -95
  99. package/src/ui/spinner.ts +0 -36
  100. package/src/ui/theme.ts +0 -35
  101. package/src/ui/welcome.ts +0 -104
  102. package/src/utils/config.ts +0 -47
  103. package/src/utils/hash.ts +0 -11
  104. package/src/utils/zip.ts +0 -22
  105. /package/dist/{dist/commands → commands}/fullstack.d.ts +0 -0
  106. /package/dist/{dist/commands → commands}/fullstack.d.ts.map +0 -0
  107. /package/dist/{dist/commands → commands}/fullstack.js +0 -0
  108. /package/dist/{dist/commands → commands}/fullstack.js.map +0 -0
  109. /package/dist/{dist/core → core}/backend.d.ts +0 -0
  110. /package/dist/{dist/core → core}/backend.d.ts.map +0 -0
  111. /package/dist/{dist/core → core}/backend.js +0 -0
  112. /package/dist/{dist/core → core}/backend.js.map +0 -0
  113. /package/dist/{dist/core → core}/env.d.ts +0 -0
  114. /package/dist/{dist/core → core}/env.d.ts.map +0 -0
  115. /package/dist/{dist/core → core}/env.js +0 -0
  116. /package/dist/{dist/core → core}/env.js.map +0 -0
  117. /package/dist/{dist/core → core}/fullstack.d.ts +0 -0
  118. /package/dist/{dist/core → core}/fullstack.d.ts.map +0 -0
  119. /package/dist/{dist/core → core}/fullstack.js +0 -0
  120. /package/dist/{dist/core → core}/fullstack.js.map +0 -0
@@ -1,31 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import os from 'os';
4
- const CONFIG_DIR = path.join(os.homedir(), '.nivii');
5
- const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
6
- export const API_BASE = process.env.NIVII_API || 'https://api.nivii.app';
7
- export function loadConfig() {
8
- try {
9
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
10
- if (!fs.existsSync(CONFIG_FILE)) {
11
- const defaults = { firstRun: true, apiBase: API_BASE, deployments: [] };
12
- saveConfig(defaults);
13
- return defaults;
14
- }
15
- return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
16
- }
17
- catch {
18
- return { firstRun: true, apiBase: API_BASE, deployments: [] };
19
- }
20
- }
21
- export function saveConfig(config) {
22
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
23
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
24
- }
25
- export function updateConfig(updates) {
26
- const current = loadConfig();
27
- const updated = { ...current, ...updates };
28
- saveConfig(updated);
29
- return updated;
30
- }
31
- //# sourceMappingURL=config.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,IAAI,CAAC;AAiBpB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;AAEzD,MAAM,CAAC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,uBAAuB,CAAC;AAEzE,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,MAAM,QAAQ,GAAgB,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;YACrF,UAAU,CAAC,QAAQ,CAAC,CAAC;YACrB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAChE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAmB;IAC5C,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAA6B;IACxD,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3C,UAAU,CAAC,OAAO,CAAC,CAAC;IACpB,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -1,3 +0,0 @@
1
- export declare function generateSlug(length?: number): string;
2
- export declare function hashFile(content: Buffer): string;
3
- //# sourceMappingURL=hash.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAEA,wBAAgB,YAAY,CAAC,MAAM,SAAI,GAAG,MAAM,CAI/C;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEhD"}
@@ -1,10 +0,0 @@
1
- import crypto from 'crypto';
2
- export function generateSlug(length = 8) {
3
- const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
4
- const bytes = crypto.randomBytes(length);
5
- return Array.from(bytes).map(b => chars[b % chars.length]).join('');
6
- }
7
- export function hashFile(content) {
8
- return crypto.createHash('sha256').update(content).digest('hex').slice(0, 16);
9
- }
10
- //# sourceMappingURL=hash.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/utils/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,UAAU,YAAY,CAAC,MAAM,GAAG,CAAC;IACrC,MAAM,KAAK,GAAG,sCAAsC,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -1,2 +0,0 @@
1
- export declare function zipDirectory(sourceDir: string): Promise<string>;
2
- //# sourceMappingURL=zip.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../src/utils/zip.ts"],"names":[],"mappings":"AAMA,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAerE"}
@@ -1,19 +0,0 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import { createWriteStream } from 'fs';
4
- import archiver from 'archiver';
5
- import os from 'os';
6
- export async function zipDirectory(sourceDir) {
7
- const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'nivii-'));
8
- const zipPath = path.join(tmpDir, 'deploy.zip');
9
- return new Promise((resolve, reject) => {
10
- const output = createWriteStream(zipPath);
11
- const archive = archiver('zip', { zlib: { level: 9 } });
12
- output.on('close', () => resolve(zipPath));
13
- archive.on('error', reject);
14
- archive.pipe(output);
15
- archive.directory(sourceDir, false);
16
- archive.finalize();
17
- });
18
- }
19
- //# sourceMappingURL=zip.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"zip.js","sourceRoot":"","sources":["../../src/utils/zip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,MAAM,IAAI,CAAC;AACvC,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,MAAM,IAAI,CAAC;AAEpB,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAAiB;IAClD,MAAM,MAAM,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAExD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QAC3C,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAE5B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,OAAO,CAAC,SAAS,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;QACpC,OAAO,CAAC,QAAQ,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC"}
package/src/cli.ts DELETED
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env node
2
- import { cac } from 'cac';
3
- import chalk from 'chalk';
4
- import { runShare } from './commands/share.js';
5
- import { runConfig } from './commands/config.js';
6
- import { runWhoami } from './commands/whoami.js';
7
- import { runAnalytics } from './core/analytics.js';
8
- import { loadConfig, updateConfig } from './utils/config.js';
9
- import { showWelcome, showHelp } from './ui/welcome.js';
10
-
11
- const cli = cac('nivii');
12
-
13
- // ─── First run ────────────────────────────────────────────────────────────────
14
- const config = loadConfig();
15
- if (config.firstRun) {
16
- showWelcome();
17
- updateConfig({ firstRun: false });
18
- }
19
-
20
- // ─── share ────────────────────────────────────────────────────────────────────
21
- cli
22
- .command('share', 'Deploy your project and get a live URL')
23
- .option('--dir <dir>', 'Directory to deploy (default: cwd)')
24
- .option('--slug <slug>', 'Custom slug (Pro) e.g. my-demo → my-demo.nivii.app')
25
- .option('--pass <password>', 'Password-protect your deployment')
26
- .option('--otp', 'Enable one-time password access')
27
- .option('--expires <duration>', 'Expiry: 1h / 24h / 7d / 30d / never')
28
- .option('--live', 'Enable live sync (watch & auto-redeploy on changes)')
29
- .option('--collab', 'Enable real-time collaborative preview (Pro)')
30
- .option('--no-build', 'Skip build, use existing output directory')
31
- .option('--cmd <cmd>', 'Custom build command')
32
- .option('--port <port>', 'Port for server-mode proxy', { default: 3000 })
33
- .option('--max-views <n>', 'Self-destruct after N views')
34
- .option('--self-destruct', 'Self-destruct after first view')
35
- .option('--no-qr', 'Skip QR code')
36
- .option('--no-open', 'Do not open browser')
37
- .action(async (options) => {
38
- try {
39
- await runShare({
40
- dir: options.dir,
41
- slug: options.slug,
42
- pass: options.pass,
43
- otp: options.otp,
44
- expires: options.expires,
45
- live: options.live,
46
- collab: options.collab,
47
- noBuild: options['no-build'],
48
- cmd: options.cmd,
49
- port: options.port,
50
- maxViews: options.maxViews,
51
- selfDestruct: options.selfDestruct,
52
- open: options.open,
53
- qr: options.qr,
54
- });
55
- } catch (err: any) {
56
- console.error(chalk.red('\n ✗ ') + err.message);
57
- process.exit(1);
58
- }
59
- });
60
-
61
- // ─── config ───────────────────────────────────────────────────────────────────
62
- cli
63
- .command('config [key] [value]', 'View or set config values')
64
- .action((key, value) => {
65
- runConfig(key, value);
66
- });
67
-
68
- // ─── whoami ───────────────────────────────────────────────────────────────────
69
- cli
70
- .command('whoami', 'Show current account info')
71
- .action(() => {
72
- runWhoami();
73
- });
74
-
75
- // ─── ls (list deployments) ────────────────────────────────────────────────────
76
- cli
77
- .command('ls', 'List your recent deployments')
78
- .action(() => {
79
- const cfg = loadConfig();
80
- const deployments = cfg.deployments || [];
81
- if (!deployments.length) {
82
- console.log(chalk.hex('#6B7280')('\n No deployments yet. Run: nivii share\n'));
83
- return;
84
- }
85
- console.log('');
86
- console.log(chalk.hex('#A78BFA')(' Recent Deployments'));
87
- console.log('');
88
- deployments.forEach((d) => {
89
- const age = timeSince(new Date(d.createdAt));
90
- console.log(` ${chalk.cyan(d.slug)} · ${chalk.underline(d.url)} · ${chalk.hex('#6B7280')(age)}`);
91
- });
92
- console.log('');
93
- });
94
-
95
- // ─── analytics ────────────────────────────────────────────────────────────────
96
- cli
97
- .command('analytics [slug]', 'View analytics for a deployment')
98
- .action(async (slug) => {
99
- await runAnalytics(slug);
100
- });
101
-
102
- cli.version('0.1.8');
103
-
104
- // ─── Show help when no command given ─────────────────────────────────────────
105
- cli.parse(process.argv, { run: false });
106
- if (!cli.matchedCommand) {
107
- showHelp();
108
- process.exit(0);
109
- }
110
- await cli.runMatchedCommand();
111
-
112
- function timeSince(date: Date): string {
113
- const seconds = Math.floor((Date.now() - date.getTime()) / 1000);
114
- if (seconds < 60) return `${seconds}s ago`;
115
- if (seconds < 3600) return `${Math.floor(seconds / 60)}m ago`;
116
- if (seconds < 86400) return `${Math.floor(seconds / 3600)}h ago`;
117
- return `${Math.floor(seconds / 86400)}d ago`;
118
- }
@@ -1,33 +0,0 @@
1
- import chalk from 'chalk';
2
- import { loadConfig, saveConfig } from '../utils/config.js';
3
- import { theme } from '../ui/theme.js';
4
-
5
- export function runConfig(key?: string, value?: string) {
6
- const config = loadConfig();
7
-
8
- if (!key) {
9
- console.log('');
10
- console.log(theme.primary(' Nivii Config') + theme.muted(' (~/.nivii/config.json)'));
11
- console.log('');
12
- Object.entries(config).forEach(([k, v]) => {
13
- if (k === 'token') {
14
- console.log(` ${chalk.cyan(k)}: ${chalk.hex('#6B7280')('[hidden]')}`);
15
- } else if (k === 'deployments') {
16
- console.log(` ${chalk.cyan(k)}: ${chalk.hex('#6B7280')(JSON.stringify(v).slice(0, 60) + '…')}`);
17
- } else {
18
- console.log(` ${chalk.cyan(k)}: ${chalk.white(String(v))}`);
19
- }
20
- });
21
- console.log('');
22
- return;
23
- }
24
-
25
- if (value === undefined) {
26
- console.log(` ${chalk.cyan(key)}: ${chalk.white(String((config as any)[key] ?? 'not set'))}`);
27
- return;
28
- }
29
-
30
- (config as any)[key] = value;
31
- saveConfig(config);
32
- console.log(theme.success(` ✓ Set ${key} = ${value}`));
33
- }
@@ -1,159 +0,0 @@
1
- import path from 'path';
2
- import chalk from 'chalk';
3
- import { detectFramework } from '../core/detect.js';
4
- import { runBuild } from '../core/build.js';
5
- import { uploadDeploy } from '../core/upload.js';
6
- import { generateSlug } from '../utils/hash.js';
7
- import { loadConfig, updateConfig } from '../utils/config.js';
8
- import { showQR, copyToClipboard, openBrowser } from '../core/qr.js';
9
- import { startLiveSync } from '../core/tunnel.js';
10
- import { showBanner } from '../ui/welcome.js';
11
- import { step, success, warn } from '../ui/spinner.js';
12
- import { theme } from '../ui/theme.js';
13
-
14
- export interface ShareOptions {
15
- dir?: string;
16
- slug?: string;
17
- pass?: string;
18
- otp?: boolean;
19
- expires?: string;
20
- live?: boolean;
21
- collab?: boolean;
22
- noBuild?: boolean;
23
- cmd?: string;
24
- port?: number;
25
- maxViews?: number;
26
- selfDestruct?: boolean;
27
- open?: boolean;
28
- qr?: boolean;
29
- }
30
-
31
- export async function runShare(opts: ShareOptions) {
32
- showBanner();
33
-
34
- const cwd = opts.dir ? path.resolve(opts.dir) : process.cwd();
35
- const config = loadConfig();
36
-
37
- // ─── 1. Detect framework ───────────────────────────────────────────────────
38
- step('🔍', 'Detecting project type…', cwd);
39
- const detected = detectFramework(cwd);
40
-
41
- const frameworkLabel: Record<string, string> = {
42
- nextjs: 'Next.js', vite: 'Vite', 'react-cra': 'React (CRA)',
43
- vue: 'Vue', svelte: 'Svelte', sveltekit: 'SvelteKit',
44
- astro: 'Astro', remix: 'Remix', nuxt: 'Nuxt',
45
- solid: 'Solid.js', express: 'Express', fastify: 'Fastify',
46
- hono: 'Hono', static: 'Static HTML', unknown: 'Unknown',
47
- };
48
-
49
- success(`Detected ${chalk.cyan(frameworkLabel[detected.framework] || detected.framework)} ` +
50
- `${theme.muted(`(${detected.confidence}% confidence)`)}`);
51
-
52
- if (detected.framework === 'unknown' && !opts.noBuild) {
53
- warn('Could not detect framework. Using current directory as static site.');
54
- }
55
-
56
- // ─── 2. Build ──────────────────────────────────────────────────────────────
57
- const { outputDir } = await runBuild({
58
- cwd,
59
- detect: detected,
60
- customCmd: opts.cmd,
61
- noBuild: opts.noBuild,
62
- });
63
-
64
- const fullOutputDir = path.resolve(cwd, outputDir);
65
-
66
- // ─── 3. Slug ───────────────────────────────────────────────────────────────
67
- let slug = opts.slug;
68
- if (!slug) {
69
- slug = generateSlug(8);
70
- } else if (config.plan !== 'pro') {
71
- warn('Custom slugs require Nivii Pro. Using random slug instead.');
72
- slug = generateSlug(8);
73
- }
74
-
75
- // ─── 4. Upload (files directly, no zip) ────────────────────────────────────
76
- const deployResult = await uploadDeploy({
77
- buildDir: fullOutputDir,
78
- slug,
79
- token: config.token,
80
- password: opts.pass,
81
- otp: opts.otp,
82
- expires: opts.expires || (config.plan === 'pro' ? undefined : '48h'),
83
- live: opts.live,
84
- collab: opts.collab,
85
- maxViews: opts.maxViews,
86
- selfDestruct: opts.selfDestruct,
87
- });
88
-
89
- // ─── 5. Save to config ─────────────────────────────────────────────────────
90
- const deployments = config.deployments || [];
91
- deployments.unshift({
92
- slug: deployResult.slug,
93
- url: deployResult.url,
94
- createdAt: new Date().toISOString(),
95
- expiresAt: deployResult.expiresAt,
96
- });
97
- updateConfig({ deployments: deployments.slice(0, 20) });
98
-
99
- // ─── 6. Output ─────────────────────────────────────────────────────────────
100
- console.log('');
101
- console.log(theme.box([
102
- theme.accent(' 🚀 Your project is live!'),
103
- '',
104
- ' ' + theme.primary('URL:') + ' ' + chalk.underline.cyan(deployResult.url),
105
- ...(deployResult.expiresAt ? [' ' + theme.muted('Expires:') + ' ' + theme.muted(new Date(deployResult.expiresAt).toLocaleString())] : []),
106
- ...(opts.pass ? [' ' + theme.muted('Protected:') + ' ' + theme.success('✓ Password')] : []),
107
- ...(opts.otp && deployResult.otpCode ? [' ' + theme.muted('OTP:') + ' ' + theme.warning(deployResult.otpCode)] : []),
108
- ...(opts.live ? [' ' + theme.muted('Live sync:') + ' ' + theme.success('✓ Active')] : []),
109
- ...(opts.collab ? [' ' + theme.muted('Collab:') + ' ' + theme.success('✓ Active')] : []),
110
- ]));
111
- console.log('');
112
-
113
- // ─── 7. Copy URL to clipboard ──────────────────────────────────────────────
114
- const copied = await copyToClipboard(deployResult.url);
115
- if (copied) {
116
- success('URL copied to clipboard');
117
- }
118
-
119
- // ─── 8. QR code ────────────────────────────────────────────────────────────
120
- if (opts.qr !== false) {
121
- await showQR(deployResult.url);
122
- }
123
-
124
- // ─── 9. Open browser ───────────────────────────────────────────────────────
125
- if (opts.open !== false) {
126
- await openBrowser(deployResult.url);
127
- }
128
-
129
- // ─── 10. Live sync ─────────────────────────────────────────────────────────
130
- if (opts.live && deployResult.liveToken) {
131
- console.log('');
132
- console.log(theme.accent(' ⚡ Live Sync Active') + theme.muted(' — watching for changes…'));
133
- console.log(theme.muted(' Press Ctrl+C to stop'));
134
- console.log('');
135
-
136
- const stopLive = startLiveSync({
137
- watchDir: fullOutputDir,
138
- slug: deployResult.slug,
139
- liveToken: deployResult.liveToken,
140
- onUpdate: async () => {
141
- await uploadDeploy({
142
- buildDir: fullOutputDir,
143
- slug: deployResult.slug,
144
- token: config.token,
145
- live: true,
146
- });
147
- },
148
- });
149
-
150
- process.on('SIGINT', () => {
151
- stopLive();
152
- console.log('');
153
- console.log(theme.muted(' ↳ Live sync stopped'));
154
- process.exit(0);
155
- });
156
-
157
- await new Promise(() => {});
158
- }
159
- }
@@ -1,16 +0,0 @@
1
- import chalk from 'chalk';
2
- import { loadConfig } from '../utils/config.js';
3
- import { theme } from '../ui/theme.js';
4
-
5
- export function runWhoami() {
6
- const config = loadConfig();
7
- console.log('');
8
- if (!config.token) {
9
- console.log(theme.muted(' Not logged in. Using anonymous mode.'));
10
- console.log(' ' + theme.accent('nivii login') + theme.muted(' to unlock Pro features.'));
11
- } else {
12
- console.log(theme.success(' ✓ Logged in'));
13
- console.log(' ' + chalk.cyan('Plan: ') + chalk.white(config.plan || 'free'));
14
- }
15
- console.log('');
16
- }
@@ -1,64 +0,0 @@
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
-
8
- export interface AnalyticsData {
9
- views: number;
10
- sessions: Array<{
11
- timestamp: string;
12
- country: string;
13
- city: string;
14
- ua: string;
15
- }>;
16
- }
17
-
18
- export async function runAnalytics(slug?: string) {
19
- const config = loadConfig();
20
- const apiBase = config.apiBase || 'https://api.nivii.app';
21
-
22
- if (!slug) {
23
- const deployments = config.deployments || [];
24
- if (!deployments.length) {
25
- console.log(theme.muted('\n No deployments found. Run: nivii share\n'));
26
- return;
27
- }
28
- slug = deployments[0].slug;
29
- }
30
-
31
- console.log('');
32
- console.log(theme.primary(' Analytics') + theme.muted(` for ${slug}.nivii.app`));
33
- console.log('');
34
-
35
- try {
36
- const { default: fetch } = await import('node-fetch');
37
- const res = await fetch(`${apiBase}/analytics/${slug}`, {
38
- headers: config.token ? { Authorization: `Bearer ${config.token}` } : {},
39
- });
40
-
41
- if (!res.ok) {
42
- console.log(theme.error(' Failed to fetch analytics: ' + res.status));
43
- return;
44
- }
45
-
46
- const data = await res.json() as AnalyticsData;
47
-
48
- console.log(' ' + chalk.cyan('Total views:') + ' ' + chalk.white(String(data.views)));
49
- console.log('');
50
-
51
- if (data.sessions && data.sessions.length > 0) {
52
- console.log(' ' + theme.muted('Recent visitors:'));
53
- console.log('');
54
- data.sessions.slice(-10).reverse().forEach(s => {
55
- const time = new Date(s.timestamp).toLocaleString();
56
- console.log(` ${chalk.hex('#6B7280')(time)} ${chalk.cyan(s.country)}/${chalk.white(s.city)}`);
57
- });
58
- }
59
-
60
- console.log('');
61
- } catch (err: any) {
62
- console.log(theme.error(' ' + err.message));
63
- }
64
- }
package/src/core/build.ts DELETED
@@ -1,46 +0,0 @@
1
- import { spawn } from 'child_process';
2
- import type { DetectResult } from './detect.js';
3
- import { createSpinner, step } from '../ui/spinner.js';
4
- import chalk from 'chalk';
5
-
6
- export interface BuildOptions {
7
- cwd: string;
8
- detect: DetectResult;
9
- customCmd?: string;
10
- noBuild?: boolean;
11
- }
12
-
13
- export async function runBuild(opts: BuildOptions): Promise<{ outputDir: string }> {
14
- const { cwd, detect, customCmd, noBuild } = opts;
15
-
16
- if (noBuild || detect.buildCommand === null) {
17
- step('📁', 'Skipping build', detect.outputDir);
18
- return { outputDir: detect.outputDir };
19
- }
20
-
21
- const cmd = customCmd || detect.buildCommand;
22
- const spinner = createSpinner(`Building with ${chalk.cyan(detect.framework)}…`);
23
- spinner.start();
24
-
25
- return new Promise((resolve, reject) => {
26
- const proc = spawn(cmd, [], {
27
- cwd,
28
- shell: true,
29
- env: { ...process.env, NODE_ENV: 'production', CI: '1' },
30
- });
31
-
32
- let stderr = '';
33
- proc.stderr.on('data', d => { stderr += d.toString(); });
34
-
35
- proc.on('close', code => {
36
- if (code === 0) {
37
- spinner.succeed(chalk.hex('#10B981')(`Build complete `) + chalk.hex('#6B7280')(`(${detect.framework})`));
38
- resolve({ outputDir: detect.outputDir });
39
- } else {
40
- spinner.fail(chalk.hex('#EF4444')('Build failed'));
41
- console.log(chalk.hex('#6B7280')(stderr.slice(-800)));
42
- reject(new Error(`Build exited with code ${code}`));
43
- }
44
- });
45
- });
46
- }