hooktunnel-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.
Files changed (58) hide show
  1. package/README.md +404 -0
  2. package/dist/commands/connect.d.ts +11 -0
  3. package/dist/commands/connect.d.ts.map +1 -0
  4. package/dist/commands/connect.js +59 -0
  5. package/dist/commands/connect.js.map +1 -0
  6. package/dist/commands/hooks.d.ts +6 -0
  7. package/dist/commands/hooks.d.ts.map +1 -0
  8. package/dist/commands/hooks.js +51 -0
  9. package/dist/commands/hooks.js.map +1 -0
  10. package/dist/commands/login.d.ts +10 -0
  11. package/dist/commands/login.d.ts.map +1 -0
  12. package/dist/commands/login.js +36 -0
  13. package/dist/commands/login.js.map +1 -0
  14. package/dist/commands/logout.d.ts +6 -0
  15. package/dist/commands/logout.d.ts.map +1 -0
  16. package/dist/commands/logout.js +16 -0
  17. package/dist/commands/logout.js.map +1 -0
  18. package/dist/commands/logs.d.ts +10 -0
  19. package/dist/commands/logs.d.ts.map +1 -0
  20. package/dist/commands/logs.js +64 -0
  21. package/dist/commands/logs.js.map +1 -0
  22. package/dist/commands/replay.d.ts +10 -0
  23. package/dist/commands/replay.d.ts.map +1 -0
  24. package/dist/commands/replay.js +43 -0
  25. package/dist/commands/replay.js.map +1 -0
  26. package/dist/commands/status.d.ts +6 -0
  27. package/dist/commands/status.d.ts.map +1 -0
  28. package/dist/commands/status.js +56 -0
  29. package/dist/commands/status.js.map +1 -0
  30. package/dist/index.d.ts +7 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +120 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/lib/api.d.ts +12 -0
  35. package/dist/lib/api.d.ts.map +1 -0
  36. package/dist/lib/api.js +75 -0
  37. package/dist/lib/api.js.map +1 -0
  38. package/dist/lib/config.d.ts +24 -0
  39. package/dist/lib/config.d.ts.map +1 -0
  40. package/dist/lib/config.js +44 -0
  41. package/dist/lib/config.js.map +1 -0
  42. package/dist/lib/errors.d.ts +14 -0
  43. package/dist/lib/errors.d.ts.map +1 -0
  44. package/dist/lib/errors.js +97 -0
  45. package/dist/lib/errors.js.map +1 -0
  46. package/dist/lib/tunnel.d.ts +30 -0
  47. package/dist/lib/tunnel.d.ts.map +1 -0
  48. package/dist/lib/tunnel.js +237 -0
  49. package/dist/lib/tunnel.js.map +1 -0
  50. package/dist/types/api.d.ts +47 -0
  51. package/dist/types/api.d.ts.map +1 -0
  52. package/dist/types/api.js +5 -0
  53. package/dist/types/api.js.map +1 -0
  54. package/dist/types/tunnel.d.ts +82 -0
  55. package/dist/types/tunnel.d.ts.map +1 -0
  56. package/dist/types/tunnel.js +6 -0
  57. package/dist/types/tunnel.js.map +1 -0
  58. package/package.json +55 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Logs Command
