mdbrowse-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/tunnel.js ADDED
@@ -0,0 +1,61 @@
1
+ import { spawn } from 'child_process';
2
+
3
+ /**
4
+ * Start a Cloudflare Tunnel pointing at the given local port.
5
+ * Returns a promise that resolves to the public tunnel URL.
6
+ */
7
+ export function startTunnel(port) {
8
+ return new Promise((resolve, reject) => {
9
+ const child = spawn('cloudflared', ['tunnel', '--url', `http://localhost:${port}`], {
10
+ stdio: ['ignore', 'pipe', 'pipe'],
11
+ });
12
+
13
+ let resolved = false;
14
+
15
+ child.on('error', (err) => {
16
+ if (err.code === 'ENOENT') {
17
+ reject(new Error(
18
+ 'cloudflared is not installed.\n' +
19
+ ' Install it: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/'
20
+ ));
21
+ } else {
22
+ reject(err);
23
+ }
24
+ });
25
+
26
+ const urlPattern = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/;
27
+
28
+ function onData(data) {
29
+ if (resolved) return;
30
+ const match = data.toString().match(urlPattern);
31
+ if (match) {
32
+ resolved = true;
33
+ resolve({ url: match[0], child });
34
+ }
35
+ }
36
+
37
+ child.stdout.on('data', onData);
38
+ child.stderr.on('data', onData);
39
+
40
+ child.on('close', (code) => {
41
+ if (!resolved) {
42
+ reject(new Error(`cloudflared exited with code ${code} before producing a tunnel URL`));
43
+ }
44
+ });
45
+ });
46
+ }
47
+
48
+ /**
49
+ * Register cleanup handlers to kill the cloudflared child process on exit.
50
+ */
51
+ export function registerCleanup(child) {
52
+ const kill = () => {
53
+ if (!child.killed) {
54
+ child.kill();
55
+ }
56
+ };
57
+
58
+ process.on('SIGINT', () => { kill(); process.exit(0); });
59
+ process.on('SIGTERM', () => { kill(); process.exit(0); });
60
+ process.on('exit', kill);
61
+ }
package/src/watcher.js ADDED
@@ -0,0 +1,40 @@
1
+ import chokidar from 'chokidar';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Start watching a directory for file changes.
6
+ * Calls `broadcast(message)` whenever a file changes.
7
+ */
8
+ export function startWatcher(rootDir, broadcast, respectIgnore = true) {
9
+ const ignored = [
10
+ '**/node_modules/**',
11
+ '**/.git/**',
12
+ ];
13
+
14
+ const watcher = chokidar.watch(rootDir, {
15
+ ignored,
16
+ persistent: true,
17
+ ignoreInitial: true,
18
+ awaitWriteFinish: {
19
+ stabilityThreshold: 100,
20
+ pollInterval: 50,
21
+ },
22
+ });
23
+
24
+ watcher.on('change', (filePath) => {
25
+ const relativePath = path.relative(rootDir, filePath);
26
+ broadcast({ type: 'change', path: relativePath });
27
+ });
28
+
29
+ watcher.on('add', (filePath) => {
30
+ const relativePath = path.relative(rootDir, filePath);
31
+ broadcast({ type: 'add', path: relativePath });
32
+ });
33
+
34
+ watcher.on('unlink', (filePath) => {
35
+ const relativePath = path.relative(rootDir, filePath);
36
+ broadcast({ type: 'unlink', path: relativePath });
37
+ });
38
+
39
+ return watcher;
40
+ }