@trevrpc/trevrpc-js 0.1.9 → 0.2.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/bin/protoc-gen-trevrpc-js.js +1 -1
- package/package.json +9 -8
- package/src/browser-channel.js +6 -2
- package/src/native-loader.js +23 -6
- package/src/webtransport.js +17 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trevrpc/trevrpc-js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "JavaScript WebTransport runtime and protobuf.js code generator for TrevRPC",
|
|
5
5
|
"homepage": "https://trev.zip/llc/TrevRPC",
|
|
6
6
|
"bugs": {
|
|
@@ -65,24 +65,25 @@
|
|
|
65
65
|
"format": "oxfmt --write",
|
|
66
66
|
"format:check": "oxfmt --check",
|
|
67
67
|
"lint": "oxlint --deny-warnings",
|
|
68
|
+
"prepack": "node -e 'if (process.env.TREVRPC_NIX_PUBLICATION !== \"1\") throw new Error(\"Build release tarballs with nix build .#trevrpc-js^npm\")'",
|
|
68
69
|
"test": "node --test --test-concurrency=1 test/*.test.js",
|
|
69
70
|
"typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.browser.json && tsc -p tsconfig.node.json",
|
|
70
71
|
"verify:native:production": "node -e 'const { readFileSync } = require(\"node:fs\"); const path = \"./build/native/trevrpc_native.node\"; const expectedExports = [\"connectMsQuic\", \"createCancellation\", \"listenMsQuic\"]; const actualExports = Object.getOwnPropertyNames(require(path)).sort(); const exportsMatch = JSON.stringify(actualExports) === JSON.stringify(expectedExports); const embedsDebugNames = readFileSync(path).includes(Buffer.from(\"_debug\")); if (!exportsMatch || embedsDebugNames) throw new Error(`production addon exports ${JSON.stringify(actualExports)}; expected exactly ${JSON.stringify(expectedExports)}${embedsDebugNames ? \"; binary contains _debug\" : \"\"}`);'"
|
|
71
72
|
},
|
|
72
73
|
"dependencies": {
|
|
73
|
-
"protobufjs": "^8.
|
|
74
|
+
"protobufjs": "^8.8.0"
|
|
74
75
|
},
|
|
75
76
|
"devDependencies": {
|
|
76
77
|
"@types/node": "^24.13.3",
|
|
77
|
-
"esbuild": "^0.28.
|
|
78
|
-
"playwright": "
|
|
78
|
+
"esbuild": "^0.28.2",
|
|
79
|
+
"playwright": "1.61.1",
|
|
79
80
|
"typescript": "^7.0.2"
|
|
80
81
|
},
|
|
81
|
-
"optionalDependencies": {
|
|
82
|
-
"@trevrpc/trevrpc-js-native-linux-x64-gnu": "0.1.9"
|
|
83
|
-
},
|
|
84
82
|
"engines": {
|
|
85
83
|
"node": ">=24 <25"
|
|
86
84
|
},
|
|
87
|
-
"packageManager": "npm@
|
|
85
|
+
"packageManager": "npm@12.0.2",
|
|
86
|
+
"optionalDependencies": {
|
|
87
|
+
"@trevrpc/trevrpc-js-native-linux-x64-gnu": "0.2.2"
|
|
88
|
+
}
|
|
88
89
|
}
|
package/src/browser-channel.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ChannelStateMachine, stripChannelOptions, waitForInitialReady } from "./channel.js";
|
|
2
2
|
import { unavailable } from "./status.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
RawWebTransport,
|
|
5
|
+
createWebTransportSession,
|
|
6
|
+
waitForWebTransportReady,
|
|
7
|
+
} from "./webtransport.js";
|
|
4
8
|
|
|
5
9
|
/** Browser channel with background session reconnection. */
|
|
6
10
|
export class Channel extends ChannelStateMachine {
|
|
@@ -31,7 +35,7 @@ async function connectWebTransport(url, options, signal) {
|
|
|
31
35
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
32
36
|
|
|
33
37
|
try {
|
|
34
|
-
await session
|
|
38
|
+
await waitForWebTransportReady(session);
|
|
35
39
|
if (signal.aborted) {
|
|
36
40
|
throw unavailable("channel is closed");
|
|
37
41
|
}
|
package/src/native-loader.js
CHANGED
|
@@ -13,17 +13,17 @@ const packageVersion = (() => {
|
|
|
13
13
|
return "unknown";
|
|
14
14
|
}
|
|
15
15
|
})();
|
|
16
|
-
const
|
|
16
|
+
const SupportedOptionalTarget = "linux/x64/glibc";
|
|
17
17
|
const LinuxX64GnuPackage = "@trevrpc/trevrpc-js-native-linux-x64-gnu";
|
|
18
18
|
|
|
19
19
|
/** Loads the target-specific native addon without building during installation. */
|
|
20
|
-
export function loadNativeAddon() {
|
|
20
|
+
export function loadNativeAddon({ loadOptionalPackage = true, loadBundledAddon = true } = {}) {
|
|
21
21
|
const target = nativeTarget();
|
|
22
22
|
const packageName = nativePackageName(target);
|
|
23
23
|
let packageError;
|
|
24
24
|
let packageState = "unsupported";
|
|
25
25
|
|
|
26
|
-
if (packageName != null) {
|
|
26
|
+
if (loadOptionalPackage && packageName != null) {
|
|
27
27
|
try {
|
|
28
28
|
return require(packageName);
|
|
29
29
|
} catch (error) {
|
|
@@ -32,6 +32,16 @@ export function loadNativeAddon() {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
const bundled = loadBundledAddon ? bundledNativePath() : null;
|
|
36
|
+
let bundledError;
|
|
37
|
+
if (bundled != null) {
|
|
38
|
+
try {
|
|
39
|
+
return require(bundled);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
bundledError = error;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
35
45
|
const fallback = developmentFallbackPath();
|
|
36
46
|
let fallbackError;
|
|
37
47
|
if (fallback != null) {
|
|
@@ -44,6 +54,8 @@ export function loadNativeAddon() {
|
|
|
44
54
|
|
|
45
55
|
const detected = targetName(target);
|
|
46
56
|
const expected = packageName ?? "no optional package (unsupported target)";
|
|
57
|
+
const bundledState =
|
|
58
|
+
bundled == null ? "no Nix-bundled addon was present" : "the Nix-bundled addon failed to load";
|
|
47
59
|
const fallbackState =
|
|
48
60
|
fallback == null
|
|
49
61
|
? "no source-checkout fallback was present"
|
|
@@ -52,10 +64,10 @@ export function loadNativeAddon() {
|
|
|
52
64
|
: "the source-checkout fallback failed to load";
|
|
53
65
|
throw new Error(
|
|
54
66
|
`TrevRPC native addon is unavailable for detected target ${detected}. ` +
|
|
55
|
-
`Supported targets: ${
|
|
56
|
-
`package state: ${packageState}; ${fallbackState}. ` +
|
|
67
|
+
`Supported optional-package targets: ${SupportedOptionalTarget}. Expected optional package: ${expected}@${packageVersion}; ` +
|
|
68
|
+
`package state: ${packageState}; ${bundledState}; ${fallbackState}. ` +
|
|
57
69
|
"Install the matching optional package or build build/native/trevrpc_native.node explicitly in a source checkout; npm installation never starts a source build.",
|
|
58
|
-
{ cause: fallbackError ?? packageError },
|
|
70
|
+
{ cause: fallbackError ?? bundledError ?? packageError },
|
|
59
71
|
);
|
|
60
72
|
}
|
|
61
73
|
|
|
@@ -75,6 +87,11 @@ function nativePackageName(target) {
|
|
|
75
87
|
return null;
|
|
76
88
|
}
|
|
77
89
|
|
|
90
|
+
function bundledNativePath() {
|
|
91
|
+
const path = join(packageRoot, "native", "trevrpc_native.node");
|
|
92
|
+
return existsSync(path) ? path : null;
|
|
93
|
+
}
|
|
94
|
+
|
|
78
95
|
function developmentFallbackPath() {
|
|
79
96
|
if (!existsSync(join(packageRoot, "native", "CMakeLists.txt"))) {
|
|
80
97
|
return null;
|
package/src/webtransport.js
CHANGED
|
@@ -30,13 +30,13 @@ export class RawWebTransport {
|
|
|
30
30
|
/** Opens a WebTransport session and wraps it in a TrevRPC client. */
|
|
31
31
|
static async connect(url, options = {}) {
|
|
32
32
|
const session = createWebTransportSession(url, options);
|
|
33
|
-
await session
|
|
33
|
+
await waitForWebTransportReady(session);
|
|
34
34
|
return new RawWebTransport(session, options);
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/** Waits for the underlying WebTransport session to become ready. */
|
|
38
38
|
async ready() {
|
|
39
|
-
await this.session
|
|
39
|
+
await waitForWebTransportReady(this.session);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/** Closes the underlying WebTransport session. */
|
|
@@ -146,6 +146,21 @@ export class RawWebTransport {
|
|
|
146
146
|
}
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
/** Waits for readiness without hanging when a session closes during setup. */
|
|
150
|
+
export async function waitForWebTransportReady(session) {
|
|
151
|
+
if (session.closed == null) {
|
|
152
|
+
await session.ready;
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await Promise.race([
|
|
157
|
+
session.ready,
|
|
158
|
+
Promise.resolve(session.closed).then(() => {
|
|
159
|
+
throw unavailable("WebTransport session closed before becoming ready");
|
|
160
|
+
}),
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
|
|
149
164
|
/** Creates a WebTransport session using only browser constructor options. */
|
|
150
165
|
export function createWebTransportSession(url, options = {}) {
|
|
151
166
|
const WebTransportCtor = options.WebTransport ?? globalThis.WebTransport;
|