3
+ * CLI-CMD-004: Logs command
4
+ */
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ import { isAuthenticated } from '../lib/config.js';
8
+ import { fetchLogs } from '../lib/api.js';
9
+ import { CLIError } from '../lib/errors.js';
10
+ export async function logsCommand(hookId, options) {
11
+ if (!isAuthenticated()) {
12
+ throw new CLIError('AUTH_REQUIRED');
13
+ }
14
+ const limit = options.limit ? parseInt(options.limit, 10) : 20;
15
+ const spinner = ora('Fetching logs...').start();
16
+ try {
17
+ const logs = await fetchLogs(hookId, limit);
18
+ spinner.stop();
19
+ if (logs.length === 0) {
20
+ console.log(chalk.yellow('\nNo logs found for this hook.'));
21
+ console.log(chalk.gray('Logs will appear after webhooks are received.\n'));
22
+ return;
23
+ }
24
+ console.log(chalk.cyan(`\n📋 Request Logs for ${hookId.slice(0, 12)}... (${logs.length})\n`));
25
+ // Table header
26
+ console.log(chalk.gray(' ') +
27
+ chalk.gray('Time'.padEnd(20)) +
28
+ chalk.gray('Method'.padEnd(8)) +
29
+ chalk.gray('Path'.padEnd(30)) +
30
+ chalk.gray('Status'.padEnd(8)) +
31
+ chalk.gray('Size'));
32
+ console.log(chalk.gray(' ' + '-'.repeat(75)));
33
+ for (const log of logs) {
34
+ const time = new Date(log.received_at).toLocaleString();
35
+ const path = log.path.length > 28 ? log.path.slice(0, 25) + '...' : log.path;
36
+ const methodColor = log.method === 'GET' ? chalk.blue :
37
+ log.method === 'POST' ? chalk.green :
38
+ log.method === 'PUT' ? chalk.yellow :
39
+ log.method === 'DELETE' ? chalk.red :
40
+ chalk.gray;
41
+ const statusColor = log.response_status >= 200 && log.response_status < 300 ? chalk.green :
42
+ log.response_status >= 400 && log.response_status < 500 ? chalk.yellow :
43
+ log.response_status >= 500 ? chalk.red :
44
+ chalk.gray;
45
+ const size = log.body_size > 1024
46
+ ? `${(log.body_size / 1024).toFixed(1)}KB`
47
+ : `${log.body_size}B`;
48
+ console.log(' ' +
49
+ chalk.gray(time.padEnd(20)) +
50
+ methodColor(log.method.padEnd(8)) +
51
+ chalk.white(path.padEnd(30)) +
52
+ statusColor(log.response_status.toString().padEnd(8)) +
53
+ chalk.gray(size));
54
+ }
55
+ console.log();
56
+ console.log(chalk.gray(` Log ID (for replay): ${logs[0]?.id || 'N/A'}`));
57
+ console.log(chalk.gray(' To replay: hooktunnel replay <logId>\n'));
58
+ }
59
+ catch (error) {
60
+ spinner.fail('Failed to fetch logs');
61
+ throw error;
62
+ }
63
+ }
64
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Replay Command
3
+ * CLI-CMD-005: Replay command
4
+ */
5
+ interface ReplayOptions {
6
+ to?: string;
7
+ }
8
+ export declare function replayCommand(logId: string, options: ReplayOptions): Promise<void>;
9
+ export {};
10
+ //# sourceMappingURL=replay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/commands/replay.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,UAAU,aAAa;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCxF"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Replay Command
3
+ * CLI-CMD-005: Replay command
4
+ */
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ import { isAuthenticated } from '../lib/config.js';
8
+ import { replayRequest } from '../lib/api.js';
9
+ import { CLIError } from '../lib/errors.js';
10
+ export async function replayCommand(logId, options) {
11
+ if (!isAuthenticated()) {
12
+ throw new CLIError('AUTH_REQUIRED');
13
+ }
14
+ const targetUrl = options.to;
15
+ console.log(chalk.cyan('\n🔄 Replay Request'));
16
+ console.log(chalk.gray(` Log ID: ${logId}`));
17
+ if (targetUrl) {
18
+ console.log(chalk.gray(` Target: ${targetUrl}`));
19
+ }
20
+ console.log();
21
+ const spinner = ora('Replaying request...').start();
22
+ try {
23
+ const result = await replayRequest(logId, targetUrl);
24
+ spinner.stop();
25
+ if (result.success) {
26
+ const statusColor = result.replay.responseStatus >= 200 && result.replay.responseStatus < 300 ? chalk.green :
27
+ result.replay.responseStatus >= 400 ? chalk.red :
28
+ chalk.yellow;
29
+ console.log(chalk.green('✓ Replay successful'));
30
+ console.log(chalk.gray(` Response status: `) + statusColor(result.replay.responseStatus.toString()));
31
+ console.log(chalk.gray(` Replay ID: ${result.replay.id}\n`));
32
+ }
33
+ else {
34
+ console.log(chalk.red('✗ Replay failed'));
35
+ console.log(chalk.gray(` Status: ${result.replay.status}\n`));
36
+ }
37
+ }
38
+ catch (error) {
39
+ spinner.fail('Replay failed');
40
+ throw error;
41
+ }
42
+ }
43
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/commands/replay.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAM5C,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa,EAAE,OAAsB;IACvE,IAAI,CAAC,eAAe,EAAE,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAAC,eAAe,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,EAAE,CAAC;IAE7B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC,CAAC;IAC9C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,SAAS,EAAE,CAAC,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,OAAO,GAAG,GAAG,CAAC,sBAAsB,CAAC,CAAC,KAAK,EAAE,CAAC;IAEpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,WAAW,GACf,MAAM,CAAC,MAAM,CAAC,cAAc,IAAI,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,cAAc,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBACzF,MAAM,CAAC,MAAM,CAAC,cAAc,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACjD,KAAK,CAAC,MAAM,CAAC;YAEf,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC,CAAC;YAChD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;YACtG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,gBAAgB,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC9B,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Status Command
3
+ * CLI-CMD-006: Status command
4
+ */
5
+ export declare function statusCommand(): Promise<void>;
6
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA4DnD"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Status Command
3
+ * CLI-CMD-006: Status command
4
+ */
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ import { isAuthenticated, getApiKey, getConfigPath } from '../lib/config.js';
8
+ import { fetchHooks } from '../lib/api.js';
9
+ export async function statusCommand() {
10
+ console.log(chalk.cyan('\n📊 HookTunnel Status\n'));
11
+ // Auth status
12
+ const isAuth = isAuthenticated();
13
+ console.log(chalk.gray(' Authentication: ') +
14
+ (isAuth ? chalk.green('✓ Logged in') : chalk.red('✗ Not logged in')));
15
+ if (!isAuth) {
16
+ console.log(chalk.gray(`\n Run "hooktunnel login" to authenticate\n`));
17
+ return;
18
+ }
19
+ // Fetch user info and hooks
20
+ const spinner = ora('Fetching status...').start();
21
+ try {
22
+ const [hooks] = await Promise.all([
23
+ fetchHooks().catch(() => []),
24
+ ]);
25
+ spinner.stop();
26
+ // API key info
27
+ const apiKey = getApiKey();
28
+ console.log(chalk.gray(' API Key: ') + chalk.white(`${apiKey?.slice(0, 8)}...`));
29
+ console.log(chalk.gray(' Config: ') + chalk.gray(getConfigPath()));
30
+ console.log();
31
+ // Hooks summary
32
+ console.log(chalk.gray(' Hooks: ') + chalk.white(hooks.length.toString()));
33
+ const activeHooks = hooks.filter(h => h.status === 'active');
34
+ console.log(chalk.gray(' Active: ') + chalk.green(activeHooks.length.toString()));
35
+ if (hooks.length > 0) {
36
+ console.log();
37
+ console.log(chalk.gray(' Recent hooks:'));
38
+ for (const hook of hooks.slice(0, 3)) {
39
+ const statusColor = hook.status === 'active' ? chalk.green : chalk.yellow;
40
+ console.log(chalk.gray(' - ') +
41
+ chalk.white(hook.hook_id.slice(0, 12) + '...') +
42
+ ' ' +
43
+ statusColor(`(${hook.status})`));
44
+ }
45
+ }
46
+ console.log();
47
+ console.log(chalk.gray(' To forward webhooks: hooktunnel connect dev <port>\n'));
48
+ }
49
+ catch (error) {
50
+ spinner.fail('Failed to fetch status');
51
+ // Still show local status
52
+ console.log(chalk.gray(' Config: ') + chalk.gray(getConfigPath()));
53
+ console.log();
54
+ }
55
+ }
56
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,GAAG,MAAM,KAAK,CAAC;AACtB,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC7E,OAAO,EAAE,UAAU,EAAe,MAAM,eAAe,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC,CAAC;IAEpD,cAAc;IACd,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC;QAChC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CACrE,CAAC;IAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC,CAAC;QACxE,OAAO;IACT,CAAC;IAED,4BAA4B;IAC5B,MAAM,OAAO,GAAG,GAAG,CAAC,oBAAoB,CAAC,CAAC,KAAK,EAAE,CAAC;IAElD,IAAI,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAChC,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC;SAC7B,CAAC,CAAC;QAEH,OAAO,CAAC,IAAI,EAAE,CAAC;QAEf,eAAe;QACf,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAClF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAEpE,OAAO,CAAC,GAAG,EAAE,CAAC;QAEd,gBAAgB;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC5E,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QAC7D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAEnF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,CAAC,GAAG,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBACrC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;gBAC1E,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;oBACpB,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC;oBAC9C,GAAG;oBACH,WAAW,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAChC,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC,CAAC;IACpF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QAEvC,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * HookTunnel CLI
4
+ * Forward webhooks to localhost
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG"}
package/dist/index.js ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * HookTunnel CLI
4
+ * Forward webhooks to localhost
5
+ */
6
+ import { Command } from 'commander';
7
+ import chalk from 'chalk';
8
+ import { handleError } from './lib/errors.js';
9
+ import { loginCommand } from './commands/login.js';
10
+ import { logoutCommand } from './commands/logout.js';
11
+ import { connectCommand } from './commands/connect.js';
12
+ import { hooksCommand } from './commands/hooks.js';
13
+ import { logsCommand } from './commands/logs.js';
14
+ import { replayCommand } from './commands/replay.js';
15
+ import { statusCommand } from './commands/status.js';
16
+ const program = new Command();
17
+ program
18
+ .name('hooktunnel')
19
+ .description('Forward webhooks to localhost for development')
20
+ .version('0.1.0');
21
+ // Login command
22
+ program
23
+ .command('login')
24
+ .description('Authenticate with HookTunnel')
25
+ .option('-k, --key <apiKey>', 'API key for authentication')
26
+ .action(async (options) => {
27
+ try {
28
+ await loginCommand(options);
29
+ }
30
+ catch (error) {
31
+ handleError(error);
32
+ }
33
+ });
34
+ // Logout command
35
+ program
36
+ .command('logout')
37
+ .description('Clear stored credentials')
38
+ .action(async () => {
39
+ try {
40
+ await logoutCommand();
41
+ }
42
+ catch (error) {
43
+ handleError(error);
44
+ }
45
+ });
46
+ // Connect command
47
+ program
48
+ .command('connect <env> <port>')
49
+ .description('Connect tunnel and forward webhooks to localhost')
50
+ .option('-v, --verbose', 'Show verbose output')
51
+ .option('-h, --host <host>', 'Local host to forward to (default: localhost)')
52
+ .action(async (env, port, options) => {
53
+ try {
54
+ await connectCommand(env, port, options);
55
+ }
56
+ catch (error) {
57
+ handleError(error);
58
+ }
59
+ });
60
+ // Hooks command
61
+ program
62
+ .command('hooks')
63
+ .description('List your webhook endpoints')
64
+ .action(async () => {
65
+ try {
66
+ await hooksCommand();
67
+ }
68
+ catch (error) {
69
+ handleError(error);
70
+ }
71
+ });
72
+ // Logs command
73
+ program
74
+ .command('logs <hookId>')
75
+ .description('View request logs for a hook')
76
+ .option('-l, --limit <count>', 'Number of logs to show (default: 20)')
77
+ .action(async (hookId, options) => {
78
+ try {
79
+ await logsCommand(hookId, options);
80
+ }
81
+ catch (error) {
82
+ handleError(error);
83
+ }
84
+ });
85
+ // Replay command
86
+ program
87
+ .command('replay <logId>')
88
+ .description('Replay a captured request (Pro feature)')
89
+ .option('-t, --to <url>', 'Target URL to send replay to')
90
+ .action(async (logId, options) => {
91
+ try {
92
+ await replayCommand(logId, options);
93
+ }
94
+ catch (error) {
95
+ handleError(error);
96
+ }
97
+ });
98
+ // Status command
99
+ program
100
+ .command('status')
101
+ .description('Show connection and authentication status')
102
+ .action(async () => {
103
+ try {
104
+ await statusCommand();
105
+ }
106
+ catch (error) {
107
+ handleError(error);
108
+ }
109
+ });
110
+ // Default action - show help
111
+ program.action(() => {
112
+ console.log(chalk.cyan(`
113
+ 🔗 HookTunnel CLI
114
+
115
+ Forward webhooks to localhost for development.
116
+ `));
117
+ program.help();
118
+ });
119
+ program.parse();
120
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * HookTunnel API Client
3
+ * CLI-API: Fetch hooks, logs, replay
4
+ */
5
+ import type { Hook, RequestLog, ReplayResponse, UserInfo } from '../types/api.js';
6
+ export declare function validateApiKey(apiKey: string): Promise<boolean>;
7
+ export declare function fetchHooks(): Promise<Hook[]>;
8
+ export declare function fetchLogs(hookId: string, limit?: number): Promise<RequestLog[]>;
9
+ export declare function replayRequest(logId: string, targetUrl?: string): Promise<ReplayResponse>;
10
+ export declare function getUserInfo(): Promise<UserInfo>;
11
+ export declare function getHook(hookId: string): Promise<Hook>;
12
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAA+B,cAAc,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AA0C/G,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAWrE;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,CAGlD;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAGjF;AAED,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAU9F;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CAErD;AAED,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3D"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * HookTunnel API Client
3
+ * CLI-API: Fetch hooks, logs, replay
4
+ */
5
+ import { getApiKey, getApiUrl } from './config.js';
6
+ import { CLIError } from './errors.js';
7
+ async function apiRequest(path, options = {}) {
8
+ const apiKey = getApiKey();
9
+ if (!apiKey) {
10
+ throw new CLIError('AUTH_REQUIRED');
11
+ }
12
+ const url = `${getApiUrl()}${path}`;
13
+ const response = await fetch(url, {
14
+ ...options,
15
+ headers: {
16
+ 'Authorization': `Bearer ${apiKey}`,
17
+ 'Content-Type': 'application/json',
18
+ ...options.headers,
19
+ },
20
+ });
21
+ if (response.status === 401) {
22
+ throw new CLIError('AUTH_INVALID');
23
+ }
24
+ if (response.status === 403) {
25
+ const data = await response.json();
26
+ if (data.code === 'PLAN_LIMIT') {
27
+ throw new CLIError('PRO_REQUIRED');
28
+ }
29
+ throw new CLIError('API_ERROR', data.error || 'Access denied');
30
+ }
31
+ if (response.status === 404) {
32
+ throw new CLIError('HOOK_NOT_FOUND');
33
+ }
34
+ if (!response.ok) {
35
+ const data = await response.json().catch(() => ({}));
36
+ throw new CLIError('API_ERROR', data.error || `HTTP ${response.status}`);
37
+ }
38
+ return response.json();
39
+ }
40
+ export async function validateApiKey(apiKey) {
41
+ const url = `${getApiUrl()}/api/keys/validate`;
42
+ const response = await fetch(url, {
43
+ method: 'POST',
44
+ headers: {
45
+ 'Authorization': `Bearer ${apiKey}`,
46
+ 'Content-Type': 'application/json',
47
+ },
48
+ });
49
+ return response.ok;
50
+ }
51
+ export async function fetchHooks() {
52
+ const data = await apiRequest('/api/hooks');
53
+ return data.hooks;
54
+ }
55
+ export async function fetchLogs(hookId, limit = 20) {
56
+ const data = await apiRequest(`/api/hooks/${hookId}/logs?limit=${limit}`);
57
+ return data.logs;
58
+ }
59
+ export async function replayRequest(logId, targetUrl) {
60
+ const body = { logId };
61
+ if (targetUrl) {
62
+ body.targetUrl = targetUrl;
63
+ }
64
+ return apiRequest('/api/replay', {
65
+ method: 'POST',
66
+ body: JSON.stringify(body),
67
+ });
68
+ }
69
+ export async function getUserInfo() {
70
+ return apiRequest('/api/me');
71
+ }
72
+ export async function getHook(hookId) {
73
+ return apiRequest(`/api/hooks/${hookId}`);
74
+ }
75
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * CLI Configuration Management
3
+ * CLI-AUTH-001: API key storage
4
+ * CLI-AUTH-002: Persist between sessions
5
+ */
6
+ import Conf from 'conf';
7
+ interface ConfigSchema {
8
+ apiKey: string | null;
9
+ apiUrl: string;
10
+ tunnelUrl: string;
11
+ defaultEnv: 'dev' | 'staging' | 'prod';
12
+ }
13
+ declare const config: Conf<ConfigSchema>;
14
+ export declare function getApiKey(): string | null;
15
+ export declare function setApiKey(key: string): void;
16
+ export declare function clearApiKey(): void;
17
+ export declare function getApiUrl(): string;
18
+ export declare function getTunnelUrl(): string;
19
+ export declare function getDefaultEnv(): 'dev' | 'staging' | 'prod';
20
+ export declare function setDefaultEnv(env: 'dev' | 'staging' | 'prod'): void;
21
+ export declare function isAuthenticated(): boolean;
22
+ export declare function getConfigPath(): string;
23
+ export { config };
24
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,UAAU,YAAY;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,CAAC;CACxC;AAED,QAAA,MAAM,MAAM,oBAQV,CAAC;AAEH,wBAAgB,SAAS,IAAI,MAAM,GAAG,IAAI,CAEzC;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE3C;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED,wBAAgB,aAAa,IAAI,KAAK,GAAG,SAAS,GAAG,MAAM,CAE1D;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAEnE;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * CLI Configuration Management
3
+ * CLI-AUTH-001: API key storage
4
+ * CLI-AUTH-002: Persist between sessions
5
+ */
6
+ import Conf from 'conf';
7
+ const config = new Conf({
8
+ projectName: 'hooktunnel-cli',
9
+ defaults: {
10
+ apiKey: null,
11
+ apiUrl: 'https://api.hooktunnel.com',
12
+ tunnelUrl: 'wss://tunnel.hooktunnel.com/ws/tunnel',
13
+ defaultEnv: 'dev',
14
+ },
15
+ });
16
+ export function getApiKey() {
17
+ return config.get('apiKey');
18
+ }
19
+ export function setApiKey(key) {
20
+ config.set('apiKey', key);
21
+ }
22
+ export function clearApiKey() {
23
+ config.delete('apiKey');
24
+ }
25
+ export function getApiUrl() {
26
+ return config.get('apiUrl');
27
+ }
28
+ export function getTunnelUrl() {
29
+ return config.get('tunnelUrl');
30
+ }
31
+ export function getDefaultEnv() {
32
+ return config.get('defaultEnv');
33
+ }
34
+ export function setDefaultEnv(env) {
35
+ config.set('defaultEnv', env);
36
+ }
37
+ export function isAuthenticated() {
38
+ return !!getApiKey();
39
+ }
40
+ export function getConfigPath() {
41
+ return config.path;
42
+ }
43
+ export { config };
44
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AASxB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAe;IACpC,WAAW,EAAE,gBAAgB;IAC7B,QAAQ,EAAE;QACR,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,4BAA4B;QACpC,SAAS,EAAE,uCAAuC;QAClD,UAAU,EAAE,KAAK;KAClB;CACF,CAAC,CAAC;AAEH,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAA+B;IAC3D,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * CLI Error Handling
3
+ * CLI-ERR-001: Helpful error messages
4
+ */
5
+ export type ErrorCode = 'AUTH_REQUIRED' | 'AUTH_INVALID' | 'CONNECTION_FAILED' | 'CONNECTION_LOST' | 'TUNNEL_ERROR' | 'API_ERROR' | 'HOOK_NOT_FOUND' | 'LOG_NOT_FOUND' | 'PRO_REQUIRED' | 'INVALID_PORT' | 'LOCAL_SERVER_ERROR' | 'UNKNOWN';
6
+ export declare class CLIError extends Error {
7
+ code: ErrorCode;
8
+ details?: string | undefined;
9
+ constructor(code: ErrorCode, details?: string | undefined);
10
+ display(): void;
11
+ }
12
+ export declare function handleError(error: unknown): never;
13
+ export declare function requireAuth(): void;
14
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,MAAM,SAAS,GACjB,eAAe,GACf,cAAc,GACd,mBAAmB,GACnB,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,gBAAgB,GAChB,eAAe,GACf,cAAc,GACd,cAAc,GACd,oBAAoB,GACpB,SAAS,CAAC;AA0Dd,qBAAa,QAAS,SAAQ,KAAK;IAExB,IAAI,EAAE,SAAS;IACf,OAAO,CAAC,EAAE,MAAM;gBADhB,IAAI,EAAE,SAAS,EACf,OAAO,CAAC,EAAE,MAAM,YAAA;IAOzB,OAAO,IAAI,IAAI;CAWhB;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAUjD;AAED,wBAAgB,WAAW,IAAI,IAAI,CAKlC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * CLI Error Handling
3
+ * CLI-ERR-001: Helpful error messages
4
+ */
5
+ import chalk from 'chalk';
6
+ const ERROR_INFO = {
7
+ AUTH_REQUIRED: {
8
+ message: 'Authentication required',
9
+ suggestion: 'Run "hooktunnel login" to authenticate',
10
+ },
11
+ AUTH_INVALID: {
12
+ message: 'Invalid API key',
13
+ suggestion: 'Check your API key and try again with "hooktunnel login"',
14
+ },
15
+ CONNECTION_FAILED: {
16
+ message: 'Failed to connect to HookTunnel',
17
+ suggestion: 'Check your internet connection and try again',
18
+ },
19
+ CONNECTION_LOST: {
20
+ message: 'Connection lost',
21
+ suggestion: 'Attempting to reconnect...',
22
+ },
23
+ TUNNEL_ERROR: {
24
+ message: 'Tunnel error',
25
+ suggestion: 'Try reconnecting with "hooktunnel connect"',
26
+ },
27
+ API_ERROR: {
28
+ message: 'API request failed',
29
+ suggestion: 'Try again later or check https://status.hooktunnel.com',
30
+ },
31
+ HOOK_NOT_FOUND: {
32
+ message: 'Hook not found',
33
+ suggestion: 'Run "hooktunnel hooks" to list your hooks',
34
+ },
35
+ LOG_NOT_FOUND: {
36
+ message: 'Request log not found',
37
+ suggestion: 'Run "hooktunnel logs <hookId>" to list logs',
38
+ },
39
+ PRO_REQUIRED: {
40
+ message: 'Pro tier required',
41
+ suggestion: 'Upgrade at https://hooktunnel.com/#pricing',
42
+ },
43
+ INVALID_PORT: {
44
+ message: 'Invalid port number',
45
+ suggestion: 'Port must be a number between 1 and 65535',
46
+ },
47
+ LOCAL_SERVER_ERROR: {
48
+ message: 'Local server error',
49
+ suggestion: 'Make sure your local server is running',
50
+ },
51
+ UNKNOWN: {
52
+ message: 'An unexpected error occurred',
53
+ suggestion: 'Try again or report at https://github.com/Hulupeep/hooktunnel-cli/issues',
54
+ },
55
+ };
56
+ export class CLIError extends Error {
57
+ code;
58
+ details;
59
+ constructor(code, details) {
60
+ const info = ERROR_INFO[code];
61
+ super(info.message);
62
+ this.code = code;
63
+ this.details = details;
64
+ this.name = 'CLIError';
65
+ }
66
+ display() {
67
+ const info = ERROR_INFO[this.code];
68
+ console.error(chalk.red(`\nError: ${info.message}`));
69
+ if (this.details) {
70
+ console.error(chalk.gray(` ${this.details}`));
71
+ }
72
+ if (info.suggestion) {
73
+ console.error(chalk.yellow(`\nSuggestion: ${info.suggestion}`));
74
+ }
75
+ console.error();
76
+ }
77
+ }
78
+ export function handleError(error) {
79
+ if (error instanceof CLIError) {
80
+ error.display();
81
+ }
82
+ else if (error instanceof Error) {
83
+ console.error(chalk.red(`\nError: ${error.message}`));
84
+ console.error(chalk.gray(error.stack || ''));
85
+ }
86
+ else {
87
+ console.error(chalk.red('\nAn unexpected error occurred'));
88
+ }
89
+ process.exit(1);
90
+ }
91
+ export function requireAuth() {
92
+ const { isAuthenticated } = require('./config.js');
93
+ if (!isAuthenticated()) {
94
+ throw new CLIError('AUTH_REQUIRED');
95
+ }
96
+ }
97
+ //# sourceMappingURL=errors.js.map