jsgar 4.5.3 → 4.6.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/gar.umd.js +188 -8
- package/gar.js +181 -3
- package/package.json +2 -2
package/dist/gar.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ?
|
|
3
|
-
typeof define === 'function' && define.amd ? define(factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.GARClient =
|
|
5
|
-
})(this, (function () { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.GARClient = {}));
|
|
5
|
+
})(this, (function (exports) { 'use strict';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* A client implementation for the Generic Active Records (GAR) protocol using WebSockets.
|
|
@@ -30,6 +30,159 @@
|
|
|
30
30
|
// - In Node.js, dynamically imports 'ws' and assigns globalThis.WebSocket
|
|
31
31
|
// All client code references the constructor via helper methods, not a top-level binding.
|
|
32
32
|
|
|
33
|
+
// AF_UNIX local-transport optimization (mirrors ipc/gar.cpp). When the endpoint
|
|
34
|
+
// resolves to an IP bound to a local interface, the GAR server is also listening
|
|
35
|
+
// on an abstract-namespace AF_UNIX socket at "\0gar.endpoint.<port>". Routing the
|
|
36
|
+
// WebSocket through that path bypasses the kernel TCP loopback stack — avoiding
|
|
37
|
+
// EDR/Falcon-style instrumentation overhead — while preserving the wire protocol.
|
|
38
|
+
//
|
|
39
|
+
// Browser environments have no raw socket access, so this is Node.js-only. The
|
|
40
|
+
// 'ws' library lets us inject a pre-connected net.Socket (or TLS-wrapped) via
|
|
41
|
+
// the createConnection option in the constructor.
|
|
42
|
+
//
|
|
43
|
+
// Set TRS_DISABLE_AF_UNIX=1 (also accepts true/on/yes, case-insensitive) to opt
|
|
44
|
+
// out and force the regular TCP path. Useful when capturing GAR traffic with
|
|
45
|
+
// tcpdump/wireshark on the loopback interface, which only sees TCP.
|
|
46
|
+
|
|
47
|
+
function _garAfUnixDisabled() {
|
|
48
|
+
const v = (typeof process !== 'undefined' && process.env)
|
|
49
|
+
? process.env.TRS_DISABLE_AF_UNIX : undefined;
|
|
50
|
+
if (!v) return false;
|
|
51
|
+
return ['1', 'true', 'on', 'yes'].includes(v.toLowerCase());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let _garNetMod = null;
|
|
55
|
+
let _garTlsMod = null;
|
|
56
|
+
let _garOsMod = null;
|
|
57
|
+
let _garDnsMod = null;
|
|
58
|
+
|
|
59
|
+
async function _garLoadNodeModules() {
|
|
60
|
+
if (_garNetMod) return true;
|
|
61
|
+
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
|
|
62
|
+
if (!isNode) return false;
|
|
63
|
+
try {
|
|
64
|
+
const { createRequire } = await import('node:module');
|
|
65
|
+
const req = createRequire(process.cwd() + '/');
|
|
66
|
+
_garNetMod = req('net');
|
|
67
|
+
_garTlsMod = req('tls');
|
|
68
|
+
_garOsMod = req('os');
|
|
69
|
+
_garDnsMod = req('dns');
|
|
70
|
+
return true;
|
|
71
|
+
} catch {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function _garLocalIPv4Set() {
|
|
77
|
+
const set = new Set(['127.0.0.1']);
|
|
78
|
+
const ifaces = _garOsMod.networkInterfaces();
|
|
79
|
+
for (const name of Object.keys(ifaces)) {
|
|
80
|
+
for (const addr of ifaces[name] || []) {
|
|
81
|
+
if (addr.family === 'IPv4' || addr.family === 4) set.add(addr.address);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return set;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Returns the optimal GAR endpoint string for |inetEndpoint|: if the URL's
|
|
88
|
+
// host resolves locally on this machine, returns the AF_UNIX form
|
|
89
|
+
// "unix:gar.endpoint.<port>"; otherwise echoes the input. Mirrors
|
|
90
|
+
// `trsutil --optimal-endpoint`. Async because DNS lookup in Node is async-only.
|
|
91
|
+
// Respects TRS_DISABLE_AF_UNIX. Does not probe the AF_UNIX listener — caller
|
|
92
|
+
// (or jsgar's connect path) handles fallback if it's unreachable.
|
|
93
|
+
async function optimalEndpoint(inetEndpoint) {
|
|
94
|
+
if (_garAfUnixDisabled()) return inetEndpoint;
|
|
95
|
+
// Skip AF_UNIX for SSL — OpenSSL's non-blocking handshake over AF_UNIX
|
|
96
|
+
// produces sporadic failures.
|
|
97
|
+
const lower = inetEndpoint.toLowerCase();
|
|
98
|
+
if (lower.startsWith('wss://') || lower.startsWith('https://')) return inetEndpoint;
|
|
99
|
+
if (!(await _garLoadNodeModules())) return inetEndpoint;
|
|
100
|
+
let parsed;
|
|
101
|
+
try { parsed = new URL(inetEndpoint); } catch { return inetEndpoint; }
|
|
102
|
+
const host = parsed.hostname;
|
|
103
|
+
const port = parsed.port;
|
|
104
|
+
if (!host || !port) return inetEndpoint;
|
|
105
|
+
let ip;
|
|
106
|
+
try {
|
|
107
|
+
if (_garNetMod.isIP(host)) {
|
|
108
|
+
ip = host;
|
|
109
|
+
} else {
|
|
110
|
+
const r = await _garDnsMod.promises.lookup(host, { family: 4 });
|
|
111
|
+
ip = r.address;
|
|
112
|
+
}
|
|
113
|
+
} catch { return inetEndpoint; }
|
|
114
|
+
if (ip.startsWith('127.') || _garLocalIPv4Set().has(ip)) {
|
|
115
|
+
return `unix:gar.endpoint.${port}`;
|
|
116
|
+
}
|
|
117
|
+
return inetEndpoint;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Returns the abstract-namespace AF_UNIX path (a string starting with \u0000)
|
|
121
|
+
// for the given GAR WebSocket endpoint if (a) it resolves to a local IPv4 and
|
|
122
|
+
// (b) the abstract listener at the matching name is reachable. Otherwise null.
|
|
123
|
+
async function _garUnixAbstractPathForEndpoint(wsEndpoint) {
|
|
124
|
+
if (_garAfUnixDisabled()) return null;
|
|
125
|
+
if (!(await _garLoadNodeModules())) return null;
|
|
126
|
+
let parsed;
|
|
127
|
+
try {
|
|
128
|
+
parsed = new URL(wsEndpoint);
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const host = parsed.hostname;
|
|
133
|
+
const port = parsed.port;
|
|
134
|
+
if (!host || !port) return null;
|
|
135
|
+
|
|
136
|
+
let ip;
|
|
137
|
+
try {
|
|
138
|
+
if (_garNetMod.isIP(host)) {
|
|
139
|
+
ip = host;
|
|
140
|
+
} else {
|
|
141
|
+
const r = await _garDnsMod.promises.lookup(host, { family: 4 });
|
|
142
|
+
ip = r.address;
|
|
143
|
+
}
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Loopback short-circuit; otherwise check against the host's interface IPs.
|
|
149
|
+
// (Less precise than RTM_GETROUTE used by the C++ side, but covers the
|
|
150
|
+
// practical "is this destination on this machine?" question for our use.)
|
|
151
|
+
if (!ip.startsWith('127.')) {
|
|
152
|
+
if (!_garLocalIPv4Set().has(ip)) return null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const abstractPath = '\u0000gar.endpoint.' + port;
|
|
156
|
+
// Reachability probe: AF_UNIX local connect either succeeds immediately or
|
|
157
|
+
// fails immediately with ECONNREFUSED/ENOENT.
|
|
158
|
+
const reachable = await new Promise((resolve) => {
|
|
159
|
+
let done = false;
|
|
160
|
+
const finish = (ok) => {
|
|
161
|
+
if (done) return;
|
|
162
|
+
done = true;
|
|
163
|
+
try { sock.destroy(); } catch { /* ignore */ }
|
|
164
|
+
resolve(ok);
|
|
165
|
+
};
|
|
166
|
+
const sock = _garNetMod.createConnection({ path: abstractPath });
|
|
167
|
+
sock.once('connect', () => finish(true));
|
|
168
|
+
sock.once('error', () => finish(false));
|
|
169
|
+
setTimeout(() => finish(false), 500);
|
|
170
|
+
});
|
|
171
|
+
return reachable ? abstractPath : null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function _garMakeUnixCreateConnectionFn(abstractPath, useSSL, sniHost, allowSelfSigned) {
|
|
175
|
+
return () => {
|
|
176
|
+
const unixSocket = _garNetMod.createConnection({ path: abstractPath });
|
|
177
|
+
if (!useSSL) return unixSocket;
|
|
178
|
+
return _garTlsMod.connect({
|
|
179
|
+
socket: unixSocket,
|
|
180
|
+
servername: sniHost,
|
|
181
|
+
rejectUnauthorized: !allowSelfSigned,
|
|
182
|
+
});
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
33
186
|
class GARClient {
|
|
34
187
|
/**
|
|
35
188
|
* Initialize the GAR client.
|
|
@@ -169,13 +322,37 @@
|
|
|
169
322
|
const WS = await this._ensureWebSocketCtor();
|
|
170
323
|
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
|
|
171
324
|
|
|
172
|
-
|
|
325
|
+
// Prefer AF_UNIX abstract-namespace transport for local destinations.
|
|
326
|
+
// Falls back to TCP automatically (next reconnect iteration) if the
|
|
327
|
+
// listener disappears between probe and real connect.
|
|
328
|
+
// Skip AF_UNIX for SSL — OpenSSL's non-blocking handshake over
|
|
329
|
+
// AF_UNIX produces sporadic failures.
|
|
330
|
+
const useSSL = this.wsEndpoint.toLowerCase().startsWith('wss://');
|
|
331
|
+
let unixAbstractPath = null;
|
|
332
|
+
let sniHost = null;
|
|
333
|
+
if (isNode && !useSSL) {
|
|
334
|
+
unixAbstractPath = await _garUnixAbstractPathForEndpoint(this.wsEndpoint);
|
|
335
|
+
if (unixAbstractPath) {
|
|
336
|
+
try { sniHost = new URL(this.wsEndpoint).hostname; } catch { /* ignore */ }
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
this.log('INFO', `Connecting to WebSocket server at ${this.wsEndpoint}${unixAbstractPath ? ' (via AF_UNIX)' : ''}`);
|
|
173
341
|
|
|
174
342
|
const connectionPromise = new Promise((resolve, reject) => {
|
|
175
343
|
let websocket;
|
|
176
|
-
|
|
344
|
+
const wsOpts = {};
|
|
345
|
+
if (this.allowSelfSignedCertificate && isNode && useSSL) {
|
|
177
346
|
// Node.js 'ws' supports options for TLS; browsers do not.
|
|
178
|
-
|
|
347
|
+
wsOpts.rejectUnauthorized = false;
|
|
348
|
+
}
|
|
349
|
+
if (unixAbstractPath) {
|
|
350
|
+
wsOpts.createConnection = _garMakeUnixCreateConnectionFn(
|
|
351
|
+
unixAbstractPath, useSSL, sniHost, this.allowSelfSignedCertificate
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
if (Object.keys(wsOpts).length > 0) {
|
|
355
|
+
websocket = new WS(this.wsEndpoint, ['gar-protocol'], wsOpts);
|
|
179
356
|
} else {
|
|
180
357
|
websocket = new WS(this.wsEndpoint, ['gar-protocol']);
|
|
181
358
|
}
|
|
@@ -1517,6 +1694,9 @@
|
|
|
1517
1694
|
}
|
|
1518
1695
|
}
|
|
1519
1696
|
|
|
1520
|
-
|
|
1697
|
+
exports.default = GARClient;
|
|
1698
|
+
exports.optimalEndpoint = optimalEndpoint;
|
|
1699
|
+
|
|
1700
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1521
1701
|
|
|
1522
1702
|
}));
|
package/gar.js
CHANGED
|
@@ -24,6 +24,159 @@
|
|
|
24
24
|
// - In Node.js, dynamically imports 'ws' and assigns globalThis.WebSocket
|
|
25
25
|
// All client code references the constructor via helper methods, not a top-level binding.
|
|
26
26
|
|
|
27
|
+
// AF_UNIX local-transport optimization (mirrors ipc/gar.cpp). When the endpoint
|
|
28
|
+
// resolves to an IP bound to a local interface, the GAR server is also listening
|
|
29
|
+
// on an abstract-namespace AF_UNIX socket at "\0gar.endpoint.<port>". Routing the
|
|
30
|
+
// WebSocket through that path bypasses the kernel TCP loopback stack — avoiding
|
|
31
|
+
// EDR/Falcon-style instrumentation overhead — while preserving the wire protocol.
|
|
32
|
+
//
|
|
33
|
+
// Browser environments have no raw socket access, so this is Node.js-only. The
|
|
34
|
+
// 'ws' library lets us inject a pre-connected net.Socket (or TLS-wrapped) via
|
|
35
|
+
// the createConnection option in the constructor.
|
|
36
|
+
//
|
|
37
|
+
// Set TRS_DISABLE_AF_UNIX=1 (also accepts true/on/yes, case-insensitive) to opt
|
|
38
|
+
// out and force the regular TCP path. Useful when capturing GAR traffic with
|
|
39
|
+
// tcpdump/wireshark on the loopback interface, which only sees TCP.
|
|
40
|
+
|
|
41
|
+
function _garAfUnixDisabled() {
|
|
42
|
+
const v = (typeof process !== 'undefined' && process.env)
|
|
43
|
+
? process.env.TRS_DISABLE_AF_UNIX : undefined;
|
|
44
|
+
if (!v) return false;
|
|
45
|
+
return ['1', 'true', 'on', 'yes'].includes(v.toLowerCase());
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
let _garNetMod = null;
|
|
49
|
+
let _garTlsMod = null;
|
|
50
|
+
let _garOsMod = null;
|
|
51
|
+
let _garDnsMod = null;
|
|
52
|
+
|
|
53
|
+
async function _garLoadNodeModules() {
|
|
54
|
+
if (_garNetMod) return true;
|
|
55
|
+
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
|
|
56
|
+
if (!isNode) return false;
|
|
57
|
+
try {
|
|
58
|
+
const { createRequire } = await import('node:module');
|
|
59
|
+
const req = createRequire(process.cwd() + '/');
|
|
60
|
+
_garNetMod = req('net');
|
|
61
|
+
_garTlsMod = req('tls');
|
|
62
|
+
_garOsMod = req('os');
|
|
63
|
+
_garDnsMod = req('dns');
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function _garLocalIPv4Set() {
|
|
71
|
+
const set = new Set(['127.0.0.1']);
|
|
72
|
+
const ifaces = _garOsMod.networkInterfaces();
|
|
73
|
+
for (const name of Object.keys(ifaces)) {
|
|
74
|
+
for (const addr of ifaces[name] || []) {
|
|
75
|
+
if (addr.family === 'IPv4' || addr.family === 4) set.add(addr.address);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return set;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Returns the optimal GAR endpoint string for |inetEndpoint|: if the URL's
|
|
82
|
+
// host resolves locally on this machine, returns the AF_UNIX form
|
|
83
|
+
// "unix:gar.endpoint.<port>"; otherwise echoes the input. Mirrors
|
|
84
|
+
// `trsutil --optimal-endpoint`. Async because DNS lookup in Node is async-only.
|
|
85
|
+
// Respects TRS_DISABLE_AF_UNIX. Does not probe the AF_UNIX listener — caller
|
|
86
|
+
// (or jsgar's connect path) handles fallback if it's unreachable.
|
|
87
|
+
async function optimalEndpoint(inetEndpoint) {
|
|
88
|
+
if (_garAfUnixDisabled()) return inetEndpoint;
|
|
89
|
+
// Skip AF_UNIX for SSL — OpenSSL's non-blocking handshake over AF_UNIX
|
|
90
|
+
// produces sporadic failures.
|
|
91
|
+
const lower = inetEndpoint.toLowerCase();
|
|
92
|
+
if (lower.startsWith('wss://') || lower.startsWith('https://')) return inetEndpoint;
|
|
93
|
+
if (!(await _garLoadNodeModules())) return inetEndpoint;
|
|
94
|
+
let parsed;
|
|
95
|
+
try { parsed = new URL(inetEndpoint); } catch { return inetEndpoint; }
|
|
96
|
+
const host = parsed.hostname;
|
|
97
|
+
const port = parsed.port;
|
|
98
|
+
if (!host || !port) return inetEndpoint;
|
|
99
|
+
let ip;
|
|
100
|
+
try {
|
|
101
|
+
if (_garNetMod.isIP(host)) {
|
|
102
|
+
ip = host;
|
|
103
|
+
} else {
|
|
104
|
+
const r = await _garDnsMod.promises.lookup(host, { family: 4 });
|
|
105
|
+
ip = r.address;
|
|
106
|
+
}
|
|
107
|
+
} catch { return inetEndpoint; }
|
|
108
|
+
if (ip.startsWith('127.') || _garLocalIPv4Set().has(ip)) {
|
|
109
|
+
return `unix:gar.endpoint.${port}`;
|
|
110
|
+
}
|
|
111
|
+
return inetEndpoint;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Returns the abstract-namespace AF_UNIX path (a string starting with \u0000)
|
|
115
|
+
// for the given GAR WebSocket endpoint if (a) it resolves to a local IPv4 and
|
|
116
|
+
// (b) the abstract listener at the matching name is reachable. Otherwise null.
|
|
117
|
+
async function _garUnixAbstractPathForEndpoint(wsEndpoint) {
|
|
118
|
+
if (_garAfUnixDisabled()) return null;
|
|
119
|
+
if (!(await _garLoadNodeModules())) return null;
|
|
120
|
+
let parsed;
|
|
121
|
+
try {
|
|
122
|
+
parsed = new URL(wsEndpoint);
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const host = parsed.hostname;
|
|
127
|
+
const port = parsed.port;
|
|
128
|
+
if (!host || !port) return null;
|
|
129
|
+
|
|
130
|
+
let ip;
|
|
131
|
+
try {
|
|
132
|
+
if (_garNetMod.isIP(host)) {
|
|
133
|
+
ip = host;
|
|
134
|
+
} else {
|
|
135
|
+
const r = await _garDnsMod.promises.lookup(host, { family: 4 });
|
|
136
|
+
ip = r.address;
|
|
137
|
+
}
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Loopback short-circuit; otherwise check against the host's interface IPs.
|
|
143
|
+
// (Less precise than RTM_GETROUTE used by the C++ side, but covers the
|
|
144
|
+
// practical "is this destination on this machine?" question for our use.)
|
|
145
|
+
if (!ip.startsWith('127.')) {
|
|
146
|
+
if (!_garLocalIPv4Set().has(ip)) return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const abstractPath = '\u0000gar.endpoint.' + port;
|
|
150
|
+
// Reachability probe: AF_UNIX local connect either succeeds immediately or
|
|
151
|
+
// fails immediately with ECONNREFUSED/ENOENT.
|
|
152
|
+
const reachable = await new Promise((resolve) => {
|
|
153
|
+
let done = false;
|
|
154
|
+
const finish = (ok) => {
|
|
155
|
+
if (done) return;
|
|
156
|
+
done = true;
|
|
157
|
+
try { sock.destroy(); } catch { /* ignore */ }
|
|
158
|
+
resolve(ok);
|
|
159
|
+
};
|
|
160
|
+
const sock = _garNetMod.createConnection({ path: abstractPath });
|
|
161
|
+
sock.once('connect', () => finish(true));
|
|
162
|
+
sock.once('error', () => finish(false));
|
|
163
|
+
setTimeout(() => finish(false), 500);
|
|
164
|
+
});
|
|
165
|
+
return reachable ? abstractPath : null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function _garMakeUnixCreateConnectionFn(abstractPath, useSSL, sniHost, allowSelfSigned) {
|
|
169
|
+
return () => {
|
|
170
|
+
const unixSocket = _garNetMod.createConnection({ path: abstractPath });
|
|
171
|
+
if (!useSSL) return unixSocket;
|
|
172
|
+
return _garTlsMod.connect({
|
|
173
|
+
socket: unixSocket,
|
|
174
|
+
servername: sniHost,
|
|
175
|
+
rejectUnauthorized: !allowSelfSigned,
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
27
180
|
class GARClient {
|
|
28
181
|
/**
|
|
29
182
|
* Initialize the GAR client.
|
|
@@ -163,13 +316,37 @@ class GARClient {
|
|
|
163
316
|
const WS = await this._ensureWebSocketCtor();
|
|
164
317
|
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
|
|
165
318
|
|
|
166
|
-
|
|
319
|
+
// Prefer AF_UNIX abstract-namespace transport for local destinations.
|
|
320
|
+
// Falls back to TCP automatically (next reconnect iteration) if the
|
|
321
|
+
// listener disappears between probe and real connect.
|
|
322
|
+
// Skip AF_UNIX for SSL — OpenSSL's non-blocking handshake over
|
|
323
|
+
// AF_UNIX produces sporadic failures.
|
|
324
|
+
const useSSL = this.wsEndpoint.toLowerCase().startsWith('wss://');
|
|
325
|
+
let unixAbstractPath = null;
|
|
326
|
+
let sniHost = null;
|
|
327
|
+
if (isNode && !useSSL) {
|
|
328
|
+
unixAbstractPath = await _garUnixAbstractPathForEndpoint(this.wsEndpoint);
|
|
329
|
+
if (unixAbstractPath) {
|
|
330
|
+
try { sniHost = new URL(this.wsEndpoint).hostname; } catch { /* ignore */ }
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
this.log('INFO', `Connecting to WebSocket server at ${this.wsEndpoint}${unixAbstractPath ? ' (via AF_UNIX)' : ''}`);
|
|
167
335
|
|
|
168
336
|
const connectionPromise = new Promise((resolve, reject) => {
|
|
169
337
|
let websocket;
|
|
170
|
-
|
|
338
|
+
const wsOpts = {};
|
|
339
|
+
if (this.allowSelfSignedCertificate && isNode && useSSL) {
|
|
171
340
|
// Node.js 'ws' supports options for TLS; browsers do not.
|
|
172
|
-
|
|
341
|
+
wsOpts.rejectUnauthorized = false;
|
|
342
|
+
}
|
|
343
|
+
if (unixAbstractPath) {
|
|
344
|
+
wsOpts.createConnection = _garMakeUnixCreateConnectionFn(
|
|
345
|
+
unixAbstractPath, useSSL, sniHost, this.allowSelfSignedCertificate
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (Object.keys(wsOpts).length > 0) {
|
|
349
|
+
websocket = new WS(this.wsEndpoint, ['gar-protocol'], wsOpts);
|
|
173
350
|
} else {
|
|
174
351
|
websocket = new WS(this.wsEndpoint, ['gar-protocol']);
|
|
175
352
|
}
|
|
@@ -1512,3 +1689,4 @@ class GARClient {
|
|
|
1512
1689
|
}
|
|
1513
1690
|
|
|
1514
1691
|
export default GARClient;
|
|
1692
|
+
export { optimalEndpoint };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsgar",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.6.2",
|
|
4
4
|
"description": "A Javascript client for the GAR protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/gar.umd.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"@eslint/json": "^0.13.2",
|
|
37
37
|
"@rollup/plugin-commonjs": "^24.0.0",
|
|
38
38
|
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
39
|
-
"eslint": "^9.
|
|
39
|
+
"eslint": "^9.39.4",
|
|
40
40
|
"globals": "^16.0.0",
|
|
41
41
|
"rollup": "^3.0.0"
|
|
42
42
|
}
|