@hediet/linkrpc 0.0.2 → 0.0.3
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 +141 -3
- package/dist/chunks/{hub.interfaces-Bf4VfWNX.js → hub.interfaces-BWqqhgtT.js} +2 -2
- package/dist/chunks/{hub.interfaces-Bf4VfWNX.js.map → hub.interfaces-BWqqhgtT.js.map} +1 -1
- package/dist/chunks/{hubAccess-C06qAKao.d.ts → hubAccess-DKl7hDrh.d.ts} +2 -2
- package/dist/chunks/{hubAccess-C06qAKao.d.ts.map → hubAccess-DKl7hDrh.d.ts.map} +1 -1
- package/dist/chunks/{hubFacade-DtQpGpUy.d.ts → hubFacade-CLgLIvBa.d.ts} +2 -2
- package/dist/chunks/{hubFacade-DtQpGpUy.d.ts.map → hubFacade-CLgLIvBa.d.ts.map} +1 -1
- package/dist/chunks/{hubFacade-BIB9CoAv.js → hubFacade-rlsBq0ZU.js} +2 -2
- package/dist/chunks/{hubFacade-BIB9CoAv.js.map → hubFacade-rlsBq0ZU.js.map} +1 -1
- package/dist/chunks/{boundedTrafficSubscription-XZ1KwXZC.js → inspectionHost-BA08eF6h.js} +766 -4
- package/dist/chunks/inspectionHost-BA08eF6h.js.map +1 -0
- package/dist/chunks/{linkRpcConnection-BadD37ok.d.ts → linkRpcConnection-C_Gs4nZ9.d.ts} +2061 -1682
- package/dist/chunks/linkRpcConnection-C_Gs4nZ9.d.ts.map +1 -0
- package/dist/chunks/{src-CAhXne71.js → src-BaCs8mWd.js} +2512 -2657
- package/dist/chunks/src-BaCs8mWd.js.map +1 -0
- package/dist/hub/client/index.d.ts +3 -3
- package/dist/hub/client/index.js +3 -3
- package/dist/hub/common/index.d.ts +2 -325
- package/dist/hub/common/index.d.ts.map +1 -1
- package/dist/hub/common/index.js +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/dist/inspection/index.d.ts +87 -2
- package/dist/inspection/index.d.ts.map +1 -1
- package/dist/inspection/index.js +2 -2
- package/dist/node.d.ts +3 -3
- package/dist/node.js +4 -4
- package/dist/web.d.ts +2 -2
- package/dist/web.js +3 -3
- package/package.json +7 -2
- package/dist/chunks/boundedTrafficSubscription-XZ1KwXZC.js.map +0 -1
- package/dist/chunks/linkRpcConnection-BadD37ok.d.ts.map +0 -1
- package/dist/chunks/src-CAhXne71.js.map +0 -1
|
@@ -972,6 +972,135 @@ function interfaceFromSchema(schema) {
|
|
|
972
972
|
return new InterfaceDefinition(info, members, { frozenSchema: schema });
|
|
973
973
|
}
|
|
974
974
|
//#endregion
|
|
975
|
+
//#region src/protocol/jsonRpc.ts
|
|
976
|
+
const ErrorCode = {
|
|
977
|
+
parseError: -32700,
|
|
978
|
+
invalidRequest: -32600,
|
|
979
|
+
methodNotFound: -32601,
|
|
980
|
+
invalidParams: -32602,
|
|
981
|
+
internalError: -32603,
|
|
982
|
+
/** Caller is authenticated but lacks a capability covering the call. */
|
|
983
|
+
permissionRequired: -32401,
|
|
984
|
+
/** The peer a request was routed to detached before it could respond. */
|
|
985
|
+
peerDisconnected: -32402,
|
|
986
|
+
/** The request exceeded the hub's idle timeout with no stream activity. */
|
|
987
|
+
requestTimeout: -32403,
|
|
988
|
+
/** The request was cancelled (by the caller, or by the hub on disconnect). */
|
|
989
|
+
cancelled: -32800
|
|
990
|
+
};
|
|
991
|
+
function isRequest(m) {
|
|
992
|
+
return typeof m.method === "string" && m.id !== void 0;
|
|
993
|
+
}
|
|
994
|
+
function isNotification(m) {
|
|
995
|
+
return typeof m.method === "string" && m.id === void 0;
|
|
996
|
+
}
|
|
997
|
+
function isResponse(m) {
|
|
998
|
+
return typeof m.method !== "string";
|
|
999
|
+
}
|
|
1000
|
+
//#endregion
|
|
1001
|
+
//#region src/crypto/cryptoProvider.ts
|
|
1002
|
+
const _b64UrlAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
1003
|
+
const _b64UrlReverse = (() => {
|
|
1004
|
+
const m = {};
|
|
1005
|
+
for (let i = 0; i < 64; i++) m[_b64UrlAlphabet[i]] = i;
|
|
1006
|
+
return m;
|
|
1007
|
+
})();
|
|
1008
|
+
function bytesToBase64Url(bytes) {
|
|
1009
|
+
let out = "";
|
|
1010
|
+
let i = 0;
|
|
1011
|
+
for (; i + 3 <= bytes.length; i += 3) {
|
|
1012
|
+
const n = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
|
|
1013
|
+
out += _b64UrlAlphabet[n >> 18 & 63] + _b64UrlAlphabet[n >> 12 & 63] + _b64UrlAlphabet[n >> 6 & 63] + _b64UrlAlphabet[n & 63];
|
|
1014
|
+
}
|
|
1015
|
+
const rem = bytes.length - i;
|
|
1016
|
+
if (rem === 1) {
|
|
1017
|
+
const n = bytes[i] << 16;
|
|
1018
|
+
out += _b64UrlAlphabet[n >> 18 & 63] + _b64UrlAlphabet[n >> 12 & 63];
|
|
1019
|
+
} else if (rem === 2) {
|
|
1020
|
+
const n = bytes[i] << 16 | bytes[i + 1] << 8;
|
|
1021
|
+
out += _b64UrlAlphabet[n >> 18 & 63] + _b64UrlAlphabet[n >> 12 & 63] + _b64UrlAlphabet[n >> 6 & 63];
|
|
1022
|
+
}
|
|
1023
|
+
return out;
|
|
1024
|
+
}
|
|
1025
|
+
function base64UrlToBytes(s) {
|
|
1026
|
+
const len = s.length;
|
|
1027
|
+
const fullGroups = Math.floor(len / 4);
|
|
1028
|
+
const rem = len % 4;
|
|
1029
|
+
if (rem === 1) throw new Error("base64UrlToBytes: invalid length");
|
|
1030
|
+
const outLen = fullGroups * 3 + (rem === 0 ? 0 : rem - 1);
|
|
1031
|
+
const out = new Uint8Array(outLen);
|
|
1032
|
+
let oi = 0;
|
|
1033
|
+
let i = 0;
|
|
1034
|
+
for (let g = 0; g < fullGroups; g++, i += 4) {
|
|
1035
|
+
const n = _lookup(s, i) << 18 | _lookup(s, i + 1) << 12 | _lookup(s, i + 2) << 6 | _lookup(s, i + 3);
|
|
1036
|
+
out[oi++] = n >> 16 & 255;
|
|
1037
|
+
out[oi++] = n >> 8 & 255;
|
|
1038
|
+
out[oi++] = n & 255;
|
|
1039
|
+
}
|
|
1040
|
+
if (rem === 2) {
|
|
1041
|
+
const n = _lookup(s, i) << 18 | _lookup(s, i + 1) << 12;
|
|
1042
|
+
out[oi++] = n >> 16 & 255;
|
|
1043
|
+
} else if (rem === 3) {
|
|
1044
|
+
const n = _lookup(s, i) << 18 | _lookup(s, i + 1) << 12 | _lookup(s, i + 2) << 6;
|
|
1045
|
+
out[oi++] = n >> 16 & 255;
|
|
1046
|
+
out[oi++] = n >> 8 & 255;
|
|
1047
|
+
}
|
|
1048
|
+
return out;
|
|
1049
|
+
}
|
|
1050
|
+
function _lookup(s, i) {
|
|
1051
|
+
const v = _b64UrlReverse[s[i]];
|
|
1052
|
+
if (v === void 0) throw new Error(`base64UrlToBytes: invalid char at ${i}`);
|
|
1053
|
+
return v;
|
|
1054
|
+
}
|
|
1055
|
+
/** Role-tag prefix on a {@link KeyId}'s inline-key form. */
|
|
1056
|
+
const KEY_ID_PREFIX = "key:";
|
|
1057
|
+
/** Role-tag prefix that wraps a genesis {@link KeyId} into a {@link PrincipalId}. */
|
|
1058
|
+
const PRINCIPAL_PREFIX = "id:";
|
|
1059
|
+
/** The inline {@link KeyId} for a raw public key: `"key:" + b64url(pk)`. */
|
|
1060
|
+
function keyIdForPublicKey(pk) {
|
|
1061
|
+
return KEY_ID_PREFIX + bytesToBase64Url(pk);
|
|
1062
|
+
}
|
|
1063
|
+
/** The perpetual {@link PrincipalId} for a raw public key: `"id:key:" + b64url(pk)`. */
|
|
1064
|
+
function principalForPublicKey(pk) {
|
|
1065
|
+
return "id:" + keyIdForPublicKey(pk);
|
|
1066
|
+
}
|
|
1067
|
+
/**
|
|
1068
|
+
* The genesis {@link KeyId} embedded in a perpetual {@link PrincipalId}
|
|
1069
|
+
* (`"id:" + keyId`). Throws if `principal` is not a well-formed `id:` name.
|
|
1070
|
+
*/
|
|
1071
|
+
function keyIdForPrincipal(principal) {
|
|
1072
|
+
if (!principal.startsWith("id:")) throw new Error(`malformed principal (missing "id:" prefix): ${principal}`);
|
|
1073
|
+
return principal.slice(3);
|
|
1074
|
+
}
|
|
1075
|
+
/**
|
|
1076
|
+
* The raw public key carried inline by a `"key:"` {@link KeyId}. Throws on a
|
|
1077
|
+
* missing prefix or malformed base64url.
|
|
1078
|
+
*/
|
|
1079
|
+
function publicKeyForKeyId(keyId) {
|
|
1080
|
+
if (!keyId.startsWith("key:")) throw new Error(`unsupported keyId (expected "${KEY_ID_PREFIX}" prefix): ${keyId}`);
|
|
1081
|
+
return base64UrlToBytes(keyId.slice(4));
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Resolve the verifying public key for `(principal, keyId)`, or `undefined`
|
|
1085
|
+
* to **reject** (fail closed). This is the single seam every verifier goes
|
|
1086
|
+
* through, replacing the old "the id *is* the key" decode.
|
|
1087
|
+
*
|
|
1088
|
+
* Phase 1 supports only inline genesis keys: the `keyId` must be a `"key:"`
|
|
1089
|
+
* form and the principal must be exactly `"id:" + keyId` (genesis
|
|
1090
|
+
* self-certification by string equality). `keydoc:`/rotation forms resolve
|
|
1091
|
+
* through `bindings`/`timeMs` later and are intentionally not handled here.
|
|
1092
|
+
*/
|
|
1093
|
+
function resolveSigningKey(args) {
|
|
1094
|
+
const { principal, keyId } = args;
|
|
1095
|
+
if (!keyId.startsWith("key:")) return;
|
|
1096
|
+
if ("id:" + keyId !== principal) return;
|
|
1097
|
+
try {
|
|
1098
|
+
return { publicKey: base64UrlToBytes(keyId.slice(4)) };
|
|
1099
|
+
} catch {
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
//#endregion
|
|
975
1104
|
//#region src/inspection/inspection.interfaces.ts
|
|
976
1105
|
const zTopologyPort = object({
|
|
977
1106
|
portId: string(),
|
|
@@ -1146,6 +1275,142 @@ const nodeInterface = defineInterface({
|
|
|
1146
1275
|
description: "Topology bootstrap: identify the node and port at this end of the direct connection."
|
|
1147
1276
|
}, { getNodeId: requestType(object({}), zNodeInfo) });
|
|
1148
1277
|
//#endregion
|
|
1278
|
+
//#region src/connection/streaming.ts
|
|
1279
|
+
/**
|
|
1280
|
+
* Direction a {@link STREAM_METHOD} message travels, relative to the
|
|
1281
|
+
* request it is correlated with. Made explicit on the wire so that a
|
|
1282
|
+
* middlebox (the hub) can *author* a stream message — e.g. inject a
|
|
1283
|
+
* cancel when a caller disconnects — without an inbound message whose
|
|
1284
|
+
* arrival link it could infer the direction from.
|
|
1285
|
+
*/
|
|
1286
|
+
const StreamDir = {
|
|
1287
|
+
/** callee → caller: progress, partial results. Routes like a response. */
|
|
1288
|
+
toCaller: "toCaller",
|
|
1289
|
+
/** caller → callee: input, cancellation, keepalive ping. */
|
|
1290
|
+
toCallee: "toCallee"
|
|
1291
|
+
};
|
|
1292
|
+
/**
|
|
1293
|
+
* Reserved control verbs. A control message carries no app `payload`; it
|
|
1294
|
+
* is interpreted by the runtime / hub itself, independently of the
|
|
1295
|
+
* originating method's stream schemas, so *any* request is cancellable
|
|
1296
|
+
* and keep-alive-able even when it declares no app stream.
|
|
1297
|
+
*/
|
|
1298
|
+
const StreamControlType = {
|
|
1299
|
+
/**
|
|
1300
|
+
* Ask the callee to abort the in-flight request. Always {@link
|
|
1301
|
+
* StreamDir.toCallee}. The callee surfaces this as an `AbortSignal`
|
|
1302
|
+
* and is expected to settle the request (typically with a
|
|
1303
|
+
* `cancelled` error response).
|
|
1304
|
+
*/
|
|
1305
|
+
cancel: "cancel",
|
|
1306
|
+
/**
|
|
1307
|
+
* Keepalive / liveness probe. Resets the hub's per-request idle timer
|
|
1308
|
+
* so a long-running call is not reaped, and lets either side actively
|
|
1309
|
+
* probe the peer. Carries a `nonce` the peer echoes in its {@link
|
|
1310
|
+
* StreamControlType.pong}. May travel in either direction. Emitted
|
|
1311
|
+
* automatically (without awaiting a pong) by the channel for streaming
|
|
1312
|
+
* calls; see {@link STREAM_METHOD}.
|
|
1313
|
+
*/
|
|
1314
|
+
ping: "ping",
|
|
1315
|
+
/**
|
|
1316
|
+
* Reply to a {@link StreamControlType.ping}, echoing the ping's
|
|
1317
|
+
* `nonce` so the prober can correlate it. Travels opposite the ping.
|
|
1318
|
+
* Carries no app effect — purely a liveness acknowledgement.
|
|
1319
|
+
*/
|
|
1320
|
+
pong: "pong"
|
|
1321
|
+
};
|
|
1322
|
+
/**
|
|
1323
|
+
* Well-known `control.reason` strings. The set is **open** — any string
|
|
1324
|
+
* is valid on the wire; these are the reasons linkrpc itself emits.
|
|
1325
|
+
*/
|
|
1326
|
+
const StreamControlReason = {
|
|
1327
|
+
/**
|
|
1328
|
+
* The caller's transport dropped while the request was in flight; the
|
|
1329
|
+
* hub cancels the callee's now-orphaned work.
|
|
1330
|
+
*/
|
|
1331
|
+
clientDisconnected: "clientDisconnected",
|
|
1332
|
+
/**
|
|
1333
|
+
* The request exceeded the hub's idle timeout with no stream activity
|
|
1334
|
+
* (no ping, no stream message). See {@link STREAM_METHOD} docs.
|
|
1335
|
+
*/
|
|
1336
|
+
idleTimeout: "idleTimeout"
|
|
1337
|
+
};
|
|
1338
|
+
/**
|
|
1339
|
+
* Streaming sub-protocol. Long-running requests can emit additional
|
|
1340
|
+
* notifications correlated with the original call in either direction
|
|
1341
|
+
* (callee → caller progress, caller → callee input / cancellation /
|
|
1342
|
+
* keepalive).
|
|
1343
|
+
*
|
|
1344
|
+
* Wire form: a JSON-RPC notification whose method is
|
|
1345
|
+
* `${streamInterface.info.id}::send` and whose params match
|
|
1346
|
+
* `streamInterface.members.send.paramsSchema`. The hub routes purely on
|
|
1347
|
+
* `requestId` (following the originating request's established path, like
|
|
1348
|
+
* a response); the originating request's capability authorization covers
|
|
1349
|
+
* its full stream lifetime, so stream notifications carry no method /
|
|
1350
|
+
* interface namespace of their own. App `payload` contents are typed per
|
|
1351
|
+
* request via the originating method's
|
|
1352
|
+
* `RequestType.clientStreamSchema` / `serverStreamSchema`; reserved
|
|
1353
|
+
* `control` messages are schema-independent.
|
|
1354
|
+
*
|
|
1355
|
+
* Idle timeout: a request that never streams (no `control` ping, no
|
|
1356
|
+
* stream message) is subject to the hub's per-request idle timeout
|
|
1357
|
+
* (default 30 minutes) — at which point it is cancelled and its caller
|
|
1358
|
+
* gets a `requestTimeout` error. This bounds the hub's pending-request
|
|
1359
|
+
* table, which is also what protects it from a slow-loris / DDoS that
|
|
1360
|
+
* opens requests and never completes them. Streaming-enabled calls keep
|
|
1361
|
+
* themselves alive by emitting a periodic {@link StreamControlType.ping}.
|
|
1362
|
+
*
|
|
1363
|
+
* The interface is declarative: nobody calls
|
|
1364
|
+
* `LinkRpcConnection.register(streamInterface, ...)`. The channel and the
|
|
1365
|
+
* hub intercept `$stream::send` directly. The definition exists so
|
|
1366
|
+
* reflection / consent UIs can describe the wire shape and so all wire
|
|
1367
|
+
* constants derive from one source.
|
|
1368
|
+
*/
|
|
1369
|
+
const streamInterface = defineInterface({
|
|
1370
|
+
id: "$stream",
|
|
1371
|
+
description: "Reserved sub-protocol for in-flight stream messages correlated to a request by `requestId`."
|
|
1372
|
+
}, { send: notificationType(object({
|
|
1373
|
+
/**
|
|
1374
|
+
* Id of the in-flight request the message belongs to.
|
|
1375
|
+
* The hub rewrites this across the forwarding boundary
|
|
1376
|
+
* in the same way it rewrites response ids.
|
|
1377
|
+
*/
|
|
1378
|
+
requestId: union([number(), string()]),
|
|
1379
|
+
/**
|
|
1380
|
+
* Which way this message travels relative to the request.
|
|
1381
|
+
* Explicit so the hub can author messages (e.g. cancel on
|
|
1382
|
+
* disconnect) without inferring direction from arrival.
|
|
1383
|
+
*/
|
|
1384
|
+
dir: enum$1(["toCaller", "toCallee"]),
|
|
1385
|
+
/**
|
|
1386
|
+
* Reserved control verb (cancel / ping / pong). Mutually
|
|
1387
|
+
* exclusive with `payload` in practice: a control message
|
|
1388
|
+
* is interpreted by the runtime, not the application.
|
|
1389
|
+
*/
|
|
1390
|
+
control: optional(object({
|
|
1391
|
+
type: enum$1([
|
|
1392
|
+
"cancel",
|
|
1393
|
+
"ping",
|
|
1394
|
+
"pong"
|
|
1395
|
+
]),
|
|
1396
|
+
/** Open-set human/diagnostic reason; see {@link StreamControlReason}. */
|
|
1397
|
+
reason: optional(string()),
|
|
1398
|
+
/**
|
|
1399
|
+
* Correlation token. A `ping` carries a fresh nonce;
|
|
1400
|
+
* the matching `pong` echoes it back so the prober
|
|
1401
|
+
* can resolve the right outstanding probe.
|
|
1402
|
+
*/
|
|
1403
|
+
nonce: optional(string())
|
|
1404
|
+
})),
|
|
1405
|
+
/** Opaque app payload — typed per call by the request's stream schema. */
|
|
1406
|
+
payload: optional(unknown())
|
|
1407
|
+
}), { description: "Emit a stream message tied to the request `requestId`." }) });
|
|
1408
|
+
/**
|
|
1409
|
+
* Full wire method name for stream notifications. Pulled from the
|
|
1410
|
+
* interface object so we have a single source of truth.
|
|
1411
|
+
*/
|
|
1412
|
+
const STREAM_METHOD = `${streamInterface.info.id}::send`;
|
|
1413
|
+
//#endregion
|
|
1149
1414
|
//#region src/inspection/trafficFlowFilter.ts
|
|
1150
1415
|
var TrafficFlowFilter = class {
|
|
1151
1416
|
_focused;
|
|
@@ -1196,24 +1461,37 @@ var TrafficWatchFlowTracker = class {
|
|
|
1196
1461
|
this._active.clear();
|
|
1197
1462
|
this._unclaimed.clear();
|
|
1198
1463
|
}
|
|
1464
|
+
forgetPort(portId) {
|
|
1465
|
+
for (const flow of this._active) if (flow.hasPort(portId)) this._removeFlow(flow);
|
|
1466
|
+
}
|
|
1199
1467
|
};
|
|
1200
1468
|
var CorrelatedFlow = class {
|
|
1201
1469
|
_endpoints = /* @__PURE__ */ new Set();
|
|
1470
|
+
_ports = /* @__PURE__ */ new Set();
|
|
1202
1471
|
_completionEndpoint;
|
|
1203
1472
|
constructor(endpoints, completionEndpoint = endpoints[0]) {
|
|
1204
|
-
for (const endpoint of endpoints)
|
|
1473
|
+
for (const endpoint of endpoints) {
|
|
1474
|
+
this._endpoints.add(endpointKey(endpoint));
|
|
1475
|
+
this._ports.add(endpoint.portId);
|
|
1476
|
+
}
|
|
1205
1477
|
this._completionEndpoint = completionEndpoint === void 0 ? void 0 : endpointKey(completionEndpoint);
|
|
1206
1478
|
}
|
|
1207
1479
|
matches(transit) {
|
|
1208
1480
|
return requestRefsOf(transit).some((endpoint) => this._endpoints.has(endpointKey(endpoint)));
|
|
1209
1481
|
}
|
|
1482
|
+
hasPort(portId) {
|
|
1483
|
+
return this._ports.has(portId);
|
|
1484
|
+
}
|
|
1210
1485
|
accept(transit) {
|
|
1211
1486
|
const endpoints = requestRefsOf(transit);
|
|
1212
1487
|
if (!this.matches(transit)) return {
|
|
1213
1488
|
matches: false,
|
|
1214
1489
|
completed: false
|
|
1215
1490
|
};
|
|
1216
|
-
for (const endpoint of endpoints)
|
|
1491
|
+
for (const endpoint of endpoints) {
|
|
1492
|
+
this._endpoints.add(endpointKey(endpoint));
|
|
1493
|
+
this._ports.add(endpoint.portId);
|
|
1494
|
+
}
|
|
1217
1495
|
const completed = transit.kind === "response" && (isTerminal(transit) || this._completionEndpoint !== void 0 && endpoints.some((endpoint) => endpointKey(endpoint) === this._completionEndpoint));
|
|
1218
1496
|
if (completed) this._endpoints.clear();
|
|
1219
1497
|
return {
|
|
@@ -1382,6 +1660,490 @@ function capPayload(value, maxBytes) {
|
|
|
1382
1660
|
return preview;
|
|
1383
1661
|
}
|
|
1384
1662
|
//#endregion
|
|
1385
|
-
|
|
1663
|
+
//#region src/inspection/endpointTrafficInspector.ts
|
|
1664
|
+
const REQUEST_CORRELATION_RETENTION_MS = 18e5;
|
|
1665
|
+
const MAX_REQUEST_CORRELATIONS = 4096;
|
|
1666
|
+
var EndpointTrafficInspector = class {
|
|
1667
|
+
_nodeId;
|
|
1668
|
+
_portId;
|
|
1669
|
+
_emit;
|
|
1670
|
+
_isObserved;
|
|
1671
|
+
_outboundRequests = /* @__PURE__ */ new Map();
|
|
1672
|
+
_inboundRequests = /* @__PURE__ */ new Map();
|
|
1673
|
+
observe = (direction, message) => {
|
|
1674
|
+
this._onMessage(direction, message);
|
|
1675
|
+
};
|
|
1676
|
+
constructor(_nodeId, _portId, _emit, _isObserved) {
|
|
1677
|
+
this._nodeId = _nodeId;
|
|
1678
|
+
this._portId = _portId;
|
|
1679
|
+
this._emit = _emit;
|
|
1680
|
+
this._isObserved = _isObserved;
|
|
1681
|
+
}
|
|
1682
|
+
dispose() {
|
|
1683
|
+
this._outboundRequests.clear();
|
|
1684
|
+
this._inboundRequests.clear();
|
|
1685
|
+
}
|
|
1686
|
+
_onMessage(direction, message) {
|
|
1687
|
+
const now = Date.now();
|
|
1688
|
+
this._pruneRequestCorrelations(now);
|
|
1689
|
+
const publiclyObserved = this._isObserved();
|
|
1690
|
+
if (!publiclyObserved) this.dispose();
|
|
1691
|
+
let transit;
|
|
1692
|
+
const endpoint = this._endpoint("id" in message ? message.id ?? void 0 : void 0);
|
|
1693
|
+
const base = {
|
|
1694
|
+
type: "transit",
|
|
1695
|
+
timeMs: now,
|
|
1696
|
+
nodeId: this._nodeId,
|
|
1697
|
+
...direction === "inbound" ? { in: endpoint } : { out: endpoint },
|
|
1698
|
+
disposition: direction === "inbound" ? "consumed" : "forwarded"
|
|
1699
|
+
};
|
|
1700
|
+
if (isRequest(message)) {
|
|
1701
|
+
const correlation = {
|
|
1702
|
+
method: message.method,
|
|
1703
|
+
timeMs: now
|
|
1704
|
+
};
|
|
1705
|
+
if (publiclyObserved) {
|
|
1706
|
+
const map = this._requestMap(direction);
|
|
1707
|
+
const key = requestKey(message.id);
|
|
1708
|
+
map.delete(key);
|
|
1709
|
+
map.set(key, correlation);
|
|
1710
|
+
}
|
|
1711
|
+
transit = {
|
|
1712
|
+
...base,
|
|
1713
|
+
kind: "request",
|
|
1714
|
+
method: message.method,
|
|
1715
|
+
params: message.params
|
|
1716
|
+
};
|
|
1717
|
+
} else if (isResponse(message)) {
|
|
1718
|
+
const responseMap = direction === "inbound" ? this._outboundRequests : this._inboundRequests;
|
|
1719
|
+
const key = requestKey(message.id);
|
|
1720
|
+
const correlation = responseMap.get(key);
|
|
1721
|
+
responseMap.delete(key);
|
|
1722
|
+
transit = {
|
|
1723
|
+
...base,
|
|
1724
|
+
kind: "response",
|
|
1725
|
+
method: correlation?.method,
|
|
1726
|
+
result: "result" in message ? message.result : void 0,
|
|
1727
|
+
error: "error" in message ? message.error : void 0
|
|
1728
|
+
};
|
|
1729
|
+
} else if (isNotification(message) && message.method === STREAM_METHOD) {
|
|
1730
|
+
const params = message.params;
|
|
1731
|
+
const streamEndpoint = this._endpoint(params?.requestId);
|
|
1732
|
+
transit = {
|
|
1733
|
+
...base,
|
|
1734
|
+
...direction === "inbound" ? { in: streamEndpoint } : { out: streamEndpoint },
|
|
1735
|
+
kind: "stream",
|
|
1736
|
+
method: STREAM_METHOD,
|
|
1737
|
+
params: message.params
|
|
1738
|
+
};
|
|
1739
|
+
} else transit = {
|
|
1740
|
+
...base,
|
|
1741
|
+
kind: "notification",
|
|
1742
|
+
method: message.method,
|
|
1743
|
+
params: message.params
|
|
1744
|
+
};
|
|
1745
|
+
function requestKey(requestId) {
|
|
1746
|
+
return JSON.stringify([typeof requestId, requestId]);
|
|
1747
|
+
}
|
|
1748
|
+
this._emit(transit);
|
|
1749
|
+
}
|
|
1750
|
+
_requestMap(direction) {
|
|
1751
|
+
return direction === "outbound" ? this._outboundRequests : this._inboundRequests;
|
|
1752
|
+
}
|
|
1753
|
+
_endpoint(requestId) {
|
|
1754
|
+
return {
|
|
1755
|
+
edgeId: this._portId,
|
|
1756
|
+
portId: this._portId,
|
|
1757
|
+
...requestId !== void 0 ? { requestId } : {}
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
_pruneRequestCorrelations(timeMs) {
|
|
1761
|
+
this._pruneRequestMap(this._outboundRequests, timeMs);
|
|
1762
|
+
this._pruneRequestMap(this._inboundRequests, timeMs);
|
|
1763
|
+
}
|
|
1764
|
+
_pruneRequestMap(map, timeMs) {
|
|
1765
|
+
while (map.size !== 0) {
|
|
1766
|
+
const first = map.entries().next().value;
|
|
1767
|
+
if (first === void 0 || map.size <= MAX_REQUEST_CORRELATIONS && timeMs - first[1].timeMs <= REQUEST_CORRELATION_RETENTION_MS) return;
|
|
1768
|
+
map.delete(first[0]);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
};
|
|
1772
|
+
//#endregion
|
|
1773
|
+
//#region src/inspection/connectionInspectionSource.ts
|
|
1774
|
+
var ConnectionInspectionSource = class {
|
|
1775
|
+
_connection;
|
|
1776
|
+
_nodeId;
|
|
1777
|
+
_options;
|
|
1778
|
+
_isObserved;
|
|
1779
|
+
constructor(_connection, _nodeId, _options, _isObserved) {
|
|
1780
|
+
this._connection = _connection;
|
|
1781
|
+
this._nodeId = _nodeId;
|
|
1782
|
+
this._options = _options;
|
|
1783
|
+
this._isObserved = _isObserved;
|
|
1784
|
+
}
|
|
1785
|
+
snapshotTopology() {
|
|
1786
|
+
const { portId, label, peer, transport } = this._options;
|
|
1787
|
+
const nodes = [{
|
|
1788
|
+
nodeId: this._nodeId,
|
|
1789
|
+
ports: [{
|
|
1790
|
+
portId,
|
|
1791
|
+
...label === void 0 ? {} : { label }
|
|
1792
|
+
}]
|
|
1793
|
+
}];
|
|
1794
|
+
const links = [];
|
|
1795
|
+
if (peer !== void 0) {
|
|
1796
|
+
nodes.push({
|
|
1797
|
+
nodeId: peer.nodeId,
|
|
1798
|
+
kind: "endpoint",
|
|
1799
|
+
...peer.label === void 0 ? {} : { label: peer.label },
|
|
1800
|
+
ports: [{ portId: peer.portId }]
|
|
1801
|
+
});
|
|
1802
|
+
links.push({
|
|
1803
|
+
from: {
|
|
1804
|
+
nodeId: this._nodeId,
|
|
1805
|
+
portId
|
|
1806
|
+
},
|
|
1807
|
+
to: {
|
|
1808
|
+
nodeId: peer.nodeId,
|
|
1809
|
+
portId: peer.portId
|
|
1810
|
+
},
|
|
1811
|
+
peerState: "identified",
|
|
1812
|
+
...transport === void 0 ? {} : { transport }
|
|
1813
|
+
});
|
|
1814
|
+
}
|
|
1815
|
+
return {
|
|
1816
|
+
nodes,
|
|
1817
|
+
links,
|
|
1818
|
+
routes: []
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
onTopologyChanged(_listener) {
|
|
1822
|
+
return { dispose: () => {} };
|
|
1823
|
+
}
|
|
1824
|
+
observeTraffic(listener) {
|
|
1825
|
+
const inspector = new EndpointTrafficInspector(this._nodeId, this._options.portId, listener, this._isObserved);
|
|
1826
|
+
const observation = this._connection.observeWireMessages(inspector.observe);
|
|
1827
|
+
return { dispose: () => {
|
|
1828
|
+
observation.dispose();
|
|
1829
|
+
inspector.dispose();
|
|
1830
|
+
} };
|
|
1831
|
+
}
|
|
1832
|
+
};
|
|
1833
|
+
//#endregion
|
|
1834
|
+
//#region src/inspection/inspectionHost.ts
|
|
1835
|
+
/** A shared inspection scope, independent of both routing and its RPC connections. */
|
|
1836
|
+
var InspectionHost = class {
|
|
1837
|
+
_options;
|
|
1838
|
+
_sources = /* @__PURE__ */ new Map();
|
|
1839
|
+
_trackedConnections = /* @__PURE__ */ new Set();
|
|
1840
|
+
_bindings = /* @__PURE__ */ new Set();
|
|
1841
|
+
_subscribers = /* @__PURE__ */ new Set();
|
|
1842
|
+
_observers = /* @__PURE__ */ new Set();
|
|
1843
|
+
_topologyListeners = /* @__PURE__ */ new Set();
|
|
1844
|
+
_trafficSources = /* @__PURE__ */ new Set();
|
|
1845
|
+
_trafficWatches = new TrafficWatchFlowTracker();
|
|
1846
|
+
_disposed = false;
|
|
1847
|
+
nodeId;
|
|
1848
|
+
constructor(_options) {
|
|
1849
|
+
this._options = _options;
|
|
1850
|
+
this.nodeId = _options.nodeId;
|
|
1851
|
+
}
|
|
1852
|
+
get observerCount() {
|
|
1853
|
+
return this._subscribers.size + this._observers.size;
|
|
1854
|
+
}
|
|
1855
|
+
addSource(source) {
|
|
1856
|
+
this._assertActive();
|
|
1857
|
+
if (this._sources.has(source)) throw new Error("Inspection source is already registered");
|
|
1858
|
+
const readPorts = () => new Set(source.snapshotTopology().nodes.flatMap((node) => node.ports.map((port) => port.portId)));
|
|
1859
|
+
let ports = readPorts();
|
|
1860
|
+
const topology = source.onTopologyChanged(() => {
|
|
1861
|
+
const nextPorts = readPorts();
|
|
1862
|
+
const removed = [...ports].filter((port) => !nextPorts.has(port));
|
|
1863
|
+
ports = nextPorts;
|
|
1864
|
+
this._forgetUnusedPorts(removed);
|
|
1865
|
+
this._invalidateTopology();
|
|
1866
|
+
});
|
|
1867
|
+
let traffic;
|
|
1868
|
+
try {
|
|
1869
|
+
traffic = source.observeTraffic((event) => this.publishTransit(event));
|
|
1870
|
+
} catch (error) {
|
|
1871
|
+
topology.dispose();
|
|
1872
|
+
throw error;
|
|
1873
|
+
}
|
|
1874
|
+
const registration = { dispose: () => {
|
|
1875
|
+
if (this._sources.get(source) !== registration) return;
|
|
1876
|
+
this._sources.delete(source);
|
|
1877
|
+
topology.dispose();
|
|
1878
|
+
traffic.dispose();
|
|
1879
|
+
this._forgetUnusedPorts([...ports]);
|
|
1880
|
+
this._invalidateTopology();
|
|
1881
|
+
} };
|
|
1882
|
+
this._sources.set(source, registration);
|
|
1883
|
+
this._invalidateTopology();
|
|
1884
|
+
return registration;
|
|
1885
|
+
}
|
|
1886
|
+
trackConnection(connection, options) {
|
|
1887
|
+
this._assertActive();
|
|
1888
|
+
if (this.getGraph("").nodes.some((node) => node.ports.some((port) => port.portId === options.portId))) throw new Error(`Inspection port "${options.portId}" is already registered`);
|
|
1889
|
+
const source = new ConnectionInspectionSource(connection, this.nodeId, options, () => this.observerCount !== 0);
|
|
1890
|
+
const registration = this.addSource(source);
|
|
1891
|
+
let close;
|
|
1892
|
+
try {
|
|
1893
|
+
close = connection.onDidClose(() => result.dispose());
|
|
1894
|
+
} catch (error) {
|
|
1895
|
+
registration.dispose();
|
|
1896
|
+
throw error;
|
|
1897
|
+
}
|
|
1898
|
+
const result = { dispose: () => {
|
|
1899
|
+
this._trackedConnections.delete(result);
|
|
1900
|
+
close.dispose();
|
|
1901
|
+
registration.dispose();
|
|
1902
|
+
} };
|
|
1903
|
+
this._trackedConnections.add(result);
|
|
1904
|
+
return result;
|
|
1905
|
+
}
|
|
1906
|
+
expose(connection, options) {
|
|
1907
|
+
this._assertActive();
|
|
1908
|
+
const portId = options.portId ?? createPortId();
|
|
1909
|
+
const binding = new InspectionBinding(portId);
|
|
1910
|
+
const registrations = [];
|
|
1911
|
+
this._bindings.add(binding);
|
|
1912
|
+
const registerOptions = { serviceId: options.serviceId };
|
|
1913
|
+
try {
|
|
1914
|
+
const controls = new EndpointTrafficInspector(this.nodeId, portId, (event) => this._trafficWatches.accept(event), () => false);
|
|
1915
|
+
registrations.push(connection.observeWireMessages(controls.observe));
|
|
1916
|
+
registrations.push({ dispose: () => controls.dispose() });
|
|
1917
|
+
registrations.push(connection.registerInspection(nodeInterface, { getNodeId: () => ({
|
|
1918
|
+
nodeId: this.nodeId,
|
|
1919
|
+
portId,
|
|
1920
|
+
...(options.descriptors ?? this._options.descriptors) === void 0 ? {} : { descriptors: [...options.descriptors ?? this._options.descriptors ?? []] }
|
|
1921
|
+
}) }, registerOptions));
|
|
1922
|
+
registrations.push(connection.registerInspection(topologyInterface, {
|
|
1923
|
+
getGraph: () => this.getGraph(options.serviceId, options.includeRoute === false ? void 0 : portId),
|
|
1924
|
+
watchGraph: (_params, _ctx, stream) => this._watchGraph(binding, stream)
|
|
1925
|
+
}, registerOptions));
|
|
1926
|
+
registrations.push(connection.registerInspection(trafficInterface, {
|
|
1927
|
+
watch: (params, _ctx, stream) => this._watchTraffic(binding, params, stream),
|
|
1928
|
+
watchWithPayloads: (params, _ctx, stream) => this._watchTraffic(binding, params, stream)
|
|
1929
|
+
}, registerOptions));
|
|
1930
|
+
} catch (error) {
|
|
1931
|
+
for (const registration of registrations.reverse()) registration.dispose();
|
|
1932
|
+
this._bindings.delete(binding);
|
|
1933
|
+
throw error;
|
|
1934
|
+
}
|
|
1935
|
+
binding.onDispose = () => {
|
|
1936
|
+
this._bindings.delete(binding);
|
|
1937
|
+
for (const registration of registrations.reverse()) registration.dispose();
|
|
1938
|
+
this._forgetUnusedPorts([portId]);
|
|
1939
|
+
this._invalidateTopology();
|
|
1940
|
+
};
|
|
1941
|
+
registrations.push(connection.onDidClose(() => binding.dispose()));
|
|
1942
|
+
this._invalidateTopology();
|
|
1943
|
+
return binding;
|
|
1944
|
+
}
|
|
1945
|
+
getGraph(observerServiceId, routePortId) {
|
|
1946
|
+
this._assertActive();
|
|
1947
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
1948
|
+
const mergeNode = (node) => {
|
|
1949
|
+
const previous = nodes.get(node.nodeId);
|
|
1950
|
+
const ports = new Map(previous?.ports.map((port) => [port.portId, port]));
|
|
1951
|
+
for (const port of node.ports) ports.set(port.portId, {
|
|
1952
|
+
...ports.get(port.portId),
|
|
1953
|
+
...port
|
|
1954
|
+
});
|
|
1955
|
+
nodes.set(node.nodeId, {
|
|
1956
|
+
...previous,
|
|
1957
|
+
...node,
|
|
1958
|
+
ports: [...ports.values()]
|
|
1959
|
+
});
|
|
1960
|
+
};
|
|
1961
|
+
mergeNode({
|
|
1962
|
+
nodeId: this.nodeId,
|
|
1963
|
+
kind: this._options.kind ?? "endpoint",
|
|
1964
|
+
...this._options.label === void 0 ? {} : { label: this._options.label },
|
|
1965
|
+
...this._options.descriptors === void 0 ? {} : { descriptors: [...this._options.descriptors] },
|
|
1966
|
+
ports: []
|
|
1967
|
+
});
|
|
1968
|
+
const links = [];
|
|
1969
|
+
const routes = [];
|
|
1970
|
+
for (const source of this._sources.keys()) {
|
|
1971
|
+
const fragment = source.snapshotTopology();
|
|
1972
|
+
for (const node of fragment.nodes) mergeNode(node);
|
|
1973
|
+
links.push(...fragment.links);
|
|
1974
|
+
routes.push(...fragment.routes);
|
|
1975
|
+
}
|
|
1976
|
+
for (const binding of this._bindings) mergeNode({
|
|
1977
|
+
nodeId: this.nodeId,
|
|
1978
|
+
ports: [{ portId: binding.portId }]
|
|
1979
|
+
});
|
|
1980
|
+
if (routePortId !== void 0) routes.push({
|
|
1981
|
+
serviceId: observerServiceId,
|
|
1982
|
+
nodeId: this.nodeId,
|
|
1983
|
+
portId: routePortId,
|
|
1984
|
+
match: "exact"
|
|
1985
|
+
});
|
|
1986
|
+
return {
|
|
1987
|
+
observerServiceId,
|
|
1988
|
+
entryNodeId: this.nodeId,
|
|
1989
|
+
nodes: [...nodes.values()],
|
|
1990
|
+
links,
|
|
1991
|
+
routes
|
|
1992
|
+
};
|
|
1993
|
+
}
|
|
1994
|
+
publishTransit(event) {
|
|
1995
|
+
if (this._disposed || this._trafficWatches.accept(event)) return;
|
|
1996
|
+
for (const observer of [...this._observers]) try {
|
|
1997
|
+
observer(event);
|
|
1998
|
+
} catch {}
|
|
1999
|
+
for (const subscriber of this._subscribers) subscriber.enqueue(event);
|
|
2000
|
+
}
|
|
2001
|
+
subscribe(options, send) {
|
|
2002
|
+
this._assertActive();
|
|
2003
|
+
if (options.trafficIgnoreKey !== void 0 && !this._trafficWatches.claim(options.trafficIgnoreKey)) throw new Error("Traffic watch request was not observed before subscription");
|
|
2004
|
+
const subscriber = new BoundedTrafficSubscription(options, send, () => {
|
|
2005
|
+
this._subscribers.delete(subscriber);
|
|
2006
|
+
this._stopUnusedTrafficSources();
|
|
2007
|
+
});
|
|
2008
|
+
this._subscribers.add(subscriber);
|
|
2009
|
+
try {
|
|
2010
|
+
this._startTrafficSources();
|
|
2011
|
+
} catch (error) {
|
|
2012
|
+
subscriber.dispose();
|
|
2013
|
+
throw error;
|
|
2014
|
+
}
|
|
2015
|
+
return subscriber;
|
|
2016
|
+
}
|
|
2017
|
+
observeTraffic(observer) {
|
|
2018
|
+
this._assertActive();
|
|
2019
|
+
this._observers.add(observer);
|
|
2020
|
+
const registration = { dispose: () => {
|
|
2021
|
+
this._observers.delete(observer);
|
|
2022
|
+
this._stopUnusedTrafficSources();
|
|
2023
|
+
} };
|
|
2024
|
+
try {
|
|
2025
|
+
this._startTrafficSources();
|
|
2026
|
+
} catch (error) {
|
|
2027
|
+
registration.dispose();
|
|
2028
|
+
throw error;
|
|
2029
|
+
}
|
|
2030
|
+
return registration;
|
|
2031
|
+
}
|
|
2032
|
+
addTrafficSource(source) {
|
|
2033
|
+
this._assertActive();
|
|
2034
|
+
const entry = { source };
|
|
2035
|
+
this._trafficSources.add(entry);
|
|
2036
|
+
try {
|
|
2037
|
+
this._startTrafficSources();
|
|
2038
|
+
} catch (error) {
|
|
2039
|
+
this._trafficSources.delete(entry);
|
|
2040
|
+
throw error;
|
|
2041
|
+
}
|
|
2042
|
+
return { dispose: () => {
|
|
2043
|
+
this._trafficSources.delete(entry);
|
|
2044
|
+
entry.observation?.dispose();
|
|
2045
|
+
entry.observation = void 0;
|
|
2046
|
+
} };
|
|
2047
|
+
}
|
|
2048
|
+
dispose() {
|
|
2049
|
+
if (this._disposed) return;
|
|
2050
|
+
this._disposed = true;
|
|
2051
|
+
for (const binding of [...this._bindings]) binding.dispose();
|
|
2052
|
+
for (const subscriber of [...this._subscribers]) subscriber.dispose();
|
|
2053
|
+
this._observers.clear();
|
|
2054
|
+
this._stopUnusedTrafficSources();
|
|
2055
|
+
this._trafficSources.clear();
|
|
2056
|
+
for (const connection of [...this._trackedConnections]) connection.dispose();
|
|
2057
|
+
for (const source of [...this._sources.values()]) source.dispose();
|
|
2058
|
+
this._topologyListeners.clear();
|
|
2059
|
+
this._trafficWatches.clear();
|
|
2060
|
+
}
|
|
2061
|
+
_startTrafficSources() {
|
|
2062
|
+
if (this.observerCount === 0) return;
|
|
2063
|
+
for (const entry of this._trafficSources) entry.observation ??= entry.source.observe((event) => this.publishTransit(event));
|
|
2064
|
+
}
|
|
2065
|
+
_stopUnusedTrafficSources() {
|
|
2066
|
+
if (this.observerCount !== 0) return;
|
|
2067
|
+
for (const entry of this._trafficSources) {
|
|
2068
|
+
entry.observation?.dispose();
|
|
2069
|
+
entry.observation = void 0;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
_invalidateTopology() {
|
|
2073
|
+
if (this._disposed) return;
|
|
2074
|
+
for (const listener of this._topologyListeners) listener();
|
|
2075
|
+
}
|
|
2076
|
+
_forgetUnusedPorts(portIds) {
|
|
2077
|
+
if (this._disposed) return;
|
|
2078
|
+
const remaining = new Set(this.getGraph("").nodes.flatMap((node) => node.ports.map((port) => port.portId)));
|
|
2079
|
+
for (const portId of portIds) if (!remaining.has(portId)) this._trafficWatches.forgetPort(portId);
|
|
2080
|
+
}
|
|
2081
|
+
_watchGraph(binding, stream) {
|
|
2082
|
+
return new Promise((resolve, reject) => {
|
|
2083
|
+
let pending = false;
|
|
2084
|
+
let active = true;
|
|
2085
|
+
const finish = () => {
|
|
2086
|
+
active = false;
|
|
2087
|
+
this._topologyListeners.delete(invalidate);
|
|
2088
|
+
stream.signal.removeEventListener("abort", finish);
|
|
2089
|
+
binding.abort.signal.removeEventListener("abort", finish);
|
|
2090
|
+
resolve({});
|
|
2091
|
+
};
|
|
2092
|
+
const invalidate = () => {
|
|
2093
|
+
if (pending || !active) return;
|
|
2094
|
+
pending = true;
|
|
2095
|
+
queueMicrotask(() => {
|
|
2096
|
+
pending = false;
|
|
2097
|
+
if (!active) return;
|
|
2098
|
+
stream.send({}).catch((error) => {
|
|
2099
|
+
reject(error);
|
|
2100
|
+
finish();
|
|
2101
|
+
});
|
|
2102
|
+
});
|
|
2103
|
+
};
|
|
2104
|
+
this._topologyListeners.add(invalidate);
|
|
2105
|
+
stream.signal.addEventListener("abort", finish, { once: true });
|
|
2106
|
+
binding.abort.signal.addEventListener("abort", finish, { once: true });
|
|
2107
|
+
if (stream.signal.aborted || binding.abort.signal.aborted) finish();
|
|
2108
|
+
});
|
|
2109
|
+
}
|
|
2110
|
+
async _watchTraffic(binding, options, stream) {
|
|
2111
|
+
const subscription = this.subscribe(options, (event) => stream.send(event));
|
|
2112
|
+
const dispose = () => subscription.dispose();
|
|
2113
|
+
stream.signal.addEventListener("abort", dispose, { once: true });
|
|
2114
|
+
binding.abort.signal.addEventListener("abort", dispose, { once: true });
|
|
2115
|
+
if (stream.signal.aborted || binding.abort.signal.aborted) dispose();
|
|
2116
|
+
try {
|
|
2117
|
+
return await subscription.closed;
|
|
2118
|
+
} finally {
|
|
2119
|
+
stream.signal.removeEventListener("abort", dispose);
|
|
2120
|
+
binding.abort.signal.removeEventListener("abort", dispose);
|
|
2121
|
+
subscription.dispose();
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
_assertActive() {
|
|
2125
|
+
if (this._disposed) throw new Error("Inspection host is disposed");
|
|
2126
|
+
}
|
|
2127
|
+
};
|
|
2128
|
+
var InspectionBinding = class {
|
|
2129
|
+
portId;
|
|
2130
|
+
abort = new AbortController();
|
|
2131
|
+
onDispose = () => {};
|
|
2132
|
+
constructor(portId) {
|
|
2133
|
+
this.portId = portId;
|
|
2134
|
+
}
|
|
2135
|
+
dispose() {
|
|
2136
|
+
if (this.abort.signal.aborted) return;
|
|
2137
|
+
this.abort.abort();
|
|
2138
|
+
this.onDispose();
|
|
2139
|
+
}
|
|
2140
|
+
};
|
|
2141
|
+
function createPortId() {
|
|
2142
|
+
const bytes = /* @__PURE__ */ new Uint8Array(16);
|
|
2143
|
+
globalThis.crypto.getRandomValues(bytes);
|
|
2144
|
+
return `port:${bytesToBase64Url(bytes)}`;
|
|
2145
|
+
}
|
|
2146
|
+
//#endregion
|
|
2147
|
+
export { jcsCanonicalize as $, PRINCIPAL_PREFIX as A, isRequest as B, zTopologyTransportInfo as C, zTrafficTransitEvent as D, zTrafficTransitEndpoint as E, principalForPublicKey as F, createSchemaToZod as G, InterfaceDefinition as H, publicKeyForKeyId as I, componentSchemaName as J, schemaToZod as K, resolveSigningKey as L, bytesToBase64Url as M, keyIdForPrincipal as N, zTrafficWatchResult as O, keyIdForPublicKey as P, sha256 as Q, ErrorCode as R, zTopologyTransportEndpoint as S, zTrafficOverflowEvent as T, defineInterface as U, isResponse as V, interfaceFromSchema as W, EXTENSION_PREFIX as X, componentSchemaRef as Y, computeInterfaceHash as Z, zTopologyGraph as _, TrafficWatchFlowTracker as a, notificationType as at, zTopologyNode as b, StreamControlType as c, normalizeJsonSchema as ct, nodeInterface as d, jcsCanonicalizeBytes as et, topologyInterface as f, zRouteClaim as g, zParticipantDescriptorSource as h, TrafficFlowFilter as i, isApplicationErrorValue as it, base64UrlToBytes as j, KEY_ID_PREFIX as k, StreamDir as l, zParticipantDescriptor as m, ConnectionInspectionSource as n, RequestType as nt, STREAM_METHOD as o, requestType as ot, trafficInterface as p, assertSchemaReferences as q, BoundedTrafficSubscription as r, applicationError as rt, StreamControlReason as s, zodToSvcJsonSchema as st, InspectionHost as t, NotificationType as tt, streamInterface as u, zTopologyLink as v, zTrafficEvent as w, zTopologyPort as x, zTopologyLinkEndpoint as y, isNotification as z };
|
|
1386
2148
|
|
|
1387
|
-
//# sourceMappingURL=
|
|
2149
|
+
//# sourceMappingURL=inspectionHost-BA08eF6h.js.map
|