@floegence/flowersec-core 2.5.4 → 3.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 +46 -18
- package/dist/browser/connectSessionV3.d.ts +13 -0
- package/dist/browser/connectSessionV3.js +75 -0
- package/dist/browser/index.d.ts +3 -2
- package/dist/browser/index.js +2 -1
- package/dist/browser/v2.d.ts +3 -0
- package/dist/browser/v2.js +2 -0
- package/dist/facade.d.ts +15 -8
- package/dist/facade.js +5 -4
- package/dist/interop/proxyServerPeer.js +1 -1
- package/dist/interop/serverParityPeer.js +8 -1
- package/dist/node/acceptor.d.ts +10 -0
- package/dist/node/acceptor.js +45 -2
- package/dist/node/acceptorV3.d.ts +57 -0
- package/dist/node/acceptorV3.js +227 -0
- package/dist/node/connectSessionV3.d.ts +21 -0
- package/dist/node/connectSessionV3.js +73 -0
- package/dist/node/index.d.ts +15 -10
- package/dist/node/index.js +6 -5
- package/dist/node/nativeTransportAddon.d.ts +39 -1
- package/dist/node/nativeTransportAddon.js +29 -5
- package/dist/node/rawQuicAdapterV3.d.ts +10 -0
- package/dist/node/rawQuicAdapterV3.js +76 -0
- package/dist/node/rawQuicServerV3.d.ts +24 -0
- package/dist/node/rawQuicServerV3.js +34 -0
- package/dist/node/runtimeAuthorizationV3.d.ts +29 -0
- package/dist/node/runtimeAuthorizationV3.js +126 -0
- package/dist/node/tunnelRuntimeV3.d.ts +57 -0
- package/dist/node/tunnelRuntimeV3.js +857 -0
- package/dist/node/v2.d.ts +11 -0
- package/dist/node/v2.js +6 -0
- package/dist/node/webSocketServerV3.d.ts +27 -0
- package/dist/node/webSocketServerV3.js +219 -0
- package/dist/public/streamHandlers.d.ts +3 -0
- package/dist/public/streamHandlers.js +6 -1
- package/dist/v2/index.d.ts +14 -0
- package/dist/v2/index.js +7 -0
- package/dist/v2/protocol.js +23 -32
- package/dist/v2/session.d.ts +5 -0
- package/dist/v2/session.js +90 -35
- package/dist/v3/admissionError.d.ts +4 -0
- package/dist/v3/admissionError.js +8 -0
- package/dist/v3/artifact.d.ts +145 -0
- package/dist/v3/artifact.js +1162 -0
- package/dist/v3/artifactLease.d.ts +17 -0
- package/dist/v3/artifactLease.js +109 -0
- package/dist/v3/browserRuntime.d.ts +37 -0
- package/dist/v3/browserRuntime.js +197 -0
- package/dist/v3/browserSessionRuntime.d.ts +2 -0
- package/dist/v3/browserSessionRuntime.js +21 -0
- package/dist/v3/capability.d.ts +32 -0
- package/dist/v3/capability.js +345 -0
- package/dist/v3/carrier.d.ts +84 -0
- package/dist/v3/carrier.js +411 -0
- package/dist/v3/connectionController.d.ts +87 -0
- package/dist/v3/connectionController.js +805 -0
- package/dist/v3/contract.d.ts +65 -0
- package/dist/v3/contract.js +3 -0
- package/dist/v3/controller.d.ts +43 -0
- package/dist/v3/controller.js +303 -0
- package/dist/v3/handshake.d.ts +81 -0
- package/dist/v3/handshake.js +471 -0
- package/dist/v3/jcs.d.ts +6 -0
- package/dist/v3/jcs.js +69 -0
- package/dist/v3/jsonPreflight.d.ts +1 -0
- package/dist/v3/jsonPreflight.js +251 -0
- package/dist/v3/nodeRuntime.d.ts +40 -0
- package/dist/v3/nodeRuntime.js +315 -0
- package/dist/v3/nodeSessionRuntime.d.ts +2 -0
- package/dist/v3/nodeSessionRuntime.js +13 -0
- package/dist/v3/protocol.d.ts +99 -0
- package/dist/v3/protocol.js +773 -0
- package/dist/v3/publicApi.d.ts +12 -0
- package/dist/v3/publicApi.js +46 -0
- package/dist/v3/publicSession.d.ts +1 -0
- package/dist/v3/publicSession.js +281 -0
- package/dist/v3/retryDisposition.d.ts +16 -0
- package/dist/v3/retryDisposition.js +30 -0
- package/dist/v3/runtimeAdapters.d.ts +9 -0
- package/dist/v3/runtimeAdapters.js +109 -0
- package/dist/v3/security.d.ts +34 -0
- package/dist/v3/security.js +100 -0
- package/dist/v3/serverAdmission.d.ts +38 -0
- package/dist/v3/serverAdmission.js +223 -0
- package/dist/v3/session.d.ts +318 -0
- package/dist/v3/session.js +2289 -0
- package/dist/v3/sessionConnector.d.ts +37 -0
- package/dist/v3/sessionConnector.js +440 -0
- package/dist/v3/streamLifetimeLedger.d.ts +31 -0
- package/dist/v3/streamLifetimeLedger.js +131 -0
- package/dist/v3/streamMetadata.d.ts +1 -0
- package/dist/v3/streamMetadata.js +7 -0
- package/dist/v3/transportConstants.d.ts +56 -0
- package/dist/v3/transportConstants.js +59 -0
- package/dist/v3/unreliableMessage.d.ts +44 -0
- package/dist/v3/unreliableMessage.js +284 -0
- package/dist/v3/webSocketCarrier.d.ts +31 -0
- package/dist/v3/webSocketCarrier.js +370 -0
- package/dist/v3/webTransportCarrier.d.ts +27 -0
- package/dist/v3/webTransportCarrier.js +534 -0
- package/package.json +4 -4
- package/sbom/cyclonedx.json +6 -6
- package/sbom/spdx.json +11 -11
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { CarrierError, } from "./carrier.js";
|
|
2
|
+
export function adaptWebTransportCarrierSessionV3(native, options) {
|
|
3
|
+
requireWebTransportSessionSurfaceV3(native);
|
|
4
|
+
return new WebTransportCarrierSessionAdapter(native, options);
|
|
5
|
+
}
|
|
6
|
+
export function hasWebTransportConstructorSurfaceV3(value) {
|
|
7
|
+
if (typeof value !== "function")
|
|
8
|
+
return false;
|
|
9
|
+
const prototype = value.prototype;
|
|
10
|
+
return typeof prototype === "object" && prototype !== null &&
|
|
11
|
+
typeof prototype.createBidirectionalStream === "function" &&
|
|
12
|
+
typeof prototype.close === "function" &&
|
|
13
|
+
"incomingBidirectionalStreams" in prototype &&
|
|
14
|
+
"datagrams" in prototype &&
|
|
15
|
+
"ready" in prototype &&
|
|
16
|
+
"closed" in prototype;
|
|
17
|
+
}
|
|
18
|
+
function requireWebTransportSessionSurfaceV3(value) {
|
|
19
|
+
const missing = [];
|
|
20
|
+
if (typeof value.createBidirectionalStream !== "function")
|
|
21
|
+
missing.push("outgoing bidirectional streams");
|
|
22
|
+
if (typeof value.incomingBidirectionalStreams?.getReader !== "function")
|
|
23
|
+
missing.push("incoming bidirectional streams");
|
|
24
|
+
if (typeof value.datagrams?.readable?.getReader !== "function")
|
|
25
|
+
missing.push("incoming DATAGRAMs");
|
|
26
|
+
if (typeof value.datagrams?.writable?.getWriter !== "function")
|
|
27
|
+
missing.push("outgoing DATAGRAMs");
|
|
28
|
+
if (typeof value.close !== "function")
|
|
29
|
+
missing.push("close");
|
|
30
|
+
if (typeof value.closed?.then !== "function")
|
|
31
|
+
missing.push("termination");
|
|
32
|
+
if (missing.length !== 0) {
|
|
33
|
+
throw new TypeError(`WebTransport runtime lacks required ${missing.join(", ")}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
class WebTransportCarrierSessionAdapter {
|
|
37
|
+
native;
|
|
38
|
+
kind = "webtransport";
|
|
39
|
+
path;
|
|
40
|
+
inboundBidirectionalStreamCapacity;
|
|
41
|
+
unreliableDatagrams;
|
|
42
|
+
incoming;
|
|
43
|
+
incomingQueue = new IncomingWebTransportStreamQueue();
|
|
44
|
+
streams = new Set();
|
|
45
|
+
datagramsAdapter;
|
|
46
|
+
closed = false;
|
|
47
|
+
terminalError;
|
|
48
|
+
closePromise;
|
|
49
|
+
activeIncomingStreams = 0;
|
|
50
|
+
constructor(native, options) {
|
|
51
|
+
this.native = native;
|
|
52
|
+
if (!Number.isInteger(options.inboundBidirectionalStreamCapacity) || options.inboundBidirectionalStreamCapacity < 3) {
|
|
53
|
+
throw new RangeError("WebTransport carrier stream capacity must be at least 3");
|
|
54
|
+
}
|
|
55
|
+
this.path = options.path;
|
|
56
|
+
this.inboundBidirectionalStreamCapacity = options.inboundBidirectionalStreamCapacity;
|
|
57
|
+
this.incoming = native.incomingBidirectionalStreams.getReader();
|
|
58
|
+
this.datagramsAdapter = new WebTransportDatagramAdapter(native.datagrams, options.datagramMaxSize);
|
|
59
|
+
this.unreliableDatagrams = this.datagramsAdapter;
|
|
60
|
+
void this.pumpIncoming();
|
|
61
|
+
void native.closed.then(() => { this.terminate(new CarrierError("closed", "WebTransport carrier is closed")); }, (error) => {
|
|
62
|
+
this.terminate(carrierFailure("WebTransport closed with an error", error));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async openStream(options = {}) {
|
|
66
|
+
this.assertOpen();
|
|
67
|
+
if (options.signal?.aborted === true)
|
|
68
|
+
throw abortedCarrierError(options.signal.reason);
|
|
69
|
+
const pending = this.native.createBidirectionalStream();
|
|
70
|
+
let stream;
|
|
71
|
+
try {
|
|
72
|
+
stream = await carrierCall(raceAbort(pending, options.signal), "WebTransport failed to open a stream");
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (isAborted(options.signal)) {
|
|
76
|
+
void pending.then((late) => abortNativeStream(late, abortedCarrierError()), () => undefined);
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
this.assertOpen();
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
abortNativeStream(stream, asError(error));
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
return this.track(stream);
|
|
88
|
+
}
|
|
89
|
+
async acceptStream(options = {}) {
|
|
90
|
+
this.assertOpen();
|
|
91
|
+
return await this.incomingQueue.shift(options.signal);
|
|
92
|
+
}
|
|
93
|
+
async waitTermination() {
|
|
94
|
+
try {
|
|
95
|
+
await this.native.closed;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw carrierFailure("WebTransport terminated with an error", error);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
close() {
|
|
102
|
+
this.closePromise ??= this.closeOnce({ closeCode: 0, reason: "" });
|
|
103
|
+
return this.closePromise;
|
|
104
|
+
}
|
|
105
|
+
abort(error = { code: 6, reason: "carrier aborted" }) {
|
|
106
|
+
if (this.closed)
|
|
107
|
+
return;
|
|
108
|
+
this.terminate(new CarrierError("aborted", "WebTransport carrier aborted"));
|
|
109
|
+
try {
|
|
110
|
+
this.native.close({ closeCode: error.code, reason: error.reason });
|
|
111
|
+
}
|
|
112
|
+
catch (cause) {
|
|
113
|
+
this.terminalError = carrierFailure("WebTransport abort failed", cause);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async closeOnce(info) {
|
|
117
|
+
if (this.closed)
|
|
118
|
+
return;
|
|
119
|
+
this.terminate(new CarrierError("closed", "WebTransport carrier is closed"));
|
|
120
|
+
try {
|
|
121
|
+
this.native.close(info);
|
|
122
|
+
await this.native.closed;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
throw carrierFailure("WebTransport close failed", error);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
assertOpen() {
|
|
129
|
+
if (this.terminalError !== undefined)
|
|
130
|
+
throw this.terminalError;
|
|
131
|
+
if (this.closed)
|
|
132
|
+
throw new CarrierError("closed", "WebTransport carrier is closed");
|
|
133
|
+
}
|
|
134
|
+
track(native, incoming = false) {
|
|
135
|
+
if (incoming)
|
|
136
|
+
this.activeIncomingStreams += 1;
|
|
137
|
+
let stream;
|
|
138
|
+
stream = new WebTransportCarrierStreamAdapter(native, () => {
|
|
139
|
+
this.streams.delete(stream);
|
|
140
|
+
if (incoming)
|
|
141
|
+
this.activeIncomingStreams = Math.max(0, this.activeIncomingStreams - 1);
|
|
142
|
+
});
|
|
143
|
+
this.streams.add(stream);
|
|
144
|
+
return stream;
|
|
145
|
+
}
|
|
146
|
+
async pumpIncoming() {
|
|
147
|
+
try {
|
|
148
|
+
while (!this.closed) {
|
|
149
|
+
const result = await this.incoming.read();
|
|
150
|
+
if (result.done || result.value === undefined) {
|
|
151
|
+
this.terminate(new CarrierError("closed", "WebTransport incoming streams closed"));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (this.activeIncomingStreams >= this.inboundBidirectionalStreamCapacity) {
|
|
155
|
+
abortNativeStream(result.value, new CarrierError("reset", "WebTransport inbound stream capacity exceeded"));
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
this.incomingQueue.push(this.track(result.value, true));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
if (!this.closed)
|
|
163
|
+
this.terminate(carrierFailure("WebTransport stream accept failed", error));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
terminate(error) {
|
|
167
|
+
if (this.closed)
|
|
168
|
+
return;
|
|
169
|
+
this.closed = true;
|
|
170
|
+
if (error.code !== "closed")
|
|
171
|
+
this.terminalError = error;
|
|
172
|
+
this.incomingQueue.fail(error);
|
|
173
|
+
for (const stream of [...this.streams])
|
|
174
|
+
stream.abort(error);
|
|
175
|
+
this.streams.clear();
|
|
176
|
+
this.datagramsAdapter.abort(error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
class WebTransportCarrierStreamAdapter {
|
|
180
|
+
onRelease;
|
|
181
|
+
reader;
|
|
182
|
+
writer;
|
|
183
|
+
readClosed = false;
|
|
184
|
+
readStopError;
|
|
185
|
+
writeClosed = false;
|
|
186
|
+
terminalError;
|
|
187
|
+
closeWritePromise;
|
|
188
|
+
stopSendingPromise;
|
|
189
|
+
resetPromise;
|
|
190
|
+
released = false;
|
|
191
|
+
constructor(stream, onRelease) {
|
|
192
|
+
this.onRelease = onRelease;
|
|
193
|
+
this.reader = stream.readable.getReader();
|
|
194
|
+
this.writer = stream.writable.getWriter();
|
|
195
|
+
}
|
|
196
|
+
async read(options = {}) {
|
|
197
|
+
this.assertReadable();
|
|
198
|
+
if (this.readClosed)
|
|
199
|
+
return null;
|
|
200
|
+
const result = await carrierCall(raceAbort(this.reader.read(), options.signal), "WebTransport stream read failed", "reset");
|
|
201
|
+
if (result.done || result.value === undefined) {
|
|
202
|
+
this.readClosed = true;
|
|
203
|
+
this.releaseIfComplete();
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
return result.value.slice();
|
|
207
|
+
}
|
|
208
|
+
async write(data) {
|
|
209
|
+
this.assertNotTerminal();
|
|
210
|
+
if (this.writeClosed)
|
|
211
|
+
throw new CarrierError("write_closed", "WebTransport stream write side is closed");
|
|
212
|
+
await carrierCall(this.writer.write(data.slice()), "WebTransport stream write failed", "reset");
|
|
213
|
+
return data.byteLength;
|
|
214
|
+
}
|
|
215
|
+
closeWrite() {
|
|
216
|
+
if (this.closeWritePromise !== undefined)
|
|
217
|
+
return this.closeWritePromise;
|
|
218
|
+
this.assertNotTerminal();
|
|
219
|
+
this.writeClosed = true;
|
|
220
|
+
this.closeWritePromise = carrierCall(this.writer.close(), "WebTransport stream FIN failed", "reset")
|
|
221
|
+
.then(() => { this.releaseIfComplete(); });
|
|
222
|
+
return this.closeWritePromise;
|
|
223
|
+
}
|
|
224
|
+
stopSending() {
|
|
225
|
+
if (this.stopSendingPromise !== undefined)
|
|
226
|
+
return this.stopSendingPromise;
|
|
227
|
+
this.assertNotTerminal();
|
|
228
|
+
const stopped = new CarrierError("stop_sending", "WebTransport stream receive side stopped");
|
|
229
|
+
this.readClosed = true;
|
|
230
|
+
this.readStopError = stopped;
|
|
231
|
+
this.stopSendingPromise ??= carrierCall(this.reader.cancel(stopped), "WebTransport STOP_SENDING failed", "stop_sending").then(() => { this.releaseIfComplete(); });
|
|
232
|
+
return this.stopSendingPromise;
|
|
233
|
+
}
|
|
234
|
+
reset() {
|
|
235
|
+
this.resetPromise ??= this.resetOnce();
|
|
236
|
+
return this.resetPromise;
|
|
237
|
+
}
|
|
238
|
+
abort(error = new CarrierError("aborted", "WebTransport stream aborted")) {
|
|
239
|
+
if (this.terminalError !== undefined)
|
|
240
|
+
return;
|
|
241
|
+
this.terminalError = error instanceof CarrierError
|
|
242
|
+
? error
|
|
243
|
+
: new CarrierError("aborted", "WebTransport stream aborted", error);
|
|
244
|
+
this.readClosed = true;
|
|
245
|
+
this.writeClosed = true;
|
|
246
|
+
void this.writer.abort(this.terminalError).catch(() => undefined);
|
|
247
|
+
void this.reader.cancel(this.terminalError).catch(() => undefined);
|
|
248
|
+
this.release();
|
|
249
|
+
}
|
|
250
|
+
async resetOnce() {
|
|
251
|
+
if (this.terminalError !== undefined)
|
|
252
|
+
return;
|
|
253
|
+
this.writeClosed = true;
|
|
254
|
+
this.readClosed = true;
|
|
255
|
+
const error = new CarrierError("reset", "WebTransport stream reset");
|
|
256
|
+
this.terminalError = error;
|
|
257
|
+
try {
|
|
258
|
+
await Promise.allSettled([this.writer.abort(error), this.reader.cancel(error)]);
|
|
259
|
+
}
|
|
260
|
+
finally {
|
|
261
|
+
this.release();
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
assertReadable() {
|
|
265
|
+
this.assertNotTerminal();
|
|
266
|
+
if (this.readStopError !== undefined)
|
|
267
|
+
throw this.readStopError;
|
|
268
|
+
}
|
|
269
|
+
assertNotTerminal() {
|
|
270
|
+
if (this.terminalError !== undefined)
|
|
271
|
+
throw this.terminalError;
|
|
272
|
+
}
|
|
273
|
+
releaseIfComplete() {
|
|
274
|
+
if (this.readClosed && this.writeClosed)
|
|
275
|
+
this.release();
|
|
276
|
+
}
|
|
277
|
+
release() {
|
|
278
|
+
if (this.released)
|
|
279
|
+
return;
|
|
280
|
+
this.released = true;
|
|
281
|
+
this.onRelease();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
class WebTransportDatagramAdapter {
|
|
285
|
+
maxDatagramSize;
|
|
286
|
+
readable;
|
|
287
|
+
writable;
|
|
288
|
+
incoming = new IncomingDatagramQueue();
|
|
289
|
+
terminalError;
|
|
290
|
+
constructor(native, configuredMaxSize) {
|
|
291
|
+
const maxDatagramSize = configuredMaxSize ?? native.maxDatagramSize;
|
|
292
|
+
if (!Number.isInteger(maxDatagramSize) || maxDatagramSize < 1) {
|
|
293
|
+
throw new TypeError("WebTransport runtime did not provide a valid DATAGRAM size");
|
|
294
|
+
}
|
|
295
|
+
this.maxDatagramSize = maxDatagramSize;
|
|
296
|
+
this.readable = native.readable.getReader();
|
|
297
|
+
this.writable = native.writable.getWriter();
|
|
298
|
+
void this.pumpIncoming();
|
|
299
|
+
}
|
|
300
|
+
async send(data, options = {}) {
|
|
301
|
+
this.assertOpen();
|
|
302
|
+
if (options.signal?.aborted === true)
|
|
303
|
+
throw abortedCarrierError(options.signal.reason);
|
|
304
|
+
if (options.expiresAt !== undefined && options.expiresAt <= Date.now())
|
|
305
|
+
return "dropped_expired";
|
|
306
|
+
if (data.byteLength < 1 || data.byteLength > this.maxDatagramSize)
|
|
307
|
+
return "dropped_carrier";
|
|
308
|
+
try {
|
|
309
|
+
await raceAbort(this.writable.write(data.slice()), options.signal);
|
|
310
|
+
return "accepted";
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
if (isAborted(options.signal))
|
|
314
|
+
throw abortedCarrierError(error);
|
|
315
|
+
if (this.terminalError !== undefined)
|
|
316
|
+
throw this.terminalError;
|
|
317
|
+
return "dropped_carrier";
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async receive(options = {}) {
|
|
321
|
+
this.assertOpen();
|
|
322
|
+
return await this.incoming.shift(options.signal);
|
|
323
|
+
}
|
|
324
|
+
abort(error) {
|
|
325
|
+
if (this.terminalError !== undefined)
|
|
326
|
+
return;
|
|
327
|
+
this.terminalError = error;
|
|
328
|
+
this.incoming.fail(error);
|
|
329
|
+
void this.writable.abort(error).catch(() => undefined);
|
|
330
|
+
void this.readable.cancel(error).catch(() => undefined);
|
|
331
|
+
}
|
|
332
|
+
assertOpen() {
|
|
333
|
+
if (this.terminalError !== undefined)
|
|
334
|
+
throw this.terminalError;
|
|
335
|
+
}
|
|
336
|
+
async pumpIncoming() {
|
|
337
|
+
try {
|
|
338
|
+
while (this.terminalError === undefined) {
|
|
339
|
+
const result = await this.readable.read();
|
|
340
|
+
if (result.done || result.value === undefined) {
|
|
341
|
+
this.abort(new CarrierError("closed", "WebTransport datagrams closed"));
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (result.value.byteLength < 1 || result.value.byteLength > this.maxDatagramSize)
|
|
345
|
+
continue;
|
|
346
|
+
this.incoming.push(result.value.slice());
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
if (this.terminalError === undefined) {
|
|
351
|
+
this.abort(carrierFailure("WebTransport datagram receive failed", error));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
class IncomingWebTransportStreamQueue {
|
|
357
|
+
values = [];
|
|
358
|
+
waiters = new Set();
|
|
359
|
+
terminalError;
|
|
360
|
+
push(stream) {
|
|
361
|
+
if (this.terminalError !== undefined) {
|
|
362
|
+
stream.abort(this.terminalError);
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const waiter = this.waiters.values().next().value;
|
|
366
|
+
if (waiter === undefined)
|
|
367
|
+
this.values.push(stream);
|
|
368
|
+
else
|
|
369
|
+
waiter.deliver(stream);
|
|
370
|
+
}
|
|
371
|
+
shift(signal) {
|
|
372
|
+
if (signal?.aborted === true)
|
|
373
|
+
return Promise.reject(abortedCarrierError(signal.reason));
|
|
374
|
+
if (this.terminalError !== undefined)
|
|
375
|
+
return Promise.reject(this.terminalError);
|
|
376
|
+
const value = this.values.shift();
|
|
377
|
+
if (value !== undefined)
|
|
378
|
+
return Promise.resolve(value);
|
|
379
|
+
return new Promise((resolve, reject) => {
|
|
380
|
+
let settled = false;
|
|
381
|
+
const cleanup = () => {
|
|
382
|
+
this.waiters.delete(waiter);
|
|
383
|
+
signal?.removeEventListener("abort", abort);
|
|
384
|
+
};
|
|
385
|
+
const waiter = {
|
|
386
|
+
deliver: (stream) => {
|
|
387
|
+
if (settled)
|
|
388
|
+
return;
|
|
389
|
+
settled = true;
|
|
390
|
+
cleanup();
|
|
391
|
+
resolve(stream);
|
|
392
|
+
},
|
|
393
|
+
fail: (error) => {
|
|
394
|
+
if (settled)
|
|
395
|
+
return;
|
|
396
|
+
settled = true;
|
|
397
|
+
cleanup();
|
|
398
|
+
reject(error);
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
const abort = () => waiter.fail(abortedCarrierError(signal?.reason));
|
|
402
|
+
this.waiters.add(waiter);
|
|
403
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
404
|
+
if (signal?.aborted === true)
|
|
405
|
+
abort();
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
fail(error) {
|
|
409
|
+
if (this.terminalError !== undefined)
|
|
410
|
+
return;
|
|
411
|
+
this.terminalError = error;
|
|
412
|
+
for (const stream of this.values)
|
|
413
|
+
stream.abort(error);
|
|
414
|
+
this.values.length = 0;
|
|
415
|
+
for (const waiter of [...this.waiters])
|
|
416
|
+
waiter.fail(error);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
class IncomingDatagramQueue {
|
|
420
|
+
static MAX_VALUES = 256;
|
|
421
|
+
static MAX_BYTES = 4 * 1024 * 1024;
|
|
422
|
+
values = [];
|
|
423
|
+
bufferedBytes = 0;
|
|
424
|
+
waiters = new Set();
|
|
425
|
+
terminalError;
|
|
426
|
+
push(value) {
|
|
427
|
+
if (this.terminalError !== undefined)
|
|
428
|
+
return;
|
|
429
|
+
const waiter = this.waiters.values().next().value;
|
|
430
|
+
if (waiter === undefined) {
|
|
431
|
+
// DATAGRAMs are lossy by contract. Drop an incoming value once the
|
|
432
|
+
// bounded queue budget is exhausted, while keeping the native reader
|
|
433
|
+
// drained so an unconsumed peer cannot grow memory without bound.
|
|
434
|
+
if (this.values.length >= IncomingDatagramQueue.MAX_VALUES ||
|
|
435
|
+
this.bufferedBytes + value.byteLength > IncomingDatagramQueue.MAX_BYTES)
|
|
436
|
+
return;
|
|
437
|
+
this.values.push(value);
|
|
438
|
+
this.bufferedBytes += value.byteLength;
|
|
439
|
+
}
|
|
440
|
+
else
|
|
441
|
+
waiter.deliver(value);
|
|
442
|
+
}
|
|
443
|
+
shift(signal) {
|
|
444
|
+
if (signal?.aborted === true)
|
|
445
|
+
return Promise.reject(abortedCarrierError(signal.reason));
|
|
446
|
+
if (this.terminalError !== undefined)
|
|
447
|
+
return Promise.reject(this.terminalError);
|
|
448
|
+
const value = this.values.shift();
|
|
449
|
+
if (value !== undefined) {
|
|
450
|
+
this.bufferedBytes -= value.byteLength;
|
|
451
|
+
return Promise.resolve(value);
|
|
452
|
+
}
|
|
453
|
+
return new Promise((resolve, reject) => {
|
|
454
|
+
let settled = false;
|
|
455
|
+
const cleanup = () => {
|
|
456
|
+
this.waiters.delete(waiter);
|
|
457
|
+
signal?.removeEventListener("abort", abort);
|
|
458
|
+
};
|
|
459
|
+
const waiter = {
|
|
460
|
+
deliver: (next) => {
|
|
461
|
+
if (settled)
|
|
462
|
+
return;
|
|
463
|
+
settled = true;
|
|
464
|
+
cleanup();
|
|
465
|
+
resolve(next);
|
|
466
|
+
},
|
|
467
|
+
fail: (error) => {
|
|
468
|
+
if (settled)
|
|
469
|
+
return;
|
|
470
|
+
settled = true;
|
|
471
|
+
cleanup();
|
|
472
|
+
reject(error);
|
|
473
|
+
},
|
|
474
|
+
};
|
|
475
|
+
const abort = () => waiter.fail(abortedCarrierError(signal?.reason));
|
|
476
|
+
this.waiters.add(waiter);
|
|
477
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
478
|
+
if (signal?.aborted === true)
|
|
479
|
+
abort();
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
fail(error) {
|
|
483
|
+
if (this.terminalError !== undefined)
|
|
484
|
+
return;
|
|
485
|
+
this.terminalError = error;
|
|
486
|
+
this.values.length = 0;
|
|
487
|
+
this.bufferedBytes = 0;
|
|
488
|
+
for (const waiter of [...this.waiters])
|
|
489
|
+
waiter.fail(error);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function abortNativeStream(stream, error) {
|
|
493
|
+
const reader = stream.readable.getReader();
|
|
494
|
+
const writer = stream.writable.getWriter();
|
|
495
|
+
void reader.cancel(error).catch(() => undefined);
|
|
496
|
+
void writer.abort(error).catch(() => undefined);
|
|
497
|
+
}
|
|
498
|
+
function abortedCarrierError(cause) {
|
|
499
|
+
return new CarrierError("aborted", "WebTransport operation aborted", cause);
|
|
500
|
+
}
|
|
501
|
+
function isAborted(signal) {
|
|
502
|
+
return signal?.aborted === true;
|
|
503
|
+
}
|
|
504
|
+
async function raceAbort(promise, signal) {
|
|
505
|
+
if (signal === undefined)
|
|
506
|
+
return await promise;
|
|
507
|
+
if (signal.aborted)
|
|
508
|
+
throw abortedCarrierError(signal.reason);
|
|
509
|
+
return await new Promise((resolve, reject) => {
|
|
510
|
+
const abort = () => reject(abortedCarrierError(signal.reason));
|
|
511
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
512
|
+
void promise.then(resolve, reject).finally(() => signal.removeEventListener("abort", abort));
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
async function carrierCall(promise, message, code = "closed") {
|
|
516
|
+
try {
|
|
517
|
+
return await promise;
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
if (error instanceof CarrierError)
|
|
521
|
+
throw error;
|
|
522
|
+
if (error instanceof DOMException && error.name === "AbortError" ||
|
|
523
|
+
error instanceof Error && error.name === "AbortError") {
|
|
524
|
+
throw new CarrierError("aborted", message, error);
|
|
525
|
+
}
|
|
526
|
+
throw new CarrierError(code, message, error);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
function carrierFailure(message, cause) {
|
|
530
|
+
return cause instanceof CarrierError ? cause : new CarrierError("closed", message, cause);
|
|
531
|
+
}
|
|
532
|
+
function asError(error) {
|
|
533
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
534
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@floegence/flowersec-core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Flowersec core TypeScript library for carrier-neutral encrypted sessions and multiplexed streams.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"ensure:browser": "node ./scripts/ensure-playwright-browsers.mjs chromium",
|
|
64
64
|
"ensure:browser:firefox": "node ./scripts/ensure-playwright-browsers.mjs firefox",
|
|
65
65
|
"ensure:browser:webkit": "node ./scripts/ensure-playwright-browsers.mjs webkit",
|
|
66
|
-
"test:coverage": "npm run build &&
|
|
66
|
+
"test:coverage": "npm run build && node ../scripts/server-parity-native-addon.mjs --test-coverage",
|
|
67
67
|
"lint": "eslint .",
|
|
68
68
|
"verify:package": "node ./scripts/verify-package-exports.mjs",
|
|
69
69
|
"prepack": "npm run build",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"ws": "^8.21.2"
|
|
78
78
|
},
|
|
79
79
|
"optionalDependencies": {
|
|
80
|
-
"@floegence/flowersec-node-native": "
|
|
80
|
+
"@floegence/flowersec-node-native": "3.0.0"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
83
|
"@playwright/test": "1.62.1",
|
|
@@ -95,5 +95,5 @@
|
|
|
95
95
|
"vite": "^8.2.1",
|
|
96
96
|
"vitest": "4.1.10"
|
|
97
97
|
},
|
|
98
|
-
"flowersecSourceCommit": "
|
|
98
|
+
"flowersecSourceCommit": "ec1f9697daa70e4781cd460ec551d40df436335c"
|
|
99
99
|
}
|
package/sbom/cyclonedx.json
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.5",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:c9faed3c-b0e2-55ed-8e12-98bc68091c8c",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
7
|
"component": {
|
|
8
8
|
"type": "library",
|
|
9
9
|
"name": "@floegence/flowersec-core",
|
|
10
|
-
"version": "
|
|
11
|
-
"purl": "pkg:npm/%40floegence/flowersec-core@
|
|
12
|
-
"bom-ref": "pkg:npm/%40floegence/flowersec-core@
|
|
10
|
+
"version": "3.0.0",
|
|
11
|
+
"purl": "pkg:npm/%40floegence/flowersec-core@3.0.0",
|
|
12
|
+
"bom-ref": "pkg:npm/%40floegence/flowersec-core@3.0.0"
|
|
13
13
|
},
|
|
14
14
|
"properties": [
|
|
15
15
|
{
|
|
16
16
|
"name": "flowersec:source-inventory-sha256",
|
|
17
|
-
"value": "
|
|
17
|
+
"value": "8146654f4a197f2c5a7d100c8e25ee624d6f7ea2a6a57da0bc318ab1653b4a5c"
|
|
18
18
|
}
|
|
19
19
|
]
|
|
20
20
|
},
|
|
@@ -190,7 +190,7 @@
|
|
|
190
190
|
],
|
|
191
191
|
"dependencies": [
|
|
192
192
|
{
|
|
193
|
-
"ref": "pkg:npm/%40floegence/flowersec-core@
|
|
193
|
+
"ref": "pkg:npm/%40floegence/flowersec-core@3.0.0",
|
|
194
194
|
"dependsOn": [
|
|
195
195
|
"pkg:npm/%40noble/ciphers@2.3.0",
|
|
196
196
|
"pkg:npm/%40noble/curves@2.3.0",
|
package/sbom/spdx.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"dataLicense": "CC0-1.0",
|
|
4
4
|
"SPDXID": "SPDXRef-DOCUMENT",
|
|
5
5
|
"name": "flowersec-ts",
|
|
6
|
-
"documentNamespace": "https://github.com/floegence/flowersec/sbom/flowersec-ts/
|
|
6
|
+
"documentNamespace": "https://github.com/floegence/flowersec/sbom/flowersec-ts/8146654f4a197f2c5a7d100c8e25ee624d6f7ea2a6a57da0bc318ab1653b4a5c",
|
|
7
7
|
"creationInfo": {
|
|
8
8
|
"created": "1970-01-01T00:00:00Z",
|
|
9
9
|
"creators": [
|
|
@@ -13,19 +13,19 @@
|
|
|
13
13
|
"packages": [
|
|
14
14
|
{
|
|
15
15
|
"name": "@floegence/flowersec-core",
|
|
16
|
-
"SPDXID": "SPDXRef-Package-
|
|
17
|
-
"versionInfo": "
|
|
16
|
+
"SPDXID": "SPDXRef-Package-fcd176a26fcede75f8d8",
|
|
17
|
+
"versionInfo": "3.0.0",
|
|
18
18
|
"downloadLocation": "NOASSERTION",
|
|
19
19
|
"filesAnalyzed": false,
|
|
20
20
|
"licenseConcluded": "NOASSERTION",
|
|
21
21
|
"licenseDeclared": "NOASSERTION",
|
|
22
22
|
"copyrightText": "NOASSERTION",
|
|
23
|
-
"comment": "Flowersec source inventory SHA-256:
|
|
23
|
+
"comment": "Flowersec source inventory SHA-256: 8146654f4a197f2c5a7d100c8e25ee624d6f7ea2a6a57da0bc318ab1653b4a5c",
|
|
24
24
|
"externalRefs": [
|
|
25
25
|
{
|
|
26
26
|
"referenceCategory": "PACKAGE-MANAGER",
|
|
27
27
|
"referenceType": "purl",
|
|
28
|
-
"referenceLocator": "pkg:npm/%40floegence/flowersec-core@
|
|
28
|
+
"referenceLocator": "pkg:npm/%40floegence/flowersec-core@3.0.0"
|
|
29
29
|
}
|
|
30
30
|
]
|
|
31
31
|
},
|
|
@@ -136,30 +136,30 @@
|
|
|
136
136
|
{
|
|
137
137
|
"spdxElementId": "SPDXRef-DOCUMENT",
|
|
138
138
|
"relationshipType": "DESCRIBES",
|
|
139
|
-
"relatedSpdxElement": "SPDXRef-Package-
|
|
139
|
+
"relatedSpdxElement": "SPDXRef-Package-fcd176a26fcede75f8d8"
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
|
-
"spdxElementId": "SPDXRef-Package-
|
|
142
|
+
"spdxElementId": "SPDXRef-Package-fcd176a26fcede75f8d8",
|
|
143
143
|
"relationshipType": "DEPENDS_ON",
|
|
144
144
|
"relatedSpdxElement": "SPDXRef-Package-5ce913a03239b02770fb"
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
|
-
"spdxElementId": "SPDXRef-Package-
|
|
147
|
+
"spdxElementId": "SPDXRef-Package-fcd176a26fcede75f8d8",
|
|
148
148
|
"relationshipType": "DEPENDS_ON",
|
|
149
149
|
"relatedSpdxElement": "SPDXRef-Package-01009adf60db02c13634"
|
|
150
150
|
},
|
|
151
151
|
{
|
|
152
|
-
"spdxElementId": "SPDXRef-Package-
|
|
152
|
+
"spdxElementId": "SPDXRef-Package-fcd176a26fcede75f8d8",
|
|
153
153
|
"relationshipType": "DEPENDS_ON",
|
|
154
154
|
"relatedSpdxElement": "SPDXRef-Package-8815b117c8a1d5f7eeb0"
|
|
155
155
|
},
|
|
156
156
|
{
|
|
157
|
-
"spdxElementId": "SPDXRef-Package-
|
|
157
|
+
"spdxElementId": "SPDXRef-Package-fcd176a26fcede75f8d8",
|
|
158
158
|
"relationshipType": "DEPENDS_ON",
|
|
159
159
|
"relatedSpdxElement": "SPDXRef-Package-f8b45a289df643042b94"
|
|
160
160
|
},
|
|
161
161
|
{
|
|
162
|
-
"spdxElementId": "SPDXRef-Package-
|
|
162
|
+
"spdxElementId": "SPDXRef-Package-fcd176a26fcede75f8d8",
|
|
163
163
|
"relationshipType": "DEPENDS_ON",
|
|
164
164
|
"relatedSpdxElement": "SPDXRef-Package-b779412f685822663496"
|
|
165
165
|
},
|