tapflow 0.3.1 → 0.4.1
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/README.md +5 -7
- package/bin/postinstall.js +3 -1
- package/dist/commands/admin-init.d.ts +5 -0
- package/dist/commands/admin-init.d.ts.map +1 -0
- package/dist/commands/admin-init.js +68 -0
- package/dist/commands/admin-init.js.map +1 -0
- package/dist/commands/agent-start.d.ts.map +1 -1
- package/dist/commands/agent-start.js +2 -1
- package/dist/commands/agent-start.js.map +1 -1
- package/dist/commands/init.d.ts +4 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +143 -75
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +3 -1
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/relay-start.d.ts +1 -0
- package/dist/commands/relay-start.d.ts.map +1 -1
- package/dist/commands/relay-start.js +65 -12
- package/dist/commands/relay-start.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +8 -6
- package/dist/commands/start.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +3 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +15 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/download-binary.d.ts +7 -0
- package/dist/lib/download-binary.d.ts.map +1 -0
- package/dist/lib/download-binary.js +112 -0
- package/dist/lib/download-binary.js.map +1 -0
- package/dist/lib/print.d.ts +2 -0
- package/dist/lib/print.d.ts.map +1 -1
- package/dist/lib/print.js +19 -3
- package/dist/lib/print.js.map +1 -1
- package/dist/lib/rathole-tunnel.d.ts +23 -0
- package/dist/lib/rathole-tunnel.d.ts.map +1 -0
- package/dist/lib/rathole-tunnel.js +125 -0
- package/dist/lib/rathole-tunnel.js.map +1 -0
- package/dist/lib/ssh.d.ts +8 -0
- package/dist/lib/ssh.d.ts.map +1 -0
- package/dist/lib/ssh.js +41 -0
- package/dist/lib/ssh.js.map +1 -0
- package/dist/lib/tailscale-tunnel.d.ts +15 -0
- package/dist/lib/tailscale-tunnel.d.ts.map +1 -0
- package/dist/lib/tailscale-tunnel.js +49 -0
- package/dist/lib/tailscale-tunnel.js.map +1 -0
- package/dist/lib/tunnel.d.ts +9 -0
- package/dist/lib/tunnel.d.ts.map +1 -0
- package/dist/lib/tunnel.js +2 -0
- package/dist/lib/tunnel.js.map +1 -0
- package/package.json +7 -6
- package/dist/lib/init-config.d.ts +0 -2
- package/dist/lib/init-config.d.ts.map +0 -1
- package/dist/lib/init-config.js +0 -22
- package/dist/lib/init-config.js.map +0 -1
package/README.md
CHANGED
|
@@ -113,12 +113,9 @@ This starts both the relay and the agent on the same Mac (local mode).
|
|
|
113
113
|
|
|
114
114
|
### 3. Create the first admin account
|
|
115
115
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
# ? Password: ********
|
|
120
|
-
# ✓ Admin account created
|
|
121
|
-
```
|
|
116
|
+
Open `http://localhost:4000` in your browser. tapflow redirects you to `/setup` where you can create the admin account.
|
|
117
|
+
|
|
118
|
+
> **Headless server?** Use `tapflow admin init` to create the admin account via CLI instead.
|
|
122
119
|
|
|
123
120
|
### 4. Open the dashboard
|
|
124
121
|
|
|
@@ -173,7 +170,8 @@ tapflow agent start --relay wss://your-relay-url
|
|
|
173
170
|
| `tapflow start` | Start relay + agent together (local mode) |
|
|
174
171
|
| `tapflow relay start` | Start relay only |
|
|
175
172
|
| `tapflow agent start --relay <url>` | Start agent and connect to a relay |
|
|
176
|
-
| `tapflow init` |
|
|
173
|
+
| `tapflow init` | Scaffold `tapflow.config.json` |
|
|
174
|
+
| `tapflow admin init` | Create the first admin account (CLI fallback) |
|
|
177
175
|
| `tapflow doctor` | Diagnose environment (Node, Xcode, adb…) |
|
|
178
176
|
| `tapflow devices` | List available simulators and emulators |
|
|
179
177
|
| `tapflow boot <name\|udid>` | Boot a simulator or emulator |
|
package/bin/postinstall.js
CHANGED
|
@@ -3,12 +3,14 @@ import { readFileSync } from 'fs'
|
|
|
3
3
|
import { fileURLToPath } from 'url'
|
|
4
4
|
import { dirname, join } from 'path'
|
|
5
5
|
|
|
6
|
+
const __dirname_top = dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
|
|
6
8
|
try {
|
|
7
9
|
if (!process.stdout.isTTY) process.exit(0)
|
|
8
10
|
if (process.env.CI) process.exit(0)
|
|
9
11
|
if (process.env.npm_config_global !== 'true') process.exit(0)
|
|
10
12
|
|
|
11
|
-
const __dirname =
|
|
13
|
+
const __dirname = __dirname_top
|
|
12
14
|
const { version } = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'))
|
|
13
15
|
|
|
14
16
|
const R = '\x1b[0m'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-init.d.ts","sourceRoot":"","sources":["../../src/commands/admin-init.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DnE"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { text, password, isCancel, cancel } from '@clack/prompts';
|
|
2
|
+
import { config } from '@tapflowio/relay';
|
|
3
|
+
import { createSpinner, banner, step } from '../lib/print.js';
|
|
4
|
+
export async function cmdAdminInit(opts) {
|
|
5
|
+
const defaultRelay = config.relay.url ?? `http://localhost:${config.local.port}`;
|
|
6
|
+
const baseUrl = (opts.relay ?? defaultRelay).replace(/^wss:\/\//, 'https://').replace(/^ws:\/\//, 'http://');
|
|
7
|
+
const email = await text({
|
|
8
|
+
message: 'Admin email',
|
|
9
|
+
placeholder: 'admin@yourteam.com',
|
|
10
|
+
validate: (v) => !v?.trim() ? 'Required' : undefined,
|
|
11
|
+
});
|
|
12
|
+
if (isCancel(email)) {
|
|
13
|
+
cancel('Cancelled.');
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
const pw = await password({
|
|
17
|
+
message: 'Password',
|
|
18
|
+
validate: (v) => (v?.length ?? 0) < 8 ? 'Must be at least 8 characters' : undefined,
|
|
19
|
+
});
|
|
20
|
+
if (isCancel(pw)) {
|
|
21
|
+
cancel('Cancelled.');
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
const spinner = createSpinner('Creating admin account...');
|
|
25
|
+
spinner.start();
|
|
26
|
+
let res = null;
|
|
27
|
+
try {
|
|
28
|
+
res = await fetch(`${baseUrl}/api/v1/auth/init`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { 'Content-Type': 'application/json' },
|
|
31
|
+
body: JSON.stringify({ email: email.trim(), password: pw }),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
spinner.stop(false);
|
|
36
|
+
banner('error', 'Could not connect to relay', [
|
|
37
|
+
`Relay not found at ${baseUrl}`,
|
|
38
|
+
'Run tapflow start first, then tapflow admin init.',
|
|
39
|
+
]);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
spinner.stop(false);
|
|
44
|
+
let errorMsg;
|
|
45
|
+
try {
|
|
46
|
+
const ct = res.headers.get('content-type') ?? '';
|
|
47
|
+
if (ct.includes('application/json')) {
|
|
48
|
+
const data = await res.json();
|
|
49
|
+
errorMsg = data.error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch { /* non-JSON body — ignore */ }
|
|
53
|
+
if (res.status === 403) {
|
|
54
|
+
banner('error', 'Already initialized', [
|
|
55
|
+
'An admin account already exists.',
|
|
56
|
+
'Use Settings → Team in the dashboard to manage users.',
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
banner('error', 'Failed to create admin', [errorMsg ?? `HTTP ${res.status}`]);
|
|
61
|
+
}
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
spinner.stop(true);
|
|
65
|
+
banner('success', 'Admin account created', [`Email: ${email.trim()}`]);
|
|
66
|
+
step(`Open ${baseUrl} to sign in`);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=admin-init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"admin-init.js","sourceRoot":"","sources":["../../src/commands/admin-init.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-start.d.ts","sourceRoot":"","sources":["../../src/commands/agent-start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agent-start.d.ts","sourceRoot":"","sources":["../../src/commands/agent-start.ts"],"names":[],"mappings":"AAGA,OAAO,sBAAsB,CAAA;AAC7B,OAAO,0BAA0B,CAAA;AAGjC,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAUD,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8D1E"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { AgentRegistry } from '@tapflowio/agent-core';
|
|
3
|
+
import { config } from '@tapflowio/relay';
|
|
3
4
|
import '@tapflowio/ios-agent';
|
|
4
5
|
import '@tapflowio/android-agent';
|
|
5
6
|
import { banner, createSpinner } from '../lib/print.js';
|
|
6
|
-
const DEFAULT_RELAY =
|
|
7
|
+
const DEFAULT_RELAY = config.relay.url ?? `ws://localhost:${config.local.port}`;
|
|
7
8
|
const relayUrlSchema = z
|
|
8
9
|
.string()
|
|
9
10
|
.refine((v) => v.startsWith('ws://') || v.startsWith('wss://'), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-start.js","sourceRoot":"","sources":["../../src/commands/agent-start.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACrD,OAAO,sBAAsB,CAAA;AAC7B,OAAO,0BAA0B,CAAA;AACjC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAQvD,MAAM,aAAa,GAAG,
|
|
1
|
+
{"version":3,"file":"agent-start.js","sourceRoot":"","sources":["../../src/commands/agent-start.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export interface
|
|
2
|
-
|
|
1
|
+
export interface InitConfigOptions {
|
|
2
|
+
tunnel?: string;
|
|
3
|
+
force?: boolean;
|
|
3
4
|
}
|
|
4
|
-
export declare function
|
|
5
|
+
export declare function cmdInitConfig(opts: InitConfigOptions): Promise<void>;
|
|
5
6
|
//# sourceMappingURL=init.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AA2FD,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0D1E"}
|
package/dist/commands/init.js
CHANGED
|
@@ -1,91 +1,159 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { select, text, isCancel, cancel } from '@clack/prompts';
|
|
4
|
+
import { banner, warn } from '../lib/print.js';
|
|
5
|
+
const BASE_CONFIG = {
|
|
6
|
+
local: { port: 4000, dataDir: '.tapflow-data' },
|
|
7
|
+
relay: { url: '' },
|
|
8
|
+
smtp: { host: '', port: 587, secure: false, user: '', pass: '' },
|
|
9
|
+
};
|
|
10
|
+
function isInsideGitRepo(dir) {
|
|
11
|
+
let current = dir;
|
|
12
|
+
while (true) {
|
|
13
|
+
if (fs.existsSync(path.join(current, '.git')))
|
|
14
|
+
return true;
|
|
15
|
+
const parent = path.dirname(current);
|
|
16
|
+
if (parent === current)
|
|
17
|
+
return false;
|
|
18
|
+
current = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function addToGitignore(dir, entry) {
|
|
22
|
+
const gitignorePath = path.join(dir, '.gitignore');
|
|
23
|
+
if (fs.existsSync(gitignorePath)) {
|
|
24
|
+
const content = fs.readFileSync(gitignorePath, 'utf-8');
|
|
25
|
+
if (content.split('\n').some((line) => line.trim() === entry))
|
|
26
|
+
return 'already-present';
|
|
27
|
+
const separator = content.endsWith('\n') ? '' : '\n';
|
|
28
|
+
fs.appendFileSync(gitignorePath, `${separator}\n# tapflow runtime data\n${entry}\n`, 'utf-8');
|
|
29
|
+
return 'appended';
|
|
30
|
+
}
|
|
31
|
+
fs.writeFileSync(gitignorePath, `# tapflow runtime data\n${entry}\n`, 'utf-8');
|
|
32
|
+
return 'created';
|
|
33
|
+
}
|
|
34
|
+
async function promptTunnel() {
|
|
35
|
+
const provider = await select({
|
|
36
|
+
message: 'Tunnel provider',
|
|
37
|
+
options: [
|
|
38
|
+
{ value: 'none', label: 'None', hint: 'local only' },
|
|
39
|
+
{ value: 'tailscale', label: 'Tailscale', hint: 'recommended — E2E encrypted, no VPS required' },
|
|
40
|
+
{ value: 'rathole', label: 'rathole', hint: 'VPS required' },
|
|
41
|
+
],
|
|
42
|
+
});
|
|
43
|
+
if (isCancel(provider)) {
|
|
44
|
+
cancel('Cancelled.');
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
47
|
+
if (provider === 'tailscale')
|
|
48
|
+
return { provider: 'tailscale' };
|
|
49
|
+
if (provider !== 'rathole')
|
|
50
|
+
return null;
|
|
51
|
+
const serverAddr = await text({
|
|
52
|
+
message: 'VPS server address',
|
|
53
|
+
placeholder: 'example.com:2333',
|
|
54
|
+
validate: (v) => !v?.trim() ? 'Required' : undefined,
|
|
39
55
|
});
|
|
56
|
+
if (isCancel(serverAddr)) {
|
|
57
|
+
cancel('Cancelled.');
|
|
58
|
+
process.exit(0);
|
|
59
|
+
}
|
|
60
|
+
const publicUrl = await text({
|
|
61
|
+
message: 'Public URL',
|
|
62
|
+
placeholder: 'https://example.com',
|
|
63
|
+
validate: (v) => !v?.trim() ? 'Required' : undefined,
|
|
64
|
+
});
|
|
65
|
+
if (isCancel(publicUrl)) {
|
|
66
|
+
cancel('Cancelled.');
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
const sshHost = await text({
|
|
70
|
+
message: 'SSH host',
|
|
71
|
+
placeholder: 'example.com (leave blank to skip)',
|
|
72
|
+
});
|
|
73
|
+
if (isCancel(sshHost)) {
|
|
74
|
+
cancel('Cancelled.');
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
let ssh = null;
|
|
78
|
+
if (sshHost && sshHost.trim()) {
|
|
79
|
+
const sshUser = await text({
|
|
80
|
+
message: 'SSH user',
|
|
81
|
+
placeholder: 'ubuntu',
|
|
82
|
+
defaultValue: 'ubuntu',
|
|
83
|
+
});
|
|
84
|
+
if (isCancel(sshUser)) {
|
|
85
|
+
cancel('Cancelled.');
|
|
86
|
+
process.exit(0);
|
|
87
|
+
}
|
|
88
|
+
const sshKeyPath = await text({
|
|
89
|
+
message: 'SSH key path',
|
|
90
|
+
placeholder: '~/.ssh/id_ed25519',
|
|
91
|
+
defaultValue: '~/.ssh/id_ed25519',
|
|
92
|
+
});
|
|
93
|
+
if (isCancel(sshKeyPath)) {
|
|
94
|
+
cancel('Cancelled.');
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
ssh = { host: sshHost.trim(), user: sshUser || 'ubuntu', keyPath: sshKeyPath || '~/.ssh/id_ed25519' };
|
|
98
|
+
}
|
|
99
|
+
return { provider: 'rathole', serverAddr: serverAddr.trim(), publicUrl: publicUrl.trim(), ssh };
|
|
40
100
|
}
|
|
41
|
-
export async function
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
banner('error', 'INVALID INPUT', ['Email is required.']);
|
|
101
|
+
export async function cmdInitConfig(opts) {
|
|
102
|
+
const configPath = path.join(process.cwd(), 'tapflow.config.json');
|
|
103
|
+
if (fs.existsSync(configPath) && !opts.force) {
|
|
104
|
+
banner('error', 'ALREADY INITIALIZED', [
|
|
105
|
+
'tapflow.config.json already exists.',
|
|
106
|
+
'Use --force to overwrite.',
|
|
107
|
+
]);
|
|
49
108
|
process.exit(1);
|
|
50
109
|
}
|
|
51
|
-
|
|
52
|
-
|
|
110
|
+
const SUPPORTED = ['tailscale', 'rathole'];
|
|
111
|
+
if (opts.tunnel && !SUPPORTED.includes(opts.tunnel)) {
|
|
112
|
+
banner('error', 'INVALID TUNNEL', [
|
|
113
|
+
`Unknown tunnel provider: "${opts.tunnel}". Supported: tailscale, rathole`,
|
|
114
|
+
]);
|
|
53
115
|
process.exit(1);
|
|
54
116
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
117
|
+
let tunnel = null;
|
|
118
|
+
if (opts.tunnel === 'tailscale') {
|
|
119
|
+
tunnel = { provider: 'tailscale' };
|
|
120
|
+
}
|
|
121
|
+
else if (opts.tunnel === 'rathole') {
|
|
122
|
+
tunnel = { provider: 'rathole', serverAddr: '', publicUrl: '', ssh: null };
|
|
123
|
+
}
|
|
124
|
+
else if (process.stdin.isTTY) {
|
|
125
|
+
tunnel = await promptTunnel();
|
|
126
|
+
}
|
|
127
|
+
const configOut = tunnel != null ? { ...BASE_CONFIG, tunnel } : BASE_CONFIG;
|
|
58
128
|
try {
|
|
59
|
-
|
|
60
|
-
method: 'POST',
|
|
61
|
-
headers: { 'Content-Type': 'application/json' },
|
|
62
|
-
body: JSON.stringify({ email, password }),
|
|
63
|
-
});
|
|
129
|
+
fs.writeFileSync(configPath, JSON.stringify(configOut, null, 2) + '\n', 'utf-8');
|
|
64
130
|
}
|
|
65
|
-
catch {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
`Relay not found at ${baseUrl}`,
|
|
69
|
-
'Run tapflow start first, then tapflow init.',
|
|
131
|
+
catch (err) {
|
|
132
|
+
banner('error', 'WRITE FAILED', [
|
|
133
|
+
`Could not write tapflow.config.json: ${err instanceof Error ? err.message : String(err)}`,
|
|
70
134
|
]);
|
|
71
135
|
process.exit(1);
|
|
72
136
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
banner('error', 'Already initialized', [
|
|
78
|
-
'An admin account already exists.',
|
|
79
|
-
'Use Settings → Team in the dashboard to manage users.',
|
|
80
|
-
]);
|
|
137
|
+
let gitignoreUpdated = 'skipped';
|
|
138
|
+
if (isInsideGitRepo(process.cwd())) {
|
|
139
|
+
try {
|
|
140
|
+
gitignoreUpdated = addToGitignore(process.cwd(), '.tapflow-data/');
|
|
81
141
|
}
|
|
82
|
-
|
|
83
|
-
|
|
142
|
+
catch (err) {
|
|
143
|
+
warn(`Could not update .gitignore: ${err instanceof Error ? err.message : String(err)}`);
|
|
84
144
|
}
|
|
85
|
-
process.exit(1);
|
|
86
145
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
146
|
+
const lines = ['tapflow.config.json created.'];
|
|
147
|
+
if (gitignoreUpdated === 'created')
|
|
148
|
+
lines.push('.gitignore created (.tapflow-data/ added).');
|
|
149
|
+
else if (gitignoreUpdated === 'appended')
|
|
150
|
+
lines.push('.tapflow-data/ added to .gitignore.');
|
|
151
|
+
if (tunnel?.provider === 'rathole' && (!tunnel.serverAddr || !tunnel.publicUrl)) {
|
|
152
|
+
lines.push('Fill in tunnel.serverAddr and tunnel.publicUrl in tapflow.config.json.');
|
|
153
|
+
}
|
|
154
|
+
if (tunnel)
|
|
155
|
+
lines.push(`Tunnel: ${tunnel.provider}`);
|
|
156
|
+
lines.push('Next: tapflow start');
|
|
157
|
+
banner('success', 'CONFIG CREATED', lines);
|
|
90
158
|
}
|
|
91
159
|
//# sourceMappingURL=init.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAGA,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBrF"}
|
package/dist/commands/logs.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { config } from '@tapflowio/relay';
|
|
1
2
|
import { DIM, RED, R } from '../lib/print.js';
|
|
2
3
|
export async function cmdLogs(opts) {
|
|
3
|
-
const
|
|
4
|
+
const defaultRelay = config.relay.url ?? `http://localhost:${config.local.port}`;
|
|
5
|
+
const base = (opts.relay ?? defaultRelay).replace(/^ws/, 'http');
|
|
4
6
|
const lines = opts.lines ?? 100;
|
|
5
7
|
const url = `${base}/api/v1/logs?lines=${lines}`;
|
|
6
8
|
const res = await fetch(url).catch(() => null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAwC;IACpE,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,iBAAiB,CAAA;AAE7C,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAwC;IACpE,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,oBAAoB,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;IAChF,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAChE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,GAAG,CAAA;IAC/B,MAAM,GAAG,GAAG,GAAG,IAAI,sBAAsB,KAAK,EAAE,CAAA;IAEhD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAE9C,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,8BAA8B,IAAI,qCAAqC,CAAC,CAAA;QACrG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,OAAO,GAAa,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IAE1C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,OAAO,GAAG,sBAAsB,CAAC,IAAI,CAAC,CAAA;QAClD,OAAM;IACR,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,CAAA;IACb,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,CAAA;IACpC,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAA;AACf,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-start.d.ts","sourceRoot":"","sources":["../../src/commands/relay-start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"relay-start.d.ts","sourceRoot":"","sources":["../../src/commands/relay-start.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAMD,wBAAsB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuE1E"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
1
2
|
import path from 'path';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { RelayServer, initDb, config } from '@tapflowio/relay';
|
|
4
|
-
import { banner, step } from '../lib/print.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
5
|
+
import { banner, step, warn } from '../lib/print.js';
|
|
6
|
+
import { RatholeTunnel } from '../lib/rathole-tunnel.js';
|
|
7
|
+
import { TailscaleTunnel } from '../lib/tailscale-tunnel.js';
|
|
8
|
+
const DEFAULT_PORT = config.local.port;
|
|
7
9
|
const portSchema = z.number().int().min(1).max(65535, 'port must be between 1 and 65535');
|
|
8
10
|
export async function cmdRelayStart(opts) {
|
|
9
11
|
const rawPort = opts.port ?? DEFAULT_PORT;
|
|
@@ -13,16 +15,67 @@ export async function cmdRelayStart(opts) {
|
|
|
13
15
|
process.exit(1);
|
|
14
16
|
}
|
|
15
17
|
const port = portResult.data;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
if (!fs.existsSync(path.join(process.cwd(), 'tapflow.config.json'))) {
|
|
19
|
+
warn('tapflow.config.json not found — using defaults. Run tapflow init to configure.');
|
|
20
|
+
}
|
|
21
|
+
initDb(path.join(config.local.dataDir, 'tapflow.db'));
|
|
22
|
+
const server = new RelayServer({ port, uploadsDir: path.join(config.local.dataDir, 'uploads'), wsBackpressureBytes: config.local.wsBackpressureBytes });
|
|
19
23
|
await server.start();
|
|
20
24
|
step(`Relay started on ws://localhost:${port}`);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const SUPPORTED_PROVIDERS = ['rathole', 'tailscale'];
|
|
26
|
+
if (opts.tunnel && !SUPPORTED_PROVIDERS.includes(opts.tunnel)) {
|
|
27
|
+
banner('error', 'TUNNEL CONFIG ERROR', [`Unsupported tunnel provider: "${opts.tunnel}". Supported: ${SUPPORTED_PROVIDERS.join(', ')}`]);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const tunnelCfg = config.tunnel;
|
|
31
|
+
let tunnel = null;
|
|
32
|
+
if (tunnelCfg != null || opts.tunnel) {
|
|
33
|
+
if (!tunnelCfg) {
|
|
34
|
+
banner('error', 'TUNNEL CONFIG ERROR', ['tunnel section is required in tapflow.config.json when using --tunnel']);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
if (tunnelCfg.provider === 'tailscale') {
|
|
38
|
+
tunnel = new TailscaleTunnel({ publicUrl: tunnelCfg.publicUrl });
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
const token = process.env.TAPFLOW_TUNNEL_TOKEN ?? '';
|
|
42
|
+
if (!token) {
|
|
43
|
+
banner('error', 'TUNNEL CONFIG ERROR', ['TAPFLOW_TUNNEL_TOKEN env var is required for rathole tunnel']);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
tunnel = new RatholeTunnel({ serverAddr: tunnelCfg.serverAddr, publicUrl: tunnelCfg.publicUrl, token, ssh: tunnelCfg.ssh ?? undefined });
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
await tunnel.setupServer();
|
|
50
|
+
const { publicUrl } = await tunnel.start(port);
|
|
51
|
+
step(`Tunnel ready — Public URL: ${publicUrl}`);
|
|
52
|
+
banner('success', 'TAPFLOW RELAY READY', [
|
|
53
|
+
`Relay : http://localhost:${port}`,
|
|
54
|
+
`Public : ${publicUrl}`,
|
|
55
|
+
`Connect Mac agents: tapflow start --relay ws://<host>:${port}`,
|
|
56
|
+
'Press Ctrl+C to stop.',
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.warn(`Tunnel failed to start: ${err instanceof Error ? err.message : String(err)}`);
|
|
61
|
+
tunnel = null;
|
|
62
|
+
banner('success', 'TAPFLOW RELAY READY', [
|
|
63
|
+
`Relay : http://localhost:${port}`,
|
|
64
|
+
`Connect Mac agents: tapflow start --relay ws://<host>:${port}`,
|
|
65
|
+
'Press Ctrl+C to stop.',
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
banner('success', 'TAPFLOW RELAY READY', [
|
|
71
|
+
`Relay : http://localhost:${port}`,
|
|
72
|
+
`Connect Mac agents: tapflow start --relay ws://<host>:${port}`,
|
|
73
|
+
'Press Ctrl+C to stop.',
|
|
74
|
+
]);
|
|
75
|
+
}
|
|
76
|
+
process.on('SIGINT', () => {
|
|
77
|
+
void tunnel?.stop();
|
|
78
|
+
process.exit(0);
|
|
79
|
+
});
|
|
27
80
|
}
|
|
28
81
|
//# sourceMappingURL=relay-start.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-start.js","sourceRoot":"","sources":["../../src/commands/relay-start.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAA;AACvB,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAC9D,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"relay-start.js","sourceRoot":"","sources":["../../src/commands/relay-start.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/commands/start.ts"],"names":[],"mappings":"AAIA,OAAO,sBAAsB,CAAA;AAC7B,OAAO,0BAA0B,CAAA;AAGjC,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAID,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAsEhE"}
|