@dbx-tools/cli-tunnel 0.6.104 → 0.6.106

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 CHANGED
@@ -1,7 +1,8 @@
1
1
  # @dbx-tools/cli-tunnel
2
2
 
3
- Wrap any command in a public [portr](https://github.com/amalshaji/portr) tunnel
4
- fronted by [`@dbx-tools/auth`](../../node/auth) email OTP and passkeys.
3
+ Wrap any command in a public [Portr](https://github.com/amalshaji/portr),
4
+ [FRP](https://github.com/fatedier/frp), or combined tunnel fronted by
5
+ [`@dbx-tools/auth`](../../node/auth) email OTP and passkeys.
5
6
 
6
7
  Run `dbx tunnel -- <command>` when a local or self-hosted process needs a public
7
8
  URL that only approved email addresses can reach. The wrapper claims the public
@@ -11,12 +12,12 @@ about.
11
12
 
12
13
  Key features:
13
14
 
14
- - Public portr tunnel + Better Auth passwordless gate around a command the
15
+ - Portr, FRP, or both tunnel clients + a Better Auth passwordless gate around a command the
15
16
  wrapper does not have to modify, import, or even be written in the same
16
17
  language as.
17
18
  - A reverse proxy that answers the login routes itself and forwards only
18
19
  verified traffic to the wrapped process.
19
- - Flag → environment → `databricks.yml` resolution for every gate and portr
20
+ - Flag → environment → `databricks.yml` resolution for every gate and tunnel
20
21
  setting, delegated to [`@dbx-tools/tunnel`](../../node/tunnel) so the CLI
21
22
  cannot drift from the in-process plugin.
22
23
  - The same server-less `appkit.createApp` lifecycle as plugin mode. It can
@@ -75,16 +76,20 @@ subcommand, so `dbx tunnel -- cmd` and `dbx tunnel run -- cmd` are equivalent.
75
76
  dbx tunnel status --allow databricks.com
76
77
  ```
77
78
 
78
- The most common failure is a tunnel that silently does nothing because no portr
79
- token or public domain resolved. `status` prints the fully resolved ports, gate
80
- config, and portr config as JSON without starting a process.
79
+ The most common failure is a tunnel that silently does nothing because its
80
+ credentials or public domain did not resolve. `status` prints the fully resolved
81
+ ports, gate config, and client configs as JSON without starting a process.
81
82
 
82
83
  ```sh
83
84
  dbx tunnel install
84
85
  ```
85
86
 
86
- `install` downloads the portr binary and exits, so a first run does not pay for
87
- the download.
87
+ `install` defaults to Portr. Pass `frp` or `both` to preinstall those clients:
88
+
89
+ ```sh
90
+ dbx tunnel install frp
91
+ dbx tunnel install both
92
+ ```
88
93
 
89
94
  ## Commands And Flags
90
95
 
@@ -92,7 +97,7 @@ the download.
92
97
  dbx tunnel [options] -- <command...> # wrap a command (default)
93
98
  dbx tunnel run [options] -- <command...>
94
99
  dbx tunnel status [options]
95
- dbx tunnel install
100
+ dbx tunnel install [portr|frp|both]
96
101
  ```
97
102
 
98
103
  Every flag below is accepted on the root command and on `run` / `status`.
@@ -101,8 +106,15 @@ Omitted values fall back to the environment, a `.env` file, then
101
106
 
102
107
  | Flag | Meaning |
103
108
  | ----------------------------- | ---------------------------------------------------------- |
104
- | `--public-domain <host>` | portr public domain (`<subdomain>.<server>`) |
109
+ | `--transport <mode>` | `portr` (default), `frp`, or `both` |
110
+ | `--public-domain <host>` | Portr public domain (`<subdomain>.<server>`) |
105
111
  | `--subdomain <name>` | portr subdomain, else derived from the public domain |
112
+ | `--frp-public-domain <host>` | FRP public HTTP domain |
113
+ | `--frp-server <host>` | frps control host, else the FRP public domain |
114
+ | `--frp-server-port <port>` | frps control port (default `443`) |
115
+ | `--frp-protocol <protocol>` | frpc transport protocol (default `wss`) |
116
+ | `--frp-token <token>` | optional frps auth token |
117
+ | `--frp-proxy-name <name>` | frp proxy name, else the domain's first label |
106
118
  | `--port <port>` | public port the wrapper listens on (`DATABRICKS_APP_PORT`) |
107
119
  | `--app-port <port>` | private port the wrapped app binds, else a free one |
108
120
  | `--allow <patterns...>` | email allow-list (domain, glob, or `/regex/`) |
@@ -126,7 +138,7 @@ local debugging, not for anything reachable.
126
138
 
127
139
  ## How A Request Flows
128
140
 
129
- 1. The wrapper binds the PUBLIC port - the one portr and the Databricks Apps
141
+ 1. The wrapper binds the PUBLIC port - the one tunnel clients and Databricks Apps
130
142
  runtime route to - and spawns the command on a private loopback port.
131
143
  2. A login route (`/auth/*`) is answered by the proxy itself, using the gate
132
144
  handlers from a server-less AppKit app that supplies the code store, signing
@@ -134,8 +146,8 @@ local debugging, not for anything reachable.
134
146
  3. Anything else goes through `gate.gateRequest`. A verified session is proxied
135
147
  to the child with caller-supplied `x-` headers stripped; an unverified
136
148
  request gets the login page or a `401`.
137
- 4. portr publishes the public port once a token and domain resolve. Without
138
- them the wrapper still serves locally and says so.
149
+ 4. The selected client(s) publish the public port. In `both` mode, configure
150
+ different Portr and FRP domains; the gate recognizes both hosts.
139
151
 
140
152
  ## Modules
141
153
 
package/lib/src/cli.js CHANGED
@@ -24,7 +24,7 @@
24
24
  import { spawn } from "node:child_process";
25
25
  import { createServer } from "node:net";
26
26
  import { log } from "@dbx-tools/shared-core";
27
- import { portr } from "@dbx-tools/tunnel";
27
+ import { frp, portr } from "@dbx-tools/tunnel";
28
28
  import { Command, CommanderError } from "commander";
29
29
  import { resolveTunnelOptions } from "./options.js";
30
30
  import { startProxy } from "./proxy.js";
@@ -55,7 +55,8 @@ function freePort() {
55
55
  */
56
56
  function addOptions(command) {
57
57
  return command
58
- .option("--public-domain <host>", "portr public domain (<subdomain>.<server>)")
58
+ .option("--transport <transport>", "public tunnel transport: portr, frp, or both")
59
+ .option("--public-domain <host>", "public tunnel domain")
59
60
  .option("--subdomain <name>", "portr subdomain (else derived from the public domain)")
60
61
  .option("--port <port>", "public port the wrapper listens on")
61
62
  .option("--app-port <port>", "private port the wrapped app is told to bind")
@@ -71,6 +72,12 @@ function addOptions(command) {
71
72
  .option("--forward-headers <patterns...>", "extra x- headers tunnel traffic may forward")
72
73
  .option("--gate-path <prefix...>", "path prefixes to gate beyond /api/ (e.g. /ws)")
73
74
  .option("--bind <host...>", "interface IPs the gate listens on (default: 0.0.0.0)")
75
+ .option("--frp-server <host>", "frps control host (default: FRP public domain)")
76
+ .option("--frp-public-domain <host>", "FRP public HTTP domain")
77
+ .option("--frp-server-port <port>", "frps control port (default: 443)")
78
+ .option("--frp-protocol <protocol>", "frpc transport protocol (default: wss)")
79
+ .option("--frp-token <token>", "frps auth token")
80
+ .option("--frp-proxy-name <name>", "frp proxy registration name")
74
81
  .option("--insecure", "run open, with no gate");
75
82
  }
76
83
  /**
@@ -147,23 +154,29 @@ async function run(raw, command) {
147
154
  brandName: resolved.gate.brandName,
148
155
  bindHosts: resolved.bindHosts,
149
156
  });
150
- if (resolved.portr) {
157
+ if ((resolved.transport === "portr" || resolved.transport === "both") && resolved.portr) {
151
158
  const portrEnv = await portr.installPortr();
152
159
  await portr.writePortrConfig(resolved.portr, portrEnv);
153
160
  children.push(await portr.startPortr(resolved.portr, portrEnv));
154
161
  }
155
- else {
156
- logger.info("no PORTR_TOKEN / TUNNEL_PUBLIC_DOMAIN - serving locally only", {
162
+ if ((resolved.transport === "frp" || resolved.transport === "both") && resolved.frp) {
163
+ const frpEnv = await frp.installFrp();
164
+ const configPath = await frp.writeFrpConfig(resolved.frp, frpEnv);
165
+ children.push(frp.startFrp(resolved.frp, frpEnv, configPath));
166
+ }
167
+ const activeTunnelCount = children.length - (executable ? 1 : 0);
168
+ if (!activeTunnelCount)
169
+ logger.info("no selected public tunnel is configured", {
170
+ transport: resolved.transport,
157
171
  publicPort: resolved.publicPort,
158
172
  });
159
- }
160
173
  supervise(children);
161
174
  }
162
175
  /** The `dbx tunnel` program. No side effects until parsed. */
163
176
  export function buildProgram(name = "dbx tunnel") {
164
177
  const program = addOptions(new Command()
165
178
  .name(name)
166
- .description("Front a command with a portr tunnel and passwordless auth"));
179
+ .description("Front a command with a public tunnel and passwordless auth"));
167
180
  // `run` is the DEFAULT action as well as a named subcommand, preserving the old
168
181
  // wrapper's ergonomics (`dbx tunnel --allow x -- bun src/server.ts`) while
169
182
  // leaving somewhere for `status` and `install` to live.
@@ -186,10 +199,17 @@ export function buildProgram(name = "dbx tunnel") {
186
199
  });
187
200
  program
188
201
  .command("install")
189
- .description("Install the portr binary and exit")
190
- .action(async () => {
191
- await portr.installPortr();
202
+ .argument("[transport]", "portr, frp, or both", "portr")
203
+ .description("Install public tunnel client binaries and exit")
204
+ .action(async (transport) => {
205
+ if (transport === "portr" || transport === "both")
206
+ await portr.installPortr();
207
+ if (transport === "frp" || transport === "both")
208
+ await frp.installFrp();
209
+ if (transport !== "portr" && transport !== "frp" && transport !== "both") {
210
+ throw new CommanderError(1, "tunnel.invalid-transport", `invalid transport: ${transport}`);
211
+ }
192
212
  });
193
213
  return program;
194
214
  }
195
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVILE9BQU8sRUFBcUIsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDOUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3BELE9BQU8sRUFBRSxvQkFBb0IsRUFBc0IsTUFBTSxjQUFjLENBQUM7QUFDeEUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLFlBQVksQ0FBQztBQUV4QyxPQUFPLEVBQUUsY0FBYyxFQUFFLENBQUM7QUFFMUIsTUFBTSxNQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVwQyxpRkFBaUY7QUFDakYsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUM7QUFFaEM7Ozs7R0FJRztBQUNILFNBQVMsUUFBUTtJQUNmLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDckMsTUFBTSxLQUFLLEdBQUcsWUFBWSxFQUFFLENBQUM7UUFDN0IsS0FBSyxDQUFDLEVBQUUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDMUIsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsV0FBVyxFQUFFLEdBQUcsRUFBRTtZQUNoQyxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDaEMsTUFBTSxJQUFJLEdBQUcsT0FBTyxPQUFPLEtBQUssUUFBUSxJQUFJLE9BQU8sQ0FBQyxD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QUFDLFNBQVMsQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUNqRSxDQUFDLENBQUMsQ0FBQztJQUVILE9BQU87U0FDSixPQUFPLENBQUMsU0FBUyxDQUFDO1NBQ2xCLFdBQVcsQ0FBQyxtQ0FBbUMsQ0FBQztTQUNoRCxNQUFNLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDakIsTUFBTSxLQUFLLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDN0IsQ0FBQyxDQUFDLENBQUM7SUFFTCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBgZGJ4IHR1bm5lbGAgLSBmcm9udCBhIGNvbW1hbmQgd2l0aCBhIHB1YmxpYyBwb3J0ciB0dW5uZWwgYW5kIHBhc3N3b3JkbGVzcyBnYXRlLlxuICpcbiAqIFRoaXMgaXMgdGhlIFdSQVBQRVIgcGF0aCwgYW5kIGl0IGV4aXN0cyBmb3Igb25lIGNhc2U6IGEgcHJvamVjdCB0aGF0IGRvZXMgbm90XG4gKiB1c2UgYEBkYngtdG9vbHMvYXBwa2l0YCdzIGBjcmVhdGVBcHBgLCBhbmQgdGhlcmVmb3JlIGNhbm5vdCByZWdpc3RlclxuICogYHR1bm5lbEludGVyY2VwdG9yKClgICsgdGhlIGBhdXRoR2F0ZWAgcGx1Z2luIGluLXByb2Nlc3MuIEFuIEFwcEtpdCBhcHAgc2hvdWxkXG4gKiBzdGlsbCB0YWtlIHRoZSBwbHVnaW4gcGF0aCAtIG9uZSBwcm9jZXNzLCBubyBwcm94eSBob3AsIG5vIGR1cGxpY2F0ZWQgaGVhZGVyXG4gKiBoYW5kbGluZy5cbiAqXG4gKiBUaGUgd3JhcHBlciBjbGFpbXMgdGhlIFBVQkxJQyBwb3J0IChgREFUQUJSSUNLU19BUFBfUE9SVGAsIHRoZSBwb3J0IHRoZVxuICogcGxhdGZvcm0gYW5kIHBvcnRyIHJvdXRlIHRvKSwgbW92ZXMgdGhlIHdyYXBwZWQgYXBwIHRvIGEgcHJpdmF0ZSBvbmUsIGFuZFxuICogcmV2ZXJzZS1wcm94aWVzIGJldHdlZW4gdGhlbSBzbyB0aGUgZ2F0ZSBzaXRzIGluIGZyb250IG9mIHRyYWZmaWMgaXQgd291bGRcbiAqIG90aGVyd2lzZSBoYXZlIG5vIHdheSB0byBpbnRlcmNlcHQuIEV2ZXJ5dGhpbmcgZWxzZSBpcyBkZWxlZ2F0ZWQ6IHRoZSBnYXRlXG4gKiBjb25maWcgY29tZXMgZnJvbSBgcGx1Z2luLnJlc29sdmVBdXRoR2F0ZUNvbmZpZ2AsIHRoZSBwb3J0ciBsaWZlY3ljbGUgZnJvbVxuICogYHBvcnRyLipgIC0gYm90aCB0aGUgc2FtZSBmdW5jdGlvbnMgdGhlIGluLXByb2Nlc3MgcGF0aCB1c2VzLlxuICpcbiAqIFNoaXBzIG5vIGJpbi4gYEBkYngtdG9vbHMvY2xpYCBtb3VudHMgYGJ1aWxkUHJvZ3JhbSgpYCBhcyBgZGJ4IHR1bm5lbGAgbGF6aWx5LFxuICogc28gYGRieCBkZXZgIHBheXMgZm9yIG5vbmUgb2YgdGhpcywgYW5kIGAtLWluc2VjdXJlYCAvIGBzdGF0dXNgIC8gYGluc3RhbGxgXG4gKiBuZXZlciBsb2FkIEFwcEtpdCBvciB0aGUgU01UUCBzdGFjayBlaXRoZXIgKHRoZSBnYXRlIGFwcCBpcyBiZWhpbmQgYSBkeW5hbWljXG4gKiBpbXBvcnQpLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyB0eXBlIENoaWxkUHJvY2Vzcywgc3Bhd24gfSBmcm9tIFwibm9kZTpjaGlsZF9wcm9jZXNzXCI7XG5pbXBvcnQgeyBjcmVhdGVTZXJ2ZXIgfSBmcm9tIFwibm9kZTpuZXRcIjtcbmltcG9ydCB7IGxvZyB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBwb3J0ciB9IGZyb20gXCJAZGJ4LXRvb2xzL3R1bm5lbFwiO1xuaW1wb3J0IHsgQ29tbWFuZCwgQ29tbWFuZGVyRXJyb3IgfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyByZXNvbHZlVHVubmVsT3B0aW9ucywgdHlwZSBUdW5uZWxPcHRpb25zIH0gZnJvbSBcIi4vb3B0aW9ucy50c1wiO1xuaW1wb3J0IHsgc3RhcnRQcm94eSB9IGZyb20gXCIuL3Byb3h5LnRzXCI7XG5cbmV4cG9ydCB7IENvbW1hbmRlckVycm9yIH07XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ0dW5uZWxcIik7XG5cbi8qKiBIb3cgbG9uZyBhIGNoaWxkIGdldHMgdG8gZXhpdCBvbiBTSUdURVJNIGJlZm9yZSB0aGUgd3JhcHBlciBsZWF2ZXMgYW55d2F5LiAqL1xuY29uc3QgU0hVVERPV05fR1JBQ0VfTVMgPSAzXzAwMDtcblxuLyoqXG4gKiBBIGZyZWUgbG9vcGJhY2sgcG9ydCwgZnJvbSB0aGUgT1MgcmF0aGVyIHRoYW4gYSByYW5kb20gZ3Vlc3M6IGJpbmRpbmcgYDBgIGFuZFxuICogcmVhZGluZyBiYWNrIHdoYXQgd2FzIGFzc2lnbmVkIGlzIHRoZSBvbmx5IHdheSB0byBrbm93IHRoZSBwb3J0IGlzIGFjdHVhbGx5XG4gKiBhdmFpbGFibGUsIHNvIHR3byB0dW5uZWxzIGNhbiBydW4gc2lkZSBieSBzaWRlIHdpdGhvdXQgY29sbGlkaW5nLlxuICovXG5mdW5jdGlvbiBmcmVlUG9ydCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb2JlID0gY3JlYXRlU2VydmVyKCk7XG4gICAgcHJvYmUub24oXCJlcnJvclwiLCByZWplY3QpO1xuICAgIHByb2JlLmxpc3RlbigwLCBcIjEyNy4wLjAuMVwiLCAoKSA9PiB7XG4gICAgICBjb25zdCBhZGRyZXNzID0gcHJvYmUuYWRkcmVzcygpO1xuICAgICAgY29uc3QgcG9ydCA9IHR5cGVvZiBhZGRyZXNzID09PSBcIm9iamVjdFwiICYmIGFkZHJlc3MgPyBhZGRyZXNzLnBvcnQgOiAwO1xuICAgICAgcHJvYmUuY2xvc2UoKCkgPT4gKHBvcnQgPiAwID8gcmVzb2x2ZShwb3J0KSA6IHJlamVjdChuZXcgRXJyb3IoXCJubyBmcmVlIHBvcnRcIikpKSk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIEV2ZXJ5IGdhdGUvcG9ydHIgZmxhZy4gRGVjbGFyZWQgb24gdGhlIHJvb3QgY29tbWFuZCBBTkQgb24gYHJ1bmAvYHN0YXR1c2Agc29cbiAqIGBkYnggdHVubmVsIC0tYWxsb3cgeCAtLSBjbWRgIGFuZCBgZGJ4IHR1bm5lbCBydW4gLS1hbGxvdyB4IC0tIGNtZGAgYmVoYXZlXG4gKiBpZGVudGljYWxseSAtIGNvbW1hbmRlciBkb2VzIG5vdCBpbmhlcml0IG9wdGlvbnMgZG93bndhcmQuXG4gKi9cbmZ1bmN0aW9uIGFkZE9wdGlvbnMoY29tbWFuZDogQ29tbWFuZCk6IENvbW1hbmQge1xuICByZXR1cm4gY29tbWFuZFxuICAgIC5vcHRpb24oXCItLXB1YmxpYy1kb21haW4gPGhvc3Q+XCIsIFwicG9ydHIgcHVibGljIGRvbWFpbiAoPHN1YmRvbWFpbj4uPHNlcnZlcj4pXCIpXG4gICAgLm9wdGlvbihcIi0tc3ViZG9tYWluIDxuYW1lPlwiLCBcInBvcnRyIHN1YmRvbWFpbiAoZWxzZSBkZXJpdmVkIGZyb20gdGhlIHB1YmxpYyBkb21haW4pXCIpXG4gICAgLm9wdGlvbihcIi0tcG9ydCA8cG9ydD5cIiwgXCJwdWJsaWMgcG9ydCB0aGUgd3JhcHBlciBsaXN0ZW5zIG9uXCIpXG4gICAgLm9wdGlvbihcIi0tYXBwLXBvcnQgPHBvcnQ+XCIsIFwicHJpdmF0ZSBwb3J0IHRoZSB3cmFwcGVkIGFwcCBpcyB0b2xkIHRvIGJpbmRcIilcbiAgICAub3B0aW9uKFwiLS1hbGxvdyA8cGF0dGVybnMuLi4+XCIsIFwiZW1haWwgYWxsb3ctbGlzdCAoZG9tYWluIC8gZ2xvYiAvIC9yZWdleC8pXCIpXG4gICAgLm9wdGlvbihcIi0tc3ViamVjdCA8dGV4dD5cIiwgXCJ2ZXJpZmljYXRpb24gZW1haWwgc3ViamVjdFwiKVxuICAgIC5vcHRpb24oXCItLWJyYW5kLW5hbWUgPG5hbWU+XCIsIFwidmVyaWZpY2F0aW9uIGVtYWlsIGJyYW5kIG5hbWVcIilcbiAgICAub3B0aW9uKFwiLS1tZXNzYWdlIDx0ZXh0PlwiLCBcInZlcmlmaWNhdGlvbiBlbWFpbCBtZXNzYWdlXCIpXG4gICAgLm9wdGlvbihcIi0tc2Vzc2lvbi10dGwgPHNlY29uZHM+XCIsIFwic2Vzc2lvbiBsaWZldGltZVwiKVxuICAgIC5vcHRpb24oXCItLWNvZGUtdHRsIDxzZWNvbmRzPlwiLCBcIm9uZS10aW1lLWNvZGUgbGlmZXRpbWVcIilcbiAgICAub3B0aW9uKFwiLS1zZXNzaW9uLWN1dG9mZiA8d2hlbj5cIiwgXCJpbnZhbGlkYXRlIGV2ZXJ5IHNlc3Npb24gaXNzdWVkIGJlZm9yZSB0aGlzXCIpXG4gICAgLm9wdGlvbihcIi0tYXV0aC1zdG9yYWdlIDxtb2RlPlwiLCBcImF1dGggZGF0YWJhc2U6IGF1dG8sIGxha2ViYXNlLCBvciBzcWxpdGVcIilcbiAgICAub3B0aW9uKFwiLS1hdXRoLXNxbGl0ZS1wYXRoIDxwYXRoPlwiLCBcImxvY2FsIEJldHRlciBBdXRoIFNRTGl0ZSBmaWxlXCIpXG4gICAgLm9wdGlvbihcIi0tZm9yd2FyZC1oZWFkZXJzIDxwYXR0ZXJucy4uLj5cIiwgXCJleHRyYSB4LSBoZWFkZXJzIHR1bm5lbCB0cmFmZmljIG1heSBmb3J3YXJkXCIpXG4gICAgLm9wdGlvbihcIi0tZ2F0ZS1wYXRoIDxwcmVmaXguLi4+XCIsIFwicGF0aCBwcmVmaXhlcyB0byBnYXRlIGJleW9uZCAvYXBpLyAoZS5nLiAvd3MpXCIpXG4gICAgLm9wdGlvbihcIi0tYmluZCA8aG9zdC4uLj5cIiwgXCJpbnRlcmZhY2UgSVBzIHRoZSBnYXRlIGxpc3RlbnMgb24gKGRlZmF1bHQ6IDAuMC4wLjApXCIpXG4gICAgLm9wdGlvbihcIi0taW5zZWN1cmVcIiwgXCJydW4gb3Blbiwgd2l0aCBubyBnYXRlXCIpO1xufVxuXG4vKipcbiAqIFRpZSB0aGUgd3JhcHBlcidzIGxpZmV0aW1lIHRvIGl0cyBjaGlsZHJlbidzLCBpbiBib3RoIGRpcmVjdGlvbnM6IGEgY2hpbGQgdGhhdFxuICogZXhpdHMgdGFrZXMgdGhlIHdyYXBwZXIgZG93biB3aXRoIGl0cyBjb2RlLCBhbmQgYSBzaWduYWwgdG8gdGhlIHdyYXBwZXIgaXNcbiAqIGZvcndhcmRlZCBiZWZvcmUgaXQgbGVhdmVzLiBXaXRob3V0IHRoaXMgYSBjcmFzaGVkIGFwcCBsZWF2ZXMgYSBwb3J0ciB0dW5uZWxcbiAqIHNlcnZpbmcgYSBkZWFkIHBvcnQsIHdoaWNoIGxvb2tzIGxpa2UgYSBoYW5nIHJhdGhlciB0aGFuIGEgZmFpbHVyZS5cbiAqL1xuZnVuY3Rpb24gc3VwZXJ2aXNlKGNoaWxkcmVuOiByZWFkb25seSBDaGlsZFByb2Nlc3NbXSk6IHZvaWQge1xuICBsZXQgc3RvcHBpbmcgPSBmYWxzZTtcbiAgY29uc3Qgc3RvcCA9IChjb2RlOiBudW1iZXIpOiB2b2lkID0+IHtcbiAgICBpZiAoc3RvcHBpbmcpIHJldHVybjtcbiAgICBzdG9wcGluZyA9IHRydWU7XG4gICAgZm9yIChjb25zdCBjaGlsZCBvZiBjaGlsZHJlbikgaWYgKCFjaGlsZC5raWxsZWQpIGNoaWxkLmtpbGwoXCJTSUdURVJNXCIpO1xuICAgIHNldFRpbWVvdXQoKCkgPT4gcHJvY2Vzcy5leGl0KGNvZGUpLCBTSFVURE9XTl9HUkFDRV9NUykudW5yZWYoKTtcbiAgfTtcbiAgZm9yIChjb25zdCBjaGlsZCBvZiBjaGlsZHJlbikgY2hpbGQub24oXCJleGl0XCIsIChjb2RlKSA9PiBzdG9wKGNvZGUgPz8gMSkpO1xuICBmb3IgKGNvbnN0IHNpZ25hbCBvZiBbXCJTSUdURVJNXCIsIFwiU0lHSU5UXCIsIFwiU0lHSFVQXCJdIGFzIGNvbnN0KSB7XG4gICAgcHJvY2Vzcy5vbihzaWduYWwsICgpID0+IHN0b3AoMCkpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHJ1bihyYXc6IFR1bm5lbE9wdGlvbnMsIGNvbW1hbmQ6IHJlYWRvbmx5IHN0cmluZ1tdKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IFtleGVjdXRhYmxlLCAuLi5hcmdzXSA9IGNvbW1hbmQ7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVR1bm5lbE9wdGlvbnMocmF3KTtcbiAgY29uc3QgY2hpbGRyZW46IENoaWxkUHJvY2Vzc1tdID0gW107XG5cbiAgLy8gVHdvIHVwc3RyZWFtIG1vZGVzOlxuICAvLyAgIC0gV1JBUDogYSBjb21tYW5kIGFmdGVyIGAtLWAuIFRoZSB3cmFwcGVyIHNwYXducyBpdCBvbiBhIHByaXZhdGUgbG9vcGJhY2tcbiAgLy8gICAgIHBvcnQgYW5kIGlzIHRoZSBvbmx5IHRoaW5nIHRoYXQgdGFsa3MgdG8gaXQuXG4gIC8vICAgLSBBVFRBQ0g6IG5vIGNvbW1hbmQsIGJ1dCBgLS1hcHAtcG9ydGAgbmFtZXMgYW4gYWxyZWFkeS1ydW5uaW5nIHVwc3RyZWFtXG4gIC8vICAgICAoZS5nLiBhIGxvY2FsIHJldmVyc2UgcHJveHkpLiBUaGUgZ2F0ZSBmcm9udHMgaXQgd2l0aG91dCBzcGF3bmluZyBhXG4gIC8vICAgICBjaGlsZC4gVGhpcyBpcyB3aGF0IGxldHMgdGhlIGdhdGUgc2l0IG9uIGFuIGludGVyZmFjZSBpbiBmcm9udCBvZiBhXG4gIC8vICAgICBzZXBhcmF0ZWx5LXN1cGVydmlzZWQgc3RhY2suXG4gIGxldCBhcHBQb3J0OiBudW1iZXI7XG4gIGlmIChleGVjdXRhYmxlKSB7XG4gICAgYXBwUG9ydCA9IHJlc29sdmVkLmFwcFBvcnQgPz8gKGF3YWl0IGZyZWVQb3J0KCkpO1xuICAgIGNvbnN0IGFwcCA9IHNwYXduKGV4ZWN1dGFibGUsIGFyZ3MsIHtcbiAgICAgIGVudjoge1xuICAgICAgICAuLi5wcm9jZXNzLmVudixcbiAgICAgICAgREFUQUJSSUNLU19BUFBfUE9SVDogU3RyaW5nKGFwcFBvcnQpLFxuICAgICAgICBQT1JUOiBTdHJpbmcoYXBwUG9ydCksXG4gICAgICAgIEhPU1Q6IFwiMTI3LjAuMC4xXCIsXG4gICAgICB9LFxuICAgICAgc3RkaW86IFwiaW5oZXJpdFwiLFxuICAgIH0pO1xuICAgIGNoaWxkcmVuLnB1c2goYXBwKTtcbiAgfSBlbHNlIGlmIChyZXNvbHZlZC5hcHBQb3J0KSB7XG4gICAgYXBwUG9ydCA9IHJlc29sdmVkLmFwcFBvcnQ7XG4gICAgbG9nZ2VyLmluZm8oXCJhdHRhY2hpbmcgZ2F0ZSB0byBleGlzdGluZyB1cHN0cmVhbVwiLCB7IGFwcFBvcnQgfSk7XG4gIH0gZWxzZSB7XG4gICAgdGhyb3cgbmV3IENvbW1hbmRlckVycm9yKFxuICAgICAgMSxcbiAgICAgIFwidHVubmVsLm5vLXVwc3RyZWFtXCIsXG4gICAgICBcIm5vIGNvbW1hbmQgZ2l2ZW4gKHBhc3MgaXQgYWZ0ZXIgYC0tYCkgYW5kIG5vIC0tYXBwLXBvcnQgdG8gYXR0YWNoIHRvXCIsXG4gICAgKTtcbiAgfVxuXG4gIC8vIER5bmFtaWMgaW1wb3J0OiB0aGUgZ2F0ZSBpcyB0aGUgb25seSB0aGluZyBoZXJlIHRoYXQgbmVlZHMgQXBwS2l0ICsgU01UUCwgc29cbiAgLy8gYW4gYC0taW5zZWN1cmVgIHJ1biBuZXZlciBsb2FkcyBlaXRoZXIuXG4gIGNvbnN0IGdhdGUgPSByZXNvbHZlZC5nYXRlLmluc2VjdXJlXG4gICAgPyB1bmRlZmluZWRcbiAgICA6IGF3YWl0IChcbiAgICAgICAgYXdhaXQgaW1wb3J0KFwiLi9hcHAudHNcIilcbiAgICAgICkuc3RhcnRHYXRlQXBwKHtcbiAgICAgICAgLi4ucmVzb2x2ZWQuZ2F0ZUNvbmZpZyxcbiAgICAgICAgcHVibGljRG9tYWluOiByZXNvbHZlZC5nYXRlLnB1YmxpY0RvbWFpbiA/PyBgbG9jYWxob3N0OiR7cmVzb2x2ZWQucHVibGljUG9ydH1gLFxuICAgICAgfSk7XG4gIGlmICghZ2F0ZSkgbG9nZ2VyLndhcm4oXCJydW5uaW5nIE9QRU4gLSBubyBnYXRlIGlzIGluIGZyb250IG9mIHRoaXMgdHVubmVsXCIpO1xuXG4gIGF3YWl0IHN0YXJ0UHJveHkoe1xuICAgIHB1YmxpY1BvcnQ6IHJlc29sdmVkLnB1YmxpY1BvcnQsXG4gICAgYXBwUG9ydCxcbiAgICBnYXRlLFxuICAgIGZvcndhcmRIZWFkZXJzOiByZXNvbHZlZC5nYXRlLmZvcndhcmRIZWFkZXJzLFxuICAgIGdhdGVQYXRoczogcmVzb2x2ZWQuZ2F0ZS5nYXRlUGF0aHMsXG4gICAgYnJhbmROYW1lOiByZXNvbHZlZC5nYXRlLmJyYW5kTmFtZSxcbiAgICBiaW5kSG9zdHM6IHJlc29sdmVkLmJpbmRIb3N0cyxcbiAgfSk7XG5cbiAgaWYgKHJlc29sdmVkLnBvcnRyKSB7XG4gICAgY29uc3QgcG9ydHJFbnYgPSBhd2FpdCBwb3J0ci5pbnN0YWxsUG9ydHIoKTtcbiAgICBhd2FpdCBwb3J0ci53cml0ZVBvcnRyQ29uZmlnKHJlc29sdmVkLnBvcnRyLCBwb3J0ckVudik7XG4gICAgY2hpbGRyZW4ucHVzaChhd2FpdCBwb3J0ci5zdGFydFBvcnRyKHJlc29sdmVkLnBvcnRyLCBwb3J0ckVudikpO1xuICB9IGVsc2Uge1xuICAgIGxvZ2dlci5pbmZvKFwibm8gUE9SVFJfVE9LRU4gLyBUVU5ORUxfUFVCTElDX0RPTUFJTiAtIHNlcnZpbmcgbG9jYWxseSBvbmx5XCIsIHtcbiAgICAgIHB1YmxpY1BvcnQ6IHJlc29sdmVkLnB1YmxpY1BvcnQsXG4gICAgfSk7XG4gIH1cbiAgc3VwZXJ2aXNlKGNoaWxkcmVuKTtcbn1cblxuLyoqIFRoZSBgZGJ4IHR1bm5lbGAgcHJvZ3JhbS4gTm8gc2lkZSBlZmZlY3RzIHVudGlsIHBhcnNlZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZFByb2dyYW0obmFtZSA9IFwiZGJ4IHR1bm5lbFwiKTogQ29tbWFuZCB7XG4gIGNvbnN0IHByb2dyYW0gPSBhZGRPcHRpb25zKFxuICAgIG5ldyBDb21tYW5kKClcbiAgICAgIC5uYW1lKG5hbWUpXG4gICAgICAuZGVzY3JpcHRpb24oXCJGcm9udCBhIGNvbW1hbmQgd2l0aCBhIHBvcnRyIHR1bm5lbCBhbmQgcGFzc3dvcmRsZXNzIGF1dGhcIiksXG4gICk7XG5cbiAgLy8gYHJ1bmAgaXMgdGhlIERFRkFVTFQgYWN0aW9uIGFzIHdlbGwgYXMgYSBuYW1lZCBzdWJjb21tYW5kLCBwcmVzZXJ2aW5nIHRoZSBvbGRcbiAgLy8gd3JhcHBlcidzIGVyZ29ub21pY3MgKGBkYnggdHVubmVsIC0tYWxsb3cgeCAtLSBidW4gc3JjL3NlcnZlci50c2ApIHdoaWxlXG4gIC8vIGxlYXZpbmcgc29tZXdoZXJlIGZvciBgc3RhdHVzYCBhbmQgYGluc3RhbGxgIHRvIGxpdmUuXG4gIHByb2dyYW1cbiAgICAuYXJndW1lbnQoXCJbY29tbWFuZC4uLl1cIiwgXCJ0aGUgY29tbWFuZCB0byB3cmFwLCBhZnRlciBgLS1gXCIpXG4gICAgLmFjdGlvbihhc3luYyAoY29tbWFuZDogc3RyaW5nW10sIF9vcHRpb25zOiBUdW5uZWxPcHRpb25zLCBjbWQ6IENvbW1hbmQpID0+IHtcbiAgICAgIGF3YWl0IHJ1bihjbWQub3B0czxUdW5uZWxPcHRpb25zPigpLCBjb21tYW5kKTtcbiAgICB9KTtcblxuICBhZGRPcHRpb25zKHByb2dyYW0uY29tbWFuZChcInJ1blwiKS5kZXNjcmlwdGlvbihcIldyYXAgYSBjb21tYW5kICh0aGUgZGVmYXVsdCBhY3Rpb24pXCIpKVxuICAgIC5hcmd1bWVudChcIjxjb21tYW5kLi4uPlwiLCBcInRoZSBjb21tYW5kIHRvIHdyYXAsIGFmdGVyIGAtLWBcIilcbiAgICAuYWN0aW9uKGFzeW5jIChjb21tYW5kOiBzdHJpbmdbXSwgX29wdGlvbnM6IFR1bm5lbE9wdGlvbnMsIGNtZDogQ29tbWFuZCkgPT4ge1xuICAgICAgYXdhaXQgcnVuKGNtZC5vcHRzPFR1bm5lbE9wdGlvbnM+KCksIGNvbW1hbmQpO1xuICAgIH0pO1xuXG4gIC8vIFdvcnRoIGl0cyBvd24gY29tbWFuZDogdGhlIG1vc3QgY29tbW9uIGZhaWx1cmUgaXMgYSB0dW5uZWwgdGhhdCBzaWxlbnRseVxuICAvLyBkb2VzIG5vdGhpbmcgYmVjYXVzZSBubyB0b2tlbiBvciBkb21haW4gcmVzb2x2ZWQsIGFuZCB0aGlzIHByaW50cyBleGFjdGx5XG4gIC8vIHdoYXQgd291bGQgaGFwcGVuIHdpdGhvdXQgc3RhcnRpbmcgYW55dGhpbmcuXG4gIGFkZE9wdGlvbnMoXG4gICAgcHJvZ3JhbS5jb21tYW5kKFwic3RhdHVzXCIpLmRlc2NyaXB0aW9uKFwiUmVzb2x2ZSB0aGUgY29uZmlndXJhdGlvbiBhbmQgcHJpbnQgaXRcIiksXG4gICkuYWN0aW9uKChfb3B0aW9uczogVHVubmVsT3B0aW9ucywgY21kOiBDb21tYW5kKSA9PiB7XG4gICAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlVHVubmVsT3B0aW9ucyhjbWQub3B0czxUdW5uZWxPcHRpb25zPigpKTtcbiAgICBwcm9jZXNzLnN0ZG91dC53cml0ZShgJHtKU09OLnN0cmluZ2lmeShyZXNvbHZlZCwgbnVsbCwgMil9XFxuYCk7XG4gIH0pO1xuXG4gIHByb2dyYW1cbiAgICAuY29tbWFuZChcImluc3RhbGxcIilcbiAgICAuZGVzY3JpcHRpb24oXCJJbnN0YWxsIHRoZSBwb3J0ciBiaW5hcnkgYW5kIGV4aXRcIilcbiAgICAuYWN0aW9uKGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHBvcnRyLmluc3RhbGxQb3J0cigpO1xuICAgIH0pO1xuXG4gIHJldHVybiBwcm9ncmFtO1xufVxuIl19
215
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NsaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXNCRztBQUVILE9BQU8sRUFBcUIsS0FBSyxFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDOUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUN4QyxPQUFPLEVBQUUsR0FBRyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwRCxPQUFPLEVBQUUsb0JBQW9CLEVBQXNCLE1BQU0sY0FBYyxDQUFDO0FBQ3hFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFeEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxDQUFDO0FBRTFCLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFFcEMsaUZBQWlGO0FBQ2pGLE1BQU0saUJBQWlCLEdBQUcsS0FBSyxDQUFDO0FBRWhDOzs7O0dBSUc7QUFDSCxTQUFTLFFBQVE7SUFDZixPQUFPLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO1FBQ3JDLE1BQU0sS0FBSyxHQUFHLFlBQVksRUFBRSxDQUFDO1FBQzdCLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzFCLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLFdBQVcsRUFBRSxHQUFHLEVBQUU7WUFDaEMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxHQUFHLE9BQU8sT0FBTyxLQUFLLFFBQVEsSUFBSSxP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QUNqRSxDQUFDLENBQUMsQ0FBQztJQUVILE9BQU87U0FDSixPQUFPLENBQUMsU0FBUyxDQUFDO1NBQ2xCLFFBQVEsQ0FBQyxhQUFhLEVBQUUscUJBQXFCLEVBQUUsT0FBTyxDQUFDO1NBQ3ZELFdBQVcsQ0FBQyxnREFBZ0QsQ0FBQztTQUM3RCxNQUFNLENBQUMsS0FBSyxFQUFFLFNBQWlCLEVBQUUsRUFBRTtRQUNsQyxJQUFJLFNBQVMsS0FBSyxPQUFPLElBQUksU0FBUyxLQUFLLE1BQU07WUFBRSxNQUFNLEtBQUssQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUM5RSxJQUFJLFNBQVMsS0FBSyxLQUFLLElBQUksU0FBUyxLQUFLLE1BQU07WUFBRSxNQUFNLEdBQUcsQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUN4RSxJQUFJLFNBQVMsS0FBSyxPQUFPLElBQUksU0FBUyxLQUFLLEtBQUssSUFBSSxTQUFTLEtBQUssTUFBTSxFQUFFLENBQUM7WUFDekUsTUFBTSxJQUFJLGNBQWMsQ0FBQyxDQUFDLEVBQUUsMEJBQTBCLEVBQUUsc0JBQXNCLFNBQVMsRUFBRSxDQUFDLENBQUM7UUFDN0YsQ0FBQztJQUNILENBQUMsQ0FBQyxDQUFDO0lBRUwsT0FBTyxPQUFPLENBQUM7QUFDakIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYGRieCB0dW5uZWxgIC0gZnJvbnQgYSBjb21tYW5kIHdpdGggYSBwdWJsaWMgcG9ydHIgdHVubmVsIGFuZCBwYXNzd29yZGxlc3MgZ2F0ZS5cbiAqXG4gKiBUaGlzIGlzIHRoZSBXUkFQUEVSIHBhdGgsIGFuZCBpdCBleGlzdHMgZm9yIG9uZSBjYXNlOiBhIHByb2plY3QgdGhhdCBkb2VzIG5vdFxuICogdXNlIGBAZGJ4LXRvb2xzL2FwcGtpdGAncyBgY3JlYXRlQXBwYCwgYW5kIHRoZXJlZm9yZSBjYW5ub3QgcmVnaXN0ZXJcbiAqIGB0dW5uZWxJbnRlcmNlcHRvcigpYCArIHRoZSBgYXV0aEdhdGVgIHBsdWdpbiBpbi1wcm9jZXNzLiBBbiBBcHBLaXQgYXBwIHNob3VsZFxuICogc3RpbGwgdGFrZSB0aGUgcGx1Z2luIHBhdGggLSBvbmUgcHJvY2Vzcywgbm8gcHJveHkgaG9wLCBubyBkdXBsaWNhdGVkIGhlYWRlclxuICogaGFuZGxpbmcuXG4gKlxuICogVGhlIHdyYXBwZXIgY2xhaW1zIHRoZSBQVUJMSUMgcG9ydCAoYERBVEFCUklDS1NfQVBQX1BPUlRgLCB0aGUgcG9ydCB0aGVcbiAqIHBsYXRmb3JtIGFuZCBwb3J0ciByb3V0ZSB0byksIG1vdmVzIHRoZSB3cmFwcGVkIGFwcCB0byBhIHByaXZhdGUgb25lLCBhbmRcbiAqIHJldmVyc2UtcHJveGllcyBiZXR3ZWVuIHRoZW0gc28gdGhlIGdhdGUgc2l0cyBpbiBmcm9udCBvZiB0cmFmZmljIGl0IHdvdWxkXG4gKiBvdGhlcndpc2UgaGF2ZSBubyB3YXkgdG8gaW50ZXJjZXB0LiBFdmVyeXRoaW5nIGVsc2UgaXMgZGVsZWdhdGVkOiB0aGUgZ2F0ZVxuICogY29uZmlnIGNvbWVzIGZyb20gYHBsdWdpbi5yZXNvbHZlQXV0aEdhdGVDb25maWdgLCB0aGUgcG9ydHIgbGlmZWN5Y2xlIGZyb21cbiAqIGBwb3J0ci4qYCAtIGJvdGggdGhlIHNhbWUgZnVuY3Rpb25zIHRoZSBpbi1wcm9jZXNzIHBhdGggdXNlcy5cbiAqXG4gKiBTaGlwcyBubyBiaW4uIGBAZGJ4LXRvb2xzL2NsaWAgbW91bnRzIGBidWlsZFByb2dyYW0oKWAgYXMgYGRieCB0dW5uZWxgIGxhemlseSxcbiAqIHNvIGBkYnggZGV2YCBwYXlzIGZvciBub25lIG9mIHRoaXMsIGFuZCBgLS1pbnNlY3VyZWAgLyBgc3RhdHVzYCAvIGBpbnN0YWxsYFxuICogbmV2ZXIgbG9hZCBBcHBLaXQgb3IgdGhlIFNNVFAgc3RhY2sgZWl0aGVyICh0aGUgZ2F0ZSBhcHAgaXMgYmVoaW5kIGEgZHluYW1pY1xuICogaW1wb3J0KS5cbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuaW1wb3J0IHsgdHlwZSBDaGlsZFByb2Nlc3MsIHNwYXduIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgY3JlYXRlU2VydmVyIH0gZnJvbSBcIm5vZGU6bmV0XCI7XG5pbXBvcnQgeyBsb2cgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgZnJwLCBwb3J0ciB9IGZyb20gXCJAZGJ4LXRvb2xzL3R1bm5lbFwiO1xuaW1wb3J0IHsgQ29tbWFuZCwgQ29tbWFuZGVyRXJyb3IgfSBmcm9tIFwiY29tbWFuZGVyXCI7XG5pbXBvcnQgeyByZXNvbHZlVHVubmVsT3B0aW9ucywgdHlwZSBUdW5uZWxPcHRpb25zIH0gZnJvbSBcIi4vb3B0aW9ucy50c1wiO1xuaW1wb3J0IHsgc3RhcnRQcm94eSB9IGZyb20gXCIuL3Byb3h5LnRzXCI7XG5cbmV4cG9ydCB7IENvbW1hbmRlckVycm9yIH07XG5cbmNvbnN0IGxvZ2dlciA9IGxvZy5sb2dnZXIoXCJ0dW5uZWxcIik7XG5cbi8qKiBIb3cgbG9uZyBhIGNoaWxkIGdldHMgdG8gZXhpdCBvbiBTSUdURVJNIGJlZm9yZSB0aGUgd3JhcHBlciBsZWF2ZXMgYW55d2F5LiAqL1xuY29uc3QgU0hVVERPV05fR1JBQ0VfTVMgPSAzXzAwMDtcblxuLyoqXG4gKiBBIGZyZWUgbG9vcGJhY2sgcG9ydCwgZnJvbSB0aGUgT1MgcmF0aGVyIHRoYW4gYSByYW5kb20gZ3Vlc3M6IGJpbmRpbmcgYDBgIGFuZFxuICogcmVhZGluZyBiYWNrIHdoYXQgd2FzIGFzc2lnbmVkIGlzIHRoZSBvbmx5IHdheSB0byBrbm93IHRoZSBwb3J0IGlzIGFjdHVhbGx5XG4gKiBhdmFpbGFibGUsIHNvIHR3byB0dW5uZWxzIGNhbiBydW4gc2lkZSBieSBzaWRlIHdpdGhvdXQgY29sbGlkaW5nLlxuICovXG5mdW5jdGlvbiBmcmVlUG9ydCgpOiBQcm9taXNlPG51bWJlcj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb2JlID0gY3JlYXRlU2VydmVyKCk7XG4gICAgcHJvYmUub24oXCJlcnJvclwiLCByZWplY3QpO1xuICAgIHByb2JlLmxpc3RlbigwLCBcIjEyNy4wLjAuMVwiLCAoKSA9PiB7XG4gICAgICBjb25zdCBhZGRyZXNzID0gcHJvYmUuYWRkcmVzcygpO1xuICAgICAgY29uc3QgcG9ydCA9IHR5cGVvZiBhZGRyZXNzID09PSBcIm9iamVjdFwiICYmIGFkZHJlc3MgPyBhZGRyZXNzLnBvcnQgOiAwO1xuICAgICAgcHJvYmUuY2xvc2UoKCkgPT4gKHBvcnQgPiAwID8gcmVzb2x2ZShwb3J0KSA6IHJlamVjdChuZXcgRXJyb3IoXCJubyBmcmVlIHBvcnRcIikpKSk7XG4gICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIEV2ZXJ5IGdhdGUvcG9ydHIgZmxhZy4gRGVjbGFyZWQgb24gdGhlIHJvb3QgY29tbWFuZCBBTkQgb24gYHJ1bmAvYHN0YXR1c2Agc29cbiAqIGBkYnggdHVubmVsIC0tYWxsb3cgeCAtLSBjbWRgIGFuZCBgZGJ4IHR1bm5lbCBydW4gLS1hbGxvdyB4IC0tIGNtZGAgYmVoYXZlXG4gKiBpZGVudGljYWxseSAtIGNvbW1hbmRlciBkb2VzIG5vdCBpbmhlcml0IG9wdGlvbnMgZG93bndhcmQuXG4gKi9cbmZ1bmN0aW9uIGFkZE9wdGlvbnMoY29tbWFuZDogQ29tbWFuZCk6IENvbW1hbmQge1xuICByZXR1cm4gY29tbWFuZFxuICAgIC5vcHRpb24oXCItLXRyYW5zcG9ydCA8dHJhbnNwb3J0PlwiLCBcInB1YmxpYyB0dW5uZWwgdHJhbnNwb3J0OiBwb3J0ciwgZnJwLCBvciBib3RoXCIpXG4gICAgLm9wdGlvbihcIi0tcHVibGljLWRvbWFpbiA8aG9zdD5cIiwgXCJwdWJsaWMgdHVubmVsIGRvbWFpblwiKVxuICAgIC5vcHRpb24oXCItLXN1YmRvbWFpbiA8bmFtZT5cIiwgXCJwb3J0ciBzdWJkb21haW4gKGVsc2UgZGVyaXZlZCBmcm9tIHRoZSBwdWJsaWMgZG9tYWluKVwiKVxuICAgIC5vcHRpb24oXCItLXBvcnQgPHBvcnQ+XCIsIFwicHVibGljIHBvcnQgdGhlIHdyYXBwZXIgbGlzdGVucyBvblwiKVxuICAgIC5vcHRpb24oXCItLWFwcC1wb3J0IDxwb3J0PlwiLCBcInByaXZhdGUgcG9ydCB0aGUgd3JhcHBlZCBhcHAgaXMgdG9sZCB0byBiaW5kXCIpXG4gICAgLm9wdGlvbihcIi0tYWxsb3cgPHBhdHRlcm5zLi4uPlwiLCBcImVtYWlsIGFsbG93LWxpc3QgKGRvbWFpbiAvIGdsb2IgLyAvcmVnZXgvKVwiKVxuICAgIC5vcHRpb24oXCItLXN1YmplY3QgPHRleHQ+XCIsIFwidmVyaWZpY2F0aW9uIGVtYWlsIHN1YmplY3RcIilcbiAgICAub3B0aW9uKFwiLS1icmFuZC1uYW1lIDxuYW1lPlwiLCBcInZlcmlmaWNhdGlvbiBlbWFpbCBicmFuZCBuYW1lXCIpXG4gICAgLm9wdGlvbihcIi0tbWVzc2FnZSA8dGV4dD5cIiwgXCJ2ZXJpZmljYXRpb24gZW1haWwgbWVzc2FnZVwiKVxuICAgIC5vcHRpb24oXCItLXNlc3Npb24tdHRsIDxzZWNvbmRzPlwiLCBcInNlc3Npb24gbGlmZXRpbWVcIilcbiAgICAub3B0aW9uKFwiLS1jb2RlLXR0bCA8c2Vjb25kcz5cIiwgXCJvbmUtdGltZS1jb2RlIGxpZmV0aW1lXCIpXG4gICAgLm9wdGlvbihcIi0tc2Vzc2lvbi1jdXRvZmYgPHdoZW4+XCIsIFwiaW52YWxpZGF0ZSBldmVyeSBzZXNzaW9uIGlzc3VlZCBiZWZvcmUgdGhpc1wiKVxuICAgIC5vcHRpb24oXCItLWF1dGgtc3RvcmFnZSA8bW9kZT5cIiwgXCJhdXRoIGRhdGFiYXNlOiBhdXRvLCBsYWtlYmFzZSwgb3Igc3FsaXRlXCIpXG4gICAgLm9wdGlvbihcIi0tYXV0aC1zcWxpdGUtcGF0aCA8cGF0aD5cIiwgXCJsb2NhbCBCZXR0ZXIgQXV0aCBTUUxpdGUgZmlsZVwiKVxuICAgIC5vcHRpb24oXCItLWZvcndhcmQtaGVhZGVycyA8cGF0dGVybnMuLi4+XCIsIFwiZXh0cmEgeC0gaGVhZGVycyB0dW5uZWwgdHJhZmZpYyBtYXkgZm9yd2FyZFwiKVxuICAgIC5vcHRpb24oXCItLWdhdGUtcGF0aCA8cHJlZml4Li4uPlwiLCBcInBhdGggcHJlZml4ZXMgdG8gZ2F0ZSBiZXlvbmQgL2FwaS8gKGUuZy4gL3dzKVwiKVxuICAgIC5vcHRpb24oXCItLWJpbmQgPGhvc3QuLi4+XCIsIFwiaW50ZXJmYWNlIElQcyB0aGUgZ2F0ZSBsaXN0ZW5zIG9uIChkZWZhdWx0OiAwLjAuMC4wKVwiKVxuICAgIC5vcHRpb24oXCItLWZycC1zZXJ2ZXIgPGhvc3Q+XCIsIFwiZnJwcyBjb250cm9sIGhvc3QgKGRlZmF1bHQ6IEZSUCBwdWJsaWMgZG9tYWluKVwiKVxuICAgIC5vcHRpb24oXCItLWZycC1wdWJsaWMtZG9tYWluIDxob3N0PlwiLCBcIkZSUCBwdWJsaWMgSFRUUCBkb21haW5cIilcbiAgICAub3B0aW9uKFwiLS1mcnAtc2VydmVyLXBvcnQgPHBvcnQ+XCIsIFwiZnJwcyBjb250cm9sIHBvcnQgKGRlZmF1bHQ6IDQ0MylcIilcbiAgICAub3B0aW9uKFwiLS1mcnAtcHJvdG9jb2wgPHByb3RvY29sPlwiLCBcImZycGMgdHJhbnNwb3J0IHByb3RvY29sIChkZWZhdWx0OiB3c3MpXCIpXG4gICAgLm9wdGlvbihcIi0tZnJwLXRva2VuIDx0b2tlbj5cIiwgXCJmcnBzIGF1dGggdG9rZW5cIilcbiAgICAub3B0aW9uKFwiLS1mcnAtcHJveHktbmFtZSA8bmFtZT5cIiwgXCJmcnAgcHJveHkgcmVnaXN0cmF0aW9uIG5hbWVcIilcbiAgICAub3B0aW9uKFwiLS1pbnNlY3VyZVwiLCBcInJ1biBvcGVuLCB3aXRoIG5vIGdhdGVcIik7XG59XG5cbi8qKlxuICogVGllIHRoZSB3cmFwcGVyJ3MgbGlmZXRpbWUgdG8gaXRzIGNoaWxkcmVuJ3MsIGluIGJvdGggZGlyZWN0aW9uczogYSBjaGlsZCB0aGF0XG4gKiBleGl0cyB0YWtlcyB0aGUgd3JhcHBlciBkb3duIHdpdGggaXRzIGNvZGUsIGFuZCBhIHNpZ25hbCB0byB0aGUgd3JhcHBlciBpc1xuICogZm9yd2FyZGVkIGJlZm9yZSBpdCBsZWF2ZXMuIFdpdGhvdXQgdGhpcyBhIGNyYXNoZWQgYXBwIGxlYXZlcyBhIHBvcnRyIHR1bm5lbFxuICogc2VydmluZyBhIGRlYWQgcG9ydCwgd2hpY2ggbG9va3MgbGlrZSBhIGhhbmcgcmF0aGVyIHRoYW4gYSBmYWlsdXJlLlxuICovXG5mdW5jdGlvbiBzdXBlcnZpc2UoY2hpbGRyZW46IHJlYWRvbmx5IENoaWxkUHJvY2Vzc1tdKTogdm9pZCB7XG4gIGxldCBzdG9wcGluZyA9IGZhbHNlO1xuICBjb25zdCBzdG9wID0gKGNvZGU6IG51bWJlcik6IHZvaWQgPT4ge1xuICAgIGlmIChzdG9wcGluZykgcmV0dXJuO1xuICAgIHN0b3BwaW5nID0gdHJ1ZTtcbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIGNoaWxkcmVuKSBpZiAoIWNoaWxkLmtpbGxlZCkgY2hpbGQua2lsbChcIlNJR1RFUk1cIik7XG4gICAgc2V0VGltZW91dCgoKSA9PiBwcm9jZXNzLmV4aXQoY29kZSksIFNIVVRET1dOX0dSQUNFX01TKS51bnJlZigpO1xuICB9O1xuICBmb3IgKGNvbnN0IGNoaWxkIG9mIGNoaWxkcmVuKSBjaGlsZC5vbihcImV4aXRcIiwgKGNvZGUpID0+IHN0b3AoY29kZSA/PyAxKSk7XG4gIGZvciAoY29uc3Qgc2lnbmFsIG9mIFtcIlNJR1RFUk1cIiwgXCJTSUdJTlRcIiwgXCJTSUdIVVBcIl0gYXMgY29uc3QpIHtcbiAgICBwcm9jZXNzLm9uKHNpZ25hbCwgKCkgPT4gc3RvcCgwKSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcnVuKHJhdzogVHVubmVsT3B0aW9ucywgY29tbWFuZDogcmVhZG9ubHkgc3RyaW5nW10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgW2V4ZWN1dGFibGUsIC4uLmFyZ3NdID0gY29tbWFuZDtcbiAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlVHVubmVsT3B0aW9ucyhyYXcpO1xuICBjb25zdCBjaGlsZHJlbjogQ2hpbGRQcm9jZXNzW10gPSBbXTtcblxuICAvLyBUd28gdXBzdHJlYW0gbW9kZXM6XG4gIC8vICAgLSBXUkFQOiBhIGNvbW1hbmQgYWZ0ZXIgYC0tYC4gVGhlIHdyYXBwZXIgc3Bhd25zIGl0IG9uIGEgcHJpdmF0ZSBsb29wYmFja1xuICAvLyAgICAgcG9ydCBhbmQgaXMgdGhlIG9ubHkgdGhpbmcgdGhhdCB0YWxrcyB0byBpdC5cbiAgLy8gICAtIEFUVEFDSDogbm8gY29tbWFuZCwgYnV0IGAtLWFwcC1wb3J0YCBuYW1lcyBhbiBhbHJlYWR5LXJ1bm5pbmcgdXBzdHJlYW1cbiAgLy8gICAgIChlLmcuIGEgbG9jYWwgcmV2ZXJzZSBwcm94eSkuIFRoZSBnYXRlIGZyb250cyBpdCB3aXRob3V0IHNwYXduaW5nIGFcbiAgLy8gICAgIGNoaWxkLiBUaGlzIGlzIHdoYXQgbGV0cyB0aGUgZ2F0ZSBzaXQgb24gYW4gaW50ZXJmYWNlIGluIGZyb250IG9mIGFcbiAgLy8gICAgIHNlcGFyYXRlbHktc3VwZXJ2aXNlZCBzdGFjay5cbiAgbGV0IGFwcFBvcnQ6IG51bWJlcjtcbiAgaWYgKGV4ZWN1dGFibGUpIHtcbiAgICBhcHBQb3J0ID0gcmVzb2x2ZWQuYXBwUG9ydCA/PyAoYXdhaXQgZnJlZVBvcnQoKSk7XG4gICAgY29uc3QgYXBwID0gc3Bhd24oZXhlY3V0YWJsZSwgYXJncywge1xuICAgICAgZW52OiB7XG4gICAgICAgIC4uLnByb2Nlc3MuZW52LFxuICAgICAgICBEQVRBQlJJQ0tTX0FQUF9QT1JUOiBTdHJpbmcoYXBwUG9ydCksXG4gICAgICAgIFBPUlQ6IFN0cmluZyhhcHBQb3J0KSxcbiAgICAgICAgSE9TVDogXCIxMjcuMC4wLjFcIixcbiAgICAgIH0sXG4gICAgICBzdGRpbzogXCJpbmhlcml0XCIsXG4gICAgfSk7XG4gICAgY2hpbGRyZW4ucHVzaChhcHApO1xuICB9IGVsc2UgaWYgKHJlc29sdmVkLmFwcFBvcnQpIHtcbiAgICBhcHBQb3J0ID0gcmVzb2x2ZWQuYXBwUG9ydDtcbiAgICBsb2dnZXIuaW5mbyhcImF0dGFjaGluZyBnYXRlIHRvIGV4aXN0aW5nIHVwc3RyZWFtXCIsIHsgYXBwUG9ydCB9KTtcbiAgfSBlbHNlIHtcbiAgICB0aHJvdyBuZXcgQ29tbWFuZGVyRXJyb3IoXG4gICAgICAxLFxuICAgICAgXCJ0dW5uZWwubm8tdXBzdHJlYW1cIixcbiAgICAgIFwibm8gY29tbWFuZCBnaXZlbiAocGFzcyBpdCBhZnRlciBgLS1gKSBhbmQgbm8gLS1hcHAtcG9ydCB0byBhdHRhY2ggdG9cIixcbiAgICApO1xuICB9XG5cbiAgLy8gRHluYW1pYyBpbXBvcnQ6IHRoZSBnYXRlIGlzIHRoZSBvbmx5IHRoaW5nIGhlcmUgdGhhdCBuZWVkcyBBcHBLaXQgKyBTTVRQLCBzb1xuICAvLyBhbiBgLS1pbnNlY3VyZWAgcnVuIG5ldmVyIGxvYWRzIGVpdGhlci5cbiAgY29uc3QgZ2F0ZSA9IHJlc29sdmVkLmdhdGUuaW5zZWN1cmVcbiAgICA/IHVuZGVmaW5lZFxuICAgIDogYXdhaXQgKFxuICAgICAgICBhd2FpdCBpbXBvcnQoXCIuL2FwcC50c1wiKVxuICAgICAgKS5zdGFydEdhdGVBcHAoe1xuICAgICAgICAuLi5yZXNvbHZlZC5nYXRlQ29uZmlnLFxuICAgICAgICBwdWJsaWNEb21haW46IHJlc29sdmVkLmdhdGUucHVibGljRG9tYWluID8/IGBsb2NhbGhvc3Q6JHtyZXNvbHZlZC5wdWJsaWNQb3J0fWAsXG4gICAgICB9KTtcbiAgaWYgKCFnYXRlKSBsb2dnZXIud2FybihcInJ1bm5pbmcgT1BFTiAtIG5vIGdhdGUgaXMgaW4gZnJvbnQgb2YgdGhpcyB0dW5uZWxcIik7XG5cbiAgYXdhaXQgc3RhcnRQcm94eSh7XG4gICAgcHVibGljUG9ydDogcmVzb2x2ZWQucHVibGljUG9ydCxcbiAgICBhcHBQb3J0LFxuICAgIGdhdGUsXG4gICAgZm9yd2FyZEhlYWRlcnM6IHJlc29sdmVkLmdhdGUuZm9yd2FyZEhlYWRlcnMsXG4gICAgZ2F0ZVBhdGhzOiByZXNvbHZlZC5nYXRlLmdhdGVQYXRocyxcbiAgICBicmFuZE5hbWU6IHJlc29sdmVkLmdhdGUuYnJhbmROYW1lLFxuICAgIGJpbmRIb3N0czogcmVzb2x2ZWQuYmluZEhvc3RzLFxuICB9KTtcblxuICBpZiAoKHJlc29sdmVkLnRyYW5zcG9ydCA9PT0gXCJwb3J0clwiIHx8IHJlc29sdmVkLnRyYW5zcG9ydCA9PT0gXCJib3RoXCIpICYmIHJlc29sdmVkLnBvcnRyKSB7XG4gICAgY29uc3QgcG9ydHJFbnYgPSBhd2FpdCBwb3J0ci5pbnN0YWxsUG9ydHIoKTtcbiAgICBhd2FpdCBwb3J0ci53cml0ZVBvcnRyQ29uZmlnKHJlc29sdmVkLnBvcnRyLCBwb3J0ckVudik7XG4gICAgY2hpbGRyZW4ucHVzaChhd2FpdCBwb3J0ci5zdGFydFBvcnRyKHJlc29sdmVkLnBvcnRyLCBwb3J0ckVudikpO1xuICB9XG4gIGlmICgocmVzb2x2ZWQudHJhbnNwb3J0ID09PSBcImZycFwiIHx8IHJlc29sdmVkLnRyYW5zcG9ydCA9PT0gXCJib3RoXCIpICYmIHJlc29sdmVkLmZycCkge1xuICAgIGNvbnN0IGZycEVudiA9IGF3YWl0IGZycC5pbnN0YWxsRnJwKCk7XG4gICAgY29uc3QgY29uZmlnUGF0aCA9IGF3YWl0IGZycC53cml0ZUZycENvbmZpZyhyZXNvbHZlZC5mcnAsIGZycEVudik7XG4gICAgY2hpbGRyZW4ucHVzaChmcnAuc3RhcnRGcnAocmVzb2x2ZWQuZnJwLCBmcnBFbnYsIGNvbmZpZ1BhdGgpKTtcbiAgfVxuICBjb25zdCBhY3RpdmVUdW5uZWxDb3VudCA9IGNoaWxkcmVuLmxlbmd0aCAtIChleGVjdXRhYmxlID8gMSA6IDApO1xuICBpZiAoIWFjdGl2ZVR1bm5lbENvdW50KSBsb2dnZXIuaW5mbyhcIm5vIHNlbGVjdGVkIHB1YmxpYyB0dW5uZWwgaXMgY29uZmlndXJlZFwiLCB7XG4gICAgdHJhbnNwb3J0OiByZXNvbHZlZC50cmFuc3BvcnQsXG4gICAgcHVibGljUG9ydDogcmVzb2x2ZWQucHVibGljUG9ydCxcbiAgfSk7XG4gIHN1cGVydmlzZShjaGlsZHJlbik7XG59XG5cbi8qKiBUaGUgYGRieCB0dW5uZWxgIHByb2dyYW0uIE5vIHNpZGUgZWZmZWN0cyB1bnRpbCBwYXJzZWQuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRQcm9ncmFtKG5hbWUgPSBcImRieCB0dW5uZWxcIik6IENvbW1hbmQge1xuICBjb25zdCBwcm9ncmFtID0gYWRkT3B0aW9ucyhcbiAgICBuZXcgQ29tbWFuZCgpXG4gICAgICAubmFtZShuYW1lKVxuICAgICAgLmRlc2NyaXB0aW9uKFwiRnJvbnQgYSBjb21tYW5kIHdpdGggYSBwdWJsaWMgdHVubmVsIGFuZCBwYXNzd29yZGxlc3MgYXV0aFwiKSxcbiAgKTtcblxuICAvLyBgcnVuYCBpcyB0aGUgREVGQVVMVCBhY3Rpb24gYXMgd2VsbCBhcyBhIG5hbWVkIHN1YmNvbW1hbmQsIHByZXNlcnZpbmcgdGhlIG9sZFxuICAvLyB3cmFwcGVyJ3MgZXJnb25vbWljcyAoYGRieCB0dW5uZWwgLS1hbGxvdyB4IC0tIGJ1biBzcmMvc2VydmVyLnRzYCkgd2hpbGVcbiAgLy8gbGVhdmluZyBzb21ld2hlcmUgZm9yIGBzdGF0dXNgIGFuZCBgaW5zdGFsbGAgdG8gbGl2ZS5cbiAgcHJvZ3JhbVxuICAgIC5hcmd1bWVudChcIltjb21tYW5kLi4uXVwiLCBcInRoZSBjb21tYW5kIHRvIHdyYXAsIGFmdGVyIGAtLWBcIilcbiAgICAuYWN0aW9uKGFzeW5jIChjb21tYW5kOiBzdHJpbmdbXSwgX29wdGlvbnM6IFR1bm5lbE9wdGlvbnMsIGNtZDogQ29tbWFuZCkgPT4ge1xuICAgICAgYXdhaXQgcnVuKGNtZC5vcHRzPFR1bm5lbE9wdGlvbnM+KCksIGNvbW1hbmQpO1xuICAgIH0pO1xuXG4gIGFkZE9wdGlvbnMocHJvZ3JhbS5jb21tYW5kKFwicnVuXCIpLmRlc2NyaXB0aW9uKFwiV3JhcCBhIGNvbW1hbmQgKHRoZSBkZWZhdWx0IGFjdGlvbilcIikpXG4gICAgLmFyZ3VtZW50KFwiPGNvbW1hbmQuLi4+XCIsIFwidGhlIGNvbW1hbmQgdG8gd3JhcCwgYWZ0ZXIgYC0tYFwiKVxuICAgIC5hY3Rpb24oYXN5bmMgKGNvbW1hbmQ6IHN0cmluZ1tdLCBfb3B0aW9uczogVHVubmVsT3B0aW9ucywgY21kOiBDb21tYW5kKSA9PiB7XG4gICAgICBhd2FpdCBydW4oY21kLm9wdHM8VHVubmVsT3B0aW9ucz4oKSwgY29tbWFuZCk7XG4gICAgfSk7XG5cbiAgLy8gV29ydGggaXRzIG93biBjb21tYW5kOiB0aGUgbW9zdCBjb21tb24gZmFpbHVyZSBpcyBhIHR1bm5lbCB0aGF0IHNpbGVudGx5XG4gIC8vIGRvZXMgbm90aGluZyBiZWNhdXNlIG5vIHRva2VuIG9yIGRvbWFpbiByZXNvbHZlZCwgYW5kIHRoaXMgcHJpbnRzIGV4YWN0bHlcbiAgLy8gd2hhdCB3b3VsZCBoYXBwZW4gd2l0aG91dCBzdGFydGluZyBhbnl0aGluZy5cbiAgYWRkT3B0aW9ucyhcbiAgICBwcm9ncmFtLmNvbW1hbmQoXCJzdGF0dXNcIikuZGVzY3JpcHRpb24oXCJSZXNvbHZlIHRoZSBjb25maWd1cmF0aW9uIGFuZCBwcmludCBpdFwiKSxcbiAgKS5hY3Rpb24oKF9vcHRpb25zOiBUdW5uZWxPcHRpb25zLCBjbWQ6IENvbW1hbmQpID0+IHtcbiAgICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVUdW5uZWxPcHRpb25zKGNtZC5vcHRzPFR1bm5lbE9wdGlvbnM+KCkpO1xuICAgIHByb2Nlc3Muc3Rkb3V0LndyaXRlKGAke0pTT04uc3RyaW5naWZ5KHJlc29sdmVkLCBudWxsLCAyKX1cXG5gKTtcbiAgfSk7XG5cbiAgcHJvZ3JhbVxuICAgIC5jb21tYW5kKFwiaW5zdGFsbFwiKVxuICAgIC5hcmd1bWVudChcIlt0cmFuc3BvcnRdXCIsIFwicG9ydHIsIGZycCwgb3IgYm90aFwiLCBcInBvcnRyXCIpXG4gICAgLmRlc2NyaXB0aW9uKFwiSW5zdGFsbCBwdWJsaWMgdHVubmVsIGNsaWVudCBiaW5hcmllcyBhbmQgZXhpdFwiKVxuICAgIC5hY3Rpb24oYXN5bmMgKHRyYW5zcG9ydDogc3RyaW5nKSA9PiB7XG4gICAgICBpZiAodHJhbnNwb3J0ID09PSBcInBvcnRyXCIgfHwgdHJhbnNwb3J0ID09PSBcImJvdGhcIikgYXdhaXQgcG9ydHIuaW5zdGFsbFBvcnRyKCk7XG4gICAgICBpZiAodHJhbnNwb3J0ID09PSBcImZycFwiIHx8IHRyYW5zcG9ydCA9PT0gXCJib3RoXCIpIGF3YWl0IGZycC5pbnN0YWxsRnJwKCk7XG4gICAgICBpZiAodHJhbnNwb3J0ICE9PSBcInBvcnRyXCIgJiYgdHJhbnNwb3J0ICE9PSBcImZycFwiICYmIHRyYW5zcG9ydCAhPT0gXCJib3RoXCIpIHtcbiAgICAgICAgdGhyb3cgbmV3IENvbW1hbmRlckVycm9yKDEsIFwidHVubmVsLmludmFsaWQtdHJhbnNwb3J0XCIsIGBpbnZhbGlkIHRyYW5zcG9ydDogJHt0cmFuc3BvcnR9YCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgcmV0dXJuIHByb2dyYW07XG59XG4iXX0=
@@ -12,9 +12,10 @@
12
12
  * @module
13
13
  */
14
14
  import type { AuthStorageMode } from "@dbx-tools/auth";
15
- import { type AuthGateConfig, plugin, portr } from "@dbx-tools/tunnel";
15
+ import { type AuthGateConfig, frp, interceptor, plugin, portr } from "@dbx-tools/tunnel";
16
16
  /** Raw commander flag values (every numeric flag arrives as a string). */
17
17
  export interface TunnelOptions {
18
+ transport?: interceptor.TunnelTransport;
18
19
  publicDomain?: string;
19
20
  subdomain?: string;
20
21
  port?: string | number;
@@ -32,6 +33,12 @@ export interface TunnelOptions {
32
33
  gatePath?: string[];
33
34
  bind?: string[];
34
35
  insecure?: boolean;
36
+ frpServer?: string;
37
+ frpPublicDomain?: string;
38
+ frpServerPort?: string | number;
39
+ frpProtocol?: string;
40
+ frpToken?: string;
41
+ frpProxyName?: string;
35
42
  }
36
43
  export interface ResolvedTunnelOptions {
37
44
  /** The port the wrapper itself listens on - what portr forwards to. */
@@ -40,6 +47,7 @@ export interface ResolvedTunnelOptions {
40
47
  appPort?: number;
41
48
  /** Interface IPs the gate listens on. Empty means the default (0.0.0.0). */
42
49
  bindHosts: string[];
50
+ transport: interceptor.TunnelTransport;
43
51
  /**
44
52
  * The gate config as the `authGate` PLUGIN takes it - flags only, nothing
45
53
  * resolved. Passed straight to the plugin so it applies its own fallbacks
@@ -49,5 +57,6 @@ export interface ResolvedTunnelOptions {
49
57
  /** The same config after the plugin's resolution, for `status` and for routing. */
50
58
  gate: plugin.ResolvedAuthGateConfig;
51
59
  portr: ReturnType<typeof portr.resolvePortrConfig>;
60
+ frp: ReturnType<typeof frp.resolveFrpConfig>;
52
61
  }
53
62
  export declare function resolveTunnelOptions(options: TunnelOptions): ResolvedTunnelOptions;
@@ -13,7 +13,7 @@
13
13
  */
14
14
  import { config } from "@dbx-tools/core";
15
15
  import { object } from "@dbx-tools/shared-core";
16
- import { plugin, portr } from "@dbx-tools/tunnel";
16
+ import { frp, interceptor, plugin, portr } from "@dbx-tools/tunnel";
17
17
  export function resolveTunnelOptions(options) {
18
18
  // The Databricks Apps runtime contract: the platform routes to
19
19
  // DATABRICKS_APP_PORT, so the WRAPPER claims it and the wrapped app is moved
@@ -37,12 +37,15 @@ export function resolveTunnelOptions(options) {
37
37
  gatePaths: options.gatePath,
38
38
  insecure: options.insecure,
39
39
  publicDomain: options.publicDomain,
40
+ publicDomains: options.frpPublicDomain ? [options.frpPublicDomain] : undefined,
40
41
  };
41
42
  const gate = plugin.resolveAuthGateConfig(gateConfig);
43
+ const transport = interceptor.resolveTunnelTransport(options.transport);
42
44
  return {
43
45
  publicPort,
44
46
  ...(appPort > 0 ? { appPort } : {}),
45
47
  bindHosts: options.bind ?? [],
48
+ transport,
46
49
  gateConfig,
47
50
  gate,
48
51
  portr: portr.resolvePortrConfig({
@@ -50,6 +53,15 @@ export function resolveTunnelOptions(options) {
50
53
  subdomain: options.subdomain,
51
54
  port: publicPort,
52
55
  }),
56
+ frp: frp.resolveFrpConfig({
57
+ publicDomain: options.frpPublicDomain,
58
+ server: options.frpServer,
59
+ serverPort: options.frpServerPort,
60
+ protocol: options.frpProtocol,
61
+ token: options.frpToken,
62
+ proxyName: options.frpProxyName,
63
+ port: publicPort,
64
+ }),
53
65
  };
54
66
  }
55
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vcHRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7R0FZRztBQUdILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEQsT0FBTyxFQUF1QixNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUF5Q3ZFLE1BQU0sVUFBVSxvQkFBb0IsQ0FBQyxPQUFzQjtJQUN6RCwrREFBK0Q7SUFDL0QsNkVBQTZFO0lBQzdFLG9CQUFvQjtJQUNwQixNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUscUJBQXFCLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDMUUsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLFVBQVUsRUFBRSxDQUFDLEVBQUUsRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUNsRixNQUFNLFVBQVUsR0FBbUI7UUFDakMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1FBQ3BCLE9BQU8sRUFBRSxPQUFPLENBQUMsT0FBTztRQUN4QixTQUFTLEVBQUUsT0FBTyxDQUFDLFNBQVM7UUFDNUIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQ3hCLDBFQUEwRTtRQUMxRSw0RUFBNEU7UUFDNUUsa0RBQWtEO1FBQ2xELGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztRQUN0RCxjQUFjLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO1FBQ2hELGFBQWEsRUFBRSxPQUFPLENBQUMsYUFBYTtRQUNwQyxPQUFPLEVBQUUsT0FBTyxDQUFDLFdBQVc7UUFDNUIsVUFBVSxFQUFFLE9BQU8sQ0FBQyxjQUFjO1FBQ2xDLGNBQWMsRUFBRSxPQUFPLENBQUMsY0FBYztRQUN0QyxTQUFTLEVBQUUsT0FBTyxDQUFDLFFBQVE7UUFDM0IsUUFBUSxFQUFFLE9BQU8sQ0FBQyxRQUFRO1FBQzFCLFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtLQUNuQyxDQUFDO0lBQ0YsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3RELE9BQU87UUFDTCxVQUFVO1FBQ1YsR0FBRyxDQUFDLE9BQU8sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNuQyxTQUFTLEVBQUUsT0FBTyxDQUFDLElBQUksSUFBSSxFQUFFO1FBQzdCLFVBQVU7UUFDVixJQUFJO1FBQ0osS0FBSyxFQUFFLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztZQUM5QixZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVk7WUFDL0IsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO1lBQzVCLElBQUksRUFBRSxVQUFVO1NBQ2pCLENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmxhZyAtPiBjb25maWcgLT4gZGVmYXVsdCByZXNvbHV0aW9uIGZvciBgZGJ4IHR1bm5lbGAuXG4gKlxuICogVGhlIHBvaW50IG9mIHRoaXMgbW9kdWxlIGlzIHRoYXQgaXQgZG9lcyBhbG1vc3QgTk9USElORyBpdHNlbGY6IGV2ZXJ5IGdhdGVcbiAqIHNldHRpbmcgaXMgaGFuZGVkIHN0cmFpZ2h0IHRvIGBAZGJ4LXRvb2xzL3R1bm5lbGAncyBvd25cbiAqIGBwbHVnaW4ucmVzb2x2ZUF1dGhHYXRlQ29uZmlnYCwgd2hpY2ggaXMgdGhlIHNhbWUgZnVuY3Rpb24gdGhlIGluLXByb2Nlc3NcbiAqIHBsdWdpbiBwYXRoIGNhbGxzLiBUaGUgQ0xJIHRoZXJlZm9yZSBjYW5ub3QgZHJpZnQgZnJvbSB0aGUgcGx1Z2luIG9uIGEgZGVmYXVsdCxcbiAqIGFuIGVudiBuYW1lLCBvciBhIGNvZXJjaW9uIHJ1bGUgLSBhIGZsYWcgaXMganVzdCBhIHZhbHVlIHBhc3NlZCB3aGVyZSB0aGVcbiAqIHBsdWdpbidzIGBjb25maWdgIG9iamVjdCB3b3VsZCBnbywgYW5kIGBjb25maWcuKmAgZmlsbHMgdGhlIHJlc3QgaW4gZnJvbSB0aGVcbiAqIGVudmlyb25tZW50LCBhIGAuZW52YCBmaWxlLCBvciBgZGF0YWJyaWNrcy55bWxgLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IEF1dGhTdG9yYWdlTW9kZSB9IGZyb20gXCJAZGJ4LXRvb2xzL2F1dGhcIjtcbmltcG9ydCB7IGNvbmZpZyB9IGZyb20gXCJAZGJ4LXRvb2xzL2NvcmVcIjtcbmltcG9ydCB7IG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyB0eXBlIEF1dGhHYXRlQ29uZmlnLCBwbHVnaW4sIHBvcnRyIH0gZnJvbSBcIkBkYngtdG9vbHMvdHVubmVsXCI7XG5cbi8qKiBSYXcgY29tbWFuZGVyIGZsYWcgdmFsdWVzIChldmVyeSBudW1lcmljIGZsYWcgYXJyaXZlcyBhcyBhIHN0cmluZykuICovXG5leHBvcnQgaW50ZXJmYWNlIFR1bm5lbE9wdGlvbnMge1xuICBwdWJsaWNEb21haW4/OiBzdHJpbmc7XG4gIHN1YmRvbWFpbj86IHN0cmluZztcbiAgcG9ydD86IHN0cmluZyB8IG51bWJlcjtcbiAgYXBwUG9ydD86IHN0cmluZyB8IG51bWJlcjtcbiAgYWxsb3c/OiBzdHJpbmdbXTtcbiAgc3ViamVjdD86IHN0cmluZztcbiAgYnJhbmROYW1lPzogc3RyaW5nO1xuICBtZXNzYWdlPzogc3RyaW5nO1xuICBzZXNzaW9uVHRsPzogc3RyaW5nIHwgbnVtYmVyO1xuICBjb2RlVHRsPzogc3RyaW5nIHwgbnVtYmVyO1xuICBzZXNzaW9uQ3V0b2ZmPzogc3RyaW5nO1xuICBhdXRoU3RvcmFnZT86IEF1dGhTdG9yYWdlTW9kZTtcbiAgYXV0aFNxbGl0ZVBhdGg/OiBzdHJpbmc7XG4gIGZvcndhcmRIZWFkZXJzPzogc3RyaW5nW107XG4gIGdhdGVQYXRoPzogc3RyaW5nW107XG4gIGJpbmQ/OiBzdHJpbmdbXTtcbiAgaW5zZWN1cmU/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlc29sdmVkVHVubmVsT3B0aW9ucyB7XG4gIC8qKiBUaGUgcG9ydCB0aGUgd3JhcHBlciBpdHNlbGYgbGlzdGVucyBvbiAtIHdoYXQgcG9ydHIgZm9yd2FyZHMgdG8uICovXG4gIHB1YmxpY1BvcnQ6IG51bWJlcjtcbiAgLyoqIFRoZSBwcml2YXRlIHBvcnQgdGhlIHdyYXBwZWQgYXBwIGlzIHRvbGQgdG8gYmluZC4gVW5zZXQgbWVhbnMgXCJwaWNrIG9uZVwiLiAqL1xuICBhcHBQb3J0PzogbnVtYmVyO1xuICAvKiogSW50ZXJmYWNlIElQcyB0aGUgZ2F0ZSBsaXN0ZW5zIG9uLiBFbXB0eSBtZWFucyB0aGUgZGVmYXVsdCAoMC4wLjAuMCkuICovXG4gIGJpbmRIb3N0czogc3RyaW5nW107XG4gIC8qKlxuICAgKiBUaGUgZ2F0ZSBjb25maWcgYXMgdGhlIGBhdXRoR2F0ZWAgUExVR0lOIHRha2VzIGl0IC0gZmxhZ3Mgb25seSwgbm90aGluZ1xuICAgKiByZXNvbHZlZC4gUGFzc2VkIHN0cmFpZ2h0IHRvIHRoZSBwbHVnaW4gc28gaXQgYXBwbGllcyBpdHMgb3duIGZhbGxiYWNrc1xuICAgKiBleGFjdGx5IG9uY2UsIGluIHRoZSBvbmUgcGxhY2UgdGhhdCBvd25zIHRoZW0uXG4gICAqL1xuICBnYXRlQ29uZmlnOiBBdXRoR2F0ZUNvbmZpZztcbiAgLyoqIFRoZSBzYW1lIGNvbmZpZyBhZnRlciB0aGUgcGx1Z2luJ3MgcmVzb2x1dGlvbiwgZm9yIGBzdGF0dXNgIGFuZCBmb3Igcm91dGluZy4gKi9cbiAgZ2F0ZTogcGx1Z2luLlJlc29sdmVkQXV0aEdhdGVDb25maWc7XG4gIHBvcnRyOiBSZXR1cm5UeXBlPHR5cGVvZiBwb3J0ci5yZXNvbHZlUG9ydHJDb25maWc+O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVR1bm5lbE9wdGlvbnMob3B0aW9uczogVHVubmVsT3B0aW9ucyk6IFJlc29sdmVkVHVubmVsT3B0aW9ucyB7XG4gIC8vIFRoZSBEYXRhYnJpY2tzIEFwcHMgcnVudGltZSBjb250cmFjdDogdGhlIHBsYXRmb3JtIHJvdXRlcyB0b1xuICAvLyBEQVRBQlJJQ0tTX0FQUF9QT1JULCBzbyB0aGUgV1JBUFBFUiBjbGFpbXMgaXQgYW5kIHRoZSB3cmFwcGVkIGFwcCBpcyBtb3ZlZFxuICAvLyB0byBhIHByaXZhdGUgb25lLlxuICBjb25zdCBwdWJsaWNQb3J0ID0gY29uZmlnLnBvcnQob3B0aW9ucy5wb3J0LCBcIkRBVEFCUklDS1NfQVBQX1BPUlRcIiwgODAwMCk7XG4gIGNvbnN0IGFwcFBvcnQgPSBjb25maWcucG9ydChvcHRpb25zLmFwcFBvcnQsIFwiQVBQX1BPUlRcIiwgMCwgeyBwcmVmaXg6IFwiVFVOTkVMXCIgfSk7XG4gIGNvbnN0IGdhdGVDb25maWc6IEF1dGhHYXRlQ29uZmlnID0ge1xuICAgIGFsbG93OiBvcHRpb25zLmFsbG93LFxuICAgIHN1YmplY3Q6IG9wdGlvbnMuc3ViamVjdCxcbiAgICBicmFuZE5hbWU6IG9wdGlvbnMuYnJhbmROYW1lLFxuICAgIG1lc3NhZ2U6IG9wdGlvbnMubWVzc2FnZSxcbiAgICAvLyBDb2VyY2VkLCBub3QgcmVzb2x2ZWQ6IHRoZSBwbHVnaW4gb3ducyB0aGUgZW52IG5hbWUgYW5kIHRoZSBkZWZhdWx0IGZvclxuICAgIC8vIHRoZXNlLCBzbyB0aGUgZmxhZyBpcyBwYXNzZWQgdGhyb3VnaCBhcyB0aGUgYGNvbmZpZ2AgdmFsdWUgaXQgZXhwZWN0cyBhbmRcbiAgICAvLyBvbmx5IG5lZWRzIGEgc3RyaW5nIC0+IG51bWJlciBudWRnZSBvbiB0aGUgd2F5LlxuICAgIHNlc3Npb25UdGxTZWNvbmRzOiBvYmplY3QudG9OdW1iZXIob3B0aW9ucy5zZXNzaW9uVHRsKSxcbiAgICBjb2RlVHRsU2Vjb25kczogb2JqZWN0LnRvTnVtYmVyKG9wdGlvbnMuY29kZVR0bCksXG4gICAgc2Vzc2lvbkN1dG9mZjogb3B0aW9ucy5zZXNzaW9uQ3V0b2ZmLFxuICAgIHN0b3JhZ2U6IG9wdGlvbnMuYXV0aFN0b3JhZ2UsXG4gICAgc3FsaXRlUGF0aDogb3B0aW9ucy5hdXRoU3FsaXRlUGF0aCxcbiAgICBmb3J3YXJkSGVhZGVyczogb3B0aW9ucy5mb3J3YXJkSGVhZGVycyxcbiAgICBnYXRlUGF0aHM6IG9wdGlvbnMuZ2F0ZVBhdGgsXG4gICAgaW5zZWN1cmU6IG9wdGlvbnMuaW5zZWN1cmUsXG4gICAgcHVibGljRG9tYWluOiBvcHRpb25zLnB1YmxpY0RvbWFpbixcbiAgfTtcbiAgY29uc3QgZ2F0ZSA9IHBsdWdpbi5yZXNvbHZlQXV0aEdhdGVDb25maWcoZ2F0ZUNvbmZpZyk7XG4gIHJldHVybiB7XG4gICAgcHVibGljUG9ydCxcbiAgICAuLi4oYXBwUG9ydCA+IDAgPyB7IGFwcFBvcnQgfSA6IHt9KSxcbiAgICBiaW5kSG9zdHM6IG9wdGlvbnMuYmluZCA/PyBbXSxcbiAgICBnYXRlQ29uZmlnLFxuICAgIGdhdGUsXG4gICAgcG9ydHI6IHBvcnRyLnJlc29sdmVQb3J0ckNvbmZpZyh7XG4gICAgICBwdWJsaWNEb21haW46IGdhdGUucHVibGljRG9tYWluLFxuICAgICAgc3ViZG9tYWluOiBvcHRpb25zLnN1YmRvbWFpbixcbiAgICAgIHBvcnQ6IHB1YmxpY1BvcnQsXG4gICAgfSksXG4gIH07XG59XG4iXX0=
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3B0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vcHRpb25zLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7R0FZRztBQUdILE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QyxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEQsT0FBTyxFQUF1QixHQUFHLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQWtEekYsTUFBTSxVQUFVLG9CQUFvQixDQUFDLE9BQXNCO0lBQ3pELCtEQUErRDtJQUMvRCw2RUFBNkU7SUFDN0Usb0JBQW9CO0lBQ3BCLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxxQkFBcUIsRUFBRSxJQUFJLENBQUMsQ0FBQztJQUMxRSxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUMsRUFBRSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2xGLE1BQU0sVUFBVSxHQUFtQjtRQUNqQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7UUFDcEIsT0FBTyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQ3hCLFNBQVMsRUFBRSxPQUFPLENBQUMsU0FBUztRQUM1QixPQUFPLEVBQUUsT0FBTyxDQUFDLE9BQU87UUFDeEIsMEVBQTBFO1FBQzFFLDRFQUE0RTtRQUM1RSxrREFBa0Q7UUFDbEQsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDO1FBQ3RELGNBQWMsRUFBRSxNQUFNLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFDaEQsYUFBYSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1FBQ3BDLE9BQU8sRUFBRSxPQUFPLENBQUMsV0FBVztRQUM1QixVQUFVLEVBQUUsT0FBTyxDQUFDLGNBQWM7UUFDbEMsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjO1FBQ3RDLFNBQVMsRUFBRSxPQUFPLENBQUMsUUFBUTtRQUMzQixRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7UUFDMUIsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1FBQ2xDLGFBQWEsRUFBRSxPQUFPLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUztLQUMvRSxDQUFDO0lBQ0YsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQ3RELE1BQU0sU0FBUyxHQUFHLFdBQVcsQ0FBQyxzQkFBc0IsQ0FBQyxPQUFPLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDeEUsT0FBTztRQUNMLFVBQVU7UUFDVixHQUFHLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ25DLFNBQVMsRUFBRSxPQUFPLENBQUMsSUFBSSxJQUFJLEVBQUU7UUFDN0IsU0FBUztRQUNULFVBQVU7UUFDVixJQUFJO1FBQ0osS0FBSyxFQUFFLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQztZQUM5QixZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVk7WUFDL0IsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTO1lBQzVCLElBQUksRUFBRSxVQUFVO1NBQ2pCLENBQUM7UUFDRixHQUFHLEVBQUUsR0FBRyxDQUFDLGdCQUFnQixDQUFDO1lBQ3hCLFlBQVksRUFBRSxPQUFPLENBQUMsZUFBZTtZQUNyQyxNQUFNLEVBQUUsT0FBTyxDQUFDLFNBQVM7WUFDekIsVUFBVSxFQUFFLE9BQU8sQ0FBQyxhQUFhO1lBQ2pDLFFBQVEsRUFBRSxPQUFPLENBQUMsV0FBVztZQUM3QixLQUFLLEVBQUUsT0FBTyxDQUFDLFFBQVE7WUFDdkIsU0FBUyxFQUFFLE9BQU8sQ0FBQyxZQUFZO1lBQy9CLElBQUksRUFBRSxVQUFVO1NBQ2pCLENBQUM7S0FDSCxDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmxhZyAtPiBjb25maWcgLT4gZGVmYXVsdCByZXNvbHV0aW9uIGZvciBgZGJ4IHR1bm5lbGAuXG4gKlxuICogVGhlIHBvaW50IG9mIHRoaXMgbW9kdWxlIGlzIHRoYXQgaXQgZG9lcyBhbG1vc3QgTk9USElORyBpdHNlbGY6IGV2ZXJ5IGdhdGVcbiAqIHNldHRpbmcgaXMgaGFuZGVkIHN0cmFpZ2h0IHRvIGBAZGJ4LXRvb2xzL3R1bm5lbGAncyBvd25cbiAqIGBwbHVnaW4ucmVzb2x2ZUF1dGhHYXRlQ29uZmlnYCwgd2hpY2ggaXMgdGhlIHNhbWUgZnVuY3Rpb24gdGhlIGluLXByb2Nlc3NcbiAqIHBsdWdpbiBwYXRoIGNhbGxzLiBUaGUgQ0xJIHRoZXJlZm9yZSBjYW5ub3QgZHJpZnQgZnJvbSB0aGUgcGx1Z2luIG9uIGEgZGVmYXVsdCxcbiAqIGFuIGVudiBuYW1lLCBvciBhIGNvZXJjaW9uIHJ1bGUgLSBhIGZsYWcgaXMganVzdCBhIHZhbHVlIHBhc3NlZCB3aGVyZSB0aGVcbiAqIHBsdWdpbidzIGBjb25maWdgIG9iamVjdCB3b3VsZCBnbywgYW5kIGBjb25maWcuKmAgZmlsbHMgdGhlIHJlc3QgaW4gZnJvbSB0aGVcbiAqIGVudmlyb25tZW50LCBhIGAuZW52YCBmaWxlLCBvciBgZGF0YWJyaWNrcy55bWxgLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgdHlwZSB7IEF1dGhTdG9yYWdlTW9kZSB9IGZyb20gXCJAZGJ4LXRvb2xzL2F1dGhcIjtcbmltcG9ydCB7IGNvbmZpZyB9IGZyb20gXCJAZGJ4LXRvb2xzL2NvcmVcIjtcbmltcG9ydCB7IG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyB0eXBlIEF1dGhHYXRlQ29uZmlnLCBmcnAsIGludGVyY2VwdG9yLCBwbHVnaW4sIHBvcnRyIH0gZnJvbSBcIkBkYngtdG9vbHMvdHVubmVsXCI7XG5cbi8qKiBSYXcgY29tbWFuZGVyIGZsYWcgdmFsdWVzIChldmVyeSBudW1lcmljIGZsYWcgYXJyaXZlcyBhcyBhIHN0cmluZykuICovXG5leHBvcnQgaW50ZXJmYWNlIFR1bm5lbE9wdGlvbnMge1xuICB0cmFuc3BvcnQ/OiBpbnRlcmNlcHRvci5UdW5uZWxUcmFuc3BvcnQ7XG4gIHB1YmxpY0RvbWFpbj86IHN0cmluZztcbiAgc3ViZG9tYWluPzogc3RyaW5nO1xuICBwb3J0Pzogc3RyaW5nIHwgbnVtYmVyO1xuICBhcHBQb3J0Pzogc3RyaW5nIHwgbnVtYmVyO1xuICBhbGxvdz86IHN0cmluZ1tdO1xuICBzdWJqZWN0Pzogc3RyaW5nO1xuICBicmFuZE5hbWU/OiBzdHJpbmc7XG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG4gIHNlc3Npb25UdGw/OiBzdHJpbmcgfCBudW1iZXI7XG4gIGNvZGVUdGw/OiBzdHJpbmcgfCBudW1iZXI7XG4gIHNlc3Npb25DdXRvZmY/OiBzdHJpbmc7XG4gIGF1dGhTdG9yYWdlPzogQXV0aFN0b3JhZ2VNb2RlO1xuICBhdXRoU3FsaXRlUGF0aD86IHN0cmluZztcbiAgZm9yd2FyZEhlYWRlcnM/OiBzdHJpbmdbXTtcbiAgZ2F0ZVBhdGg/OiBzdHJpbmdbXTtcbiAgYmluZD86IHN0cmluZ1tdO1xuICBpbnNlY3VyZT86IGJvb2xlYW47XG4gIGZycFNlcnZlcj86IHN0cmluZztcbiAgZnJwUHVibGljRG9tYWluPzogc3RyaW5nO1xuICBmcnBTZXJ2ZXJQb3J0Pzogc3RyaW5nIHwgbnVtYmVyO1xuICBmcnBQcm90b2NvbD86IHN0cmluZztcbiAgZnJwVG9rZW4/OiBzdHJpbmc7XG4gIGZycFByb3h5TmFtZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXNvbHZlZFR1bm5lbE9wdGlvbnMge1xuICAvKiogVGhlIHBvcnQgdGhlIHdyYXBwZXIgaXRzZWxmIGxpc3RlbnMgb24gLSB3aGF0IHBvcnRyIGZvcndhcmRzIHRvLiAqL1xuICBwdWJsaWNQb3J0OiBudW1iZXI7XG4gIC8qKiBUaGUgcHJpdmF0ZSBwb3J0IHRoZSB3cmFwcGVkIGFwcCBpcyB0b2xkIHRvIGJpbmQuIFVuc2V0IG1lYW5zIFwicGljayBvbmVcIi4gKi9cbiAgYXBwUG9ydD86IG51bWJlcjtcbiAgLyoqIEludGVyZmFjZSBJUHMgdGhlIGdhdGUgbGlzdGVucyBvbi4gRW1wdHkgbWVhbnMgdGhlIGRlZmF1bHQgKDAuMC4wLjApLiAqL1xuICBiaW5kSG9zdHM6IHN0cmluZ1tdO1xuICB0cmFuc3BvcnQ6IGludGVyY2VwdG9yLlR1bm5lbFRyYW5zcG9ydDtcbiAgLyoqXG4gICAqIFRoZSBnYXRlIGNvbmZpZyBhcyB0aGUgYGF1dGhHYXRlYCBQTFVHSU4gdGFrZXMgaXQgLSBmbGFncyBvbmx5LCBub3RoaW5nXG4gICAqIHJlc29sdmVkLiBQYXNzZWQgc3RyYWlnaHQgdG8gdGhlIHBsdWdpbiBzbyBpdCBhcHBsaWVzIGl0cyBvd24gZmFsbGJhY2tzXG4gICAqIGV4YWN0bHkgb25jZSwgaW4gdGhlIG9uZSBwbGFjZSB0aGF0IG93bnMgdGhlbS5cbiAgICovXG4gIGdhdGVDb25maWc6IEF1dGhHYXRlQ29uZmlnO1xuICAvKiogVGhlIHNhbWUgY29uZmlnIGFmdGVyIHRoZSBwbHVnaW4ncyByZXNvbHV0aW9uLCBmb3IgYHN0YXR1c2AgYW5kIGZvciByb3V0aW5nLiAqL1xuICBnYXRlOiBwbHVnaW4uUmVzb2x2ZWRBdXRoR2F0ZUNvbmZpZztcbiAgcG9ydHI6IFJldHVyblR5cGU8dHlwZW9mIHBvcnRyLnJlc29sdmVQb3J0ckNvbmZpZz47XG4gIGZycDogUmV0dXJuVHlwZTx0eXBlb2YgZnJwLnJlc29sdmVGcnBDb25maWc+O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzb2x2ZVR1bm5lbE9wdGlvbnMob3B0aW9uczogVHVubmVsT3B0aW9ucyk6IFJlc29sdmVkVHVubmVsT3B0aW9ucyB7XG4gIC8vIFRoZSBEYXRhYnJpY2tzIEFwcHMgcnVudGltZSBjb250cmFjdDogdGhlIHBsYXRmb3JtIHJvdXRlcyB0b1xuICAvLyBEQVRBQlJJQ0tTX0FQUF9QT1JULCBzbyB0aGUgV1JBUFBFUiBjbGFpbXMgaXQgYW5kIHRoZSB3cmFwcGVkIGFwcCBpcyBtb3ZlZFxuICAvLyB0byBhIHByaXZhdGUgb25lLlxuICBjb25zdCBwdWJsaWNQb3J0ID0gY29uZmlnLnBvcnQob3B0aW9ucy5wb3J0LCBcIkRBVEFCUklDS1NfQVBQX1BPUlRcIiwgODAwMCk7XG4gIGNvbnN0IGFwcFBvcnQgPSBjb25maWcucG9ydChvcHRpb25zLmFwcFBvcnQsIFwiQVBQX1BPUlRcIiwgMCwgeyBwcmVmaXg6IFwiVFVOTkVMXCIgfSk7XG4gIGNvbnN0IGdhdGVDb25maWc6IEF1dGhHYXRlQ29uZmlnID0ge1xuICAgIGFsbG93OiBvcHRpb25zLmFsbG93LFxuICAgIHN1YmplY3Q6IG9wdGlvbnMuc3ViamVjdCxcbiAgICBicmFuZE5hbWU6IG9wdGlvbnMuYnJhbmROYW1lLFxuICAgIG1lc3NhZ2U6IG9wdGlvbnMubWVzc2FnZSxcbiAgICAvLyBDb2VyY2VkLCBub3QgcmVzb2x2ZWQ6IHRoZSBwbHVnaW4gb3ducyB0aGUgZW52IG5hbWUgYW5kIHRoZSBkZWZhdWx0IGZvclxuICAgIC8vIHRoZXNlLCBzbyB0aGUgZmxhZyBpcyBwYXNzZWQgdGhyb3VnaCBhcyB0aGUgYGNvbmZpZ2AgdmFsdWUgaXQgZXhwZWN0cyBhbmRcbiAgICAvLyBvbmx5IG5lZWRzIGEgc3RyaW5nIC0+IG51bWJlciBudWRnZSBvbiB0aGUgd2F5LlxuICAgIHNlc3Npb25UdGxTZWNvbmRzOiBvYmplY3QudG9OdW1iZXIob3B0aW9ucy5zZXNzaW9uVHRsKSxcbiAgICBjb2RlVHRsU2Vjb25kczogb2JqZWN0LnRvTnVtYmVyKG9wdGlvbnMuY29kZVR0bCksXG4gICAgc2Vzc2lvbkN1dG9mZjogb3B0aW9ucy5zZXNzaW9uQ3V0b2ZmLFxuICAgIHN0b3JhZ2U6IG9wdGlvbnMuYXV0aFN0b3JhZ2UsXG4gICAgc3FsaXRlUGF0aDogb3B0aW9ucy5hdXRoU3FsaXRlUGF0aCxcbiAgICBmb3J3YXJkSGVhZGVyczogb3B0aW9ucy5mb3J3YXJkSGVhZGVycyxcbiAgICBnYXRlUGF0aHM6IG9wdGlvbnMuZ2F0ZVBhdGgsXG4gICAgaW5zZWN1cmU6IG9wdGlvbnMuaW5zZWN1cmUsXG4gICAgcHVibGljRG9tYWluOiBvcHRpb25zLnB1YmxpY0RvbWFpbixcbiAgICBwdWJsaWNEb21haW5zOiBvcHRpb25zLmZycFB1YmxpY0RvbWFpbiA/IFtvcHRpb25zLmZycFB1YmxpY0RvbWFpbl0gOiB1bmRlZmluZWQsXG4gIH07XG4gIGNvbnN0IGdhdGUgPSBwbHVnaW4ucmVzb2x2ZUF1dGhHYXRlQ29uZmlnKGdhdGVDb25maWcpO1xuICBjb25zdCB0cmFuc3BvcnQgPSBpbnRlcmNlcHRvci5yZXNvbHZlVHVubmVsVHJhbnNwb3J0KG9wdGlvbnMudHJhbnNwb3J0KTtcbiAgcmV0dXJuIHtcbiAgICBwdWJsaWNQb3J0LFxuICAgIC4uLihhcHBQb3J0ID4gMCA/IHsgYXBwUG9ydCB9IDoge30pLFxuICAgIGJpbmRIb3N0czogb3B0aW9ucy5iaW5kID8/IFtdLFxuICAgIHRyYW5zcG9ydCxcbiAgICBnYXRlQ29uZmlnLFxuICAgIGdhdGUsXG4gICAgcG9ydHI6IHBvcnRyLnJlc29sdmVQb3J0ckNvbmZpZyh7XG4gICAgICBwdWJsaWNEb21haW46IGdhdGUucHVibGljRG9tYWluLFxuICAgICAgc3ViZG9tYWluOiBvcHRpb25zLnN1YmRvbWFpbixcbiAgICAgIHBvcnQ6IHB1YmxpY1BvcnQsXG4gICAgfSksXG4gICAgZnJwOiBmcnAucmVzb2x2ZUZycENvbmZpZyh7XG4gICAgICBwdWJsaWNEb21haW46IG9wdGlvbnMuZnJwUHVibGljRG9tYWluLFxuICAgICAgc2VydmVyOiBvcHRpb25zLmZycFNlcnZlcixcbiAgICAgIHNlcnZlclBvcnQ6IG9wdGlvbnMuZnJwU2VydmVyUG9ydCxcbiAgICAgIHByb3RvY29sOiBvcHRpb25zLmZycFByb3RvY29sLFxuICAgICAgdG9rZW46IG9wdGlvbnMuZnJwVG9rZW4sXG4gICAgICBwcm94eU5hbWU6IG9wdGlvbnMuZnJwUHJveHlOYW1lLFxuICAgICAgcG9ydDogcHVibGljUG9ydCxcbiAgICB9KSxcbiAgfTtcbn1cbiJdfQ==
package/package.json CHANGED
@@ -24,13 +24,13 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@databricks/appkit": "^0.43.0",
27
- "@dbx-tools/appkit": "0.6.104",
28
- "@dbx-tools/auth": "0.6.104",
29
- "@dbx-tools/core": "0.6.104",
30
- "@dbx-tools/email": "0.6.104",
31
- "@dbx-tools/shared-core": "0.6.104",
32
- "@dbx-tools/shared-email": "0.6.104",
33
- "@dbx-tools/tunnel": "0.6.104",
27
+ "@dbx-tools/appkit": "0.6.106",
28
+ "@dbx-tools/auth": "0.6.106",
29
+ "@dbx-tools/core": "0.6.106",
30
+ "@dbx-tools/email": "0.6.106",
31
+ "@dbx-tools/shared-core": "0.6.106",
32
+ "@dbx-tools/shared-email": "0.6.106",
33
+ "@dbx-tools/tunnel": "0.6.106",
34
34
  "commander": "^15.0.0",
35
35
  "http-proxy-3": "^1.23.1"
36
36
  },
@@ -64,7 +64,7 @@
64
64
  "./package.json": "./package.json"
65
65
  }
66
66
  },
67
- "version": "0.6.104",
67
+ "version": "0.6.106",
68
68
  "types": "./lib/index.d.ts",
69
69
  "type": "module",
70
70
  "exports": {
package/src/cli.ts CHANGED
@@ -25,7 +25,7 @@
25
25
  import { type ChildProcess, spawn } from "node:child_process";
26
26
  import { createServer } from "node:net";
27
27
  import { log } from "@dbx-tools/shared-core";
28
- import { portr } from "@dbx-tools/tunnel";
28
+ import { frp, portr } from "@dbx-tools/tunnel";
29
29
  import { Command, CommanderError } from "commander";
30
30
  import { resolveTunnelOptions, type TunnelOptions } from "./options.ts";
31
31
  import { startProxy } from "./proxy.ts";
@@ -61,7 +61,8 @@ function freePort(): Promise<number> {
61
61
  */
62
62
  function addOptions(command: Command): Command {
63
63
  return command
64
- .option("--public-domain <host>", "portr public domain (<subdomain>.<server>)")
64
+ .option("--transport <transport>", "public tunnel transport: portr, frp, or both")
65
+ .option("--public-domain <host>", "public tunnel domain")
65
66
  .option("--subdomain <name>", "portr subdomain (else derived from the public domain)")
66
67
  .option("--port <port>", "public port the wrapper listens on")
67
68
  .option("--app-port <port>", "private port the wrapped app is told to bind")
@@ -77,6 +78,12 @@ function addOptions(command: Command): Command {
77
78
  .option("--forward-headers <patterns...>", "extra x- headers tunnel traffic may forward")
78
79
  .option("--gate-path <prefix...>", "path prefixes to gate beyond /api/ (e.g. /ws)")
79
80
  .option("--bind <host...>", "interface IPs the gate listens on (default: 0.0.0.0)")
81
+ .option("--frp-server <host>", "frps control host (default: FRP public domain)")
82
+ .option("--frp-public-domain <host>", "FRP public HTTP domain")
83
+ .option("--frp-server-port <port>", "frps control port (default: 443)")
84
+ .option("--frp-protocol <protocol>", "frpc transport protocol (default: wss)")
85
+ .option("--frp-token <token>", "frps auth token")
86
+ .option("--frp-proxy-name <name>", "frp proxy registration name")
80
87
  .option("--insecure", "run open, with no gate");
81
88
  }
82
89
 
@@ -158,15 +165,21 @@ async function run(raw: TunnelOptions, command: readonly string[]): Promise<void
158
165
  bindHosts: resolved.bindHosts,
159
166
  });
160
167
 
161
- if (resolved.portr) {
168
+ if ((resolved.transport === "portr" || resolved.transport === "both") && resolved.portr) {
162
169
  const portrEnv = await portr.installPortr();
163
170
  await portr.writePortrConfig(resolved.portr, portrEnv);
164
171
  children.push(await portr.startPortr(resolved.portr, portrEnv));
165
- } else {
166
- logger.info("no PORTR_TOKEN / TUNNEL_PUBLIC_DOMAIN - serving locally only", {
167
- publicPort: resolved.publicPort,
168
- });
169
172
  }
173
+ if ((resolved.transport === "frp" || resolved.transport === "both") && resolved.frp) {
174
+ const frpEnv = await frp.installFrp();
175
+ const configPath = await frp.writeFrpConfig(resolved.frp, frpEnv);
176
+ children.push(frp.startFrp(resolved.frp, frpEnv, configPath));
177
+ }
178
+ const activeTunnelCount = children.length - (executable ? 1 : 0);
179
+ if (!activeTunnelCount) logger.info("no selected public tunnel is configured", {
180
+ transport: resolved.transport,
181
+ publicPort: resolved.publicPort,
182
+ });
170
183
  supervise(children);
171
184
  }
172
185
 
@@ -175,7 +188,7 @@ export function buildProgram(name = "dbx tunnel"): Command {
175
188
  const program = addOptions(
176
189
  new Command()
177
190
  .name(name)
178
- .description("Front a command with a portr tunnel and passwordless auth"),
191
+ .description("Front a command with a public tunnel and passwordless auth"),
179
192
  );
180
193
 
181
194
  // `run` is the DEFAULT action as well as a named subcommand, preserving the old
@@ -205,9 +218,14 @@ export function buildProgram(name = "dbx tunnel"): Command {
205
218
 
206
219
  program
207
220
  .command("install")
208
- .description("Install the portr binary and exit")
209
- .action(async () => {
210
- await portr.installPortr();
221
+ .argument("[transport]", "portr, frp, or both", "portr")
222
+ .description("Install public tunnel client binaries and exit")
223
+ .action(async (transport: string) => {
224
+ if (transport === "portr" || transport === "both") await portr.installPortr();
225
+ if (transport === "frp" || transport === "both") await frp.installFrp();
226
+ if (transport !== "portr" && transport !== "frp" && transport !== "both") {
227
+ throw new CommanderError(1, "tunnel.invalid-transport", `invalid transport: ${transport}`);
228
+ }
211
229
  });
212
230
 
213
231
  return program;
package/src/options.ts CHANGED
@@ -15,10 +15,11 @@
15
15
  import type { AuthStorageMode } from "@dbx-tools/auth";
16
16
  import { config } from "@dbx-tools/core";
17
17
  import { object } from "@dbx-tools/shared-core";
18
- import { type AuthGateConfig, plugin, portr } from "@dbx-tools/tunnel";
18
+ import { type AuthGateConfig, frp, interceptor, plugin, portr } from "@dbx-tools/tunnel";
19
19
 
20
20
  /** Raw commander flag values (every numeric flag arrives as a string). */
21
21
  export interface TunnelOptions {
22
+ transport?: interceptor.TunnelTransport;
22
23
  publicDomain?: string;
23
24
  subdomain?: string;
24
25
  port?: string | number;
@@ -36,6 +37,12 @@ export interface TunnelOptions {
36
37
  gatePath?: string[];
37
38
  bind?: string[];
38
39
  insecure?: boolean;
40
+ frpServer?: string;
41
+ frpPublicDomain?: string;
42
+ frpServerPort?: string | number;
43
+ frpProtocol?: string;
44
+ frpToken?: string;
45
+ frpProxyName?: string;
39
46
  }
40
47
 
41
48
  export interface ResolvedTunnelOptions {
@@ -45,6 +52,7 @@ export interface ResolvedTunnelOptions {
45
52
  appPort?: number;
46
53
  /** Interface IPs the gate listens on. Empty means the default (0.0.0.0). */
47
54
  bindHosts: string[];
55
+ transport: interceptor.TunnelTransport;
48
56
  /**
49
57
  * The gate config as the `authGate` PLUGIN takes it - flags only, nothing
50
58
  * resolved. Passed straight to the plugin so it applies its own fallbacks
@@ -54,6 +62,7 @@ export interface ResolvedTunnelOptions {
54
62
  /** The same config after the plugin's resolution, for `status` and for routing. */
55
63
  gate: plugin.ResolvedAuthGateConfig;
56
64
  portr: ReturnType<typeof portr.resolvePortrConfig>;
65
+ frp: ReturnType<typeof frp.resolveFrpConfig>;
57
66
  }
58
67
 
59
68
  export function resolveTunnelOptions(options: TunnelOptions): ResolvedTunnelOptions {
@@ -79,12 +88,15 @@ export function resolveTunnelOptions(options: TunnelOptions): ResolvedTunnelOpti
79
88
  gatePaths: options.gatePath,
80
89
  insecure: options.insecure,
81
90
  publicDomain: options.publicDomain,
91
+ publicDomains: options.frpPublicDomain ? [options.frpPublicDomain] : undefined,
82
92
  };
83
93
  const gate = plugin.resolveAuthGateConfig(gateConfig);
94
+ const transport = interceptor.resolveTunnelTransport(options.transport);
84
95
  return {
85
96
  publicPort,
86
97
  ...(appPort > 0 ? { appPort } : {}),
87
98
  bindHosts: options.bind ?? [],
99
+ transport,
88
100
  gateConfig,
89
101
  gate,
90
102
  portr: portr.resolvePortrConfig({
@@ -92,5 +104,14 @@ export function resolveTunnelOptions(options: TunnelOptions): ResolvedTunnelOpti
92
104
  subdomain: options.subdomain,
93
105
  port: publicPort,
94
106
  }),
107
+ frp: frp.resolveFrpConfig({
108
+ publicDomain: options.frpPublicDomain,
109
+ server: options.frpServer,
110
+ serverPort: options.frpServerPort,
111
+ protocol: options.frpProtocol,
112
+ token: options.frpToken,
113
+ proxyName: options.frpProxyName,
114
+ port: publicPort,
115
+ }),
95
116
  };
96
117
  }