@floegence/flowersec-core 3.2.1 → 5.0.0
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 +57 -200
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/dist/browser/index.d.ts +0 -5
- package/dist/browser/index.js +0 -3
- package/dist/cli.js +93 -64
- package/dist/facade.d.ts +0 -17
- package/dist/facade.js +0 -11
- package/dist/generated/unicode151.d.ts +2 -0
- package/dist/generated/unicode151.js +83 -0
- package/dist/interop/proxyServerPeer.js +34 -20
- package/dist/interop/serverParityPeer.js +11 -252
- package/dist/node/acceptor.d.ts +1 -57
- package/dist/node/acceptor.js +3 -420
- package/dist/node/acceptorV3.js +2 -2
- package/dist/node/connectSessionV3.js +2 -2
- package/dist/node/index.d.ts +2 -17
- package/dist/node/index.js +1 -9
- package/dist/node/nativeTransportAddon.d.ts +7 -36
- package/dist/node/nativeTransportAddon.js +7 -27
- package/dist/node/proxyServer.d.ts +2 -2
- package/dist/node/proxyServer.js +2 -2
- package/dist/node/rawQuicAdapterV3.d.ts +2 -2
- package/dist/node/rawQuicAdapterV3.js +1 -1
- package/dist/node/rawQuicServerV3.d.ts +2 -2
- package/dist/node/rawQuicServerV3.js +1 -1
- package/dist/node/rawQuicTls.d.ts +2 -0
- package/dist/node/{rawQuicAdapter.js → rawQuicTls.js} +30 -45
- package/dist/node/tunnelRuntimeV3.js +2 -2
- package/dist/proxy/index.d.ts +1 -1
- package/dist/proxy/index.js +1 -1
- package/dist/proxy/integration.d.ts +5 -5
- package/dist/proxy/integration.js +2 -2
- package/dist/proxy/runtime.js +11 -26
- package/dist/proxy/serviceWorkerRuntime.d.ts +7 -0
- package/dist/proxy/serviceWorkerRuntime.js +75 -0
- package/dist/proxy/types.d.ts +0 -1
- package/dist/proxy/windowBridge.d.ts +2 -0
- package/dist/proxy/windowBridge.js +53 -6
- package/dist/public/contract.d.ts +1 -3
- package/dist/public/streamHandlers.d.ts +0 -3
- package/dist/public/streamHandlers.js +2 -4
- package/dist/public/streamMetadata.js +2 -2
- package/dist/runtime/errors.d.ts +2 -2
- package/dist/testSupport/tlsFixture.d.ts +2 -0
- package/dist/testSupport/tlsFixture.js +8 -0
- package/dist/utils/errors.d.ts +0 -2
- package/dist/utils/errors.js +0 -80
- package/dist/v3/artifact.js +17 -3
- package/dist/v3/carrier.d.ts +2 -2
- package/dist/v3/controller.js +2 -6
- package/dist/v3/protocol.js +2 -103
- package/dist/v3/retryDisposition.d.ts +2 -2
- package/dist/v3/retryDisposition.js +0 -7
- package/dist/v3/security.d.ts +1 -10
- package/dist/v3/security.js +2 -9
- package/dist/vendor/tr46.d.ts +4 -0
- package/dist/vendor/tr46.js +37 -32
- package/package.json +19 -17
- package/sbom/cyclonedx.json +62 -62
- package/sbom/spdx.json +65 -65
- package/dist/browser/connectSession.d.ts +0 -13
- package/dist/browser/connectSession.js +0 -40
- package/dist/browser/runtimeCapability.d.ts +0 -13
- package/dist/browser/runtimeCapability.js +0 -27
- package/dist/browser/sessionRuntime.d.ts +0 -2
- package/dist/browser/sessionRuntime.js +0 -21
- package/dist/browser/v2.d.ts +0 -3
- package/dist/browser/v2.js +0 -2
- package/dist/browser/webTransportClient.d.ts +0 -8
- package/dist/browser/webTransportClient.js +0 -55
- package/dist/connectionController.d.ts +0 -55
- package/dist/connectionController.js +0 -441
- package/dist/connector/adapters/rawQuicCandidate.d.ts +0 -5
- package/dist/connector/adapters/rawQuicCandidate.js +0 -71
- package/dist/connector/adapters/webSocketCandidate.d.ts +0 -7
- package/dist/connector/adapters/webSocketCandidate.js +0 -116
- package/dist/connector/adapters/webTransportCandidate.d.ts +0 -5
- package/dist/connector/adapters/webTransportCandidate.js +0 -73
- package/dist/connector/admissionCommit.d.ts +0 -31
- package/dist/connector/admissionCommit.js +0 -239
- package/dist/connector/sessionAcceptor.d.ts +0 -38
- package/dist/connector/sessionAcceptor.js +0 -158
- package/dist/connector/sessionConfig.d.ts +0 -3
- package/dist/connector/sessionConfig.js +0 -30
- package/dist/connector/sessionConnector.d.ts +0 -47
- package/dist/connector/sessionConnector.js +0 -606
- package/dist/node/connectSession.d.ts +0 -23
- package/dist/node/connectSession.js +0 -93
- package/dist/node/controlplane.d.ts +0 -137
- package/dist/node/controlplane.js +0 -443
- package/dist/node/rawQuicAdapter.d.ts +0 -9
- package/dist/node/rawQuicServer.d.ts +0 -24
- package/dist/node/rawQuicServer.js +0 -37
- package/dist/node/runtimeCapability.d.ts +0 -14
- package/dist/node/runtimeCapability.js +0 -24
- package/dist/node/sessionRuntime.d.ts +0 -2
- package/dist/node/sessionRuntime.js +0 -13
- package/dist/node/tunnelRuntime.d.ts +0 -42
- package/dist/node/tunnelRuntime.js +0 -559
- package/dist/node/v2.d.ts +0 -11
- package/dist/node/v2.js +0 -6
- package/dist/node/webSocketServer.d.ts +0 -24
- package/dist/node/webSocketServer.js +0 -135
- package/dist/public/artifact.d.ts +0 -11
- package/dist/public/artifact.js +0 -44
- package/dist/public/artifactLease.d.ts +0 -10
- package/dist/public/artifactLease.js +0 -41
- package/dist/public/connectError.d.ts +0 -6
- package/dist/public/connectError.js +0 -9
- package/dist/transport/webSocketAdapter.d.ts +0 -31
- package/dist/transport/webSocketAdapter.js +0 -370
- package/dist/transport/webTransportAdapter.d.ts +0 -27
- package/dist/transport/webTransportAdapter.js +0 -534
- package/dist/v2/admissionError.d.ts +0 -4
- package/dist/v2/admissionError.js +0 -8
- package/dist/v2/artifact.d.ts +0 -128
- package/dist/v2/artifact.js +0 -1131
- package/dist/v2/artifactLease.d.ts +0 -1
- package/dist/v2/artifactLease.js +0 -7
- package/dist/v2/capability.d.ts +0 -29
- package/dist/v2/capability.js +0 -190
- package/dist/v2/carrier.d.ts +0 -84
- package/dist/v2/carrier.js +0 -411
- package/dist/v2/contract.d.ts +0 -46
- package/dist/v2/contract.js +0 -1
- package/dist/v2/handshake.d.ts +0 -80
- package/dist/v2/handshake.js +0 -470
- package/dist/v2/index.d.ts +0 -14
- package/dist/v2/index.js +0 -7
- package/dist/v2/opaqueArtifact.d.ts +0 -1
- package/dist/v2/opaqueArtifact.js +0 -2
- package/dist/v2/protocol.d.ts +0 -99
- package/dist/v2/protocol.js +0 -737
- package/dist/v2/publicSession.d.ts +0 -1
- package/dist/v2/publicSession.js +0 -281
- package/dist/v2/retryDisposition.d.ts +0 -16
- package/dist/v2/retryDisposition.js +0 -30
- package/dist/v2/session.d.ts +0 -310
- package/dist/v2/session.js +0 -2127
- package/dist/v2/streamLifetimeLedger.d.ts +0 -31
- package/dist/v2/streamLifetimeLedger.js +0 -131
- package/dist/v2/streamMetadata.d.ts +0 -1
- package/dist/v2/streamMetadata.js +0 -7
- package/dist/v2/unreliableMessage.d.ts +0 -43
- package/dist/v2/unreliableMessage.js +0 -254
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { adaptNativeCarrierSessionV2, } from "../../v2/carrier.js";
|
|
2
|
-
export function createWebTransportCandidateFactoryV2(factory) {
|
|
3
|
-
return {
|
|
4
|
-
create(candidate, artifact) {
|
|
5
|
-
if (candidate.carrier !== "webtransport") {
|
|
6
|
-
throw new Error(`unsupported WebTransport carrier ${candidate.carrier}`);
|
|
7
|
-
}
|
|
8
|
-
return new WebTransportCandidateAttempt(candidate, artifact, factory);
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
class WebTransportCandidateAttempt {
|
|
13
|
-
candidate;
|
|
14
|
-
artifact;
|
|
15
|
-
factory;
|
|
16
|
-
controller = new AbortController();
|
|
17
|
-
carrier;
|
|
18
|
-
finalized = false;
|
|
19
|
-
constructor(candidate, artifact, factory) {
|
|
20
|
-
this.candidate = candidate;
|
|
21
|
-
this.artifact = artifact;
|
|
22
|
-
this.factory = factory;
|
|
23
|
-
}
|
|
24
|
-
async ready(signal) {
|
|
25
|
-
const unlink = linkAbort(signal, this.controller);
|
|
26
|
-
try {
|
|
27
|
-
const carrier = await this.factory(this.candidate, this.artifact, this.controller.signal);
|
|
28
|
-
this.carrier = carrier;
|
|
29
|
-
return {
|
|
30
|
-
candidate: this.candidate,
|
|
31
|
-
kind: carrier.kind,
|
|
32
|
-
path: carrier.path,
|
|
33
|
-
inboundBidirectionalStreamCapacity: carrier.inboundBidirectionalStreamCapacity,
|
|
34
|
-
openAdmissionChannel: async (channelSignal) => {
|
|
35
|
-
const options = channelSignal === undefined ? {} : { signal: channelSignal };
|
|
36
|
-
const stream = carrier.kind === "webtransport"
|
|
37
|
-
? await carrier.acceptStream(options)
|
|
38
|
-
: await carrier.openStream(options);
|
|
39
|
-
return {
|
|
40
|
-
framing: "stream",
|
|
41
|
-
stream,
|
|
42
|
-
abort: (error) => stream.abort(error),
|
|
43
|
-
};
|
|
44
|
-
},
|
|
45
|
-
finalize: () => {
|
|
46
|
-
if (this.finalized)
|
|
47
|
-
throw new Error("WebTransport candidate already finalized");
|
|
48
|
-
this.finalized = true;
|
|
49
|
-
return adaptNativeCarrierSessionV2(carrier);
|
|
50
|
-
},
|
|
51
|
-
close: async () => await carrier.close(),
|
|
52
|
-
abort: () => carrier.abort({ code: 6, reason: "candidate aborted" }),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
finally {
|
|
56
|
-
unlink();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
abort() {
|
|
60
|
-
this.controller.abort(new Error("WebTransport candidate aborted"));
|
|
61
|
-
this.carrier?.abort({ code: 6, reason: "candidate aborted" });
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function linkAbort(parent, child) {
|
|
65
|
-
if (parent === undefined)
|
|
66
|
-
return () => undefined;
|
|
67
|
-
const abort = () => child.abort(parent.reason);
|
|
68
|
-
if (parent.aborted)
|
|
69
|
-
abort();
|
|
70
|
-
else
|
|
71
|
-
parent.addEventListener("abort", abort, { once: true });
|
|
72
|
-
return () => parent.removeEventListener("abort", abort);
|
|
73
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { type CanonicalArtifactCandidateV2 } from "../v2/artifact.js";
|
|
2
|
-
import type { CarrierSessionV2, NativeCarrierStreamV2 } from "../v2/carrier.js";
|
|
3
|
-
import type { CarrierKind, OperationOptionsV2, PathKind } from "../v2/contract.js";
|
|
4
|
-
import type { SessionConfigV2 } from "../v2/session.js";
|
|
5
|
-
import { type ArtifactLeaseV2 } from "../v2/artifactLease.js";
|
|
6
|
-
export declare class CredentialCommitError extends Error {
|
|
7
|
-
constructor(cause: unknown);
|
|
8
|
-
}
|
|
9
|
-
export type ClientAdmissionChannelV2 = Readonly<{
|
|
10
|
-
framing: "message";
|
|
11
|
-
write(data: Uint8Array, options?: OperationOptionsV2): Promise<void>;
|
|
12
|
-
read(options?: OperationOptionsV2): Promise<Uint8Array>;
|
|
13
|
-
abort(error: Error): void;
|
|
14
|
-
}> | Readonly<{
|
|
15
|
-
framing: "stream";
|
|
16
|
-
stream: NativeCarrierStreamV2;
|
|
17
|
-
abort(error: Error): void;
|
|
18
|
-
}>;
|
|
19
|
-
export type ReadyAdmissionTransportV2 = Readonly<{
|
|
20
|
-
candidate: CanonicalArtifactCandidateV2;
|
|
21
|
-
kind: CarrierKind;
|
|
22
|
-
path: PathKind;
|
|
23
|
-
inboundBidirectionalStreamCapacity: number;
|
|
24
|
-
openAdmissionChannel(signal?: AbortSignal): Promise<ClientAdmissionChannelV2>;
|
|
25
|
-
finalize(): CarrierSessionV2;
|
|
26
|
-
close(): Promise<void>;
|
|
27
|
-
abort(): void;
|
|
28
|
-
}>;
|
|
29
|
-
export declare function commitClientAdmissionV2(ready: ReadyAdmissionTransportV2, lease: ArtifactLeaseV2, assertCredentialValid: () => void, rawFSB2: Uint8Array, config: SessionConfigV2, signal?: AbortSignal): Promise<CarrierSessionV2>;
|
|
30
|
-
export declare function requireExactCarrierCapacityV2(physical: number, logical: number): void;
|
|
31
|
-
export declare function validateOutboundAdmissionV2(rawFSB2: Uint8Array, config: SessionConfigV2, carrier: CarrierKind): void;
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { AdmissionStatusV2, computeSessionContractHashV2, decodeFSB2RequestV2, decodeFSA2ResponseV2, } from "../v2/artifact.js";
|
|
2
|
-
import { AdmissionSessionV2Error } from "../v2/admissionError.js";
|
|
3
|
-
import { base64urlDecode, base64urlEncode } from "../utils/base64url.js";
|
|
4
|
-
import { commitArtifactLeaseSpendV2, } from "../v2/artifactLease.js";
|
|
5
|
-
export class CredentialCommitError extends Error {
|
|
6
|
-
constructor(cause) {
|
|
7
|
-
super("durable credential spend failed", { cause });
|
|
8
|
-
this.name = "CredentialCommitError";
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
export async function commitClientAdmissionV2(ready, lease, assertCredentialValid, rawFSB2, config, signal) {
|
|
12
|
-
throwIfAborted(signal);
|
|
13
|
-
requireReadyTransportBinding(ready, config);
|
|
14
|
-
validateOutboundAdmissionV2(rawFSB2, config, ready.kind);
|
|
15
|
-
const channel = await ready.openAdmissionChannel(signal);
|
|
16
|
-
try {
|
|
17
|
-
assertCredentialValid();
|
|
18
|
-
try {
|
|
19
|
-
await commitArtifactLeaseSpendV2(lease, signal);
|
|
20
|
-
}
|
|
21
|
-
catch (error) {
|
|
22
|
-
throw new CredentialCommitError(error);
|
|
23
|
-
}
|
|
24
|
-
assertCredentialValid();
|
|
25
|
-
throwIfAborted(signal);
|
|
26
|
-
const rawFSA2 = channel.framing === "message"
|
|
27
|
-
? await exchangeMessage(channel, rawFSB2, signal)
|
|
28
|
-
: await exchangeStream(channel.stream, rawFSB2, signal);
|
|
29
|
-
requireAdmissionSuccessV2(rawFSA2);
|
|
30
|
-
return ready.finalize();
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
const failure = asError(error);
|
|
34
|
-
channel.abort(failure);
|
|
35
|
-
ready.abort();
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function requireReadyTransportBinding(ready, config) {
|
|
40
|
-
if (ready.candidate.carrier !== ready.kind) {
|
|
41
|
-
throw new AdmissionSessionV2Error("carrier_mismatch", "ready carrier does not match its artifact candidate");
|
|
42
|
-
}
|
|
43
|
-
if (ready.path !== config.path) {
|
|
44
|
-
throw new AdmissionSessionV2Error("path_mismatch", "ready carrier path does not match SessionV2 path");
|
|
45
|
-
}
|
|
46
|
-
requireExactCarrierCapacityV2(ready.inboundBidirectionalStreamCapacity, config.maxInboundStreams);
|
|
47
|
-
}
|
|
48
|
-
async function exchangeMessage(channel, rawFSB2, signal) {
|
|
49
|
-
const options = signalOptions(signal);
|
|
50
|
-
await channel.write(rawFSB2, options);
|
|
51
|
-
return await channel.read(options);
|
|
52
|
-
}
|
|
53
|
-
async function exchangeStream(stream, rawFSB2, signal) {
|
|
54
|
-
await writeAll(stream, rawFSB2, signal);
|
|
55
|
-
await raceAbort(stream.closeWrite(), signal);
|
|
56
|
-
const reader = new NativeExactReader(stream);
|
|
57
|
-
const header = await reader.readExactly(8, signal);
|
|
58
|
-
const reasonLength = new DataView(header.buffer, header.byteOffset, header.byteLength).getUint16(6, false);
|
|
59
|
-
if (reasonLength > 64)
|
|
60
|
-
throw new AdmissionSessionV2Error("invalid_fsa2", "FSA2 reason exceeds limit");
|
|
61
|
-
const rawFSA2 = concat(header, await reader.readExactly(reasonLength, signal));
|
|
62
|
-
await reader.expectCleanEOF(signal);
|
|
63
|
-
return rawFSA2;
|
|
64
|
-
}
|
|
65
|
-
export function requireExactCarrierCapacityV2(physical, logical) {
|
|
66
|
-
if (!validLogicalStreamCapacity(logical) || physical !== logical + 2) {
|
|
67
|
-
throw new AdmissionSessionV2Error("stream_capacity_mismatch", "carrier inbound bidirectional stream capacity does not match SessionV2 logical limit");
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
export function validateOutboundAdmissionV2(rawFSB2, config, carrier) {
|
|
71
|
-
let decoded;
|
|
72
|
-
try {
|
|
73
|
-
decoded = decodeFSB2RequestV2(rawFSB2);
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
throw new AdmissionSessionV2Error("invalid_fsb2", error instanceof Error ? error.message : "invalid FSB2 request");
|
|
77
|
-
}
|
|
78
|
-
const request = decoded.request;
|
|
79
|
-
if (request.pathKind !== config.path) {
|
|
80
|
-
throw new AdmissionSessionV2Error("path_mismatch", "FSB2 path does not match SessionV2 path");
|
|
81
|
-
}
|
|
82
|
-
validateSessionContract(config);
|
|
83
|
-
const expectedRole = request.pathKind === "tunnel" && request.role === 2 ? "server" : "client";
|
|
84
|
-
if (config.role !== expectedRole) {
|
|
85
|
-
throw new AdmissionSessionV2Error("role_mismatch", "FSB2 role does not match SessionV2 role");
|
|
86
|
-
}
|
|
87
|
-
if (request.channel_id !== config.channelID ||
|
|
88
|
-
request.session_contract_hash_b64u !== base64urlEncode(config.sessionContractHash)) {
|
|
89
|
-
throw new AdmissionSessionV2Error("session_config_mismatch", "FSB2 session identity does not match SessionV2 config");
|
|
90
|
-
}
|
|
91
|
-
if (request.pathKind === "tunnel" && request.endpoint_instance_id !== config.localEndpointInstanceID) {
|
|
92
|
-
throw new AdmissionSessionV2Error("endpoint_mismatch", "FSB2 endpoint identity does not match SessionV2 config");
|
|
93
|
-
}
|
|
94
|
-
if (!bytesEqual(decoded.localAdmissionBinding, config.localAdmissionBinding)) {
|
|
95
|
-
throw new AdmissionSessionV2Error("admission_binding_mismatch", "FSB2 admission binding does not match SessionV2 config");
|
|
96
|
-
}
|
|
97
|
-
if (request.pathKind === "direct" && !bytesEqual(decoded.localAdmissionBinding, config.peerAdmissionBinding)) {
|
|
98
|
-
throw new AdmissionSessionV2Error("peer_admission_binding_mismatch", "direct FSB2 admission binding does not match SessionV2 peer binding");
|
|
99
|
-
}
|
|
100
|
-
const candidate = request.candidates.find((entry) => entry.id === request.chosen_candidate_id);
|
|
101
|
-
if (candidate?.carrier !== carrier) {
|
|
102
|
-
throw new AdmissionSessionV2Error("carrier_mismatch", "FSB2 chosen candidate does not match the carrier");
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
function validateSessionContract(config) {
|
|
106
|
-
const contract = config.sessionContract;
|
|
107
|
-
if (contract === undefined) {
|
|
108
|
-
throw new AdmissionSessionV2Error("session_config_mismatch", "admitted SessionV2 requires a validated session contract");
|
|
109
|
-
}
|
|
110
|
-
let hash;
|
|
111
|
-
let hashBase64URL;
|
|
112
|
-
let psk;
|
|
113
|
-
try {
|
|
114
|
-
hashBase64URL = computeSessionContractHashV2(contract).hashBase64URL;
|
|
115
|
-
hash = base64urlDecode(hashBase64URL);
|
|
116
|
-
psk = base64urlDecode(contract.e2ee_psk_b64u);
|
|
117
|
-
}
|
|
118
|
-
catch (error) {
|
|
119
|
-
throw new AdmissionSessionV2Error("session_config_mismatch", error instanceof Error ? error.message : "invalid session contract");
|
|
120
|
-
}
|
|
121
|
-
if (contract.contract_hash_b64u !== hashBase64URL ||
|
|
122
|
-
!bytesEqual(hash, config.sessionContractHash) ||
|
|
123
|
-
contract.channel_id !== config.channelID ||
|
|
124
|
-
contract.max_inbound_streams !== config.maxInboundStreams ||
|
|
125
|
-
contract.default_suite !== config.suite ||
|
|
126
|
-
!contract.allowed_suites.includes(config.suite) ||
|
|
127
|
-
!bytesEqual(psk, config.psk) ||
|
|
128
|
-
contract.selected_features !== 0 ||
|
|
129
|
-
(config.idleTimeoutMs ?? 60_000) !== contract.idle_timeout_seconds * 1_000 ||
|
|
130
|
-
(config.deadlines?.establishTimeoutMs ?? 30_000) !== contract.establish_timeout_seconds * 1_000 ||
|
|
131
|
-
(config.deadlines?.rekeyPrepareTimeoutMs ?? 10_000) !== contract.rekey_prepare_timeout_seconds * 1_000 ||
|
|
132
|
-
(config.deadlines?.rekeyCompletionTimeoutMs ?? 30_000) !== contract.rekey_completion_timeout_seconds * 1_000) {
|
|
133
|
-
throw new AdmissionSessionV2Error("session_config_mismatch", "SessionV2 config does not match the signed session contract");
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
function requireAdmissionSuccessV2(rawFSA2) {
|
|
137
|
-
const response = decodeFSA2ResponseV2(rawFSA2);
|
|
138
|
-
if (response.status !== AdmissionStatusV2.Success) {
|
|
139
|
-
throw new AdmissionSessionV2Error(response.reason, `Flowersec v2 admission rejected: ${response.reason}`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
class NativeExactReader {
|
|
143
|
-
stream;
|
|
144
|
-
chunks = [];
|
|
145
|
-
offset = 0;
|
|
146
|
-
bytes = 0;
|
|
147
|
-
constructor(stream) {
|
|
148
|
-
this.stream = stream;
|
|
149
|
-
}
|
|
150
|
-
async readExactly(length, signal) {
|
|
151
|
-
while (this.bytes < length) {
|
|
152
|
-
throwIfAborted(signal);
|
|
153
|
-
const chunk = await raceAbort(this.stream.read(), signal);
|
|
154
|
-
if (chunk === null)
|
|
155
|
-
throw new AdmissionSessionV2Error("truncated_fsa2", "unexpected admission EOF");
|
|
156
|
-
if (chunk.length === 0)
|
|
157
|
-
continue;
|
|
158
|
-
this.chunks.push(chunk);
|
|
159
|
-
this.bytes += chunk.length;
|
|
160
|
-
}
|
|
161
|
-
const output = new Uint8Array(length);
|
|
162
|
-
let written = 0;
|
|
163
|
-
while (written < length) {
|
|
164
|
-
const chunk = this.chunks[0];
|
|
165
|
-
const take = Math.min(length - written, chunk.length - this.offset);
|
|
166
|
-
output.set(chunk.subarray(this.offset, this.offset + take), written);
|
|
167
|
-
written += take;
|
|
168
|
-
this.offset += take;
|
|
169
|
-
this.bytes -= take;
|
|
170
|
-
if (this.offset === chunk.length) {
|
|
171
|
-
this.chunks.shift();
|
|
172
|
-
this.offset = 0;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return output;
|
|
176
|
-
}
|
|
177
|
-
async expectCleanEOF(signal) {
|
|
178
|
-
if (this.bytes !== 0)
|
|
179
|
-
throw new AdmissionSessionV2Error("invalid_fsa2", "trailing bytes after FSA2");
|
|
180
|
-
while (true) {
|
|
181
|
-
throwIfAborted(signal);
|
|
182
|
-
const chunk = await raceAbort(this.stream.read(), signal);
|
|
183
|
-
if (chunk === null)
|
|
184
|
-
return;
|
|
185
|
-
if (chunk.length !== 0)
|
|
186
|
-
throw new AdmissionSessionV2Error("invalid_fsa2", "trailing bytes after FSA2");
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
async function writeAll(stream, value, signal) {
|
|
191
|
-
let offset = 0;
|
|
192
|
-
while (offset < value.length) {
|
|
193
|
-
throwIfAborted(signal);
|
|
194
|
-
const written = await raceAbort(stream.write(value.subarray(offset)), signal);
|
|
195
|
-
if (written < 1 || written > value.length - offset) {
|
|
196
|
-
throw new AdmissionSessionV2Error("short_write", "short admission write");
|
|
197
|
-
}
|
|
198
|
-
offset += written;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
function signalOptions(signal) {
|
|
202
|
-
return signal === undefined ? {} : { signal };
|
|
203
|
-
}
|
|
204
|
-
function throwIfAborted(signal) {
|
|
205
|
-
if (signal?.aborted === true)
|
|
206
|
-
throw new AdmissionSessionV2Error("aborted", "admission aborted");
|
|
207
|
-
}
|
|
208
|
-
async function raceAbort(promise, signal) {
|
|
209
|
-
if (signal === undefined)
|
|
210
|
-
return await promise;
|
|
211
|
-
throwIfAborted(signal);
|
|
212
|
-
return await new Promise((resolve, reject) => {
|
|
213
|
-
const abort = () => reject(signal.reason instanceof Error
|
|
214
|
-
? signal.reason
|
|
215
|
-
: new AdmissionSessionV2Error("aborted", "admission aborted"));
|
|
216
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
217
|
-
void promise.then((value) => { signal.removeEventListener("abort", abort); resolve(value); }, (error) => { signal.removeEventListener("abort", abort); reject(error); });
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
function concat(left, right) {
|
|
221
|
-
const output = new Uint8Array(left.length + right.length);
|
|
222
|
-
output.set(left);
|
|
223
|
-
output.set(right, left.length);
|
|
224
|
-
return output;
|
|
225
|
-
}
|
|
226
|
-
function asError(error) {
|
|
227
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
228
|
-
}
|
|
229
|
-
function validLogicalStreamCapacity(logical) {
|
|
230
|
-
return Number.isInteger(logical) && logical >= 1 && logical <= 128;
|
|
231
|
-
}
|
|
232
|
-
function bytesEqual(left, right) {
|
|
233
|
-
if (left.length !== right.length)
|
|
234
|
-
return false;
|
|
235
|
-
let different = 0;
|
|
236
|
-
for (let index = 0; index < left.length; index++)
|
|
237
|
-
different |= left[index] ^ right[index];
|
|
238
|
-
return different === 0;
|
|
239
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { AdmissionStatusV2, type ArtifactV2, type DecodedFSB2RequestV2 } from "../v2/artifact.js";
|
|
2
|
-
import type { CarrierSessionV2, CarrierStreamV2 } from "../v2/carrier.js";
|
|
3
|
-
import type { SessionProtocolRuntimeV2, SessionV2 as InternalSessionV2 } from "../v2/session.js";
|
|
4
|
-
import type { RpcRouter } from "../rpc/server.js";
|
|
5
|
-
export type AdmissionDecisionV2 = Readonly<{
|
|
6
|
-
accepted: true;
|
|
7
|
-
artifact: ArtifactV2;
|
|
8
|
-
}> | Readonly<{
|
|
9
|
-
accepted: false;
|
|
10
|
-
status: AdmissionStatusV2.Reject | AdmissionStatusV2.Retryable;
|
|
11
|
-
reason: string;
|
|
12
|
-
}>;
|
|
13
|
-
export type AdmissionAuthorizerV2 = (request: DecodedFSB2RequestV2, signal?: AbortSignal) => Promise<AdmissionDecisionV2>;
|
|
14
|
-
export type ReceivedSessionAdmissionV2 = Readonly<{
|
|
15
|
-
carrier: CarrierSessionV2;
|
|
16
|
-
stream: CarrierStreamV2;
|
|
17
|
-
rawFSB2: Uint8Array;
|
|
18
|
-
decoded: DecodedFSB2RequestV2;
|
|
19
|
-
}>;
|
|
20
|
-
export declare function receiveSessionAdmissionV2(carrier: CarrierSessionV2, signal?: AbortSignal): Promise<ReceivedSessionAdmissionV2>;
|
|
21
|
-
export declare function rejectSessionAdmissionV2(received: ReceivedSessionAdmissionV2, decision: Extract<AdmissionDecisionV2, Readonly<{
|
|
22
|
-
accepted: false;
|
|
23
|
-
}>>, signal?: AbortSignal): Promise<never>;
|
|
24
|
-
export declare function acceptReceivedSessionV2(received: ReceivedSessionAdmissionV2, artifact: ArtifactV2, options: Readonly<{
|
|
25
|
-
runtime: SessionProtocolRuntimeV2;
|
|
26
|
-
rpcRouter?: RpcRouter;
|
|
27
|
-
signal?: AbortSignal;
|
|
28
|
-
role?: "client" | "server";
|
|
29
|
-
localAdmissionBinding?: Uint8Array;
|
|
30
|
-
peerAdmissionBinding?: Uint8Array;
|
|
31
|
-
localEndpointInstanceID?: string;
|
|
32
|
-
expectedPeerEndpointInstanceID?: string;
|
|
33
|
-
}>): Promise<InternalSessionV2>;
|
|
34
|
-
export declare function acceptNativeSessionV2(carrier: CarrierSessionV2, authorize: AdmissionAuthorizerV2, options: Readonly<{
|
|
35
|
-
runtime: SessionProtocolRuntimeV2;
|
|
36
|
-
rpcRouter?: RpcRouter;
|
|
37
|
-
signal?: AbortSignal;
|
|
38
|
-
}>): Promise<InternalSessionV2>;
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { AdmissionStatusV2, buildFSB2RequestV2, decodeFSB2RequestV2, encodeFSB2RequestV2, encodeFSA2ResponseV2, } from "../v2/artifact.js";
|
|
2
|
-
import { establishSessionV2 } from "../v2/session.js";
|
|
3
|
-
import { AdmissionSessionV2Error } from "../v2/admissionError.js";
|
|
4
|
-
import { sessionConfigFromArtifactV2 } from "./sessionConfig.js";
|
|
5
|
-
export async function receiveSessionAdmissionV2(carrier, signal) {
|
|
6
|
-
const stream = carrier.kind === "webtransport"
|
|
7
|
-
? await carrier.openStream(signalOptions(signal))
|
|
8
|
-
: await carrier.acceptStream(signalOptions(signal));
|
|
9
|
-
try {
|
|
10
|
-
const rawFSB2 = await readFSB2(stream, signal);
|
|
11
|
-
return Object.freeze({ carrier, stream, rawFSB2, decoded: decodeFSB2RequestV2(rawFSB2) });
|
|
12
|
-
}
|
|
13
|
-
catch (error) {
|
|
14
|
-
stream.abort(asError(error));
|
|
15
|
-
carrier.abort({ code: 6, reason: "admission failed" });
|
|
16
|
-
throw error;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
export async function rejectSessionAdmissionV2(received, decision, signal) {
|
|
20
|
-
await respondAdmission(received.stream, { status: decision.status, reason: decision.reason }, signal);
|
|
21
|
-
received.carrier.abort({ code: 6, reason: "admission rejected" });
|
|
22
|
-
throw new AdmissionSessionV2Error(decision.reason, `Flowersec v2 admission rejected: ${decision.reason}`);
|
|
23
|
-
}
|
|
24
|
-
export async function acceptReceivedSessionV2(received, artifact, options) {
|
|
25
|
-
try {
|
|
26
|
-
const expected = encodeFSB2RequestV2(buildFSB2RequestV2(artifact, received.decoded.request.chosen_candidate_id));
|
|
27
|
-
if (!equalBytes(expected, received.rawFSB2))
|
|
28
|
-
throw new Error("authorized artifact does not match admission");
|
|
29
|
-
await respondAdmission(received.stream, { status: AdmissionStatusV2.Success, reason: "" }, options.signal);
|
|
30
|
-
const base = sessionConfigFromArtifactV2(artifact, received.rawFSB2, options.runtime, undefined, options.role);
|
|
31
|
-
const config = {
|
|
32
|
-
...base,
|
|
33
|
-
...(options.rpcRouter === undefined ? {} : { rpcRouter: options.rpcRouter }),
|
|
34
|
-
...(options.localAdmissionBinding === undefined ? {} : { localAdmissionBinding: options.localAdmissionBinding }),
|
|
35
|
-
...(options.peerAdmissionBinding === undefined ? {} : { peerAdmissionBinding: options.peerAdmissionBinding }),
|
|
36
|
-
...(options.localEndpointInstanceID === undefined ? {} : { localEndpointInstanceID: options.localEndpointInstanceID }),
|
|
37
|
-
...(options.expectedPeerEndpointInstanceID === undefined ? {} : { expectedPeerEndpointInstanceID: options.expectedPeerEndpointInstanceID }),
|
|
38
|
-
};
|
|
39
|
-
return await establishSessionV2(received.carrier, config, signalOptions(options.signal));
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
received.stream.abort(asError(error));
|
|
43
|
-
received.carrier.abort({ code: 6, reason: "admission failed" });
|
|
44
|
-
throw error;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
export async function acceptNativeSessionV2(carrier, authorize, options) {
|
|
48
|
-
const received = await receiveSessionAdmissionV2(carrier, options.signal);
|
|
49
|
-
try {
|
|
50
|
-
const decision = await authorize(received.decoded, options.signal);
|
|
51
|
-
if (!decision.accepted) {
|
|
52
|
-
return await rejectSessionAdmissionV2(received, decision, options.signal);
|
|
53
|
-
}
|
|
54
|
-
return await acceptReceivedSessionV2(received, decision.artifact, { ...options, role: "server" });
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
received.stream.abort(asError(error));
|
|
58
|
-
carrier.abort({ code: 6, reason: "admission failed" });
|
|
59
|
-
throw error;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
async function respondAdmission(stream, response, signal) {
|
|
63
|
-
await writeAll(stream, encodeFSA2ResponseV2(response), signal);
|
|
64
|
-
await raceAbort(stream.closeWrite(), signal);
|
|
65
|
-
}
|
|
66
|
-
function equalBytes(left, right) {
|
|
67
|
-
if (left.length !== right.length)
|
|
68
|
-
return false;
|
|
69
|
-
let difference = 0;
|
|
70
|
-
for (let index = 0; index < left.length; index += 1)
|
|
71
|
-
difference |= left[index] ^ right[index];
|
|
72
|
-
return difference === 0;
|
|
73
|
-
}
|
|
74
|
-
async function readFSB2(stream, signal) {
|
|
75
|
-
const reader = new NativeReader(stream);
|
|
76
|
-
const header = await reader.readExactly(12, signal);
|
|
77
|
-
const length = new DataView(header.buffer, header.byteOffset, header.byteLength).getUint32(8, false);
|
|
78
|
-
if (length < 1 || length > 32_768)
|
|
79
|
-
throw new Error("invalid FSB2 payload length");
|
|
80
|
-
const payload = await reader.readExactly(length, signal);
|
|
81
|
-
await reader.expectEOF(signal);
|
|
82
|
-
const raw = new Uint8Array(header.length + payload.length);
|
|
83
|
-
raw.set(header);
|
|
84
|
-
raw.set(payload, header.length);
|
|
85
|
-
return raw;
|
|
86
|
-
}
|
|
87
|
-
class NativeReader {
|
|
88
|
-
stream;
|
|
89
|
-
chunks = [];
|
|
90
|
-
offset = 0;
|
|
91
|
-
available = 0;
|
|
92
|
-
constructor(stream) {
|
|
93
|
-
this.stream = stream;
|
|
94
|
-
}
|
|
95
|
-
async readExactly(length, signal) {
|
|
96
|
-
while (this.available < length) {
|
|
97
|
-
const chunk = await raceAbort(this.stream.read(), signal);
|
|
98
|
-
if (chunk === null)
|
|
99
|
-
throw new Error("truncated admission stream");
|
|
100
|
-
if (chunk.length === 0)
|
|
101
|
-
continue;
|
|
102
|
-
this.chunks.push(chunk);
|
|
103
|
-
this.available += chunk.length;
|
|
104
|
-
}
|
|
105
|
-
const result = new Uint8Array(length);
|
|
106
|
-
let written = 0;
|
|
107
|
-
while (written < length) {
|
|
108
|
-
const chunk = this.chunks[0];
|
|
109
|
-
const take = Math.min(length - written, chunk.length - this.offset);
|
|
110
|
-
result.set(chunk.subarray(this.offset, this.offset + take), written);
|
|
111
|
-
this.offset += take;
|
|
112
|
-
this.available -= take;
|
|
113
|
-
written += take;
|
|
114
|
-
if (this.offset === chunk.length) {
|
|
115
|
-
this.chunks.shift();
|
|
116
|
-
this.offset = 0;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return result;
|
|
120
|
-
}
|
|
121
|
-
async expectEOF(signal) {
|
|
122
|
-
if (this.available !== 0)
|
|
123
|
-
throw new Error("trailing bytes after FSB2");
|
|
124
|
-
while (true) {
|
|
125
|
-
const chunk = await raceAbort(this.stream.read(), signal);
|
|
126
|
-
if (chunk === null)
|
|
127
|
-
return;
|
|
128
|
-
if (chunk.length !== 0)
|
|
129
|
-
throw new Error("trailing bytes after FSB2");
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
async function writeAll(stream, value, signal) {
|
|
134
|
-
let offset = 0;
|
|
135
|
-
while (offset < value.length) {
|
|
136
|
-
const written = await raceAbort(stream.write(value.subarray(offset)), signal);
|
|
137
|
-
if (written < 1 || written > value.length - offset)
|
|
138
|
-
throw new Error("short admission write");
|
|
139
|
-
offset += written;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
function signalOptions(signal) {
|
|
143
|
-
return signal === undefined ? {} : { signal };
|
|
144
|
-
}
|
|
145
|
-
async function raceAbort(promise, signal) {
|
|
146
|
-
if (signal === undefined)
|
|
147
|
-
return await promise;
|
|
148
|
-
if (signal.aborted)
|
|
149
|
-
throw signal.reason;
|
|
150
|
-
return await new Promise((resolve, reject) => {
|
|
151
|
-
const abort = () => reject(signal.reason);
|
|
152
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
153
|
-
void promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
function asError(error) {
|
|
157
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
158
|
-
}
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { type ArtifactV2 } from "../v2/artifact.js";
|
|
2
|
-
import type { SessionConfigV2, SessionDeadlineFactoryV2, SessionProtocolRuntimeV2 } from "../v2/session.js";
|
|
3
|
-
export declare function sessionConfigFromArtifactV2(artifact: ArtifactV2, rawFSB2: Uint8Array, runtime: SessionProtocolRuntimeV2, deadlineFactory?: SessionDeadlineFactoryV2, role?: SessionConfigV2["role"]): SessionConfigV2;
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { admissionBindingV2 } from "../v2/artifact.js";
|
|
2
|
-
import { base64urlDecode } from "../utils/base64url.js";
|
|
3
|
-
const SESSION_CLOSE_TIMEOUT_MS = 5_000;
|
|
4
|
-
export function sessionConfigFromArtifactV2(artifact, rawFSB2, runtime, deadlineFactory, role) {
|
|
5
|
-
const localBinding = admissionBindingV2(rawFSB2);
|
|
6
|
-
const tunnel = artifact.path.kind === "tunnel" ? artifact.path : undefined;
|
|
7
|
-
return {
|
|
8
|
-
role: role ?? (tunnel?.role === 2 ? "server" : "client"),
|
|
9
|
-
path: artifact.path.kind,
|
|
10
|
-
channelID: artifact.session.channel_id,
|
|
11
|
-
sessionContractHash: base64urlDecode(artifact.session.contract_hash_b64u),
|
|
12
|
-
suite: artifact.session.default_suite,
|
|
13
|
-
psk: base64urlDecode(artifact.session.e2ee_psk_b64u),
|
|
14
|
-
maxInboundStreams: artifact.session.max_inbound_streams,
|
|
15
|
-
sessionContract: artifact.session,
|
|
16
|
-
idleTimeoutMs: artifact.session.idle_timeout_seconds * 1_000,
|
|
17
|
-
closeTimeoutMs: SESSION_CLOSE_TIMEOUT_MS,
|
|
18
|
-
runtime,
|
|
19
|
-
localAdmissionBinding: localBinding,
|
|
20
|
-
peerAdmissionBinding: tunnel === undefined ? localBinding : new Uint8Array(32),
|
|
21
|
-
localEndpointInstanceID: tunnel?.local_endpoint_instance_id ?? "",
|
|
22
|
-
expectedPeerEndpointInstanceID: tunnel?.expected_peer_endpoint_instance_id ?? "",
|
|
23
|
-
deadlines: {
|
|
24
|
-
establishTimeoutMs: artifact.session.establish_timeout_seconds * 1_000,
|
|
25
|
-
rekeyPrepareTimeoutMs: artifact.session.rekey_prepare_timeout_seconds * 1_000,
|
|
26
|
-
rekeyCompletionTimeoutMs: artifact.session.rekey_completion_timeout_seconds * 1_000,
|
|
27
|
-
...(deadlineFactory === undefined ? {} : { factory: deadlineFactory }),
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { type ArtifactV2, type CanonicalArtifactCandidateV2 } from "../v2/artifact.js";
|
|
2
|
-
import { type SessionDeadlineFactoryV2, type SessionProtocolRuntimeV2, type SessionV2 as InternalSessionV2 } from "../v2/session.js";
|
|
3
|
-
import type { ArtifactLeaseV2 } from "../v2/artifactLease.js";
|
|
4
|
-
import { type RuntimeCapabilityDescriptorV2 } from "../v2/capability.js";
|
|
5
|
-
import type { RpcRouter } from "../rpc/server.js";
|
|
6
|
-
import { type ReadyAdmissionTransportV2 } from "./admissionCommit.js";
|
|
7
|
-
export type SessionConnectorStateV2 = "attempt" | "ready" | "winner" | "admitted" | "established" | "terminated";
|
|
8
|
-
export type ConnectorArtifactLeaseV2 = ArtifactLeaseV2;
|
|
9
|
-
export type CandidateAttemptV2 = Readonly<{
|
|
10
|
-
candidate: CanonicalArtifactCandidateV2;
|
|
11
|
-
ready(signal?: AbortSignal): Promise<ReadyAdmissionTransportV2>;
|
|
12
|
-
abort(): void;
|
|
13
|
-
}>;
|
|
14
|
-
export type CandidateAttemptFactoryV2 = Readonly<{
|
|
15
|
-
create(candidate: CanonicalArtifactCandidateV2, artifact: ArtifactV2): CandidateAttemptV2;
|
|
16
|
-
}>;
|
|
17
|
-
export declare function composeCandidateAttemptFactoryV2(factories: Readonly<Partial<Record<CanonicalArtifactCandidateV2["carrier"], CandidateAttemptFactoryV2>>>): CandidateAttemptFactoryV2;
|
|
18
|
-
export type SessionConnectorOptionsV2 = Readonly<{
|
|
19
|
-
signal?: AbortSignal;
|
|
20
|
-
connectTimeoutMs?: number;
|
|
21
|
-
}>;
|
|
22
|
-
type SessionConnectorInternalOptionsV2 = Readonly<{
|
|
23
|
-
runtime: SessionProtocolRuntimeV2;
|
|
24
|
-
rpcRouter?: RpcRouter;
|
|
25
|
-
connectTimeoutMs?: number;
|
|
26
|
-
deadlineFactory?: SessionDeadlineFactoryV2;
|
|
27
|
-
loserCloseTimeoutMs?: number;
|
|
28
|
-
now?: () => number;
|
|
29
|
-
capability?: RuntimeCapabilityDescriptorV2;
|
|
30
|
-
}>;
|
|
31
|
-
export type SessionConnectResultV2 = Readonly<{
|
|
32
|
-
candidate: CanonicalArtifactCandidateV2;
|
|
33
|
-
session: InternalSessionV2;
|
|
34
|
-
}>;
|
|
35
|
-
export declare class SessionConnectorV2 {
|
|
36
|
-
private readonly lease;
|
|
37
|
-
private readonly attemptFactory;
|
|
38
|
-
private readonly options;
|
|
39
|
-
state: SessionConnectorStateV2;
|
|
40
|
-
private claimed;
|
|
41
|
-
private readonly artifact;
|
|
42
|
-
constructor(lease: ConnectorArtifactLeaseV2, attemptFactory: CandidateAttemptFactoryV2, options: SessionConnectorInternalOptionsV2);
|
|
43
|
-
connect(options?: Readonly<{
|
|
44
|
-
signal?: AbortSignal;
|
|
45
|
-
}>): Promise<SessionConnectResultV2>;
|
|
46
|
-
}
|
|
47
|
-
export {};
|