@floegence/flowersec-core 3.0.2 → 3.1.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 +24 -7
- package/THIRD_PARTY_NOTICES.md +5 -5
- package/dist/browser/index.d.ts +6 -2
- package/dist/browser/index.js +3 -1
- package/dist/facade.d.ts +25 -8
- package/dist/facade.js +15 -4
- package/dist/interop/serverParityPeer.js +219 -3
- package/dist/node/index.d.ts +26 -10
- package/dist/node/index.js +12 -4
- package/dist/public/contract.d.ts +6 -3
- package/dist/v2/protocol.js +2 -0
- package/dist/v2/session.d.ts +4 -0
- package/dist/v2/session.js +15 -2
- package/dist/v2/unreliableMessage.js +8 -6
- package/dist/v3/connectionController.d.ts +10 -1
- package/dist/v3/connectionController.js +70 -32
- package/dist/v3/controller.js +14 -4
- package/dist/v3/protocol.js +2 -0
- package/dist/v3/security.d.ts +15 -4
- package/dist/v3/security.js +32 -12
- package/dist/v3/session.d.ts +4 -0
- package/dist/v3/session.js +15 -2
- package/dist/v3/unreliableMessage.js +8 -6
- package/package.json +5 -5
- package/sbom/cyclonedx.json +31 -31
- package/sbom/spdx.json +36 -36
package/README.md
CHANGED
|
@@ -15,19 +15,26 @@ npm install @floegence/flowersec-core
|
|
|
15
15
|
|
|
16
16
|
- `@floegence/flowersec-core` exports the portable artifact, lease, session, stream, RPC, stream-metadata, and connection-controller API, plus profile-owned unreliable messages when negotiated.
|
|
17
17
|
- `@floegence/flowersec-core/browser` adds `connect(...)`, `createConnectionController(...)`, and their options.
|
|
18
|
-
- `@floegence/flowersec-core/node` adds the V3 `connect(...)`, `createConnectionController(...)`, direct-only `createAcceptor(...)`, opaque `createTunnelRuntime(...)`, `AcceptedSession`, `SessionHandlers`, and `RPCHandlers` APIs. Legacy V2 server, control-plane, and `ProxyServer` APIs are available only under the explicit `node.v2` namespace.
|
|
18
|
+
- `@floegence/flowersec-core/node` adds the V3 `connect(...)`, `createConnectionController(...)`, direct-only `createAcceptor(...)`, opaque `createTunnelRuntime(...)`, `AcceptedSession`, `SessionHandlers`, and `RPCHandlers` APIs. Legacy V2 server, control-plane, and `ProxyServer` APIs are available only under the explicit `node.v2` namespace; the Go control-plane remains the only v3 invitation issuer.
|
|
19
19
|
- `@floegence/flowersec-core/proxy` adds the `Session`-based HTTP/WebSocket runtime, Service Worker and controller/app-window bridges, strict `proxy.runtime@2` validation, and `connectProxyBrowser(...)` composition.
|
|
20
20
|
|
|
21
21
|
The root type exports are:
|
|
22
22
|
|
|
23
23
|
- Artifact lifecycle: `Artifact`, closed `ArtifactError` parse failures, and `ArtifactLease`.
|
|
24
24
|
- Sessions: `Session`, `SessionTermination`, `RpcPeer`, `RpcResult<Response>`, `ByteStream`, `IncomingStream`, `StreamMetadata`, `OperationOptions`, and `StreamOpenOptions`. Create metadata with `createStreamMetadata(...)`; invalid values throw `StreamMetadataError` before opening a stream.
|
|
25
|
-
- Unreliable messages: `UnreliableMessageChannel`, `UnreliableMessageSendOptions`, and `
|
|
25
|
+
- Unreliable messages: `UnreliableMessageChannel`, `UnreliableMessageSendOptions`, `UnreliableMessageSendResult`, and the closed `UnreliableMessageErrorCode` set.
|
|
26
26
|
- JSON values: `JsonPrimitive`, `JsonValue`, and `JsonObject`.
|
|
27
27
|
- Errors: `ConnectErrorCode`, `SessionErrorCode`, and structured `RetryDisposition`.
|
|
28
|
-
- Connection lifecycle: `ArtifactSource`, `ArtifactSourceResult`, `ConnectionController`, `ConnectionState`, `ConnectionSnapshot`, `ConnectionControllerFailure`, `ConnectionControllerError`, and `RetryDisposition`.
|
|
28
|
+
- Connection lifecycle: `ArtifactSource`, `ArtifactSourceResult`, `ConnectionController`, `ConnectionState`, `ConnectionSnapshot`, `ConnectionDiagnostic`, `ConnectionControllerFailure`, `ConnectionControllerError`, and `RetryDisposition`.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
Unversioned names are the recommended strict-v3 API. Explicit `V3` exports are
|
|
31
|
+
deprecated aliases. `ConnectError.retryDisposition` and
|
|
32
|
+
`retry_after.notBeforeUnixMilliseconds` are canonical; deprecated
|
|
33
|
+
`disposition` and `absoluteUnixMilliseconds` properties remain readable through
|
|
34
|
+
their aliases. Retry ownership belongs to `ConnectionController`;
|
|
35
|
+
applications do not classify error text or run a parallel retry scheduler.
|
|
36
|
+
Public failures remain redacted and reveal no carrier, candidate, URL,
|
|
37
|
+
credential, stage, key, or implementation details.
|
|
31
38
|
|
|
32
39
|
`RpcResult<Response>` is a discriminated union. `RpcPeer.call(...)` requires a decoder for successful payloads, so the typed success value has passed application validation before it is returned. Check `result.ok` before reading either the typed success `payload` or bounded application `error`; a result cannot contain both. RPC call and notify accept only `JsonValue` payloads and reject values that cannot be represented on the wire before sending. TypeScript `RpcPeer.onNotify(typeId, decoder, handler)` receives peer outbound notifications through the local Session's inbound reserved RPC stream. A notification reaches the handler only after its decoder succeeds; decoder and handler failures are isolated from RPC serving.
|
|
33
40
|
|
|
@@ -50,7 +57,11 @@ const session = await connect(lease, {
|
|
|
50
57
|
### Long-lived Node client
|
|
51
58
|
|
|
52
59
|
```ts
|
|
53
|
-
import {
|
|
60
|
+
import {
|
|
61
|
+
RPCHandlers,
|
|
62
|
+
connectionDiagnostic,
|
|
63
|
+
createConnectionController,
|
|
64
|
+
} from "@floegence/flowersec-core/node";
|
|
54
65
|
|
|
55
66
|
const rpcHandlers = new RPCHandlers();
|
|
56
67
|
rpcHandlers.handleRPC(7, async (payload) => ({ payload }));
|
|
@@ -60,10 +71,15 @@ const controller = createConnectionController(source, {
|
|
|
60
71
|
});
|
|
61
72
|
controller.start();
|
|
62
73
|
const session = await controller.waitForSession();
|
|
74
|
+
const unsubscribe = controller.subscribe((snapshot) => {
|
|
75
|
+
monitor(connectionDiagnostic(snapshot));
|
|
76
|
+
});
|
|
63
77
|
```
|
|
64
78
|
|
|
65
79
|
The immutable callback definition applies to every generation, while each
|
|
66
|
-
Session gets a fresh router.
|
|
80
|
+
Session gets a fresh router. `waitForSession()` never starts the controller.
|
|
81
|
+
Diagnostics contain only state, attempt, failure phase/code, and retry
|
|
82
|
+
disposition. Terminated Session work is never replayed.
|
|
67
83
|
|
|
68
84
|
### Application streams on any Session
|
|
69
85
|
|
|
@@ -151,7 +167,8 @@ Flowersec-owned optional native addon wrapper and one of its supported
|
|
|
151
167
|
prebuilt platform packages; it never loads from the browser entrypoint. The
|
|
152
168
|
wrapper selects the matching optional package for macOS arm64/x64 or Linux
|
|
153
169
|
arm64/x64 glibc. Windows and musl packages are not published. The V3 Node
|
|
154
|
-
entrypoint keeps the control plane and `ProxyServer` behind `node.v2`;
|
|
170
|
+
entrypoint keeps the legacy control plane and `ProxyServer` behind `node.v2`; it
|
|
171
|
+
does not issue v3 invitations, which are produced by the Go control-plane. The
|
|
155
172
|
relay never terminates an E2EE Session. WebTransport is an optional adapter
|
|
156
173
|
profile and the Node.js runtime
|
|
157
174
|
does not currently expose a production adapter.
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
This file is generated from the canonical Flowersec source dependency inventory for flowersec-ts.
|
|
4
4
|
Do not edit it manually. License decisions are reviewed by the repository source license policy.
|
|
5
5
|
|
|
6
|
-
- @floegence/flowersec-node-native 3.0
|
|
7
|
-
- @floegence/flowersec-node-native-darwin-arm64 3.0
|
|
8
|
-
- @floegence/flowersec-node-native-darwin-x64 3.0
|
|
9
|
-
- @floegence/flowersec-node-native-linux-arm64-gnu 3.0
|
|
10
|
-
- @floegence/flowersec-node-native-linux-x64-gnu 3.0
|
|
6
|
+
- @floegence/flowersec-node-native 3.1.0 (Declared: MIT; selected: MIT; source: https://github.com/floegence/flowersec.git)
|
|
7
|
+
- @floegence/flowersec-node-native-darwin-arm64 3.1.0 (Declared: MIT; selected: MIT; source: https://github.com/floegence/flowersec.git)
|
|
8
|
+
- @floegence/flowersec-node-native-darwin-x64 3.1.0 (Declared: MIT; selected: MIT; source: https://github.com/floegence/flowersec.git)
|
|
9
|
+
- @floegence/flowersec-node-native-linux-arm64-gnu 3.1.0 (Declared: MIT; selected: MIT; source: https://github.com/floegence/flowersec.git)
|
|
10
|
+
- @floegence/flowersec-node-native-linux-x64-gnu 3.1.0 (Declared: MIT; selected: MIT; source: https://github.com/floegence/flowersec.git)
|
|
11
11
|
- @noble/ciphers 2.3.0 (Declared: MIT; selected: MIT; source: https://registry.npmjs.org/@noble/ciphers/-/ciphers-2.3.0.tgz)
|
|
12
12
|
- @noble/curves 2.3.0 (Declared: MIT; selected: MIT; source: https://registry.npmjs.org/@noble/curves/-/curves-2.3.0.tgz)
|
|
13
13
|
- @noble/hashes 2.3.0 (Declared: MIT; selected: MIT; source: https://registry.npmjs.org/@noble/hashes/-/hashes-2.3.0.tgz)
|
package/dist/browser/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export * from "../facade.js";
|
|
2
2
|
export * as v2 from "./v2.js";
|
|
3
|
-
export { connectV3 as connect,
|
|
4
|
-
|
|
3
|
+
export { connectV3 as connect, createConnectionControllerV3 as createConnectionController, } from "./connectSessionV3.js";
|
|
4
|
+
/** @deprecated Use connect and createConnectionController. */
|
|
5
|
+
export { connectV3, createConnectionControllerV3 } from "./connectSessionV3.js";
|
|
6
|
+
export type { ConnectionControllerOptionsV3 as ConnectionControllerOptions, SessionOptionsV3 as SessionOptions, } from "./connectSessionV3.js";
|
|
7
|
+
/** @deprecated Use ConnectionControllerOptions and SessionOptions. */
|
|
8
|
+
export type { ConnectionControllerOptionsV3, SessionOptionsV3 } from "./connectSessionV3.js";
|
package/dist/browser/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export * from "../facade.js";
|
|
2
2
|
export * as v2 from "./v2.js";
|
|
3
|
-
export { connectV3 as connect,
|
|
3
|
+
export { connectV3 as connect, createConnectionControllerV3 as createConnectionController, } from "./connectSessionV3.js";
|
|
4
|
+
/** @deprecated Use connect and createConnectionController. */
|
|
5
|
+
export { connectV3, createConnectionControllerV3 } from "./connectSessionV3.js";
|
package/dist/facade.d.ts
CHANGED
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
import type { Session as PublicSession } from "./public/contract.js";
|
|
2
2
|
import type { ConnectionControllerSnapshotV3 as CoreConnectionControllerSnapshotV3, ConnectionControllerV3 as CoreConnectionControllerV3 } from "./v3/connectionController.js";
|
|
3
3
|
export * as v2 from "./v2/index.js";
|
|
4
|
-
export type { ByteStream, IncomingStream, JsonObject, JsonPrimitive, JsonValue, OperationOptions, RpcPeer, RpcResult, SessionErrorCode, StreamOpenOptions, UnreliableMessageChannel, UnreliableMessageSendOptions, UnreliableMessageSendResult, SessionTermination, Session, } from "./public/contract.js";
|
|
4
|
+
export type { ByteStream, IncomingStream, JsonObject, JsonPrimitive, JsonValue, OperationOptions, RpcPeer, RpcResult, SessionErrorCode, UnreliableMessageErrorCode, StreamOpenOptions, UnreliableMessageChannel, UnreliableMessageSendOptions, UnreliableMessageSendResult, SessionTermination, Session, } from "./public/contract.js";
|
|
5
5
|
export { SessionError, UnreliableMessageError } from "./public/contract.js";
|
|
6
6
|
export { createStreamMetadata, StreamMetadataError } from "./public/streamMetadata.js";
|
|
7
7
|
export type { StreamMetadata } from "./public/streamMetadata.js";
|
|
8
8
|
export { HandlerRegistrationError, StreamHandlers, } from "./public/streamHandlers.js";
|
|
9
9
|
export type { StreamHandler, StreamHandlerOptions, } from "./public/streamHandlers.js";
|
|
10
|
-
export { ArtifactHandleV3 as Artifact,
|
|
11
|
-
export type { ArtifactParseErrorCodeV3 as ArtifactErrorCode,
|
|
12
|
-
|
|
13
|
-
export
|
|
10
|
+
export { ArtifactHandleV3 as Artifact, ArtifactParseErrorV3 as ArtifactError, createArtifactLeaseV3 as createArtifactLease, parseArtifactV3 as parseArtifact, } from "./v3/publicApi.js";
|
|
11
|
+
export type { ArtifactParseErrorCodeV3 as ArtifactErrorCode, } from "./v3/publicApi.js";
|
|
12
|
+
/** @deprecated Use Artifact, ArtifactError, createArtifactLease, and parseArtifact. */
|
|
13
|
+
export { ArtifactHandleV3, ArtifactParseErrorV3, createArtifactLeaseV3, parseArtifactV3, } from "./v3/publicApi.js";
|
|
14
|
+
/** @deprecated Use ArtifactErrorCode. */
|
|
15
|
+
export type { ArtifactParseErrorCodeV3 } from "./v3/publicApi.js";
|
|
16
|
+
export { ArtifactLeaseV3 as ArtifactLease, ArtifactLeaseV3Error as ArtifactLeaseError, } from "./v3/artifactLease.js";
|
|
17
|
+
/** @deprecated Use ArtifactLease and ArtifactLeaseError. */
|
|
18
|
+
export { ArtifactLeaseV3, ArtifactLeaseV3Error } from "./v3/artifactLease.js";
|
|
19
|
+
export type { ArtifactSourceResultV3 as ArtifactSourceResult, ArtifactSourceV3 as ArtifactSource, ConnectionDiagnosticV3 as ConnectionDiagnostic, ConnectionControllerFailureV3 as ConnectionControllerFailure, ConnectionControllerStateV3 as ConnectionState, } from "./v3/connectionController.js";
|
|
20
|
+
/** @deprecated Use the corresponding unversioned controller types. */
|
|
21
|
+
export type { ArtifactSourceResultV3, ArtifactSourceV3, ConnectionDiagnosticV3, ConnectionControllerFailureV3, ConnectionControllerSnapshotV3, ConnectionControllerStateV3, ConnectionControllerV3, } from "./v3/connectionController.js";
|
|
22
|
+
export { connectionDiagnosticV3 as connectionDiagnostic } from "./v3/connectionController.js";
|
|
23
|
+
/** @deprecated Use connectionDiagnostic. */
|
|
24
|
+
export { connectionDiagnosticV3 } from "./v3/connectionController.js";
|
|
14
25
|
export type ConnectionController = CoreConnectionControllerV3<PublicSession>;
|
|
15
26
|
export type ConnectionSnapshot = CoreConnectionControllerSnapshotV3<PublicSession>;
|
|
16
27
|
export type ConnectionControllerOptions = Readonly<{
|
|
17
28
|
maximumAttempts?: number;
|
|
18
29
|
}>;
|
|
19
|
-
export { ConnectionControllerV3Error as ConnectionControllerError,
|
|
20
|
-
|
|
21
|
-
export
|
|
30
|
+
export { ConnectionControllerV3Error as ConnectionControllerError, } from "./v3/connectionController.js";
|
|
31
|
+
/** @deprecated Use ConnectionControllerError. */
|
|
32
|
+
export { ConnectionControllerV3Error } from "./v3/connectionController.js";
|
|
33
|
+
export { ConnectErrorV3 as ConnectError } from "./v3/security.js";
|
|
34
|
+
/** @deprecated Use ConnectError. */
|
|
35
|
+
export { ConnectErrorV3 } from "./v3/security.js";
|
|
36
|
+
export type { PublicConnectErrorCodeV3 as ConnectErrorCode, RetryDispositionV3 as RetryDisposition, } from "./v3/security.js";
|
|
37
|
+
/** @deprecated Use ConnectErrorCode and RetryDisposition. */
|
|
38
|
+
export type { PublicConnectErrorCodeV3, RetryDispositionV3 } from "./v3/security.js";
|
package/dist/facade.js
CHANGED
|
@@ -2,7 +2,18 @@ export * as v2 from "./v2/index.js";
|
|
|
2
2
|
export { SessionError, UnreliableMessageError } from "./public/contract.js";
|
|
3
3
|
export { createStreamMetadata, StreamMetadataError } from "./public/streamMetadata.js";
|
|
4
4
|
export { HandlerRegistrationError, StreamHandlers, } from "./public/streamHandlers.js";
|
|
5
|
-
export { ArtifactHandleV3 as Artifact,
|
|
6
|
-
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
5
|
+
export { ArtifactHandleV3 as Artifact, ArtifactParseErrorV3 as ArtifactError, createArtifactLeaseV3 as createArtifactLease, parseArtifactV3 as parseArtifact, } from "./v3/publicApi.js";
|
|
6
|
+
/** @deprecated Use Artifact, ArtifactError, createArtifactLease, and parseArtifact. */
|
|
7
|
+
export { ArtifactHandleV3, ArtifactParseErrorV3, createArtifactLeaseV3, parseArtifactV3, } from "./v3/publicApi.js";
|
|
8
|
+
export { ArtifactLeaseV3 as ArtifactLease, ArtifactLeaseV3Error as ArtifactLeaseError, } from "./v3/artifactLease.js";
|
|
9
|
+
/** @deprecated Use ArtifactLease and ArtifactLeaseError. */
|
|
10
|
+
export { ArtifactLeaseV3, ArtifactLeaseV3Error } from "./v3/artifactLease.js";
|
|
11
|
+
export { connectionDiagnosticV3 as connectionDiagnostic } from "./v3/connectionController.js";
|
|
12
|
+
/** @deprecated Use connectionDiagnostic. */
|
|
13
|
+
export { connectionDiagnosticV3 } from "./v3/connectionController.js";
|
|
14
|
+
export { ConnectionControllerV3Error as ConnectionControllerError, } from "./v3/connectionController.js";
|
|
15
|
+
/** @deprecated Use ConnectionControllerError. */
|
|
16
|
+
export { ConnectionControllerV3Error } from "./v3/connectionController.js";
|
|
17
|
+
export { ConnectErrorV3 as ConnectError } from "./v3/security.js";
|
|
18
|
+
/** @deprecated Use ConnectError. */
|
|
19
|
+
export { ConnectErrorV3 } from "./v3/security.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
2
|
import { createPrivateKey, createPublicKey, X509Certificate } from "node:crypto";
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
3
5
|
import { createStreamMetadata, } from "../public/streamMetadata.js";
|
|
4
6
|
import { createAcceptor, RPCHandlers, SessionHandlers } from "../node/acceptor.js";
|
|
5
7
|
import { createTunnelRuntime } from "../node/tunnelRuntime.js";
|
|
@@ -8,7 +10,14 @@ import { parseArtifact } from "../public/artifact.js";
|
|
|
8
10
|
import { connect } from "../node/connectSession.js";
|
|
9
11
|
import { Issuer, createEndpointSet } from "../node/controlplane.js";
|
|
10
12
|
import { SessionError } from "../public/contract.js";
|
|
13
|
+
import { createAcceptorV3 } from "../node/acceptorV3.js";
|
|
14
|
+
import { createTunnelRuntimeV3 } from "../node/tunnelRuntimeV3.js";
|
|
15
|
+
import { verifyTunnelAuthorizationGrantV3 } from "../node/runtimeAuthorizationV3.js";
|
|
16
|
+
import { connectV3 } from "../node/connectSessionV3.js";
|
|
17
|
+
import { createArtifactLeaseV3, parseArtifactV3 } from "../v3/publicApi.js";
|
|
18
|
+
import { SessionHandlersV3 } from "../node/acceptor.js";
|
|
11
19
|
const RUNTIME = "node-typescript";
|
|
20
|
+
const PROTOCOL = process.env.FLOWERSEC_PARITY_PROTOCOL ?? "v2";
|
|
12
21
|
const ORIGIN = process.env.FLOWERSEC_PARITY_ORIGIN ?? "https://client.example";
|
|
13
22
|
const ECHO_RPC = 7001;
|
|
14
23
|
const NOTIFY_RPC = 7002;
|
|
@@ -64,7 +73,9 @@ class ExecutedCases {
|
|
|
64
73
|
}
|
|
65
74
|
function createHandlers(path) {
|
|
66
75
|
const rpcHandlers = new RPCHandlers();
|
|
67
|
-
const sessionHandlers =
|
|
76
|
+
const sessionHandlers = PROTOCOL === "v3"
|
|
77
|
+
? new SessionHandlersV3({ maxConcurrentStreams: 16 })
|
|
78
|
+
: new SessionHandlers({ maxConcurrentStreams: 16 });
|
|
68
79
|
const notifications = new SignalQueue();
|
|
69
80
|
const activeStreams = { value: 0 };
|
|
70
81
|
const executed = new ExecutedCases();
|
|
@@ -334,7 +345,29 @@ async function connectArtifact(artifactJSON, relay, rpcHandlers) {
|
|
|
334
345
|
rpcHandlers,
|
|
335
346
|
});
|
|
336
347
|
}
|
|
348
|
+
async function connectArtifactV3(artifactJSON, relay, rpcHandlers) {
|
|
349
|
+
return await connectV3(createArtifactLeaseV3(parseArtifactV3(artifactJSON), async () => undefined), { origin: relay.origin, roots: relay.trust_pem, rpcHandlers });
|
|
350
|
+
}
|
|
351
|
+
async function issueV3(input) {
|
|
352
|
+
const goRoot = fileURLToPath(new URL("../../../flowersec-go", import.meta.url));
|
|
353
|
+
const child = spawn("go", ["run", "./internal/cmd/parity-artifact-issuer"], {
|
|
354
|
+
cwd: goRoot,
|
|
355
|
+
env: { ...process.env, FLOWERSEC_SERVER_PARITY_PEER: "1" },
|
|
356
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
357
|
+
});
|
|
358
|
+
child.stdin.end(`${JSON.stringify(input)}\n`);
|
|
359
|
+
const stdout = [];
|
|
360
|
+
const stderr = [];
|
|
361
|
+
child.stdout.on("data", (chunk) => stdout.push(chunk));
|
|
362
|
+
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
|
363
|
+
const code = await new Promise((resolve) => child.once("exit", resolve));
|
|
364
|
+
if (code !== 0)
|
|
365
|
+
throw new Error(`v3 parity issuer failed: ${Buffer.concat(stderr).toString("utf8").trim()}`);
|
|
366
|
+
return JSON.parse(Buffer.concat(stdout).toString("utf8"));
|
|
367
|
+
}
|
|
337
368
|
async function runServer(tls, carrier) {
|
|
369
|
+
if (PROTOCOL === "v3")
|
|
370
|
+
return await runServerV3(tls, carrier);
|
|
338
371
|
const issuedByLookup = new Map();
|
|
339
372
|
const state = createHandlers("direct");
|
|
340
373
|
const acceptor = await createAcceptor({
|
|
@@ -391,6 +424,50 @@ async function runServer(tls, carrier) {
|
|
|
391
424
|
await acceptor.close();
|
|
392
425
|
}
|
|
393
426
|
}
|
|
427
|
+
async function runServerV3(tls, carrier) {
|
|
428
|
+
const state = createHandlers("direct");
|
|
429
|
+
let trustedArtifact;
|
|
430
|
+
const acceptor = await createAcceptorV3({
|
|
431
|
+
listeners: [directListenerOptionsV3(carrier, tls)],
|
|
432
|
+
maxInboundStreams: 16,
|
|
433
|
+
authorize: async () => trustedArtifact === undefined
|
|
434
|
+
? { accepted: false, retryable: false, reason: "invalid_credential" }
|
|
435
|
+
: { accepted: true, artifact: trustedArtifact },
|
|
436
|
+
resolveHandlers: () => state.sessionHandlers,
|
|
437
|
+
});
|
|
438
|
+
try {
|
|
439
|
+
const address = acceptor.addresses()[0];
|
|
440
|
+
if (address === undefined)
|
|
441
|
+
throw new Error(`direct ${carrier} listener did not bind`);
|
|
442
|
+
const issued = await issueV3({ mode: "direct", endpoint: endpointURLV3(carrier, "direct", address.port) });
|
|
443
|
+
if (issued.artifact_json === undefined)
|
|
444
|
+
throw new Error("v3 parity issuer omitted direct artifact");
|
|
445
|
+
trustedArtifact = parseArtifactV3(issued.artifact_json);
|
|
446
|
+
const accepting = acceptor.accept();
|
|
447
|
+
writeJSON({
|
|
448
|
+
type: "ready", runtime: RUNTIME, carrier, path: "direct",
|
|
449
|
+
artifact_json: issued.artifact_json, trust_pem: tls.tls.root_certificate_pem, origin: ORIGIN,
|
|
450
|
+
});
|
|
451
|
+
const accepted = await accepting;
|
|
452
|
+
state.executed.record("admission");
|
|
453
|
+
const serving = accepted.serve().catch((error) => error);
|
|
454
|
+
if (process.env.FLOWERSEC_PARITY_CLIENT_PROFILE !== undefined) {
|
|
455
|
+
await externalServer(accepted.session, state);
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
await exerciseServer(accepted.session, state, "direct", true, carrier);
|
|
459
|
+
}
|
|
460
|
+
await serving;
|
|
461
|
+
await accepted.close().catch(() => undefined);
|
|
462
|
+
if (state.activeStreams.value !== 0)
|
|
463
|
+
throw new Error(`direct server cleanup left ${state.activeStreams.value} streams`);
|
|
464
|
+
state.executed.record("cleanup");
|
|
465
|
+
writeJSON(result("server-result", "direct", state.executed.snapshot(), carrier));
|
|
466
|
+
}
|
|
467
|
+
finally {
|
|
468
|
+
await acceptor.close();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
394
471
|
async function runClient(input, carrier) {
|
|
395
472
|
const ready = await input.next();
|
|
396
473
|
if (ready.type !== "ready" ||
|
|
@@ -399,7 +476,9 @@ async function runClient(input, carrier) {
|
|
|
399
476
|
ready.artifact_json === "")
|
|
400
477
|
throw new Error("invalid direct ready message");
|
|
401
478
|
const state = createHandlers("direct");
|
|
402
|
-
const session =
|
|
479
|
+
const session = PROTOCOL === "v3"
|
|
480
|
+
? await connectArtifactV3(ready.artifact_json, ready, state.rpcHandlers)
|
|
481
|
+
: await connectArtifact(ready.artifact_json, ready, state.rpcHandlers);
|
|
403
482
|
state.executed.record("admission");
|
|
404
483
|
await exerciseClient(session, state, "direct", carrier);
|
|
405
484
|
await session.close().catch((error) => {
|
|
@@ -413,6 +492,8 @@ async function runClient(input, carrier) {
|
|
|
413
492
|
writeJSON(result("client-result", "direct", state.executed.snapshot(), carrier));
|
|
414
493
|
}
|
|
415
494
|
async function runRelay(tls, input, carrier) {
|
|
495
|
+
if (PROTOCOL === "v3")
|
|
496
|
+
return await runRelayV3(tls, input, carrier);
|
|
416
497
|
const decisions = new Map();
|
|
417
498
|
const released = new Set();
|
|
418
499
|
const executed = new ExecutedCases();
|
|
@@ -492,7 +573,77 @@ async function runRelay(tls, input, carrier) {
|
|
|
492
573
|
released_leases: released.size,
|
|
493
574
|
});
|
|
494
575
|
}
|
|
576
|
+
async function runRelayV3(tls, input, carrier) {
|
|
577
|
+
const authorizations = new Map();
|
|
578
|
+
const verificationRecords = new Map();
|
|
579
|
+
const released = new Set();
|
|
580
|
+
const executed = new ExecutedCases();
|
|
581
|
+
const runtime = createTunnelRuntimeV3({
|
|
582
|
+
listeners: [tunnelListenerOptionsV3(carrier, tls)],
|
|
583
|
+
maxInboundStreams: 16,
|
|
584
|
+
maxPendingLegs: 16,
|
|
585
|
+
maxActivePairs: 8,
|
|
586
|
+
authorize: async (request) => {
|
|
587
|
+
const item = authorizations.get(request.lookupKey());
|
|
588
|
+
const artifactJSON = verificationRecords.get(request.lookupKey());
|
|
589
|
+
if (item === undefined || artifactJSON === undefined)
|
|
590
|
+
return { decision: "reject", reason: "invalid_credential" };
|
|
591
|
+
return {
|
|
592
|
+
decision: "allow",
|
|
593
|
+
grant: verifyTunnelAuthorizationGrantV3(request, parseArtifactV3(artifactJSON), {
|
|
594
|
+
leaseId: item.leaseId,
|
|
595
|
+
allowReplacement: item.allowReplacement,
|
|
596
|
+
}),
|
|
597
|
+
};
|
|
598
|
+
},
|
|
599
|
+
release: (leaseId) => { released.add(leaseId); },
|
|
600
|
+
});
|
|
601
|
+
try {
|
|
602
|
+
await runtime.start();
|
|
603
|
+
const address = runtime.addresses()[0];
|
|
604
|
+
if (address === undefined)
|
|
605
|
+
throw new Error(`tunnel ${carrier} listener did not bind`);
|
|
606
|
+
writeJSON({
|
|
607
|
+
type: "relay-ready", runtime: RUNTIME, carrier, path: "tunnel",
|
|
608
|
+
endpoint_url: endpointURLV3(carrier, "tunnel", address.port),
|
|
609
|
+
trust_pem: tls.tls.root_certificate_pem,
|
|
610
|
+
trust_roots_der: [tls.tls.root_certificate_der_base64],
|
|
611
|
+
server_certificate_der: tls.tls.leaf_certificate_der_base64,
|
|
612
|
+
origin: ORIGIN,
|
|
613
|
+
});
|
|
614
|
+
const configure = await input.next();
|
|
615
|
+
if (configure.type !== "configure" || !Array.isArray(configure.authorizations) ||
|
|
616
|
+
configure.authorizations.length === 0 || configure.verification_records === undefined) {
|
|
617
|
+
throw new Error("invalid v3 tunnel relay configuration");
|
|
618
|
+
}
|
|
619
|
+
for (const item of configure.authorizations)
|
|
620
|
+
authorizations.set(item.credentialId, item);
|
|
621
|
+
for (const [credentialID, artifactJSON] of Object.entries(configure.verification_records)) {
|
|
622
|
+
verificationRecords.set(credentialID, artifactJSON);
|
|
623
|
+
}
|
|
624
|
+
const close = await input.next();
|
|
625
|
+
if (close.type !== "close")
|
|
626
|
+
throw new Error("invalid tunnel relay close command");
|
|
627
|
+
executed.record("close");
|
|
628
|
+
}
|
|
629
|
+
finally {
|
|
630
|
+
await runtime.close();
|
|
631
|
+
executed.record("cancel");
|
|
632
|
+
}
|
|
633
|
+
if (released.size !== authorizations.size)
|
|
634
|
+
throw new Error(`relay cleanup released ${released.size} of ${authorizations.size} leases`);
|
|
635
|
+
executed.record("admission", "pairing", "opaque-forwarding");
|
|
636
|
+
if (carrier === "raw-quic")
|
|
637
|
+
executed.record("datagram-forwarding");
|
|
638
|
+
executed.record("cleanup");
|
|
639
|
+
writeJSON({
|
|
640
|
+
type: "relay-result", runtime: RUNTIME, carrier, path: "tunnel", cases: executed.snapshot(),
|
|
641
|
+
observed_plaintext: false, released_leases: released.size,
|
|
642
|
+
});
|
|
643
|
+
}
|
|
495
644
|
async function runTunnelEndpointB(input, carrier) {
|
|
645
|
+
if (PROTOCOL === "v3")
|
|
646
|
+
return await runTunnelEndpointBV3(input, carrier);
|
|
496
647
|
const envelope = await input.next();
|
|
497
648
|
const { topology, relay } = envelope;
|
|
498
649
|
validateTunnelDimensions(topology, relay, "endpoint_b", carrier);
|
|
@@ -539,7 +690,53 @@ async function runTunnelEndpointB(input, carrier) {
|
|
|
539
690
|
state.executed.record("cleanup");
|
|
540
691
|
writeJSON(result("endpoint-b-result", "tunnel", state.executed.snapshot(), carrier));
|
|
541
692
|
}
|
|
693
|
+
async function runTunnelEndpointBV3(input, carrier) {
|
|
694
|
+
const envelope = await input.next();
|
|
695
|
+
const { topology, relay } = envelope;
|
|
696
|
+
validateTunnelDimensions(topology, relay, "endpoint_b", carrier);
|
|
697
|
+
const issued = await issueV3({ mode: "tunnel", endpoint: relay.endpoint_url, topology_id: topology.id });
|
|
698
|
+
if (issued.endpoint_a_artifact_json === undefined || issued.endpoint_b_artifact_json === undefined ||
|
|
699
|
+
issued.authorizations === undefined || issued.verification_records === undefined) {
|
|
700
|
+
throw new Error("v3 parity issuer omitted tunnel material");
|
|
701
|
+
}
|
|
702
|
+
const ready = {
|
|
703
|
+
type: "endpoint-b-ready", runtime: RUNTIME, carrier, path: "tunnel",
|
|
704
|
+
endpoint_a_artifact_json: issued.endpoint_a_artifact_json,
|
|
705
|
+
endpoint_b_artifact_json: issued.endpoint_b_artifact_json,
|
|
706
|
+
relay, authorizations: issued.authorizations, verification_records: issued.verification_records,
|
|
707
|
+
};
|
|
708
|
+
writeJSON(ready);
|
|
709
|
+
const command = await input.next();
|
|
710
|
+
if (command.type !== "connect")
|
|
711
|
+
throw new Error("endpoint B did not receive connect command");
|
|
712
|
+
const state = createHandlers("tunnel");
|
|
713
|
+
const session = await connectArtifactV3(ready.endpoint_b_artifact_json, relay, state.rpcHandlers);
|
|
714
|
+
state.executed.record("admission");
|
|
715
|
+
if (process.env.FLOWERSEC_PARITY_CLIENT_PROFILE !== undefined) {
|
|
716
|
+
await externalServer(session, state);
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
await exerciseServer(session, state, "tunnel", false, carrier);
|
|
720
|
+
}
|
|
721
|
+
await session.close().catch(() => undefined);
|
|
722
|
+
state.executed.record("close");
|
|
723
|
+
if (state.activeStreams.value !== 0)
|
|
724
|
+
throw new Error(`endpoint B cleanup left ${state.activeStreams.value} streams`);
|
|
725
|
+
state.executed.record("cleanup");
|
|
726
|
+
writeJSON(result("endpoint-b-result", "tunnel", state.executed.snapshot(), carrier));
|
|
727
|
+
}
|
|
542
728
|
async function externalServer(session, state) {
|
|
729
|
+
const cancellation = new AbortController();
|
|
730
|
+
cancellation.abort();
|
|
731
|
+
try {
|
|
732
|
+
await session.waitTermination({ signal: cancellation.signal });
|
|
733
|
+
}
|
|
734
|
+
catch (error) {
|
|
735
|
+
if (!(error instanceof SessionError) || error.code !== "canceled")
|
|
736
|
+
throw error;
|
|
737
|
+
}
|
|
738
|
+
state.executed.record("cancel");
|
|
739
|
+
await session.probeLiveness();
|
|
543
740
|
await session.waitTermination();
|
|
544
741
|
state.executed.record("close");
|
|
545
742
|
}
|
|
@@ -553,7 +750,9 @@ async function runTunnelEndpointA(input, carrier) {
|
|
|
553
750
|
ready.endpoint_a_artifact_json === "")
|
|
554
751
|
throw new Error("invalid endpoint B ready message");
|
|
555
752
|
const state = createHandlers("tunnel");
|
|
556
|
-
const session =
|
|
753
|
+
const session = PROTOCOL === "v3"
|
|
754
|
+
? await connectArtifactV3(ready.endpoint_a_artifact_json, ready.relay, state.rpcHandlers)
|
|
755
|
+
: await connectArtifact(ready.endpoint_a_artifact_json, ready.relay, state.rpcHandlers);
|
|
557
756
|
state.executed.record("admission");
|
|
558
757
|
await exerciseClient(session, state, "tunnel", carrier);
|
|
559
758
|
await session.close().catch(() => undefined);
|
|
@@ -624,6 +823,11 @@ function endpointURL(carrier, path, port) {
|
|
|
624
823
|
? `wss://localhost:${port}/flowersec/v2/${path}`
|
|
625
824
|
: `quic://127.0.0.1:${port}`;
|
|
626
825
|
}
|
|
826
|
+
function endpointURLV3(carrier, path, port) {
|
|
827
|
+
return carrier === "websocket"
|
|
828
|
+
? `wss://localhost:${port}/flowersec/v3/${path}`
|
|
829
|
+
: `quic://127.0.0.1:${port}`;
|
|
830
|
+
}
|
|
627
831
|
function directListenerOptions(carrier, tls) {
|
|
628
832
|
const material = { certificate: tls.tls.certificate_chain_pem, privateKey: tls.tls.private_key_pem };
|
|
629
833
|
return carrier === "websocket"
|
|
@@ -636,6 +840,18 @@ function tunnelListenerOptions(carrier, tls) {
|
|
|
636
840
|
? { carrier, host: "127.0.0.1", port: 0, tls: material, allowedOrigins: [ORIGIN] }
|
|
637
841
|
: { carrier: "raw_quic", host: "127.0.0.1", port: 0, tls: material };
|
|
638
842
|
}
|
|
843
|
+
function directListenerOptionsV3(carrier, tls) {
|
|
844
|
+
const material = { certificate: tls.tls.certificate_chain_pem, privateKey: tls.tls.private_key_pem };
|
|
845
|
+
return carrier === "websocket"
|
|
846
|
+
? { carrier, path: "direct", host: "127.0.0.1", port: 0, tls: material, allowedOrigins: [ORIGIN] }
|
|
847
|
+
: { carrier: "raw_quic", path: "direct", host: "127.0.0.1", port: 0, tls: material };
|
|
848
|
+
}
|
|
849
|
+
function tunnelListenerOptionsV3(carrier, tls) {
|
|
850
|
+
const material = { certificate: tls.tls.certificate_chain_pem, privateKey: tls.tls.private_key_pem };
|
|
851
|
+
return carrier === "websocket"
|
|
852
|
+
? { carrier, host: "127.0.0.1", port: 0, tls: material, allowedOrigins: [ORIGIN] }
|
|
853
|
+
: { carrier: "raw_quic", host: "127.0.0.1", port: 0, tls: material };
|
|
854
|
+
}
|
|
639
855
|
async function main() {
|
|
640
856
|
const { role, carrier } = parseArguments(process.argv.slice(2));
|
|
641
857
|
switch (role) {
|
package/dist/node/index.d.ts
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
|
-
export { AcceptedSessionV3 as AcceptedSession,
|
|
2
|
-
export type { AcceptorListenerV3 as AcceptorListener,
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export type {
|
|
1
|
+
export { AcceptedSessionV3 as AcceptedSession, AcceptorV3 as Acceptor, createAcceptorV3 as createAcceptor, } from "./acceptorV3.js";
|
|
2
|
+
export type { AcceptorListenerV3 as AcceptorListener, AcceptorAuthorizationDecisionV3 as AcceptorAuthorizationDecision, AcceptorAuthorizerV3 as AcceptorAuthorizer, AcceptorOptionsV3 as AcceptorOptions, } from "./acceptorV3.js";
|
|
3
|
+
/** @deprecated Use the corresponding unversioned acceptor exports. */
|
|
4
|
+
export { AcceptedSessionV3, AcceptorV3, createAcceptorV3 } from "./acceptorV3.js";
|
|
5
|
+
/** @deprecated Use the corresponding unversioned acceptor types. */
|
|
6
|
+
export type { AcceptorListenerV3, AcceptorAuthorizationDecisionV3, AcceptorAuthorizerV3, AcceptorOptionsV3, } from "./acceptorV3.js";
|
|
7
|
+
export { TunnelRuntimeV3 as TunnelRuntime, createTunnelRuntimeV3 as createTunnelRuntime, } from "./tunnelRuntimeV3.js";
|
|
8
|
+
export type { TunnelAuthorizationDecisionV3 as TunnelAuthorizationDecision, TunnelRuntimeListenerV3 as TunnelRuntimeListener, TunnelRuntimeOptionsV3 as TunnelRuntimeOptions, } from "./tunnelRuntimeV3.js";
|
|
9
|
+
/** @deprecated Use TunnelRuntime and createTunnelRuntime. */
|
|
10
|
+
export { TunnelRuntimeV3, createTunnelRuntimeV3 } from "./tunnelRuntimeV3.js";
|
|
11
|
+
/** @deprecated Use the corresponding unversioned tunnel runtime types. */
|
|
12
|
+
export type { TunnelAuthorizationDecisionV3, TunnelRuntimeListenerV3, TunnelRuntimeOptionsV3, } from "./tunnelRuntimeV3.js";
|
|
13
|
+
export { RuntimeAuthorizationRequestV3 as RuntimeAuthorizationRequest, TunnelAuthorizationGrantV3 as TunnelAuthorizationGrant, verifyTunnelAuthorizationGrantV3 as verifyTunnelAuthorizationGrant, } from "./runtimeAuthorizationV3.js";
|
|
14
|
+
export type { TunnelAuthorizationGrantOptionsV3 as TunnelAuthorizationGrantOptions, } from "./runtimeAuthorizationV3.js";
|
|
15
|
+
/** @deprecated Use the corresponding unversioned runtime-authorization exports. */
|
|
16
|
+
export { RuntimeAuthorizationRequestV3, TunnelAuthorizationGrantV3, verifyTunnelAuthorizationGrantV3, } from "./runtimeAuthorizationV3.js";
|
|
17
|
+
/** @deprecated Use TunnelAuthorizationGrantOptions. */
|
|
18
|
+
export type { TunnelAuthorizationGrantOptionsV3 } from "./runtimeAuthorizationV3.js";
|
|
7
19
|
export * from "../facade.js";
|
|
8
20
|
export * as v2 from "./v2.js";
|
|
9
|
-
import type { NodeTLSRootsV3 } from "./connectSessionV3.js";
|
|
10
|
-
export { connectV3 as connect,
|
|
11
|
-
|
|
21
|
+
import type { NodeTLSRootsV3 as NodeTLSRoots } from "./connectSessionV3.js";
|
|
22
|
+
export { connectV3 as connect, createConnectionControllerV3 as createConnectionController, } from "./connectSessionV3.js";
|
|
23
|
+
/** @deprecated Use connect and createConnectionController. */
|
|
24
|
+
export { connectV3, createConnectionControllerV3 } from "./connectSessionV3.js";
|
|
25
|
+
export type { ConnectionControllerOptionsV3 as ConnectionControllerOptions, NodeTLSRootsV3 as NodeTLSRoots, SessionOptionsV3 as SessionOptions, } from "./connectSessionV3.js";
|
|
26
|
+
/** @deprecated Use ConnectionControllerOptions, SessionTLSOptions, and SessionOptions. */
|
|
27
|
+
export type { ConnectionControllerOptionsV3, NodeTLSRootsV3, SessionOptionsV3, } from "./connectSessionV3.js";
|
|
12
28
|
export type SessionTLSOptions = Readonly<{
|
|
13
|
-
ca?:
|
|
29
|
+
ca?: NodeTLSRoots;
|
|
14
30
|
}>;
|
|
15
31
|
export { HandlerRegistrationError, RPCHandlers, SessionHandlersV3 as SessionHandlers, } from "./acceptor.js";
|
|
16
32
|
export type { NotificationHandler, RPCHandler, RPCHandlerResult, SessionHandlerOptions, } from "./acceptor.js";
|
package/dist/node/index.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
-
export { AcceptedSessionV3 as AcceptedSession,
|
|
2
|
-
|
|
3
|
-
export {
|
|
1
|
+
export { AcceptedSessionV3 as AcceptedSession, AcceptorV3 as Acceptor, createAcceptorV3 as createAcceptor, } from "./acceptorV3.js";
|
|
2
|
+
/** @deprecated Use the corresponding unversioned acceptor exports. */
|
|
3
|
+
export { AcceptedSessionV3, AcceptorV3, createAcceptorV3 } from "./acceptorV3.js";
|
|
4
|
+
export { TunnelRuntimeV3 as TunnelRuntime, createTunnelRuntimeV3 as createTunnelRuntime, } from "./tunnelRuntimeV3.js";
|
|
5
|
+
/** @deprecated Use TunnelRuntime and createTunnelRuntime. */
|
|
6
|
+
export { TunnelRuntimeV3, createTunnelRuntimeV3 } from "./tunnelRuntimeV3.js";
|
|
7
|
+
export { RuntimeAuthorizationRequestV3 as RuntimeAuthorizationRequest, TunnelAuthorizationGrantV3 as TunnelAuthorizationGrant, verifyTunnelAuthorizationGrantV3 as verifyTunnelAuthorizationGrant, } from "./runtimeAuthorizationV3.js";
|
|
8
|
+
/** @deprecated Use the corresponding unversioned runtime-authorization exports. */
|
|
9
|
+
export { RuntimeAuthorizationRequestV3, TunnelAuthorizationGrantV3, verifyTunnelAuthorizationGrantV3, } from "./runtimeAuthorizationV3.js";
|
|
4
10
|
export * from "../facade.js";
|
|
5
11
|
export * as v2 from "./v2.js";
|
|
6
|
-
export { connectV3 as connect,
|
|
12
|
+
export { connectV3 as connect, createConnectionControllerV3 as createConnectionController, } from "./connectSessionV3.js";
|
|
13
|
+
/** @deprecated Use connect and createConnectionController. */
|
|
14
|
+
export { connectV3, createConnectionControllerV3 } from "./connectSessionV3.js";
|
|
7
15
|
export { HandlerRegistrationError, RPCHandlers, SessionHandlersV3 as SessionHandlers, } from "./acceptor.js";
|
|
@@ -18,14 +18,17 @@ export interface UnreliableMessageChannel {
|
|
|
18
18
|
send(message: Uint8Array, options: UnreliableMessageSendOptions): Promise<UnreliableMessageSendResult>;
|
|
19
19
|
receive(options?: OperationOptions): Promise<Uint8Array>;
|
|
20
20
|
}
|
|
21
|
+
export type UnreliableMessageErrorCode = "unavailable" | "invalid_message" | "too_large" | "canceled" | "closed" | "operation_failed";
|
|
21
22
|
export declare class UnreliableMessageError extends Error {
|
|
22
|
-
readonly code:
|
|
23
|
-
constructor(code:
|
|
23
|
+
readonly code: UnreliableMessageErrorCode;
|
|
24
|
+
constructor(code: UnreliableMessageErrorCode);
|
|
24
25
|
}
|
|
25
26
|
export type StreamOpenOptions = OperationOptions & Readonly<{
|
|
26
27
|
metadata?: StreamMetadata;
|
|
27
28
|
}>;
|
|
28
|
-
|
|
29
|
+
/** @deprecated Unreliable-message operations use UnreliableMessageErrorCode. */
|
|
30
|
+
export type LegacyUnreliableSessionErrorCode = "unreliable_unavailable" | "unreliable_too_large" | "unreliable_dropped";
|
|
31
|
+
export type SessionErrorCode = "canceled" | "timeout" | "closed" | "going_away" | "resource_exhausted" | "stream_rejected" | "stream_reset" | "rekey_failed" | "liveness_failed" | LegacyUnreliableSessionErrorCode | "operation_failed";
|
|
29
32
|
/** A closed, carrier-neutral session failure with no internal cause or peer detail. */
|
|
30
33
|
export declare class SessionError extends Error {
|
|
31
34
|
readonly code: SessionErrorCode;
|
package/dist/v2/protocol.js
CHANGED
|
@@ -385,6 +385,8 @@ export function decodeStreamKeyUpdateACKV2(raw) {
|
|
|
385
385
|
assertLogicalStreamID(value.logicalStreamID);
|
|
386
386
|
if (value.transition === 0n)
|
|
387
387
|
throw new ProtocolV2Error("stream rekey transition must be non-zero");
|
|
388
|
+
if (value.epoch === 0)
|
|
389
|
+
throw new ProtocolV2Error("stream rekey epoch must be non-zero");
|
|
388
390
|
return value;
|
|
389
391
|
}
|
|
390
392
|
export function buildRecordAAD(h3, logicalStreamID, direction, rawHeader) {
|
package/dist/v2/session.d.ts
CHANGED
|
@@ -135,6 +135,7 @@ export declare class SessionV2 implements SessionV2Contract {
|
|
|
135
135
|
private idleWatchdogStarted;
|
|
136
136
|
private idleTimerCancel;
|
|
137
137
|
private readonly terminationState;
|
|
138
|
+
private readonly terminationController;
|
|
138
139
|
private readonly rpcRouter;
|
|
139
140
|
constructor(carrier: CarrierSessionV2, control: CarrierStreamV2, controlReader: ExactReader, config: SessionConfigV2, material: HandshakeMaterial);
|
|
140
141
|
openStream(kind: string, options?: InternalStreamOpenOptionsV2): Promise<ByteStreamV2>;
|
|
@@ -149,6 +150,7 @@ export declare class SessionV2 implements SessionV2Contract {
|
|
|
149
150
|
installReceiveRoots(epoch: number, roots: EpochRootsV2): void;
|
|
150
151
|
transcriptHash(): Uint8Array;
|
|
151
152
|
receiveDirectionValue(): DirectionV2;
|
|
153
|
+
terminationSignal(): AbortSignal;
|
|
152
154
|
sendStreamRecord(stream: EncryptedStreamV2, type: InnerTypeV2, payload: Uint8Array, signal?: AbortSignal): Promise<void>;
|
|
153
155
|
readStreamRecord(stream: EncryptedStreamV2): Promise<Readonly<{
|
|
154
156
|
type: InnerTypeV2;
|
|
@@ -238,6 +240,7 @@ declare class EncryptedStreamV2 implements ByteStreamV2 {
|
|
|
238
240
|
private pendingSendRekey;
|
|
239
241
|
private lastSendRekeyACK;
|
|
240
242
|
private receiveRekey;
|
|
243
|
+
private receiveRekeyChanged;
|
|
241
244
|
constructor(session: SessionV2, carrier: CarrierStreamV2, id: bigint, kind: string, sendEpoch: number, receiveEpoch: number, permitRelease: () => void, reader?: ExactReader);
|
|
242
245
|
read(options?: OperationOptionsV2): Promise<Uint8Array | null>;
|
|
243
246
|
write(payload: Uint8Array, options?: OperationOptionsV2): Promise<number>;
|
|
@@ -253,6 +256,7 @@ declare class EncryptedStreamV2 implements ByteStreamV2 {
|
|
|
253
256
|
}>;
|
|
254
257
|
waitReceiveRekey(transition: bigint, epoch: number, signal?: AbortSignal): Promise<void>;
|
|
255
258
|
publishReceiveRekey(transition: bigint, epoch: number): void;
|
|
259
|
+
private notifyReceiveRekeyChanged;
|
|
256
260
|
startPump(): void;
|
|
257
261
|
markOpen(): void;
|
|
258
262
|
markTerminal(error: Error): boolean;
|