pinggy 0.3.5 → 0.3.7

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 (68) hide show
  1. package/README.md +1 -1
  2. package/dist/chunk-65R2GMKQ.js +2101 -0
  3. package/dist/index.cjs +1798 -1349
  4. package/dist/index.d.cts +616 -0
  5. package/dist/index.d.ts +616 -0
  6. package/dist/index.js +24 -2
  7. package/dist/{main-K44C44NW.js → main-2QDG7PWL.js} +166 -1705
  8. package/package.json +2 -3
  9. package/.github/workflows/npm-publish-github-packages.yml +0 -34
  10. package/.github/workflows/publish-binaries.yml +0 -223
  11. package/Makefile +0 -4
  12. package/caxa_build.js +0 -24
  13. package/dist/chunk-T5ESYDJY.js +0 -121
  14. package/ent.plist +0 -14
  15. package/jest.config.js +0 -19
  16. package/src/_tests_/build_config.test.ts +0 -91
  17. package/src/cli/buildConfig.ts +0 -535
  18. package/src/cli/defaults.ts +0 -20
  19. package/src/cli/extendedOptions.ts +0 -153
  20. package/src/cli/help.ts +0 -43
  21. package/src/cli/options.ts +0 -50
  22. package/src/cli/starCli.ts +0 -229
  23. package/src/index.ts +0 -31
  24. package/src/logger.ts +0 -138
  25. package/src/main.ts +0 -87
  26. package/src/remote_management/handler.ts +0 -244
  27. package/src/remote_management/remoteManagement.ts +0 -226
  28. package/src/remote_management/remote_schema.ts +0 -176
  29. package/src/remote_management/websocket_handlers.ts +0 -180
  30. package/src/tui/blessed/TunnelTui.ts +0 -340
  31. package/src/tui/blessed/components/DisplayUpdaters.ts +0 -189
  32. package/src/tui/blessed/components/KeyBindings.ts +0 -236
  33. package/src/tui/blessed/components/Modals.ts +0 -302
  34. package/src/tui/blessed/components/UIComponents.ts +0 -306
  35. package/src/tui/blessed/components/index.ts +0 -4
  36. package/src/tui/blessed/config.ts +0 -53
  37. package/src/tui/blessed/headerFetcher.ts +0 -42
  38. package/src/tui/blessed/index.ts +0 -2
  39. package/src/tui/blessed/qrCodeGenerator.ts +0 -20
  40. package/src/tui/blessed/webDebuggerConnection.ts +0 -128
  41. package/src/tui/ink/asciArt.ts +0 -7
  42. package/src/tui/ink/hooks/useQrCodes.ts +0 -27
  43. package/src/tui/ink/hooks/useReqResHeaders.ts +0 -27
  44. package/src/tui/ink/hooks/useTerminalSize.ts +0 -26
  45. package/src/tui/ink/hooks/useTerminalStats.ts +0 -24
  46. package/src/tui/ink/hooks/useWebDebugger.ts +0 -98
  47. package/src/tui/ink/index.tsx +0 -243
  48. package/src/tui/ink/layout/Borders.tsx +0 -15
  49. package/src/tui/ink/layout/Container.tsx +0 -15
  50. package/src/tui/ink/sections/DebuggerDetailModal.tsx +0 -53
  51. package/src/tui/ink/sections/KeyBindings.tsx +0 -58
  52. package/src/tui/ink/sections/QrCodeSection.tsx +0 -28
  53. package/src/tui/ink/sections/StatsSection.tsx +0 -20
  54. package/src/tui/ink/sections/URLsSection.tsx +0 -53
  55. package/src/tui/ink/utils/utils.ts +0 -35
  56. package/src/tui/spinner/spinner.ts +0 -64
  57. package/src/tunnel_manager/TunnelManager.ts +0 -1212
  58. package/src/types.ts +0 -255
  59. package/src/utils/FileServer.ts +0 -112
  60. package/src/utils/detect_vc_redist_on_windows.ts +0 -111
  61. package/src/utils/getFreePort.ts +0 -41
  62. package/src/utils/htmlTemplates.ts +0 -146
  63. package/src/utils/parseArgs.ts +0 -79
  64. package/src/utils/printer.ts +0 -81
  65. package/src/utils/util.ts +0 -18
  66. package/src/workers/file_serve_worker.ts +0 -33
  67. package/tsconfig.json +0 -17
  68. package/tsup.config.ts +0 -12
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pinggy",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "description": "Create secure, shareable tunnels to your localhost and manage them from the command line. ",
@@ -50,7 +50,7 @@
50
50
  ]
