@floegence/flowersec-core 2.5.3 → 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.
Files changed (119) hide show
  1. package/README.md +46 -18
  2. package/dist/browser/connectSessionV3.d.ts +13 -0
  3. package/dist/browser/connectSessionV3.js +75 -0
  4. package/dist/browser/index.d.ts +3 -2
  5. package/dist/browser/index.js +2 -1
  6. package/dist/browser/v2.d.ts +3 -0
  7. package/dist/browser/v2.js +2 -0
  8. package/dist/facade.d.ts +15 -8
  9. package/dist/facade.js +5 -4
  10. package/dist/framing/jsonframe.d.ts +1 -1
  11. package/dist/framing/jsonframe.js +3 -1
  12. package/dist/interop/proxyServerPeer.js +1 -1
  13. package/dist/interop/serverParityPeer.js +8 -1
  14. package/dist/node/acceptor.d.ts +10 -0
  15. package/dist/node/acceptor.js +53 -7
  16. package/dist/node/acceptorV3.d.ts +57 -0
  17. package/dist/node/acceptorV3.js +227 -0
  18. package/dist/node/connectSessionV3.d.ts +21 -0
  19. package/dist/node/connectSessionV3.js +73 -0
  20. package/dist/node/index.d.ts +15 -10
  21. package/dist/node/index.js +6 -5
  22. package/dist/node/nativeTransportAddon.d.ts +39 -1
  23. package/dist/node/nativeTransportAddon.js +29 -5
  24. package/dist/node/rawQuicAdapterV3.d.ts +10 -0
  25. package/dist/node/rawQuicAdapterV3.js +76 -0
  26. package/dist/node/rawQuicServerV3.d.ts +24 -0
  27. package/dist/node/rawQuicServerV3.js +34 -0
  28. package/dist/node/runtimeAuthorizationV3.d.ts +29 -0
  29. package/dist/node/runtimeAuthorizationV3.js +126 -0
  30. package/dist/node/tunnelRuntimeV3.d.ts +57 -0
  31. package/dist/node/tunnelRuntimeV3.js +857 -0
  32. package/dist/node/v2.d.ts +11 -0
  33. package/dist/node/v2.js +6 -0
  34. package/dist/node/webSocketServerV3.d.ts +27 -0
  35. package/dist/node/webSocketServerV3.js +219 -0
  36. package/dist/proxy/runtime.js +39 -6
  37. package/dist/proxy/serviceWorker.d.ts +2 -0
  38. package/dist/proxy/serviceWorker.js +63 -7
  39. package/dist/proxy/windowBridge.d.ts +1 -0
  40. package/dist/proxy/windowBridge.js +93 -33
  41. package/dist/proxy/wsPatch.d.ts +1 -0
  42. package/dist/proxy/wsPatch.js +39 -6
  43. package/dist/public/streamHandlers.d.ts +3 -0
  44. package/dist/public/streamHandlers.js +6 -1
  45. package/dist/rpc/client.js +9 -7
  46. package/dist/rpc/server.js +44 -20
  47. package/dist/rpc/validate.d.ts +1 -0
  48. package/dist/rpc/validate.js +18 -6
  49. package/dist/v2/index.d.ts +14 -0
  50. package/dist/v2/index.js +7 -0
  51. package/dist/v2/protocol.js +23 -32
  52. package/dist/v2/publicSession.js +4 -0
  53. package/dist/v2/session.d.ts +5 -0
  54. package/dist/v2/session.js +94 -35
  55. package/dist/v3/admissionError.d.ts +4 -0
  56. package/dist/v3/admissionError.js +8 -0
  57. package/dist/v3/artifact.d.ts +145 -0
  58. package/dist/v3/artifact.js +1162 -0
  59. package/dist/v3/artifactLease.d.ts +17 -0
  60. package/dist/v3/artifactLease.js +109 -0
  61. package/dist/v3/browserRuntime.d.ts +37 -0
  62. package/dist/v3/browserRuntime.js +197 -0
  63. package/dist/v3/browserSessionRuntime.d.ts +2 -0
  64. package/dist/v3/browserSessionRuntime.js +21 -0
  65. package/dist/v3/capability.d.ts +32 -0
  66. package/dist/v3/capability.js +345 -0
  67. package/dist/v3/carrier.d.ts +84 -0
  68. package/dist/v3/carrier.js +411 -0
  69. package/dist/v3/connectionController.d.ts +87 -0
  70. package/dist/v3/connectionController.js +805 -0
  71. package/dist/v3/contract.d.ts +65 -0
  72. package/dist/v3/contract.js +3 -0
  73. package/dist/v3/controller.d.ts +43 -0
  74. package/dist/v3/controller.js +303 -0
  75. package/dist/v3/handshake.d.ts +81 -0
  76. package/dist/v3/handshake.js +471 -0
  77. package/dist/v3/jcs.d.ts +6 -0
  78. package/dist/v3/jcs.js +69 -0
  79. package/dist/v3/jsonPreflight.d.ts +1 -0
  80. package/dist/v3/jsonPreflight.js +251 -0
  81. package/dist/v3/nodeRuntime.d.ts +40 -0
  82. package/dist/v3/nodeRuntime.js +315 -0
  83. package/dist/v3/nodeSessionRuntime.d.ts +2 -0
  84. package/dist/v3/nodeSessionRuntime.js +13 -0
  85. package/dist/v3/protocol.d.ts +99 -0
  86. package/dist/v3/protocol.js +773 -0
  87. package/dist/v3/publicApi.d.ts +12 -0
  88. package/dist/v3/publicApi.js +46 -0
  89. package/dist/v3/publicSession.d.ts +1 -0
  90. package/dist/v3/publicSession.js +281 -0
  91. package/dist/v3/retryDisposition.d.ts +16 -0
  92. package/dist/v3/retryDisposition.js +30 -0
  93. package/dist/v3/runtimeAdapters.d.ts +9 -0
  94. package/dist/v3/runtimeAdapters.js +109 -0
  95. package/dist/v3/security.d.ts +34 -0
  96. package/dist/v3/security.js +100 -0
  97. package/dist/v3/serverAdmission.d.ts +38 -0
  98. package/dist/v3/serverAdmission.js +223 -0
  99. package/dist/v3/session.d.ts +318 -0
  100. package/dist/v3/session.js +2289 -0
  101. package/dist/v3/sessionConnector.d.ts +37 -0
  102. package/dist/v3/sessionConnector.js +440 -0
  103. package/dist/v3/streamLifetimeLedger.d.ts +31 -0
  104. package/dist/v3/streamLifetimeLedger.js +131 -0
  105. package/dist/v3/streamMetadata.d.ts +1 -0
  106. package/dist/v3/streamMetadata.js +7 -0
  107. package/dist/v3/transportConstants.d.ts +56 -0
  108. package/dist/v3/transportConstants.js +59 -0
  109. package/dist/v3/unreliableMessage.d.ts +44 -0
  110. package/dist/v3/unreliableMessage.js +284 -0
  111. package/dist/v3/webSocketCarrier.d.ts +31 -0
  112. package/dist/v3/webSocketCarrier.js +370 -0
  113. package/dist/v3/webTransportCarrier.d.ts +27 -0
  114. package/dist/v3/webTransportCarrier.js +534 -0
  115. package/dist/yamux/stream.d.ts +3 -0
  116. package/dist/yamux/stream.js +17 -4
  117. package/package.json +4 -4
  118. package/sbom/cyclonedx.json +6 -6
  119. package/sbom/spdx.json +11 -11
