p2party 0.14.7 → 0.14.10

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 (181) hide show
  1. package/README.md +26 -23
  2. package/THIRD_PARTY_NOTICES.md +33 -6
  3. package/docs/getting-started.md +103 -4
  4. package/docs/protocol-v4-security.md +57 -7
  5. package/docs/references.md +1 -1
  6. package/docs/session-api.md +9 -0
  7. package/docs/wire-format.md +102 -14
  8. package/lib/api/signalingServerApi.d.ts +38 -0
  9. package/lib/api/webrtc/interfaces.d.ts +33 -1
  10. package/lib/api/webrtc/peerSocketGeneration.d.ts +68 -0
  11. package/lib/cryptography/coverCell.d.ts +7 -0
  12. package/lib/cryptography/emscripten.d.ts +101 -0
  13. package/lib/cryptography/libcrypto.d.ts +181 -0
  14. package/lib/db/outboxTypes.d.ts +135 -0
  15. package/lib/db/types.d.ts +29 -3
  16. package/lib/db.worker.js +1 -1
  17. package/lib/handlers/coverRuntime.d.ts +14 -1
  18. package/lib/handlers/coverScheduler.d.ts +59 -1
  19. package/lib/handlers/coverTransfer.d.ts +169 -3
  20. package/lib/handlers/handleSendMessage.d.ts +79 -3
  21. package/lib/handlers/outbox.d.ts +47 -0
  22. package/lib/handlers/ratchetGate.d.ts +9 -0
  23. package/lib/handlers/reconcile.d.ts +5 -0
  24. package/lib/index.d.ts +5 -0
  25. package/lib/index.js +1 -1
  26. package/lib/index.min.js +1 -1
  27. package/lib/index.mjs +1 -1
  28. package/lib/reducers/roomSlice.d.ts +9 -2
  29. package/lib/session.js +1 -1
  30. package/lib/session.mjs +1 -1
  31. package/lib/utils/constants.d.ts +7 -0
  32. package/lib/utils/interfaces.d.ts +11 -0
  33. package/lib/utils/signalingReconnectController.d.ts +44 -0
  34. package/package.json +13 -15
  35. package/lib/api/webrtc/applyIceConfiguration.d.ts +0 -9
  36. package/lib/api/webrtc/dataChannelHandler.d.ts +0 -10
  37. package/lib/api/webrtc/deleteRoomData.d.ts +0 -13
  38. package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts +0 -9
  39. package/lib/api/webrtc/disconnectFromChannelLabelQuery.d.ts +0 -7
  40. package/lib/api/webrtc/disconnectFromPeerChannelLabelQuery.d.ts +0 -8
  41. package/lib/api/webrtc/disconnectFromPeerQuery.d.ts +0 -9
  42. package/lib/api/webrtc/disconnectFromRoomQuery.d.ts +0 -9
  43. package/lib/api/webrtc/disconnectQuery.d.ts +0 -9
  44. package/lib/api/webrtc/iceGeneration.d.ts +0 -17
  45. package/lib/api/webrtc/iceRepair.d.ts +0 -12
  46. package/lib/api/webrtc/index.d.ts +0 -17
  47. package/lib/api/webrtc/negotiationLock.d.ts +0 -36
  48. package/lib/api/webrtc/openChannelQuery.d.ts +0 -8
  49. package/lib/api/webrtc/pendingIceCandidates.d.ts +0 -14
  50. package/lib/api/webrtc/pendingOffer.d.ts +0 -29
  51. package/lib/api/webrtc/rebindDeadline.d.ts +0 -61
  52. package/lib/api/webrtc/remoteTransportChange.d.ts +0 -142
  53. package/lib/api/webrtc/retiredRemoteTransports.d.ts +0 -70
  54. package/lib/api/webrtc/roomEdgeBudget.d.ts +0 -10
  55. package/lib/api/webrtc/roomPeer.d.ts +0 -11
  56. package/lib/api/webrtc/sendMessageQuery.d.ts +0 -14
  57. package/lib/api/webrtc/setCandidateQuery.d.ts +0 -8
  58. package/lib/api/webrtc/setDescriptionQuery.d.ts +0 -16
  59. package/lib/api/webrtc/settleOnClose.d.ts +0 -36
  60. package/lib/blindRendezvous/admissionInput.d.ts +0 -11
  61. package/lib/blindRendezvous/admissionPolicy.d.ts +0 -217
  62. package/lib/blindRendezvous/canonicalSchema.d.ts +0 -139
  63. package/lib/blindRendezvous/carrierEnvelope.d.ts +0 -105
  64. package/lib/blindRendezvous/coreReduce.d.ts +0 -199
  65. package/lib/blindRendezvous/derivations.d.ts +0 -381
  66. package/lib/blindRendezvous/identityHelloAdmission.d.ts +0 -89
  67. package/lib/blindRendezvous/identityHelloAdmissionPersistence.d.ts +0 -133
  68. package/lib/blindRendezvous/identityHelloHistoricalEvidence.d.ts +0 -52
  69. package/lib/blindRendezvous/identityHelloOpen.d.ts +0 -167
  70. package/lib/blindRendezvous/identityHelloTrial.d.ts +0 -271
  71. package/lib/blindRendezvous/localAdmissibleProject.d.ts +0 -101
  72. package/lib/blindRendezvous/localPresenceKeyBinding.d.ts +0 -108
  73. package/lib/blindRendezvous/localStableIdentityCustody.d.ts +0 -46
  74. package/lib/blindRendezvous/normativeKernel.d.ts +0 -222
  75. package/lib/blindRendezvous/operation.d.ts +0 -137
  76. package/lib/blindRendezvous/operationPayload.d.ts +0 -134
  77. package/lib/blindRendezvous/pairBootstrapSuite.d.ts +0 -93
  78. package/lib/blindRendezvous/pairCrypto.d.ts +0 -122
  79. package/lib/blindRendezvous/pairLedger.d.ts +0 -154
  80. package/lib/blindRendezvous/pairOpenBudget.d.ts +0 -67
  81. package/lib/blindRendezvous/pairOpenReservation.d.ts +0 -157
  82. package/lib/blindRendezvous/pairPlaintext.d.ts +0 -240
  83. package/lib/blindRendezvous/pairStepEnvelope.d.ts +0 -60
  84. package/lib/blindRendezvous/plannerState.d.ts +0 -61
  85. package/lib/blindRendezvous/projections.d.ts +0 -71
  86. package/lib/blindRendezvous/publicWindow.d.ts +0 -330
  87. package/lib/blindRendezvous/retainedOperationStore.d.ts +0 -187
  88. package/lib/blindRendezvous/roomInviteV2.d.ts +0 -92
  89. package/lib/blindRendezvous/roomPolicyV4.d.ts +0 -90
  90. package/lib/blindRendezvous/schemas.d.ts +0 -221
  91. package/lib/blindRendezvous/storeDescriptor.d.ts +0 -160
  92. package/lib/cryptography/aeadWasm.d.ts +0 -18
  93. package/lib/cryptography/byteInput.d.ts +0 -12
  94. package/lib/cryptography/carrierAead.d.ts +0 -23
  95. package/lib/cryptography/chacha20poly1305.d.ts +0 -7
  96. package/lib/cryptography/cpace.d.ts +0 -41
  97. package/lib/cryptography/ed25519.d.ts +0 -11
  98. package/lib/cryptography/fips202.d.ts +0 -10
  99. package/lib/cryptography/hashStream.d.ts +0 -15
  100. package/lib/cryptography/hkdf.d.ts +0 -3
  101. package/lib/cryptography/hpke.d.ts +0 -84
  102. package/lib/cryptography/hpkeSuite.d.ts +0 -39
  103. package/lib/cryptography/hybridKem.d.ts +0 -42
  104. package/lib/cryptography/hybridKemSuite.d.ts +0 -22
  105. package/lib/cryptography/identityCrossSig.d.ts +0 -7
  106. package/lib/cryptography/memory.d.ts +0 -14
  107. package/lib/cryptography/merkle.d.ts +0 -42
  108. package/lib/cryptography/ownedEd25519KeyMaterial.d.ts +0 -27
  109. package/lib/cryptography/pqHealingFrame.d.ts +0 -39
  110. package/lib/cryptography/random.d.ts +0 -22
  111. package/lib/cryptography/testModule.d.ts +0 -7
  112. package/lib/cryptography/utils.d.ts +0 -13
  113. package/lib/cryptography/webCryptoSha256.d.ts +0 -20
  114. package/lib/cryptography/x25519.d.ts +0 -33
  115. package/lib/cryptography/x3dh.d.ts +0 -9
  116. package/lib/cryptography/xchacha20poly1305.d.ts +0 -7
  117. package/lib/db/api.d.ts +0 -70
  118. package/lib/db/db.worker.d.ts +0 -1
  119. package/lib/db/identityEd25519ClientBoundary.d.ts +0 -13
  120. package/lib/db/ratchetWrap.d.ts +0 -36
  121. package/lib/db/src/getDB.d.ts +0 -81
  122. package/lib/handlers/chunkFrame.d.ts +0 -13
  123. package/lib/handlers/connectionSignal.d.ts +0 -26
  124. package/lib/handlers/coverChannelRegistry.d.ts +0 -22
  125. package/lib/handlers/coverEdge.d.ts +0 -42
  126. package/lib/handlers/edgeTeardownFollowUp.d.ts +0 -35
  127. package/lib/handlers/frameType.d.ts +0 -10
  128. package/lib/handlers/handleChallenge.d.ts +0 -4
  129. package/lib/handlers/handleConnectToPeer.d.ts +0 -6
  130. package/lib/handlers/handleHandshake.d.ts +0 -70
  131. package/lib/handlers/handleMessageQueueing.d.ts +0 -54
  132. package/lib/handlers/handleOpenChannel.d.ts +0 -12
  133. package/lib/handlers/handleQueuedIceCandidates.d.ts +0 -2
  134. package/lib/handlers/handleReadReceipt.d.ts +0 -17
  135. package/lib/handlers/handleReceiveMessage.d.ts +0 -32
  136. package/lib/handlers/handleWebSocketMessage.d.ts +0 -3
  137. package/lib/handlers/messageChunkCrypto.d.ts +0 -70
  138. package/lib/handlers/peerRosterDelta.d.ts +0 -12
  139. package/lib/handlers/pqHealingOrchestrator.d.ts +0 -46
  140. package/lib/handlers/ratchetGateWait.d.ts +0 -13
  141. package/lib/handlers/ratchetPersist.d.ts +0 -53
  142. package/lib/handlers/receiptFrame.d.ts +0 -18
  143. package/lib/handlers/receiveMessageKeyLifetime.d.ts +0 -24
  144. package/lib/handlers/requestRoom.d.ts +0 -30
  145. package/lib/handlers/roomResponse.d.ts +0 -53
  146. package/lib/handlers/transferAbort.d.ts +0 -42
  147. package/lib/middleware/keyPairListenerMiddleware.d.ts +0 -2
  148. package/lib/middleware/roomListenerMiddleware.d.ts +0 -5
  149. package/lib/roomInvite.d.ts +0 -18
  150. package/lib/roomPinAttempts.d.ts +0 -12
  151. package/lib/roomPinVault.d.ts +0 -26
  152. package/lib/utils/channelLabel.d.ts +0 -9
  153. package/lib/utils/chunkBounds.d.ts +0 -9
  154. package/lib/utils/correlationId.d.ts +0 -4
  155. package/lib/utils/drainAndClose.d.ts +0 -5
  156. package/lib/utils/identityRole.d.ts +0 -19
  157. package/lib/utils/leafHash.d.ts +0 -13
  158. package/lib/utils/metadata.d.ts +0 -22
  159. package/lib/utils/mutex.d.ts +0 -24
  160. package/lib/utils/protocolVersion.d.ts +0 -5
  161. package/lib/utils/receiptToken.d.ts +0 -7
  162. package/lib/utils/roomConnectAdmission.d.ts +0 -15
  163. package/lib/utils/roomRequestCoordinator.d.ts +0 -104
  164. package/lib/utils/roomRosterReconciler.d.ts +0 -83
  165. package/lib/utils/sdpFingerprint.d.ts +0 -6
  166. package/lib/utils/sendQueueKey.d.ts +0 -2
  167. package/lib/utils/signalingAttemptLifecycle.d.ts +0 -33
  168. package/lib/utils/signalingAuth.d.ts +0 -27
  169. package/lib/utils/signalingBounds.d.ts +0 -15
  170. package/lib/utils/signalingFrame.d.ts +0 -21
  171. package/lib/utils/signalingHeartbeatWatchdog.d.ts +0 -45
  172. package/lib/utils/signalingIngressQueue.d.ts +0 -49
  173. package/lib/utils/signalingPeerRequestDebouncer.d.ts +0 -13
  174. package/lib/utils/signalingRoomLifecycle.d.ts +0 -7
  175. package/lib/utils/signalingRoomOperationLifecycle.d.ts +0 -14
  176. package/lib/utils/signalingServerBoundary.d.ts +0 -11
  177. package/lib/utils/splitToChunks.d.ts +0 -30
  178. package/lib/utils/transportIdentity.d.ts +0 -5
  179. package/lib/utils/uint8array.d.ts +0 -16
  180. package/lib/utils/waitForOpen.d.ts +0 -3
  181. package/lib/utils/zeroFree.d.ts +0 -10
