vite-plugin-io1 0.1.1 → 0.1.2
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/dist/announce.d.ts +11 -0
- package/dist/announce.d.ts.map +1 -1
- package/dist/announce.js +15 -0
- package/dist/announce.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +27 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/announce.ts +18 -0
- package/src/index.ts +29 -13
package/dist/announce.d.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* contract with the CLI - which flags it takes, and how it announces a live host - is unit-tested
|
|
4
4
|
* in isolation and lives in one place.
|
|
5
5
|
*/
|
|
6
|
+
import type { AddressInfo } from 'node:net';
|
|
6
7
|
export interface RelayInvocation {
|
|
7
8
|
/** Hosts to claim, one `--host` each (the CLI appends across repeats). At least one. */
|
|
8
9
|
readonly hosts: readonly string[];
|
|
@@ -35,4 +36,14 @@ export declare function buildRelayArgs(invocation: RelayInvocation): string[];
|
|
|
35
36
|
* URLs but must not be mistaken for a live host.
|
|
36
37
|
*/
|
|
37
38
|
export declare function parseLiveUrl(line: string): string | null;
|
|
39
|
+
/**
|
|
40
|
+
* The `--to` proxy URL for a dev server bound at [address], a Node AddressInfo read once the socket is
|
|
41
|
+
* listening (so its port is the one the OS actually settled on, whatever Vite asked for). A wildcard
|
|
42
|
+
* bind - '0.0.0.0', '::', or the empty string - is not itself a connectable target, so we dial the
|
|
43
|
+
* loopback of the same family; a concrete address is kept as-is, and an IPv6 authority is bracketed.
|
|
44
|
+
* Using the bound address rather than a hardcoded 127.0.0.1 is what lets an IPv6 bind (Vite falling
|
|
45
|
+
* back to ::1 when 127.0.0.1:PORT is taken) be reached, instead of silently missing it or hitting
|
|
46
|
+
* whatever unrelated server already holds that IPv4 port.
|
|
47
|
+
*/
|
|
48
|
+
export declare function relayTargetUrl(address: AddressInfo): string;
|
|
38
49
|
//# sourceMappingURL=announce.d.ts.map
|
package/dist/announce.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announce.d.ts","sourceRoot":"","sources":["../src/announce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,iGAAiG;IACjG,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,kGAAkG;IAClG,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,EAAE,CAWpE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGxD"}
|
|
1
|
+
{"version":3,"file":"announce.d.ts","sourceRoot":"","sources":["../src/announce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAA;AAE3C,MAAM,WAAW,eAAe;IAC9B,wFAAwF;IACxF,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;IACjC,iGAAiG;IACjG,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,mFAAmF;IACnF,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,uFAAuF;IACvF,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,kGAAkG;IAClG,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CACpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,eAAe,GAAG,MAAM,EAAE,CAWpE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGxD;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAK3D"}
|
package/dist/announce.js
CHANGED
|
@@ -39,4 +39,19 @@ export function parseLiveUrl(line) {
|
|
|
39
39
|
const match = /(https?:\/\/\S+)\s+live\s*$/u.exec(line);
|
|
40
40
|
return match ? match[1] : null;
|
|
41
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* The `--to` proxy URL for a dev server bound at [address], a Node AddressInfo read once the socket is
|
|
44
|
+
* listening (so its port is the one the OS actually settled on, whatever Vite asked for). A wildcard
|
|
45
|
+
* bind - '0.0.0.0', '::', or the empty string - is not itself a connectable target, so we dial the
|
|
46
|
+
* loopback of the same family; a concrete address is kept as-is, and an IPv6 authority is bracketed.
|
|
47
|
+
* Using the bound address rather than a hardcoded 127.0.0.1 is what lets an IPv6 bind (Vite falling
|
|
48
|
+
* back to ::1 when 127.0.0.1:PORT is taken) be reached, instead of silently missing it or hitting
|
|
49
|
+
* whatever unrelated server already holds that IPv4 port.
|
|
50
|
+
*/
|
|
51
|
+
export function relayTargetUrl(address) {
|
|
52
|
+
const wildcard = '' === address.address || '0.0.0.0' === address.address || '::' === address.address;
|
|
53
|
+
const host = wildcard ? ('IPv6' === address.family ? '::1' : '127.0.0.1') : address.address;
|
|
54
|
+
const authority = host.includes(':') ? `[${host}]` : host;
|
|
55
|
+
return `http://${authority}:${address.port}`;
|
|
56
|
+
}
|
|
42
57
|
//# sourceMappingURL=announce.js.map
|
package/dist/announce.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"announce.js","sourceRoot":"","sources":["../src/announce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"announce.js","sourceRoot":"","sources":["../src/announce.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAqBH;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,UAA2B;IACxD,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC7B,KAAK,MAAM,IAAI,IAAI,UAAU,CAAC,KAAK;QAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;IAC9D,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,IAAI,EAAE,CAAA;IAC7C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;IACtE,IAAI,UAAU,CAAC,OAAO;QAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAClE,IAAI,UAAU,CAAC,OAAO;QAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC,CAAA;IAClE,IAAI,UAAU,CAAC,WAAW;QAAE,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;IAC/E,IAAI,UAAU,CAAC,SAAS;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,CAAA;IAC5D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,8BAA8B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACvD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AACjC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,OAAoB;IACjD,MAAM,QAAQ,GAAG,EAAE,KAAK,OAAO,CAAC,OAAO,IAAI,SAAS,KAAK,OAAO,CAAC,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,OAAO,CAAA;IACpG,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAA;IAC3F,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;IACzD,OAAO,UAAU,SAAS,IAAI,OAAO,CAAC,IAAI,EAAE,CAAA;AAC9C,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -27,11 +27,12 @@ export interface Io1PluginOptions {
|
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
29
|
* Vite plugin: while the dev (or preview) server runs, publish it to the internet over a
|
|
30
|
-
* `bitmot io1 relay` child process, proxying to the server
|
|
31
|
-
* tied to the server -
|
|
32
|
-
* outlives the session. The CLI is located on
|
|
33
|
-
* the deployed build). Reconnects are the
|
|
34
|
-
* (bad auth, host held by another
|
|
30
|
+
* `bitmot io1 relay` child process, proxying to the address the server actually bound. The relay's
|
|
31
|
+
* lifetime is tied to the server - armed by intercepting listen() and spawned the moment the socket
|
|
32
|
+
* binds, killed when it closes - so a shared URL never outlives the session. The CLI is located on
|
|
33
|
+
* PATH or auto-downloaded (content-addressed, so it tracks the deployed build). Reconnects are the
|
|
34
|
+
* relay's own concern; a non-zero exit is a definitive refusal (bad auth, host held by another
|
|
35
|
+
* account) and is surfaced, not retried.
|
|
35
36
|
*/
|
|
36
37
|
export declare function io1(options?: Io1PluginOptions): Plugin;
|
|
37
38
|
export default io1;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAgC,MAAM,MAAM,CAAA;AAIhE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAUD
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAgC,MAAM,MAAM,CAAA;AAIhE,YAAY,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjE,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,uFAAuF;IACvF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gFAAgF;IAChF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAUD;;;;;;;;GAQG;AACH,wBAAgB,GAAG,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,CAyG1D;AAyBD,eAAe,GAAG,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { buildRelayArgs, parseLiveUrl } from './announce.js';
|
|
2
|
+
import { buildRelayArgs, parseLiveUrl, relayTargetUrl } from './announce.js';
|
|
3
3
|
import { resolveBitmot } from './binary.js';
|
|
4
4
|
function normalizeHosts(host) {
|
|
5
5
|
const raw = host ?? process.env.IO1_DEV_HOST;
|
|
@@ -9,11 +9,12 @@ function normalizeHosts(host) {
|
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Vite plugin: while the dev (or preview) server runs, publish it to the internet over a
|
|
12
|
-
* `bitmot io1 relay` child process, proxying to the server
|
|
13
|
-
* tied to the server -
|
|
14
|
-
* outlives the session. The CLI is located on
|
|
15
|
-
* the deployed build). Reconnects are the
|
|
16
|
-
* (bad auth, host held by another
|
|
12
|
+
* `bitmot io1 relay` child process, proxying to the address the server actually bound. The relay's
|
|
13
|
+
* lifetime is tied to the server - armed by intercepting listen() and spawned the moment the socket
|
|
14
|
+
* binds, killed when it closes - so a shared URL never outlives the session. The CLI is located on
|
|
15
|
+
* PATH or auto-downloaded (content-addressed, so it tracks the deployed build). Reconnects are the
|
|
16
|
+
* relay's own concern; a non-zero exit is a definitive refusal (bad auth, host held by another
|
|
17
|
+
* account) and is surfaced, not retried.
|
|
17
18
|
*/
|
|
18
19
|
export function io1(options = {}) {
|
|
19
20
|
const hosts = normalizeHosts(options.host);
|
|
@@ -39,10 +40,24 @@ export function io1(options = {}) {
|
|
|
39
40
|
child = undefined;
|
|
40
41
|
process.removeListener('exit', onExit); // avoid piling up a listener per dev-server restart
|
|
41
42
|
};
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
43
|
+
// Arm the relay by intercepting listen() rather than only awaiting the 'listening' event: Vite
|
|
44
|
+
// calls listen once it has resolved the final port - the configured one, or (under
|
|
45
|
+
// strictPort:false) the next free port after a collision - so wrapping the very call that binds
|
|
46
|
+
// the socket is what guarantees we read the port the server actually took. The one-time
|
|
47
|
+
// 'listening' hook fires the instant the bind completes; `armed` keeps a second listen() from
|
|
48
|
+
// spawning a second relay. The casts are the price of replacing an overloaded native method.
|
|
49
|
+
const originalListen = httpServer.listen.bind(httpServer);
|
|
50
|
+
let armed = false;
|
|
51
|
+
httpServer.listen = ((...args) => {
|
|
52
|
+
if (!armed) {
|
|
53
|
+
armed = true;
|
|
54
|
+
httpServer.once('listening', () => {
|
|
55
|
+
void start(server).catch((error) => {
|
|
56
|
+
logger.error(`[io1] ${error.message}`);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return originalListen(...args);
|
|
46
61
|
});
|
|
47
62
|
httpServer.once('close', onExit);
|
|
48
63
|
process.once('exit', onExit);
|
|
@@ -51,7 +66,7 @@ export function io1(options = {}) {
|
|
|
51
66
|
const logger = server.config.logger;
|
|
52
67
|
const address = server.httpServer?.address();
|
|
53
68
|
if (!address || typeof address === 'string') {
|
|
54
|
-
logger.error('[io1] could not determine the dev server
|
|
69
|
+
logger.error('[io1] could not determine the dev server address; relay not started');
|
|
55
70
|
return;
|
|
56
71
|
}
|
|
57
72
|
const binary = await resolveBitmot({
|
|
@@ -68,7 +83,7 @@ export function io1(options = {}) {
|
|
|
68
83
|
account: options.account,
|
|
69
84
|
gateway: options.gateway,
|
|
70
85
|
extraArgs: options.extraArgs,
|
|
71
|
-
to:
|
|
86
|
+
to: relayTargetUrl(address),
|
|
72
87
|
});
|
|
73
88
|
if (stopping)
|
|
74
89
|
return; // the server closed while we were resolving the binary
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAA;AAE7D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/announce.ts
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
* in isolation and lives in one place.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { AddressInfo } from 'node:net'
|
|
8
|
+
|
|
7
9
|
export interface RelayInvocation {
|
|
8
10
|
/** Hosts to claim, one `--host` each (the CLI appends across repeats). At least one. */
|
|
9
11
|
readonly hosts: readonly string[]
|
|
@@ -52,3 +54,19 @@ export function parseLiveUrl(line: string): string | null {
|
|
|
52
54
|
const match = /(https?:\/\/\S+)\s+live\s*$/u.exec(line)
|
|
53
55
|
return match ? match[1]! : null
|
|
54
56
|
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The `--to` proxy URL for a dev server bound at [address], a Node AddressInfo read once the socket is
|
|
60
|
+
* listening (so its port is the one the OS actually settled on, whatever Vite asked for). A wildcard
|
|
61
|
+
* bind - '0.0.0.0', '::', or the empty string - is not itself a connectable target, so we dial the
|
|
62
|
+
* loopback of the same family; a concrete address is kept as-is, and an IPv6 authority is bracketed.
|
|
63
|
+
* Using the bound address rather than a hardcoded 127.0.0.1 is what lets an IPv6 bind (Vite falling
|
|
64
|
+
* back to ::1 when 127.0.0.1:PORT is taken) be reached, instead of silently missing it or hitting
|
|
65
|
+
* whatever unrelated server already holds that IPv4 port.
|
|
66
|
+
*/
|
|
67
|
+
export function relayTargetUrl(address: AddressInfo): string {
|
|
68
|
+
const wildcard = '' === address.address || '0.0.0.0' === address.address || '::' === address.address
|
|
69
|
+
const host = wildcard ? ('IPv6' === address.family ? '::1' : '127.0.0.1') : address.address
|
|
70
|
+
const authority = host.includes(':') ? `[${host}]` : host
|
|
71
|
+
return `http://${authority}:${address.port}`
|
|
72
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn, type ChildProcess } from 'node:child_process'
|
|
2
2
|
import type { Plugin, PreviewServer, ViteDevServer } from 'vite'
|
|
3
|
-
import { buildRelayArgs, parseLiveUrl } from './announce.js'
|
|
3
|
+
import { buildRelayArgs, parseLiveUrl, relayTargetUrl } from './announce.js'
|
|
4
4
|
import { resolveBitmot } from './binary.js'
|
|
5
5
|
|
|
6
6
|
export type { RelayInvocation } from './announce.js'
|
|
@@ -41,11 +41,12 @@ type ServeServer = ViteDevServer | PreviewServer
|
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
43
|
* Vite plugin: while the dev (or preview) server runs, publish it to the internet over a
|
|
44
|
-
* `bitmot io1 relay` child process, proxying to the server
|
|
45
|
-
* tied to the server -
|
|
46
|
-
* outlives the session. The CLI is located on
|
|
47
|
-
* the deployed build). Reconnects are the
|
|
48
|
-
* (bad auth, host held by another
|
|
44
|
+
* `bitmot io1 relay` child process, proxying to the address the server actually bound. The relay's
|
|
45
|
+
* lifetime is tied to the server - armed by intercepting listen() and spawned the moment the socket
|
|
46
|
+
* binds, killed when it closes - so a shared URL never outlives the session. The CLI is located on
|
|
47
|
+
* PATH or auto-downloaded (content-addressed, so it tracks the deployed build). Reconnects are the
|
|
48
|
+
* relay's own concern; a non-zero exit is a definitive refusal (bad auth, host held by another
|
|
49
|
+
* account) and is surfaced, not retried.
|
|
49
50
|
*/
|
|
50
51
|
export function io1(options: Io1PluginOptions = {}): Plugin {
|
|
51
52
|
const hosts = normalizeHosts(options.host)
|
|
@@ -74,11 +75,26 @@ export function io1(options: Io1PluginOptions = {}): Plugin {
|
|
|
74
75
|
process.removeListener('exit', onExit) // avoid piling up a listener per dev-server restart
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
// Arm the relay by intercepting listen() rather than only awaiting the 'listening' event: Vite
|
|
79
|
+
// calls listen once it has resolved the final port - the configured one, or (under
|
|
80
|
+
// strictPort:false) the next free port after a collision - so wrapping the very call that binds
|
|
81
|
+
// the socket is what guarantees we read the port the server actually took. The one-time
|
|
82
|
+
// 'listening' hook fires the instant the bind completes; `armed` keeps a second listen() from
|
|
83
|
+
// spawning a second relay. The casts are the price of replacing an overloaded native method.
|
|
84
|
+
const originalListen = httpServer.listen.bind(httpServer) as unknown as (...args: unknown[]) => unknown
|
|
85
|
+
let armed = false
|
|
86
|
+
httpServer.listen = ((...args: unknown[]): unknown => {
|
|
87
|
+
if (!armed) {
|
|
88
|
+
armed = true
|
|
89
|
+
httpServer.once('listening', () => {
|
|
90
|
+
void start(server).catch((error: unknown) => {
|
|
91
|
+
logger.error(`[io1] ${(error as Error).message}`)
|
|
92
|
+
})
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
return originalListen(...args)
|
|
96
|
+
}) as unknown as typeof httpServer.listen
|
|
97
|
+
|
|
82
98
|
httpServer.once('close', onExit)
|
|
83
99
|
process.once('exit', onExit)
|
|
84
100
|
}
|
|
@@ -87,7 +103,7 @@ export function io1(options: Io1PluginOptions = {}): Plugin {
|
|
|
87
103
|
const logger = server.config.logger
|
|
88
104
|
const address = server.httpServer?.address()
|
|
89
105
|
if (!address || typeof address === 'string') {
|
|
90
|
-
logger.error('[io1] could not determine the dev server
|
|
106
|
+
logger.error('[io1] could not determine the dev server address; relay not started')
|
|
91
107
|
return
|
|
92
108
|
}
|
|
93
109
|
|
|
@@ -105,7 +121,7 @@ export function io1(options: Io1PluginOptions = {}): Plugin {
|
|
|
105
121
|
account: options.account,
|
|
106
122
|
gateway: options.gateway,
|
|
107
123
|
extraArgs: options.extraArgs,
|
|
108
|
-
to:
|
|
124
|
+
to: relayTargetUrl(address),
|
|
109
125
|
})
|
|
110
126
|
|
|
111
127
|
if (stopping) return // the server closed while we were resolving the binary
|