@@ -616,68 +616,59 @@ export function canonicalStreamMetadataJSONV2Internal(value) {
616
616
  if (!isJSONObject(value))
617
617
  throw new ProtocolV2Error("OPEN metadata root must be an object");
618
618
  const state = { nodes: -1 };
619
- validateMetadataValue(value, 1, state);
620
- const canonical = canonicalJSONString(value);
619
+ const canonical = canonicalValidatedMetadataJSONString(value, 1, state);
621
620
  if (encoder.encode(canonical).length > MAX_OPEN_METADATA_BYTES) {
622
621
  throw new ProtocolV2Error("OPEN metadata is too large");
623
622
  }
624
623
  return canonical;
625
624
  }
626
- function validateMetadataValue(value, depth, state) {
625
+ function canonicalValidatedMetadataJSONString(value, depth, state) {
627
626
  if (depth > MAX_OPEN_METADATA_DEPTH)
628
627
  throw new ProtocolV2Error("OPEN metadata exceeds depth limit");
629
628
  state.nodes += 1;
630
629
  if (state.nodes > MAX_OPEN_METADATA_NODES)
631
630
  throw new ProtocolV2Error("OPEN metadata exceeds node limit");
632
- if (value === null || typeof value === "boolean")
633
- return;
631
+ if (value === null)
632
+ return "null";
633
+ if (typeof value === "boolean")
634
+ return value ? "true" : "false";
634
635
  if (typeof value === "number") {
635
- if (!Number.isSafeInteger(value))
636
+ if (!Number.isSafeInteger(value) || Object.is(value, -0))
636
637
  throw new ProtocolV2Error("OPEN metadata number is not an I-JSON safe integer");
637
- return;
638
+ return value.toString(10);
638
639
  }
639
640
  if (typeof value === "string") {
640
641
  if (!validOpenUnicodeString(value, MAX_OPEN_METADATA_STRING_BYTES, true)) {
641
642
  throw new ProtocolV2Error("invalid OPEN metadata string");
642
643
  }
643
- return;
644
+ return quoteCanonicalJSONString(value);
644
645
  }
645
646
  if (Array.isArray(value)) {
646
- if (value.length > MAX_OPEN_METADATA_ARRAY)
647
+ const length = value.length;
648
+ if (length > MAX_OPEN_METADATA_ARRAY)
647
649
  throw new ProtocolV2Error("OPEN metadata array is too large");
648
- for (const item of value)
649
- validateMetadataValue(item, depth + 1, state);
650
- return;
650
+ const items = new Array(length);
651
+ for (let index = 0; index < length; index++) {
652
+ const item = value[index];
653
+ items[index] = canonicalValidatedMetadataJSONString(item, depth + 1, state);
654
+ }
655
+ return `[${items.join(",")}]`;
651
656
  }
652
657
  if (!isJSONObject(value))
653
658
  throw new ProtocolV2Error("unsupported OPEN metadata value");
654
- const keys = Object.keys(value);
659
+ const keys = Object.keys(value).sort();
655
660
  if (keys.length > MAX_OPEN_METADATA_KEYS)
656
661
  throw new ProtocolV2Error("OPEN metadata object is too large");
662
+ const members = new Array(keys.length);
663
+ let index = 0;
657
664
  for (const key of keys) {
658
665
  if (!validOpenUnicodeString(key, MAX_OPEN_METADATA_KEY_BYTES, false)) {
659
666
  throw new ProtocolV2Error("invalid OPEN metadata key");
660
667
  }
661
- validateMetadataValue(value[key], depth + 1, state);
668
+ const item = value[key];
669
+ members[index++] = `${quoteCanonicalJSONString(key)}:${canonicalValidatedMetadataJSONString(item, depth + 1, state)}`;
662
670
  }
663
- }
664
- function canonicalJSONString(value) {
665
- if (value === null)
666
- return "null";
667
- if (typeof value === "boolean")
668
- return value ? "true" : "false";
669
- if (typeof value === "number")
670
- return value.toString(10);
671
- if (typeof value === "string")
672
- return quoteCanonicalJSONString(value);
673
- if (Array.isArray(value))
674
- return `[${value.map(canonicalJSONString).join(",")}]`;
675
- if (!isJSONObject(value))
676
- throw new ProtocolV2Error("unsupported OPEN metadata value");
677
- return `{${Object.keys(value)
678
- .sort()
679
- .map((key) => `${quoteCanonicalJSONString(key)}:${canonicalJSONString(value[key])}`)
680
- .join(",")}}`;
671
+ return `{${members.join(",")}}`;
681
672
  }
682
673
  function quoteCanonicalJSONString(value) {
683
674
  return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
@@ -1,5 +1,6 @@
1
1
  import { SessionError } from "./contract.js";
2
2
  import { createStreamMetadataV2, streamMetadataValuesV2 } from "./streamMetadata.js";
3
+ import { assertRpcTypeId } from "../rpc/validate.js";
3
4
  /** @internal */
4
5
  export function projectSessionV2(session) {
5
6
  const notificationOwner = {
@@ -132,6 +133,7 @@ function projectRpcPeerV2(peer, notificationOwner) {
132
133
  return Object.freeze({
133
134
  async call(typeId, payload, decodeResponse, options) {
134
135
  try {
136
+ assertRpcTypeId(typeId);
135
137
  assertJsonValue(payload);
136
138
  const result = await peer.call(typeId, payload, options?.signal);
137
139
  if (result.error !== undefined) {
@@ -146,6 +148,7 @@ function projectRpcPeerV2(peer, notificationOwner) {
146
148
  },
147
149
  async notify(typeId, payload, options) {
148
150
  try {
151
+ assertRpcTypeId(typeId);
149
152
  assertJsonValue(payload);
150
153
  if (options?.signal?.aborted)
151
154
  throw options.signal.reason ?? new DOMException("The operation was aborted", "AbortError");
@@ -156,6 +159,7 @@ function projectRpcPeerV2(peer, notificationOwner) {
156
159
  }
157
160
  },
158
161
  onNotify(typeId, decodePayload, handler) {
162
+ assertRpcTypeId(typeId);
159
163
  if (notificationOwner.closed)
160
164
  return () => undefined;
161
165
  const unsubscribe = peer.onNotify(typeId, (payload) => {
@@ -91,6 +91,7 @@ export declare class SessionV2 implements SessionV2Contract {
91
91
  private controlReceiveEpoch;
92
92
  private controlReceiveSequence;
93
93
  private controlWriteTail;
94
+ private controlTerminalSealed;
94
95
  private nextLogicalID;
95
96
  private receivedGoAway;
96
97
  private receivedGoAwayLastAccepted;
@@ -164,6 +165,10 @@ export declare class SessionV2 implements SessionV2Contract {
164
165
  private acceptCarrierStreamAfterFSS2;
165
166
  private resetInboundBeforeDelivery;
166
167
  private sendControl;
168
+ private sendControlResponse;
169
+ private sendControlCleanup;
170
+ private sendTerminalControl;
171
+ private writeControl;
167
172
  private readControl;
168
173
  private controlLoop;
169
174
  private closeOnce;
@@ -96,6 +96,7 @@ export class SessionV2 {
96
96
  controlReceiveEpoch = 0;
97
97
  controlReceiveSequence = 0n;
98
98
  controlWriteTail = Promise.resolve();
99
+ controlTerminalSealed = false;
99
100
  nextLogicalID;
100
101
  receivedGoAway = false;
101
102
  receivedGoAwayLastAccepted = 0n;
@@ -312,10 +313,11 @@ export class SessionV2 {
312
313
  this.releaseStream(stream);
313
314
  let controlConfirmed = false;
314
315
  try {
315
- await this.sendControl(InnerTypeV2.StreamReset, idReason(stream.id, 6));
316
- this.commitLocalReset(stream.id);
317
- if (stream.hasRemoteFIN())
318
- controlConfirmed = await this.confirmControlDelivery();
316
+ if (await this.sendControlCleanup(InnerTypeV2.StreamReset, idReason(stream.id, 6))) {
317
+ this.commitLocalReset(stream.id);
318
+ if (stream.hasRemoteFIN())
319
+ controlConfirmed = await this.confirmControlDelivery();
320
+ }
319
321
  }
320
322
  catch (cause) {
321
323
  this.fail(asError(cause));
@@ -343,6 +345,8 @@ export class SessionV2 {
343
345
  this.cleanupEpochRoots();
344
346
  }
345
347
  async confirmControlDelivery() {
348
+ if (this.lifecycle !== "open" || this.controlTerminalSealed)
349
+ return false;
346
350
  const nonce = this.nextPing++;
347
351
  const pending = deferred();
348
352
  this.pings.set(nonce, pending);
@@ -567,33 +571,87 @@ export class SessionV2 {
567
571
  async resetInboundBeforeDelivery(id, carrierStream) {
568
572
  await carrierStream.reset().catch(() => undefined);
569
573
  try {
570
- await this.sendControl(InnerTypeV2.StreamReset, idReason(id, 3));
571
- this.peerLedger.localResetCommitted(id);
574
+ if (await this.sendControlCleanup(InnerTypeV2.StreamReset, idReason(id, 3))) {
575
+ this.peerLedger.localResetCommitted(id);
576
+ }
572
577
  }
573
578
  catch (error) {
574
579
  this.fail(asError(error));
575
580
  }
576
581
  }
577
582
  async sendControl(type, payload, signal) {
583
+ if (this.controlTerminalSealed) {
584
+ throw this.terminalError ?? new SessionV2Error("closed", "Flowersec v2 control stream is sealed");
585
+ }
578
586
  const task = this.controlWriteTail.then(async () => {
579
587
  if (this.lifecycle === "closed")
580
588
  throw this.terminalError ?? new SessionV2Error("closed", "Flowersec v2 session closed");
581
- const inner = encodeInnerRecordV2(type, payload);
582
- const roots = this.rootForSend(this.controlSendEpoch);
583
- const material = deriveControlMaterial(roots.controlRoot, this.h3, this.sendDirection, this.controlSendEpoch);
584
- const header = {
585
- epoch: this.controlSendEpoch,
586
- sequence: this.controlSendSequence,
587
- ciphertextLength: inner.length + 16,
588
- };
589
- const ciphertext = sealRecord(this.config.suite, material, this.h3, 0n, this.sendDirection, header, inner);
590
- this.controlSendSequence += 1n;
591
- await writeAll(this.control, concat(encodeRecordHeader(header), ciphertext), signal);
592
- this.markAuthenticatedActivity();
589
+ await this.writeControl(type, payload, signal);
593
590
  });
594
591
  this.controlWriteTail = task.catch(() => undefined);
595
592
  await task;
596
593
  }
594
+ async sendControlResponse(type, payload) {
595
+ if (this.lifecycle !== "open" || this.controlTerminalSealed)
596
+ return false;
597
+ const task = this.controlWriteTail.then(async () => {
598
+ if (this.lifecycle !== "open" || this.controlTerminalSealed)
599
+ return false;
600
+ await this.writeControl(type, payload);
601
+ return true;
602
+ });
603
+ this.controlWriteTail = task.then(() => undefined, () => undefined);
604
+ return await task;
605
+ }
606
+ async sendControlCleanup(type, payload) {
607
+ if (this.controlTerminalSealed || this.lifecycle === "closed")
608
+ return false;
609
+ const task = this.controlWriteTail.then(async () => {
610
+ if (this.lifecycle === "closed")
611
+ return false;
612
+ await this.writeControl(type, payload);
613
+ return true;
614
+ });
615
+ this.controlWriteTail = task.then(() => undefined, () => undefined);
616
+ return await task;
617
+ }
618
+ sendTerminalControl(reason) {
619
+ if (this.controlTerminalSealed)
620
+ return this.controlWriteTail;
621
+ this.controlTerminalSealed = true;
622
+ const task = this.controlWriteTail.then(async () => {
623
+ if (this.lifecycle === "closed")
624
+ throw this.terminalError ?? new SessionV2Error("closed", "Flowersec v2 session closed");
625
+ if (!this.sentGoAway) {
626
+ this.sentGoAway = true;
627
+ this.sentGoAwayLastAccepted = this.peerLedger.frontier;
628
+ this.sentGoAwayReason = reason;
629
+ }
630
+ await this.writeControl(InnerTypeV2.GoAway, idReason(this.sentGoAwayLastAccepted, this.sentGoAwayReason));
631
+ if (!this.sentSessionClose) {
632
+ this.sentSessionClose = true;
633
+ await this.writeControl(InnerTypeV2.SessionClose, Uint8Array.of(0, reason));
634
+ this.sessionCloseCommitted = true;
635
+ }
636
+ await this.control.closeWrite();
637
+ });
638
+ this.controlWriteTail = task.catch(() => undefined);
639
+ return task;
640
+ }
641
+ async writeControl(type, payload, signal) {
642
+ const inner = encodeInnerRecordV2(type, payload);
643
+ const roots = this.rootForSend(this.controlSendEpoch);
644
+ const material = deriveControlMaterial(roots.controlRoot, this.h3, this.sendDirection, this.controlSendEpoch);
645
+ const header = {
646
+ epoch: this.controlSendEpoch,
647
+ sequence: this.controlSendSequence,
648
+ ciphertextLength: inner.length + 16,
649
+ };
650
+ const ciphertext = sealRecord(this.config.suite, material, this.h3, 0n, this.sendDirection, header, inner);
651
+ this.controlSendSequence += 1n;
652
+ await writeAll(this.control, concat(encodeRecordHeader(header), ciphertext), signal);
653
+ this.markAuthenticatedActivity();
654
+ }
597
655
  async readControl() {
598
656
  const header = decodeRecordHeader(await this.controlReader.readExactly(24));
599
657
  const cutover = header.epoch === this.controlReceiveEpoch + 1 &&
@@ -622,7 +680,7 @@ export class SessionV2 {
622
680
  const record = await this.readControl();
623
681
  switch (record.type) {
624
682
  case InnerTypeV2.Ping:
625
- await this.sendControl(InnerTypeV2.Pong, record.payload);
683
+ await this.sendControlResponse(InnerTypeV2.Pong, record.payload);
626
684
  break;
627
685
  case InnerTypeV2.Pong:
628
686
  this.pings.get(readU64(record.payload))?.resolve();
@@ -685,20 +743,10 @@ export class SessionV2 {
685
743
  if (this.lifecycle === "closed")
686
744
  return;
687
745
  const closed = new SessionV2Error("closed", "Flowersec v2 session closed");
746
+ const terminal = this.sendTerminalControl(1);
688
747
  const work = (async () => {
689
748
  try {
690
- await this.sendGoAway(1);
691
- }
692
- catch {
693
- // A prior GOAWAY boundary must not suppress the close response.
694
- }
695
- try {
696
- if (!this.sentSessionClose) {
697
- this.sentSessionClose = true;
698
- await this.sendControl(InnerTypeV2.SessionClose, Uint8Array.of(0, 1));
699
- this.sessionCloseCommitted = true;
700
- await this.control.closeWrite();
701
- }
749
+ await terminal;
702
750
  }
703
751
  catch {
704
752
  // Closing is best-effort once the bounded shutdown has started.
@@ -853,7 +901,12 @@ export class SessionV2 {
853
901
  }
854
902
  const streams = [...this.streams.values()];
855
903
  await Promise.all(streams.map(async (stream) => await stream.waitReceiveRekey(transition, nextEpoch, signal)));
856
- await raceAbort(this.sendControl(InnerTypeV2.SessionKeyUpdateACK, payload), signal);
904
+ const acknowledged = await raceAbort(this.sendControlResponse(InnerTypeV2.SessionKeyUpdateACK, payload), signal);
905
+ if (!acknowledged) {
906
+ this.pendingReceiveEpoch = undefined;
907
+ this.cleanupEpochRoots();
908
+ return;
909
+ }
857
910
  throwIfAborted(signal);
858
911
  this.receiveEpoch = nextEpoch;
859
912
  this.receiveTransition = transition;
@@ -897,9 +950,10 @@ export class SessionV2 {
897
950
  }
898
951
  }
899
952
  async commitOutboundReset(id) {
900
- await this.sendControl(InnerTypeV2.StreamReset, idReason(id, 6));
901
- this.outboundLedger.localResetCommitted(id);
902
- this.notifyOutboundFrontierChanged();
953
+ if (await this.sendControlCleanup(InnerTypeV2.StreamReset, idReason(id, 6))) {
954
+ this.outboundLedger.localResetCommitted(id);
955
+ this.notifyOutboundFrontierChanged();
956
+ }
903
957
  }
904
958
  commitLocalReset(id) {
905
959
  if (this.isLocalLogicalID(id)) {
@@ -1026,6 +1080,7 @@ export class SessionV2 {
1026
1080
  fail(error, abortCarrier = true) {
1027
1081
  if (this.lifecycle === "closed")
1028
1082
  return;
1083
+ this.controlTerminalSealed = true;
1029
1084
  this.beginClosing();
1030
1085
  const normalPeerCarrierClose = this.sessionCloseCommitted && error instanceof CarrierError && error.code === "closed";
1031
1086
  if (normalPeerCarrierClose)
@@ -1224,6 +1279,10 @@ class EncryptedStreamV2 {
1224
1279
  if (this.terminalError !== undefined)
1225
1280
  return false;
1226
1281
  this.terminalError = error;
1282
+ const pendingSendRekey = this.pendingSendRekey;
1283
+ this.pendingSendRekey = undefined;
1284
+ pendingSendRekey?.armed.reject(error);
1285
+ pendingSendRekey?.done.reject(error);
1227
1286
  this.opened.reject(error);
1228
1287
  this.data.fail(error);
1229
1288
  return true;
@@ -0,0 +1,4 @@
1
+ export declare class AdmissionSessionV3Error extends Error {
2
+ readonly reason: string;
3
+ constructor(reason: string, message: string);
4
+ }
@@ -0,0 +1,8 @@
1
+ export class AdmissionSessionV3Error extends Error {
2
+ reason;
3
+ constructor(reason, message) {
4
+ super(message);
5
+ this.reason = reason;
6
+ this.name = "AdmissionSessionV3Error";
7
+ }
8
+ }
@@ -0,0 +1,145 @@
1
+ import { FLOWERSEC_V3_PROFILE } from "./transportConstants.js";
2
+ export type ArtifactCarrierV3 = "websocket" | "raw_quic" | "webtransport";
3
+ export type ArtifactPathKindV3 = "direct" | "tunnel";
4
+ export type CertificatePinV3 = Readonly<{
5
+ algorithm: "sha-256";
6
+ not_after_unix_s: number;
7
+ value_b64u: string;
8
+ }>;
9
+ export type TransportSecurityPolicyV3 = Readonly<{
10
+ mode: "ca";
11
+ }> | Readonly<{
12
+ mode: "pin";
13
+ pins: readonly CertificatePinV3[];
14
+ }>;
15
+ export type ArtifactCandidateV3 = Readonly<{
16
+ id: string;
17
+ carrier: ArtifactCarrierV3;
18
+ url: string;
19
+ wire_profile: string;
20
+ tls: TransportSecurityPolicyV3;
21
+ normalized_url?: string;
22
+ }>;
23
+ export type CanonicalArtifactCandidateV3 = Readonly<{
24
+ carrier: ArtifactCarrierV3;
25
+ id: string;
26
+ normalized_url: string;
27
+ tls: TransportSecurityPolicyV3;
28
+ wire_profile: string;
29
+ }>;
30
+ export type SessionContractV3 = Readonly<{
31
+ channel_id: string;
32
+ init_expire_at_unix_s: number;
33
+ idle_timeout_seconds: number;
34
+ establish_timeout_seconds: number;
35
+ rekey_prepare_timeout_seconds: number;
36
+ rekey_completion_timeout_seconds: number;
37
+ max_inbound_streams: number;
38
+ e2ee_psk_b64u: string;
39
+ allowed_suites: readonly number[];
40
+ default_suite: number;
41
+ selected_features: number;
42
+ contract_hash_b64u: string;
43
+ }>;
44
+ export type DirectArtifactPathV3 = Readonly<{
45
+ kind: "direct";
46
+ rendezvous_group_id: string;
47
+ listener_audience: string;
48
+ routing_token: string;
49
+ candidates: readonly ArtifactCandidateV3[];
50
+ }>;
51
+ export type TunnelArtifactPathV3 = Readonly<{
52
+ kind: "tunnel";
53
+ rendezvous_group_id: string;
54
+ listener_audience: string;
55
+ role: 1 | 2;
56
+ local_endpoint_instance_id: string;
57
+ expected_peer_endpoint_instance_id: string;
58
+ token: string;
59
+ candidates: readonly ArtifactCandidateV3[];
60
+ }>;
61
+ export type ScopeMetadataV3 = Readonly<{
62
+ scope: string;
63
+ scope_version: number;
64
+ critical: boolean;
65
+ payload: Readonly<Record<string, unknown>>;
66
+ }>;
67
+ export type CorrelationTagV3 = Readonly<{
68
+ key: string;
69
+ value: string;
70
+ }>;
71
+ export type CorrelationContextV3 = Readonly<{
72
+ v: 3;
73
+ tags: readonly CorrelationTagV3[];
74
+ }>;
75
+ export type ArtifactV3 = Readonly<{
76
+ v: 3;
77
+ profile: typeof FLOWERSEC_V3_PROFILE;
78
+ session: SessionContractV3;
79
+ path: DirectArtifactPathV3 | TunnelArtifactPathV3;
80
+ scoped: readonly ScopeMetadataV3[];
81
+ correlation: CorrelationContextV3;
82
+ }>;
83
+ type CommonFSB3RequestV3 = Readonly<{
84
+ profile: typeof FLOWERSEC_V3_PROFILE;
85
+ channel_id: string;
86
+ session_contract_hash_b64u: string;
87
+ rendezvous_group_id: string;
88
+ candidates: readonly CanonicalArtifactCandidateV3[];
89
+ candidate_set_hash_b64u: string;
90
+ chosen_candidate_id: string;
91
+ listener_audience: string;
92
+ }>;
93
+ export type DirectFSB3RequestV3 = CommonFSB3RequestV3 & Readonly<{
94
+ pathKind: "direct";
95
+ routing_token: string;
96
+ }>;
97
+ export type TunnelFSB3RequestV3 = CommonFSB3RequestV3 & Readonly<{
98
+ pathKind: "tunnel";
99
+ role: 1 | 2;
100
+ endpoint_instance_id: string;
101
+ attach_token: string;
102
+ }>;
103
+ export type FSB3RequestV3 = DirectFSB3RequestV3 | TunnelFSB3RequestV3;
104
+ export type DecodedFSB3RequestV3 = Readonly<{
105
+ request: FSB3RequestV3;
106
+ raw: Uint8Array;
107
+ localAdmissionBinding: Uint8Array;
108
+ }>;
109
+ export declare enum AdmissionStatusV3 {
110
+ Success = 0,
111
+ Reject = 1,
112
+ Retryable = 2
113
+ }
114
+ export type AdmissionResponseV3 = Readonly<{
115
+ status: AdmissionStatusV3;
116
+ reason: string;
117
+ }>;
118
+ export type ArtifactV3ErrorCode = "artifact_too_large" | "fsb3_payload_too_large" | "invalid_artifact" | "invalid_candidate" | "invalid_fsa3" | "invalid_fsb3" | "noncanonical_fsb3";
119
+ export declare class ArtifactV3Error extends Error {
120
+ readonly code: ArtifactV3ErrorCode;
121
+ constructor(code: ArtifactV3ErrorCode, message: string);
122
+ }
123
+ export type LabeledHashV3 = Readonly<{
124
+ canonicalJSON: string;
125
+ hash: Uint8Array;
126
+ hashBase64URL: string;
127
+ }>;
128
+ export type CanonicalCandidateSetV3 = LabeledHashV3 & Readonly<{
129
+ candidates: readonly CanonicalArtifactCandidateV3[];
130
+ }>;
131
+ export declare function computeSessionContractHashV3(session: SessionContractV3): LabeledHashV3;
132
+ export declare function canonicalizeCandidatesV3(kind: ArtifactPathKindV3, candidates: readonly ArtifactCandidateV3[]): CanonicalCandidateSetV3;
133
+ export declare function decodeArtifactV3JSON(raw: string | Uint8Array): ArtifactV3;
134
+ export declare function encodeArtifactV3JSON(artifact: ArtifactV3): Uint8Array;
135
+ export declare function validateArtifactV3(artifact: ArtifactV3): CanonicalCandidateSetV3;
136
+ export declare function buildFSB3RequestV3(artifact: ArtifactV3, chosenCandidateID: string): FSB3RequestV3;
137
+ export declare function encodeFSB3RequestV3(request: FSB3RequestV3): Uint8Array;
138
+ export declare function decodeFSB3RequestV3(raw: Uint8Array): DecodedFSB3RequestV3;
139
+ export declare function admissionBindingV3(rawFSB3: Uint8Array): Uint8Array;
140
+ export declare function acceptorAdmissionsHashV3(framesByCandidateID: ReadonlyMap<string, Uint8Array>): Uint8Array;
141
+ export declare function encodeFSA3ResponseV3(response: AdmissionResponseV3, admissionReasons?: ReadonlySet<string>): Uint8Array;
142
+ export declare function decodeFSA3ResponseV3(raw: Uint8Array): AdmissionResponseV3;
143
+ export declare function tlsPolicyDigestV3(policy: TransportSecurityPolicyV3): LabeledHashV3;
144
+ export declare function activePinsV3(policy: TransportSecurityPolicyV3, attemptNowUnixSeconds: number): readonly CertificatePinV3[];
145
+ export {};