@@ -3,11 +3,20 @@ import type { RatchetState } from "../../cryptography/ratchet";
3
3
  import type { RatchetGateLease } from "../../handlers/ratchetGate";
4
4
  import type { CoverRuntime } from "../../handlers/coverRuntime";
5
5
  import type { SparsePqHealingState } from "../../handlers/pqHealingRuntime";
6
+ import type { PeerHandshakeFailureReason } from "../../reducers/roomSlice";
7
+ import type { PeerSocketGenerationSource } from "./peerSocketGeneration";
6
8
  export interface IRTCPeerConnection extends RTCPeerConnection {
7
9
  /** The room this transport belongs to. A room/peer pair owns one PC. */
8
10
  roomId: string;
9
11
  withPeerId: string;
10
12
  withPeerPublicKey: string;
13
+ /**
14
+ * The peer signaling socket this transport was built against. A different
15
+ * generation for the same peerId means the peer's session was replaced, and
16
+ * this transport can never be signalled again (C1). Absent against a
17
+ * pre-generation server, where it must never be read as a change.
18
+ */
19
+ peerSocketGeneration?: string;
11
20
  makingOffer: boolean;
12
21
  ignoreOffer: boolean;
13
22
  receiveMessageModule: LibCrypto;
@@ -16,6 +25,13 @@ export interface IRTCPeerConnection extends RTCPeerConnection {
16
25
  mainChannel?: IRTCDataChannel;
17
26
  /** Gate ownership captured when this concrete transport is created. */
18
27
  ratchetGateLease: RatchetGateLease;
28
+ /**
29
+ * Set when this edge's handshake failed for a reason a fresh transport
30
+ * cannot fix (a wrong PIN, a PIN throttle, a policy/suite mismatch). The
31
+ * `main` channel's close handler consults it so a terminal failure is never
32
+ * followed by a re-dial. Cleared only by building a new transport.
33
+ */
34
+ handshakeTerminalFailure?: PeerHandshakeFailureReason;
19
35
  /**
20
36
  * How many times this RTCPeerConnection has been re-bound IN PLACE onto a
21
37
  * new remote DTLS certificate since it last authenticated. The re-bind
@@ -88,6 +104,13 @@ export interface IRTCDataChannel extends RTCDataChannel {
88
104
  * delete its storage artifacts after the active handler reaches quiescence.
89
105
  */
90
106
  cancelReceiveTransfer?: () => Promise<void>;
107
+ /**
108
+ * Set by any close THIS side initiated (the pre-authentication frame guard,
109
+ * the transfer's terminal-close runner, the resume path's cleanup). Read by
110
+ * `isAuthenticatedPeerCancel` so our own close is never reported as the peer
111
+ * cancelling the transfer (C7).
112
+ */
113
+ closedLocally?: boolean;
91
114
  }
92
115
  export interface IRTCMessage {
93
116
  id: string;
@@ -106,6 +129,15 @@ export interface RTCPeerConnectionParams {
106
129
  peerPublicKey: string;
107
130
  roomId: string;
108
131
  rtcConfig?: RTCConfiguration;
132
+ /** The peer's signaling-socket generation, as last named by the server. */
133
+ peerSocketGeneration?: string;
134
+ /**
135
+ * Which inbound frame named that generation. Only a `connection` frame
136
+ * proves a fresh remote transport; a roster introduction is record-only
137
+ * while this side's transport is connected (see peerSocketGeneration).
138
+ * Omitted means advisory.
139
+ */
140
+ peerSocketGenerationSource?: PeerSocketGenerationSource;
109
141
  }
110
142
  export interface RTCSetDescriptionParams {
111
143
  peerId: string;
@@ -138,7 +170,7 @@ export interface RTCOpenChannelParams {
138
170
  export interface RTCSendMessageParams {
139
171
  /** Random 32-byte lowercase-hex identity allocated by the public API. */
140
172
  transferId: string;
141
- data: string | File;
173
+ data?: string | File;
142
174
  label: string;
143
175
  roomId: string;
144
176
  minChunks?: number;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Whether a peerId still names the same signaling session.
3
+ *
4
+ * The server binds one stable peerId to an identity public key, so a second
5
+ * tab or a phrase-restored second device reconnects as the SAME peerId and
6
+ * evicts its predecessor. Without a per-socket generation the edge stayed
7
+ * bound to the evicted socket: the transport never failed (no SDP, no ICE
8
+ * event), so nothing rebuilt it, and a responder on the new session creates no
9
+ * channel and can never offer — the split was permanent (C1).
10
+ *
11
+ * "unknown" is the fail-safe verdict: an absent or malformed generation (a
12
+ * pre-generation server, or a fresh transport that has not recorded one yet)
13
+ * must behave exactly as 0.14.7 does, never as a teardown trigger. The server
14
+ * leaves the field empty until a socket has proved ownership of its key and
15
+ * empties it again whenever a fresh challenge is issued, so "" and undefined
16
+ * are the same statement: no information.
17
+ */
18
+ export type PeerSocketGenerationVerdict = "unknown" | "unchanged" | "changed";
19
+ /**
20
+ * Which inbound frame carried a generation, and therefore how much authority
21
+ * it has.
22
+ *
23
+ * - "connection": the peer's own `connection` frame. It is emitted from one
24
+ * place only (handleConnectToPeer's connectWithPeer), and that place is
25
+ * reachable only after a FRESH transport has been built — both baseQuery and
26
+ * handleConnectToPeer early-return on a live one. A changed generation there
27
+ * always means a genuinely new remote transport.
28
+ * - "roster": a `peers` introduction. The roster is re-requested on join, on
29
+ * re-dial AND on reconcile, and a signaling socket now reconnects on its
30
+ * own, so a benign reconnect of a healthy session routinely delivers a
31
+ * changed generation for an edge that is working perfectly. Acting on that
32
+ * is a regression of cluster C4, so it is record-only while the local
33
+ * transport is connected.
34
+ */
35
+ export type PeerSocketGenerationSource = "connection" | "roster";
36
+ export declare const isCanonicalSocketGeneration: (value: unknown) => value is string;
37
+ export declare const comparePeerSocketGeneration: (recorded: string | undefined, observed: unknown) => PeerSocketGenerationVerdict;
38
+ export declare const markPeerSocketGenerationRetired: (roomId: string, peerId: string, generation: unknown) => void;
39
+ export declare const isPeerSocketGenerationRetired: (roomId: string, peerId: string, generation: unknown) => boolean;
40
+ export declare const clearRetiredPeerSocketGenerations: (roomId: string, peerId: string) => void;
41
+ export interface PeerSocketGenerationObservation {
42
+ roomId: string;
43
+ peerId: string;
44
+ /** The generation the local transport was built against, if any. */
45
+ recorded: string | undefined;
46
+ /** The generation this frame names for the peer. */
47
+ observed: unknown;
48
+ /** Which inbound frame carried it; an unattributed frame is advisory. */
49
+ source: PeerSocketGenerationSource | undefined;
50
+ /** The local transport's current state. */
51
+ connectionState: RTCPeerConnectionState;
52
+ }
53
+ /**
54
+ * Whether an observed generation is reason enough to retire the local
55
+ * transport for this edge and rebuild it against the peer's live session.
56
+ *
57
+ * Deliberately conservative in two directions. A roster introduction is acted
58
+ * on only when the local transport is demonstrably not working — a healthy
59
+ * edge must survive an ordinary signaling reconnect (C4). And a generation
60
+ * this edge has already retired never triggers a second teardown, however it
61
+ * arrives.
62
+ *
63
+ * "not working" excludes "disconnected". handleConnectToPeer answers that state
64
+ * with an ICE restart and only tears the edge down if it is still disconnected
65
+ * 8 s later, and the restart usually succeeds — so a roster frame arriving in
66
+ * that window would replace a transport that was about to heal itself.
67
+ */
68
+ export declare const shouldRetireTransportForSocketGeneration: ({ roomId, peerId, recorded, observed, source, connectionState, }: PeerSocketGenerationObservation) => boolean;
@@ -5,6 +5,8 @@ export declare const COVER_CELL_PLAINTEXT_BYTES: number;
5
5
  export declare const COVER_CELL_BINDING_BYTES = 32;
6
6
  export declare const COVER_CELL_ROOT_BYTES = 32;
7
7
  export declare const COVER_CELL_TOKEN_BYTES: number;
8
+ /** Bound token lookup/persistence work per authenticated scheduled cell. */
9
+ export declare const MAX_COVER_CHUNK_RECEIPTS = 64;
8
10
  export declare const COVER_CELL_MAX_PAYLOAD_BYTES: number;
9
11
  export type CoverCellDirection = "initiator-to-responder" | "responder-to-initiator";
10
12
  export type CoverCellContent = {
@@ -21,6 +23,11 @@ export type CoverCellContent = {
21
23
  readonly subtype: "receipt";
22
24
  readonly merkleRoot: Uint8Array;
23
25
  readonly token: Uint8Array;
26
+ } | {
27
+ /** Subtype 4: old clients drop this unknown subtype, never treat it as completion. */
28
+ readonly subtype: "chunk-receipts";
29
+ readonly merkleRoot: Uint8Array;
30
+ readonly tokens: readonly Uint8Array[];
24
31
  };
25
32
  export type CoverCellErrorCode = "authentication-failed" | "binding-mismatch" | "epoch-mismatch" | "invalid-cell" | "invalid-direction" | "invalid-padding" | "replayed-counter";
26
33
  export declare class CoverCellError extends Error {
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Module-scoped EmscriptenModule and factory types from @types/emscripten
3
+ * 1.41.5 (DefinitelyTyped). All inherited LibCrypto members are retained.
4
+ * Keeping these types local avoids a required ambient development dependency
5
+ * and does not merge with a consumer's global Emscripten declarations.
6
+ * MIT license, Copyright (c) Microsoft Corporation.
7
+ * See THIRD_PARTY_NOTICES.md for the full upstream license.
8
+ */
9
+ /* eslint-disable @typescript-eslint/no-explicit-any -- Preserve upstream API compatibility. */
10
+
11
+ // Infers the type only in TypeScript environments where GPU types are available
12
+ type MaybeGPUDevice = Navigator extends {
13
+ gpu: {
14
+ requestAdapter(...args: any[]): Promise<null | {
15
+ requestDevice(...args: any[]): Promise<null | infer T>;
16
+ }>;
17
+ };
18
+ }
19
+ ? T
20
+ : never;
21
+
22
+ export interface EmscriptenModule {
23
+ print(str: string): void;
24
+ printErr(str: string): void;
25
+ arguments: string[];
26
+ environment: "WEB" | "NODE" | "SHELL" | "WORKER";
27
+ preInit: Array<{ (): void }>;
28
+ preRun: Array<{ (): void }>;
29
+ postRun: Array<{ (): void }>;
30
+ onAbort: { (what: any): void };
31
+ onRuntimeInitialized: { (): void };
32
+ preinitializedWebGLContext: WebGLRenderingContext;
33
+ preinitializedWebGPUDevice: MaybeGPUDevice;
34
+ noInitialRun: boolean;
35
+ noExitRuntime: boolean;
36
+ logReadFiles: boolean;
37
+ filePackagePrefixURL: string;
38
+ wasmBinary: ArrayBuffer;
39
+
40
+ destroy(object: object): void;
41
+ getPreloadedPackage(
42
+ remotePackageName: string,
43
+ remotePackageSize: number,
44
+ ): ArrayBuffer;
45
+ instantiateWasm(
46
+ imports: WebAssembly.Imports,
47
+ successCallback: (module: WebAssembly.Instance) => void,
48
+ ): WebAssembly.Exports | undefined;
49
+ locateFile(url: string, scriptDirectory: string): string;
50
+ onCustomMessage(event: MessageEvent): void;
51
+
52
+ // USE_TYPED_ARRAYS == 1
53
+ HEAP: Int32Array;
54
+ IHEAP: Int32Array;
55
+ FHEAP: Float64Array;
56
+
57
+ // USE_TYPED_ARRAYS == 2
58
+ HEAP8: Int8Array;
59
+ HEAP16: Int16Array;
60
+ HEAP32: Int32Array;
61
+ HEAPU8: Uint8Array;
62
+ HEAPU16: Uint16Array;
63
+ HEAPU32: Uint32Array;
64
+ HEAPF32: Float32Array;
65
+ HEAPF64: Float64Array;
66
+ HEAP64: BigInt64Array;
67
+ HEAPU64: BigUint64Array;
68
+
69
+ TOTAL_STACK: number;
70
+ TOTAL_MEMORY: number;
71
+ FAST_MEMORY: number;
72
+
73
+ addOnPreRun(cb: () => any): void;
74
+ addOnInit(cb: () => any): void;
75
+ addOnPreMain(cb: () => any): void;
76
+ addOnExit(cb: () => any): void;
77
+ addOnPostRun(cb: () => any): void;
78
+
79
+ preloadedImages: any;
80
+ preloadedAudios: any;
81
+
82
+ _malloc(size: number): number;
83
+ _free(ptr: number): void;
84
+ }
85
+
86
+ /**
87
+ * A factory function is generated when setting the `MODULARIZE` build option
88
+ * to `1` in your Emscripten build. It return a Promise that resolves to an
89
+ * initialized, ready-to-call `EmscriptenModule` instance.
90
+ *
91
+ * By default, the factory function will be named `Module`. It's recommended to
92
+ * use the `EXPORT_ES6` option, in which the factory function will be the
93
+ * default export. If used without `EXPORT_ES6`, the factory function will be a
94
+ * global variable. You can rename the variable using the `EXPORT_NAME` build
95
+ * option. It's left to you to declare any global variables as needed in your
96
+ * application's types.
97
+ * @param moduleOverrides Default properties for the initialized module.
98
+ */
99
+ export type EmscriptenModuleFactory<
100
+ T extends EmscriptenModule = EmscriptenModule,
101
+ > = (moduleOverrides?: Partial<T>) => Promise<T>;
@@ -0,0 +1,181 @@
1
+ import type { EmscriptenModule, EmscriptenModuleFactory } from "./emscripten";
2
+
3
+ export interface LibCrypto extends EmscriptenModule {
4
+ wasmMemory: WebAssembly.Memory;
5
+ /** Web Crypto backed entropy callback supplied by the JavaScript loader. */
6
+ getRandomValue?(): number;
7
+
8
+ _crypto_init(): number;
9
+
10
+ _keypair(
11
+ public_key: number, // Uint8Array,
12
+ secret_key: number, // Uint8Array
13
+ ): number;
14
+
15
+ _keypair_from_seed(
16
+ public_key: number, // Uint8Array,
17
+ secret_key: number, // Uint8Array,
18
+ seed: number, // Uint8Array,
19
+ ): number;
20
+ _keypair_from_secret_key(
21
+ public_key: number, // Uint8Array,
22
+ secret_key: number, // Uint8Array,
23
+ ): number;
24
+
25
+ _sign(
26
+ DATA_LEN: number,
27
+ data: number, // Uint8Array,
28
+ secret_key: number, // Uint8Array,
29
+ signature: number, // Uint8Array,
30
+ ): number;
31
+ _verify(
32
+ DATA_LEN: number,
33
+ data: number, // Uint8Array,
34
+ public_key: number, // Uint8Array,
35
+ signature: number, // Uint8Array,
36
+ ): number;
37
+
38
+ _get_merkle_root(
39
+ LEAVES_LEN: number,
40
+ leaves_hashed: number, // Uint8Array.byteOffset
41
+ root: number, // Uint8Array.byteOffset
42
+ ): number;
43
+ _get_merkle_proof(
44
+ LEAVES_LEN: number,
45
+ leaves_hashed: number, // Uint8Array.byteOffset
46
+ element_hash: number, // Uint8Array.byteOffset
47
+ proof: number, // Uint8Array.byteOffset
48
+ ): number;
49
+ _get_merkle_root_from_proof(
50
+ PROOF_LEN: number,
51
+ element_hash: number, // Uint8Array.byteOffset
52
+ proof: number, // Uint8Array.byteOffset
53
+ root: number, // Uint8Array.byteOffset
54
+ ): number;
55
+ _verify_merkle_proof(
56
+ PROOF_LEN: number,
57
+ element_hash: number, // Uint8Array.byteOffset
58
+ root: number, // Uint8Array.byteOffset
59
+ proof: number, // Uint8Array.byteOffset
60
+ ): number;
61
+
62
+ _argon2(
63
+ MNEMONIC_LEN: number,
64
+ seed: number,
65
+ mnemonic: number,
66
+ salt: number,
67
+ ): number;
68
+
69
+ // Streaming SHA-512 (plain, no domain separation) — state is a heap
70
+ // crypto_hash_sha512_state (208 bytes) allocated by JS.
71
+ _sha512_init(
72
+ state: number, // Uint8Array.byteOffset (208-byte state)
73
+ ): number;
74
+ _sha512_update(
75
+ state: number, // Uint8Array.byteOffset
76
+ in_data: number, // Uint8Array.byteOffset
77
+ in_len: number,
78
+ ): number;
79
+ _sha512_final(
80
+ state: number, // Uint8Array.byteOffset
81
+ out: number, // Uint8Array.byteOffset (64 bytes)
82
+ ): number;
83
+
84
+ // v3 PAKE + ratchet primitives (pake_ratchet.c)
85
+ _cpace_ristretto255_from_hash(out: number, hash: number): void;
86
+ _cpace_ristretto255_scalarmult(
87
+ out: number,
88
+ scalar: number,
89
+ point: number,
90
+ ): number;
91
+ _cpace_ristretto255_scalar_random(out: number): void;
92
+ _x25519_keypair(pk: number, sk: number): number;
93
+ _x25519_dh(shared: number, sk: number, pk: number): number;
94
+ _hkdf_sha512_extract(
95
+ prk: number,
96
+ salt: number,
97
+ salt_len: number,
98
+ ikm: number,
99
+ ikm_len: number,
100
+ ): number;
101
+ _hkdf_sha512_expand(
102
+ out: number,
103
+ out_len: number,
104
+ prk: number,
105
+ info: number,
106
+ info_len: number,
107
+ ): number;
108
+ _encrypt_chachapoly_symmetric(
109
+ out: number,
110
+ data: number,
111
+ data_len: number,
112
+ key: number,
113
+ nonce: number,
114
+ aad: number,
115
+ aad_len: number,
116
+ ): number;
117
+ _decrypt_chachapoly_symmetric(
118
+ out: number,
119
+ ciphertext: number,
120
+ ciphertext_len: number,
121
+ key: number,
122
+ nonce: number,
123
+ aad: number,
124
+ aad_len: number,
125
+ ): number;
126
+ _carrier_aead_xchacha20poly1305_encrypt(
127
+ out: number,
128
+ data: number,
129
+ data_len: number,
130
+ key: number,
131
+ nonce: number,
132
+ aad: number,
133
+ aad_len: number,
134
+ ): number;
135
+ _carrier_aead_xchacha20poly1305_decrypt(
136
+ out: number,
137
+ ciphertext: number,
138
+ ciphertext_len: number,
139
+ key: number,
140
+ nonce: number,
141
+ aad: number,
142
+ aad_len: number,
143
+ ): number;
144
+ _receive_message_with_key(
145
+ decrypted: number,
146
+ message: number,
147
+ merkle_root: number,
148
+ message_key: number,
149
+ ): number;
150
+
151
+ // ML-KEM (FIPS 203), deterministic entry points for all standardized
152
+ // parameter sets. JavaScript supplies cryptographically secure coins;
153
+ // zero is success and a negative value is failure.
154
+ _mlkem512_keypair(pk: number, sk: number, coins64: number): number;
155
+ _mlkem512_encaps(ct: number, ss: number, pk: number, coins32: number): number;
156
+ _mlkem512_decaps(ss: number, ct: number, sk: number): number;
157
+ _mlkem768_keypair(pk: number, sk: number, coins64: number): number;
158
+ _mlkem768_encaps(ct: number, ss: number, pk: number, coins32: number): number;
159
+ _mlkem768_decaps(ss: number, ct: number, sk: number): number;
160
+ _mlkem1024_keypair(pk: number, sk: number, coins64: number): number;
161
+ _mlkem1024_encaps(
162
+ ct: number,
163
+ ss: number,
164
+ pk: number,
165
+ coins32: number,
166
+ ): number;
167
+ _mlkem1024_decaps(ss: number, ct: number, sk: number): number;
168
+
169
+ // P2Party-owned one-shot FIPS 202 boundary backed by the implementation
170
+ // already compiled into the shared ML-KEM-768 unit.
171
+ _fips202_shake256(
172
+ out: number,
173
+ out_len: number,
174
+ input: number,
175
+ input_len: number,
176
+ ): number;
177
+ _fips202_sha3_256(out: number, input: number, input_len: number): number;
178
+ }
179
+
180
+ declare const libcrypto: EmscriptenModuleFactory<LibCrypto>;
181
+ export default libcrypto;
@@ -0,0 +1,135 @@
1
+ import type { Chunk, MessageData } from "./types";
2
+ /** Durable resend metadata; secrets remain exclusively in the ratchet vault. */
3
+ export interface OutboxLease {
4
+ transferId: string;
5
+ owner: string;
6
+ fence: number;
7
+ }
8
+ export interface OutboxRecipient {
9
+ peerId: string;
10
+ publicKey: string;
11
+ delivered: boolean;
12
+ cancelled?: boolean;
13
+ }
14
+ export interface OutboxManifest {
15
+ transferId: string;
16
+ senderPublicKey: string;
17
+ identityRevision: bigint;
18
+ roomId: string;
19
+ roomUrl: string;
20
+ policyHex: string;
21
+ channelLabel: string;
22
+ filename: string;
23
+ totalSize: number;
24
+ totalChunks: number;
25
+ stagedBytes: number;
26
+ writtenBytes: number;
27
+ localBytes: number;
28
+ createdAt: number;
29
+ updatedAt: number;
30
+ expiresAt: number;
31
+ phase: "staging" | "pending" | "sending";
32
+ merkleRootHex: string;
33
+ hashHex: string;
34
+ recipients: OutboxRecipient[];
35
+ owner: string;
36
+ fence: number;
37
+ leaseUntil: number;
38
+ lastError?: string;
39
+ }
40
+ export interface OutboxCreate {
41
+ transferId: string;
42
+ senderPublicKey: string;
43
+ roomId: string;
44
+ roomUrl: string;
45
+ policyHex: string;
46
+ channelLabel: string;
47
+ filename: string;
48
+ totalSize: number;
49
+ totalChunks: number;
50
+ stagedBytes: number;
51
+ recipients: Array<{
52
+ peerId: string;
53
+ publicKey: string;
54
+ }>;
55
+ owner: string;
56
+ }
57
+ export interface OutboxReceipt {
58
+ roomId: string;
59
+ peerId: string;
60
+ peerPublicKey: string;
61
+ transferId: string;
62
+ merkleRootHex: string;
63
+ chunkIndex?: number;
64
+ cancelled?: boolean;
65
+ }
66
+ export interface OutboxAckRecord {
67
+ transferId: string;
68
+ publicKey: string;
69
+ bitmap: Uint8Array;
70
+ }
71
+ export type OutboxRequest = {
72
+ kind: "create";
73
+ input: OutboxCreate;
74
+ } | {
75
+ kind: "publish";
76
+ lease: OutboxLease;
77
+ merkleRootHex: string;
78
+ hashHex: string;
79
+ chunkHashes: ArrayBuffer;
80
+ } | {
81
+ kind: "claim";
82
+ transferId: string;
83
+ owner: string;
84
+ senderPublicKey: string;
85
+ roomId: string;
86
+ roomUrl: string;
87
+ policyHex: string;
88
+ } | {
89
+ kind: "selfChunk";
90
+ lease: OutboxLease;
91
+ chunk: Chunk;
92
+ } | {
93
+ kind: "selfMessage";
94
+ lease: OutboxLease;
95
+ message: MessageData;
96
+ } | {
97
+ kind: "renew";
98
+ lease: OutboxLease;
99
+ } | {
100
+ kind: "release";
101
+ lease: OutboxLease;
102
+ lastError?: string;
103
+ } | {
104
+ kind: "receipt";
105
+ receipt: OutboxReceipt;
106
+ } | {
107
+ kind: "list";
108
+ senderPublicKey: string;
109
+ roomId?: string;
110
+ } | {
111
+ kind: "remove";
112
+ transferId?: string;
113
+ roomId?: string;
114
+ lease?: OutboxLease;
115
+ } | {
116
+ kind: "sweep";
117
+ };
118
+ export interface OutboxResponse {
119
+ accepted: boolean;
120
+ manifest?: OutboxManifest;
121
+ manifests?: OutboxManifest[];
122
+ lease?: OutboxLease;
123
+ chunkHashes?: ArrayBuffer;
124
+ acknowledgments?: OutboxAckRecord[];
125
+ }
126
+ export interface ReceiveActivity {
127
+ merkleRoot: string;
128
+ roomId: string;
129
+ fromPeerId: string;
130
+ lastActivityAt: number;
131
+ /** Deletion fences work queued before the terminal operation. */
132
+ deletedAt?: number;
133
+ writeToken?: string;
134
+ leaseUntil?: number;
135
+ }
package/lib/db/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { OutboxLease, OutboxRequest, OutboxResponse } from "./outboxTypes";
1
2
  import type { Peer } from "../reducers/roomSlice";
2
3
  import type { RatchetRootSuite } from "../utils/constants";
3
4
  export interface UsernamedPeer extends Peer {
@@ -83,6 +84,16 @@ export interface ReceiveChunk {
83
84
  /** Text stays in IndexedDB; files use the OPFS-first receive path. */
84
85
  storage: "indexeddb" | "opfs";
85
86
  }
87
+ export interface ExpiredReceiveTransfer {
88
+ merkleRoot: string;
89
+ roomId: string;
90
+ fromPeerId: string;
91
+ }
92
+ export interface ReceiveDeleteGuard {
93
+ roomId: string;
94
+ fromPeerId: string;
95
+ incompleteOnly: true;
96
+ }
86
97
  export interface ReceiveChunkStoreResult {
87
98
  /** True only when this call inserted a previously absent chunk index. */
88
99
  stored: boolean;
@@ -216,6 +227,18 @@ export interface PinAttemptState {
216
227
  retryAfter: number;
217
228
  }
218
229
  export type WorkerMessages = {
230
+ id: number;
231
+ method: "outboxRequest";
232
+ args: [request: OutboxRequest];
233
+ } | {
234
+ id: number;
235
+ method: "sweepStaleReceives";
236
+ args: [];
237
+ } | {
238
+ id: number;
239
+ method: "sweepStaleReceiveDetails";
240
+ args: [];
241
+ } | {
219
242
  id: number;
220
243
  method: "getDBAddressBookEntry";
221
244
  args: [peerId?: string, peerPublicKey?: string];
@@ -352,7 +375,7 @@ export type WorkerMessages = {
352
375
  } | {
353
376
  id: number;
354
377
  method: "deleteReceiveTransfer";
355
- args: [merkleRootHex: string];
378
+ args: [merkleRootHex: string, guard?: ReceiveDeleteGuard];
356
379
  } | {
357
380
  id: number;
358
381
  method: "getDBAllNewChunks";
@@ -364,7 +387,7 @@ export type WorkerMessages = {
364
387
  } | {
365
388
  id: number;
366
389
  method: "setDBNewChunk";
367
- args: [chunk: NewChunk];
390
+ args: [chunk: NewChunk, lease?: OutboxLease];
368
391
  } | {
369
392
  id: number;
370
393
  method: "setDBSendQueue";
@@ -466,6 +489,9 @@ export type WorkerMessages = {
466
489
  args: [];
467
490
  };
468
491
  export interface WorkerMethodReturnTypes {
492
+ outboxRequest: OutboxResponse;
493
+ sweepStaleReceives: string[];
494
+ sweepStaleReceiveDetails: ExpiredReceiveTransfer[];
469
495
  getDBAddressBookEntry: UsernamedPeer | undefined;
470
496
  getAllDBAddressBookEntries: UsernamedPeer[];
471
497
  setDBAddressBookEntry: undefined;
@@ -493,7 +519,7 @@ export interface WorkerMethodReturnTypes {
493
519
  storeReceiveChunk: ReceiveChunkStoreResult;
494
520
  getReceiveFile: File | null;
495
521
  closeReceiveFile: undefined;
496
- deleteReceiveTransfer: undefined;
522
+ deleteReceiveTransfer: boolean | undefined;
497
523
  getDBAllNewChunks: NewChunk[];
498
524
  getDBAllNewChunksCount: number;
499
525
  setDBNewChunk: undefined;