51
51
  },
52
52
  "dependencies": {
53
- "@pinggy/pinggy": "^0.3.3",
53
+ "@pinggy/pinggy": "^0.3.5",
54
54
  "blessed": "^0.1.81",
55
55
  "clipboardy": "^5.0.0",
56
56
  "mime": "^4.1.0",
@@ -61,7 +61,6 @@
61
61
  "zod": "^4.1.5"
62
62
  },
63
63
  "devDependencies": {
64
- "@appthreat/caxa": "^1.0.13",
65
64
  "@types/blessed": "^0.1.25",
66
65
  "@types/jest": "^30.0.0",
67
66
  "@types/node": "^24.3.0",
@@ -1,34 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- release:
5
- types: [created]
6
-
7
- jobs:
8
- publish:
9
- runs-on: ubuntu-latest
10
-
11
- permissions:
12
- contents: read
13
- id-token: write # Required for npm provenance (npm >= 9.5)
14
-
15
- steps:
16
- - name: Checkout repository
17
- uses: actions/checkout@v4
18
-
19
- - name: Use Node.js
20
- uses: actions/setup-node@v4
21
- with:
22
- node-version: 20
23
- registry-url: https://registry.npmjs.org/
24
-
25
- - name: Install dependencies
26
- run: npm ci
27
-
28
- - name: Build TypeScript
29
- run: npm run build
30
-
31
- - name: Publish package
32
- run: npm publish --access public
33
- env:
34
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,223 +0,0 @@
1
- name: Publish Binaries to GitHub Release
2
-
3
- on:
4
- release:
5
- types: [created]
6
-
7
- env:
8
- RELEASE_TAG: ${{ github.event.release.tag_name }}
9
-
10
-
11
- jobs:
12
- Ubuntu:
13
- name: Build on ${{ matrix.name }} and upload to GitHub Release
14
- runs-on: ${{ matrix.runner }}
15
-
16
- strategy:
17
- matrix:
18
- include:
19
- - name: Ubuntu-x64
20
- runner: ubuntu-latest
21
-
22
- - name: Ubuntu-arm64
23
- runner: ubuntu-24.04-arm
24
-
25
- steps:
26
- - name: Checkout
27
- uses: actions/checkout@v4
28
-
29
- - name: Use Node.js
30
- uses: actions/setup-node@v4
31
- with:
32
- node-version: '24'
33
-
34
- - name: Install dependencies
35
- run: npm ci || npm install
36
-
37
- - name: Build (tsup)
38
- run: npm run build
39
-
40
- - name: Run pkg build for x64
41
- if: ${{ matrix.name == 'Ubuntu-x64' }}
42
- run: npm run pack:linux-x64
43
-
44
- - name: Run pkg build for arm64
45
- if: ${{ matrix.name == 'Ubuntu-arm64' }}
46
- run: npm run pack:linux-arm64
47
-
48
- - name: Show out directory
49
- run: ls -R ./out
50
-
51
- - name: Upload artifact to GitHub Release
52
- env:
53
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
54
- shell: bash
55
- run: |
56
- for FILE in out/*; do
57
- echo "Uploading $FILE"
58
- gh release upload "$RELEASE_TAG" "$FILE" --clobber
59
- done
60
-
61
- Windows:
62
- name: Build on ${{ matrix.name }} and upload
63
- runs-on: ${{ matrix.runner }}
64
-
65
- defaults:
66
- run:
67
- shell: bash
68
-
69
- strategy:
70
- matrix:
71
- include:
72
- - name: Windows-x64
73
- runner: windows-latest
74
-
75
- - name: Windows-arm64
76
- runner: windows-11-arm
77
-
78
- steps:
79
- - name: Checkout
80
- uses: actions/checkout@v4
81
-
82
- - name: Use Node.js
83
- uses: actions/setup-node@v4
84
- with:
85
- node-version: '24'
86
-
87
- - name: Install dependencies
88
- run: npm ci || npm install
89
-
90
- - name: Build (tsup)
91
- run: npm run build
92
-
93
- - name: Run pkg build for x64
94
- if: ${{ matrix.name == 'Windows-x64' }}
95
- run: npm run pack:win-x64
96
-
97
- - name: Run pkg build for arm64
98
- if: ${{ matrix.name == 'Windows-arm64' }}
99
- run: npm run pack:win-arm64
100
-
101
- - name: See out directory
102
- run: ls -R ./out
103
-
104
- - name: Upload artifact to GitHub Release
105
- env:
106
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
107
- shell: bash
108
- run: |
109
- for FILE in out/*; do
110
- echo "Uploading $FILE"
111
- gh release upload "$RELEASE_TAG" "$FILE" --clobber
112
- done
113
-
114
-
115
- MacOS:
116
- name: Build on ${{ matrix.name }} and upload to GitHub Release
117
- runs-on: ${{ matrix.runner }}
118
-
119
- strategy:
120
- matrix:
121
- include:
122
- - name: MacOS-x64
123
- runner: macos-15-intel
124
-
125
- - name: MacOS-arm64
126
- runner: macos-15
127
-
128
- steps:
129
- - name: Checkout
130
- uses: actions/checkout@v4
131
-
132
- - name: Use Node.js
133
- uses: actions/setup-node@v4
134
- with:
135
- node-version: '24'
136
-
137
- - name: Install dependencies
138
- run: npm ci || npm install
139
-
140
- - name: Build (tsup)
141
- run: npm run build
142
-
143
- - name: Run pkg build for x64
144
- if: ${{ matrix.name == 'MacOS-x64' }}
145
- run: npm run pack:macos-x64
146
-
147
- - name: Run pkg build for arm64
148
- if: ${{ matrix.name == 'MacOS-arm64' }}
149
- run: npm run pack:macos-arm64
150
-
151
- - name: Import Code Signing Certificate
152
- env:
153
- MACOS_CERTIFICATE: ${{ secrets.MACOS_CERTIFICATE }}
154
- MACOS_CERTIFICATE_PWD: ${{ secrets.MACOS_CERTIFICATE_PWD }}
155
- run: |
156
- # Create temporary keychain
157
- KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
158
- KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
159
-
160
- # Decode certificate and import to keychain
161
- echo "$MACOS_CERTIFICATE" | base64 --decode > certificate.p12
162
- security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
163
- security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
164
- security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
165
- security import certificate.p12 -k "$KEYCHAIN_PATH" -P "$MACOS_CERTIFICATE_PWD" -T /usr/bin/codesign
166
- security list-keychain -d user -s "$KEYCHAIN_PATH"
167
- security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
168
-
169
- # Clean up certificate file
170
- rm certificate.p12
171
-
172
- - name: Code Sign Binary
173
- env:
174
- DEVELOPER_ID: ${{ secrets.MACOS_DEVELOPER_ID }}
175
- run: |
176
- FILE=$(ls out)
177
- echo "Code signing: $FILE"
178
- codesign --deep --force --options runtime --sign "$DEVELOPER_ID" --timestamp --entitlements ent.plist "out/$FILE"
179
- codesign --verify --verbose "out/$FILE"
180
-
181
- - name: Notarize Binary (Optional)
182
- env:
183
- APPLE_ID: ${{ secrets.APPLE_ID }}
184
- APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
185
- APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
186
- run: |
187
- FILE=$(ls out)
188
-
189
- # Create a zip for notarization
190
- ditto -c -k --keepParent "out/$FILE" "out/$FILE.zip"
191
-
192
- # Submit for notarization
193
- xcrun notarytool submit "out/$FILE.zip" \
194
- --apple-id "$APPLE_ID" \
195
- --password "$APPLE_APP_SPECIFIC_PASSWORD" \
196
- --team-id "$APPLE_TEAM_ID" \
197
- --wait
198
-
199
- # Remove zip file
200
- rm "out/$FILE.zip"
201
-
202
- echo "Notarization complete"
203
-
204
- - name: See out directory
205
- run: ls -R ./out
206
-
207
- - name: Upload artifact to GitHub Release
208
- env:
209
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
210
- shell: bash
211
- run: |
212
- for FILE in out/*; do
213
- echo "Uploading $FILE"
214
- gh release upload "$RELEASE_TAG" "$FILE" --clobber
215
- done
216
-
217
- - name: Cleanup Keychain
218
- if: always()
219
- run: |
220
- KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
221
- if [ -f "$KEYCHAIN_PATH" ]; then
222
- security delete-keychain "$KEYCHAIN_PATH"
223
- fi
package/Makefile DELETED
@@ -1,4 +0,0 @@
1
- pack:
2
- npm run pack:all
3
- clean:
4
- rm -rf out
package/caxa_build.js DELETED
@@ -1,24 +0,0 @@
1
- import caxa from '@appthreat/caxa';
2
- import { readFileSync } from 'fs';
3
-
4
- (async () => {
5
- const platform = process.platform; // win32, linux, darwin
6
- const arch = process.arch; // x64, arm64, ia32
7
-
8
- const packageJson = JSON.parse(readFileSync('./package.json', 'utf-8'));
9
- const version = packageJson.version;
10
-
11
- const extension =
12
- platform === "win32" ? ".exe" :
13
- platform === "darwin" ? "" : "";
14
-
15
- await caxa({
16
- input: "./",
17
- output: `bin/pinggy-${version}-${platform}-${arch}${extension}`,
18
- includeNode: true,
19
- command: [
20
- "{{caxa}}/node_modules/.bin/node",
21
- "{{caxa}}/dist/index.js",
22
- ],
23
- });
24
- })();
@@ -1,121 +0,0 @@
1
- // src/utils/printer.ts
2
- import pico2 from "picocolors";
3
-
4
- // src/tui/spinner/spinner.ts
5
- import pico from "picocolors";
6
- var spinners = {
7
- dots: {
8
- interval: 80,
9
- frames: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"]
10
- }
11
- };
12
- var currentTimer = null;
13
- var currentText = "";
14
- function startSpinner(name = "dots", text = "Loading") {
15
- const spinner = spinners[name];
16
- let i = 0;
17
- currentText = text;
18
- if (currentTimer) {
19
- clearInterval(currentTimer);
20
- }
21
- currentTimer = setInterval(() => {
22
- const frame = spinner.frames[i = ++i % spinner.frames.length];
23
- process.stdout.write(`\r${pico.cyan(frame)} ${text}`);
24
- }, spinner.interval);
25
- return () => stopSpinner();
26
- }
27
- function stopSpinner() {
28
- if (currentTimer) {
29
- clearInterval(currentTimer);
30
- currentTimer = null;
31
- process.stdout.write("\r\x1B[K");
32
- }
33
- }
34
- function stopSpinnerSuccess(message) {
35
- if (currentTimer) {
36
- clearInterval(currentTimer);
37
- currentTimer = null;
38
- const finalMessage = message || currentText;
39
- process.stdout.write(`\r${pico.green("\u2714")} ${finalMessage}
40
- `);
41
- }
42
- }
43
- function stopSpinnerFail(message) {
44
- if (currentTimer) {
45
- clearInterval(currentTimer);
46
- currentTimer = null;
47
- const finalMessage = message || currentText;
48
- process.stdout.write(`\r${pico.red("\u2716")} ${finalMessage}
49
- `);
50
- }
51
- }
52
-
53
- // src/utils/printer.ts
54
- var _CLIPrinter = class _CLIPrinter {
55
- static isCLIError(err) {
56
- return err instanceof Error;
57
- }
58
- static print(message, ...args) {
59
- console.log(message, ...args);
60
- }
61
- static error(err) {
62
- const def = this.errorDefinitions.find((d) => d.match(err));
63
- const msg = def.message(err);
64
- console.error(pico2.red(pico2.bold("\u2716 Error:")), pico2.red(msg));
65
- process.exit(1);
66
- }
67
- static warn(message) {
68
- console.warn(pico2.yellow(pico2.bold("\u26A0 Warning:")), pico2.yellow(message));
69
- }
70
- static warnTxt(message) {
71
- console.warn(pico2.yellow(pico2.bold("\u26A0 Warning:")), pico2.yellow(message));
72
- }
73
- static success(message) {
74
- console.log(pico2.green(pico2.bold(" \u2714 Success:")), pico2.green(message));
75
- }
76
- static async info(message) {
77
- console.log(pico2.blue(message));
78
- }
79
- static startSpinner(message) {
80
- startSpinner("dots", message);
81
- }
82
- static stopSpinnerSuccess(message) {
83
- stopSpinnerSuccess(message);
84
- }
85
- static stopSpinnerFail(message) {
86
- stopSpinnerFail(message);
87
- }
88
- };
89
- _CLIPrinter.errorDefinitions = [
90
- {
91
- match: (err) => _CLIPrinter.isCLIError(err) && err.code === "ERR_PARSE_ARGS_UNKNOWN_OPTION",
92
- message: (err) => {
93
- const match = /Unknown option '(.+?)'/.exec(err.message);
94
- const option = match ? match[1] : "(unknown)";
95
- return `Unknown option '${option}'. Please check your command or use pinggy --h for guidance.`;
96
- }
97
- },
98
- {
99
- match: (err) => _CLIPrinter.isCLIError(err) && err.code === "ERR_PARSE_ARGS_MISSING_OPTION_VALUE",
100
- message: (err) => `Missing required argument for option '${err.option}'.`
101
- },
102
- {
103
- match: (err) => _CLIPrinter.isCLIError(err) && err.code === "ERR_PARSE_ARGS_INVALID_OPTION_VALUE",
104
- message: (err) => `Invalid argument'${err.message}'.`
105
- },
106
- {
107
- match: (err) => _CLIPrinter.isCLIError(err) && err.code === "ENOENT",
108
- message: (err) => `File or directory not found: ${err.message}`
109
- },
110
- {
111
- match: () => true,
112
- // fallback
113
- message: (err) => _CLIPrinter.isCLIError(err) ? err.message : String(err)
114
- }
115
- ];
116
- var CLIPrinter = _CLIPrinter;
117
- var printer_default = CLIPrinter;
118
-
119
- export {
120
- printer_default
121
- };
package/ent.plist DELETED
@@ -1,14 +0,0 @@
1
- <!-- Entitlement for mac os signing since allow-unsigned-executable-memory is required -->
2
- <?xml version="1.0" encoding="UTF-8"?>
3
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
4
- "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
5
- <plist version="1.0">
6
- <dict>
7
- <key>com.apple.security.cs.allow-jit</key>
8
- <true/>
9
- <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
10
- <true/>
11
- <key>com.apple.security.cs.disable-library-validation</key>
12
- <true/>
13
- </dict>
14
- </plist>
package/jest.config.js DELETED
@@ -1,19 +0,0 @@
1
- module.exports = {
2
- preset: 'ts-jest',
3
- testEnvironment: 'node',
4
- roots: ['<rootDir>/src/_tests_'],
5
- testMatch: [
6
- '<rootDir>/src/_tests_/**/*.(test|spec).ts',
7
- ],
8
- moduleFileExtensions: ['ts', 'js', 'json'],
9
- transform: {
10
- '^.+\\.(ts|tsx)$': ['ts-jest', { tsconfig: 'tsconfig.jest.json' }],
11
- },
12
- moduleNameMapper: {
13
- '^(.*)src/(.*)$': '<rootDir>/src/$2',
14
- },
15
- collectCoverageFrom: [
16
- 'src/**/*.ts',
17
- '!src/index.ts',
18
- ],
19
- };
@@ -1,91 +0,0 @@
1
- import { buildFinalConfig } from '../cli/buildConfig';
2
-
3
-
4
- describe('buildFinalConfig', () => {
5
- test('throws when -R is not provided', () => {
6
- expect(() => buildFinalConfig({ R: [] }, [])).toThrow(/local port not specified/i);
7
- });
8
-
9
- test('parses -R with base forwarding and additional forwardings (including IPv6)', () => {
10
- const values = {
11
- R: [
12
- '0:localhost:3000',
13
- '5555:localhost:6666',
14
- 'example.com:7777:[::1]:8080',
15
- ]
16
- };
17
- const cfg = buildFinalConfig(values, []);
18
-
19
- expect(cfg.forwardTo).toBe('localhost:3000');
20
- expect(cfg.additionalForwarding).toBeDefined();
21
- expect(cfg.additionalForwarding!.length).toBe(2);
22
- expect(cfg.additionalForwarding![0]).toEqual({
23
- remotePort: 5555,
24
- localDomain: 'localhost',
25
- localPort: 6666,
26
- });
27
- expect(cfg.additionalForwarding![1]).toEqual({
28
- remoteDomain: 'example.com',
29
- remotePort: 7777,
30
- localDomain: '::1',
31
- localPort: 8080,
32
- });
33
- });
34
-
35
- test('parses --localport with https scheme and host:port (sets SNI but base forwardTo comes from -R)', () => {
36
- const values = { R: ['0:localhost:3000'], localport: 'https://myhost.local:8443' };
37
- const cfg = buildFinalConfig(values, []);
38
- // Because -R is present, forwardTo is derived from the first -R entry
39
- expect(cfg.forwardTo).toBe('localhost:3000');
40
- // localServerTls should still be set from localport's host
41
- expect(cfg.localServerTls).toBe('myhost.local');
42
- });
43
-
44
- test('parses token@domain for server and token; type from explicit --type', () => {
45
- const positionals: string[] = [];
46
- const values = { R: ['0:localhost:22'], token: 'mytoken@ap.example.com', type: 'tcp' };
47
-
48
- const cfg = buildFinalConfig(values, positionals);
49
- expect(cfg.type).toBe('tcp');
50
- expect(cfg.serverAddress).toBe('ap.example.com');
51
- expect(cfg.token).toBe('mytoken');
52
- });
53
-
54
- test('extended options: x:, w:, b:, k:, a:, u:, r:', () => {
55
- const values = { R: ['0:localhost:3000'] };
56
- const cfg = buildFinalConfig(values, [
57
- 'x:https',
58
- 'x:xff',
59
- 'w:192.168.1.0/24',
60
- 'b:user:pass',
61
- 'k:BEARER1',
62
- 'a:X-Test:One',
63
- 'u:X-Test:Two',
64
- 'r:X-Remove',
65
- ]);
66
-
67
- expect(cfg.httpsOnly).toBe(true);
68
- expect(cfg.xff).toBe(true);
69
- expect(cfg.ipWhitelist).toEqual(['192.168.1.0/24']);
70
- expect(cfg.basicAuth).toEqual({ user: 'pass' });
71
- expect(cfg.bearerAuth).toContain('BEARER1');
72
- // Header modifications consist of add, update, remove entries
73
- expect(cfg.headerModification).toEqual(
74
- expect.arrayContaining([
75
- { action: 'add', key: 'X-Test', value: 'One' },
76
- { action: 'update', key: 'X-Test', value: 'Two' },
77
- { action: 'remove', key: 'X-Remove' },
78
- ]),
79
- );
80
- });
81
-
82
- test('invalid localport format throws error', () => {
83
- const values = { R: ['0:localhost:3000'], localport: 'bad:format:123:456' };
84
- expect(() => buildFinalConfig(values, [])).toThrow(/invalid --localport format/i);
85
- });
86
-
87
- test('invalid additional forwarding throws error', () => {
88
- const values = { R: ['0:localhost:3000', 'abc'] };
89
- expect(() => buildFinalConfig(values, [])).toThrow(/forwarding address incorrect/i);
90
- });
91
- });