my-airdrop 1.2.0 → 1.2.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 (2) hide show
  1. package/bin/cli.js +34 -9
  2. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -4,9 +4,10 @@
4
4
  const path = require('path');
5
5
  const os = require('os');
6
6
  const fs = require('fs');
7
+ const { execSync } = require('child_process');
7
8
  const chalk = require('chalk');
8
9
  const qrcode = require('qrcode-terminal');
9
- const { Tunnel } = require('cloudflared');
10
+ const { Tunnel, install, bin: cfBin } = require('cloudflared');
10
11
  const { createServer } = require('../src/server');
11
12
 
12
13
  // ── Parse args ───────────────────────────────────────
@@ -208,19 +209,43 @@ async function main() {
208
209
  if (usePublic) {
209
210
  process.stdout.write(' ' + chalk.gray('Public ') + chalk.gray('connecting...'));
210
211
  try {
211
- const tunnel = Tunnel.quick(`http://localhost:${port}`);
212
- publicURL = await new Promise((resolve, reject) => {
212
+ // 1. 바이너리 없으면 자동 설치
213
+ if (!fs.existsSync(cfBin)) {
214
+ process.stdout.write('\r ' + chalk.gray('Public ') + chalk.gray('installing cloudflared...'));
215
+ await install(cfBin);
216
+ }
217
+
218
+ // 2. macOS quarantine 제거 (Gatekeeper 차단 방지)
219
+ if (process.platform === 'darwin') {
220
+ try { execSync(`xattr -d com.apple.quarantine "${cfBin}" 2>/dev/null`); } catch {}
221
+ }
222
+
223
+ // 3. 터널 시작
224
+ const startTunnel = () => new Promise((resolve, reject) => {
225
+ const t = Tunnel.quick(`http://localhost:${port}`, { '--protocol': 'http2' });
213
226
  const timer = setTimeout(() => reject(new Error('timeout')), 20000);
214
- tunnel.once('url', url => { clearTimeout(timer); resolve(url); });
215
- tunnel.once('error', err => { clearTimeout(timer); reject(err); });
227
+ t.once('url', url => { clearTimeout(timer); resolve({ tunnel: t, url }); });
228
+ t.once('error', err => { clearTimeout(timer); reject(err); });
216
229
  });
230
+
231
+ const { tunnel, url } = await startTunnel();
232
+ publicURL = url;
217
233
  process.stdout.write('\r ' + chalk.gray('Public ') + chalk.bold.cyan(publicURL) + '\n');
218
234
 
219
- tunnel.on('exit', () => {
220
- console.log('\n' + chalk.yellow(' ⚠ Public tunnel closed'));
235
+ // 4. 터널 끊기면 자동 재연결
236
+ tunnel.on('exit', async () => {
237
+ console.log('\n' + chalk.yellow(' ⚠ Public tunnel disconnected — reconnecting...'));
238
+ try {
239
+ const { tunnel: t2, url: u2 } = await startTunnel();
240
+ console.log(' ' + chalk.gray('Public ') + chalk.bold.cyan(u2) + chalk.gray(' (new URL)'));
241
+ t2.on('exit', () => console.log('\n' + chalk.yellow(' ⚠ Public tunnel closed')));
242
+ } catch {
243
+ console.log(chalk.yellow(' ⚠ Reconnect failed — use --public to restart'));
244
+ }
221
245
  });
222
- } catch {
223
- process.stdout.write('\r ' + chalk.yellow('⚠ Public tunnel failed (no internet?)') + '\n');
246
+ } catch (e) {
247
+ const reason = e.message === 'timeout' ? 'timed out' : (e.message || 'no internet?');
248
+ process.stdout.write('\r ' + chalk.yellow(`⚠ Public tunnel failed (${reason})`) + '\n');
224
249
  }
225
250
  }
226
251
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "my-airdrop",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "Share files over local network — like AirDrop but from your terminal",
5
5
  "keywords": [
6
6
  "file-sharing",