p2party 0.14.1 → 0.14.2

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 CHANGED
@@ -46,7 +46,7 @@ Apache-2.0 · [LICENSE.md](LICENSE.md)
46
46
  `window`, or `localStorage`.
47
47
 
48
48
  Immediate delivery over the existing signaling rendezvous is the shipped
49
- default. Scheduled timing cover is also wired as of 0.14.1: a room policy may
49
+ default. Scheduled timing cover is also wired as of 0.14.2: a room policy may
50
50
  pin a cadence, lane count, and frames per cell, and every edge in the room then
51
51
  emits fixed-size cells on that schedule whether or not there is data to send.
52
52
  Sparse post-quantum healing (the OFFER/ADVANCE/ACK epoch exchange) is likewise
@@ -633,8 +633,8 @@ script in and `window.p2party` is there — no npm, no bundler, no build:
633
633
  <title>p2party in one file</title>
634
634
 
635
635
  <script
636
- src="https://cdn.p2party.com/@0.14.1/p2party.min.js"
637
- integrity="sha384-qoibStilVTBvKFmPiKma5X42R9V57ibjV4pfKyYbPrY/Q/5l1Js1r4Ye6wi1ZUHf"
636
+ src="https://cdn.p2party.com/@0.14.2/p2party.min.js"
637
+ integrity="sha384-KJLIhsZkQzkYg1lyk57oAacQBR3DeWHX92Ksv9QTO9tUJVw1pxUNHI9e2nIcacgZ"
638
638
  crossorigin="anonymous"
639
639
  ></script>
640
640
 
@@ -665,15 +665,15 @@ connect directly to each other.
665
665
  The three published objects:
666
666
 
667
667
  ```text
668
- https://cdn.p2party.com/@0.14.1/p2party.min.js UMD bundle -> window.p2party
669
- https://cdn.p2party.com/@0.14.1/db.worker.js IndexedDB/OPFS worker
670
- https://cdn.p2party.com/@0.14.1/libcrypto.wasm the cryptographic module
668
+ https://cdn.p2party.com/@0.14.2/p2party.min.js UMD bundle -> window.p2party
669
+ https://cdn.p2party.com/@0.14.2/db.worker.js IndexedDB/OPFS worker
670
+ https://cdn.p2party.com/@0.14.2/libcrypto.wasm the cryptographic module
671
671
  ```
672
672
 
673
673
  The `integrity` value above is this release's bundle, and the release build
674
674
  fails if the README and the built artifact ever disagree — so it is safe to
675
675
  copy verbatim. The worker, if you host it yourself, is
676
- `sha384-xpC0axO9Z2Q/XvKvps45jwZ7ldG9jgXx1b5rcSv24+rCiM5qhox6jqlBaIStbzoa`.
676
+ `sha384-qWbMGmyz8mCS/hgbn0jEf4Fo73iXiy6w+H/NfO6ymxKwzldUeHSxolNZtSZfV1nf`.
677
677
 
678
678
  The WASM is integrity-checked whether or not you pin the script: that hash is
679
679
  compiled into the bundle and cannot be turned off.
@@ -688,7 +688,7 @@ same release bytes before calling `connect()`:
688
688
  import p2party from "p2party";
689
689
 
690
690
  p2party.setWasmSourceUrl(
691
- new URL("/vendor/p2party-0.14.1/libcrypto.wasm", window.location.href),
691
+ new URL("/vendor/p2party-0.14.2/libcrypto.wasm", window.location.href),
692
692
  );
693
693
  ```
694
694
 
@@ -701,8 +701,8 @@ object. The path carries the version, so a URL always names exactly one build
701
701
  and is safe to cache forever:
702
702
 
703
703
  ```sh
704
- curl -O https://cdn.p2party.com/@0.14.1/libcrypto.wasm
705
- curl -O https://cdn.p2party.com/@0.14.1/libcrypto.provenance.json
704
+ curl -O https://cdn.p2party.com/@0.14.2/libcrypto.wasm
705
+ curl -O https://cdn.p2party.com/@0.14.2/libcrypto.provenance.json
706
706
  ```
707
707
 
708
708
  Check what you downloaded before you serve it. The SHA-256 and the SRI value
@@ -713,7 +713,7 @@ shasum -a 256 libcrypto.wasm
713
713
  openssl dgst -sha384 -binary libcrypto.wasm | openssl base64 -A
714
714
  ```
715
715
 
716
- For 0.14.1 those are
716
+ For 0.14.2 those are
717
717
  `7eea31157e69ac61f3a512b624d5c210296302fd289fc2b65c63ecc31a056267` and
718
718
  `sha384-pBMyUqQ3KBztxgeJMgDFZeohfj9QlAFNwt4/gRlqT0vlZ2kbkKxv+q5DwbZOBuUP`.
719
719
  They are the same bytes npm ships — the release workflow uploads the CDN object
@@ -152,6 +152,6 @@ third-party security audit. Cite the implementation:
152
152
  @software{p2party,
153
153
  title = {p2party: protocol-v4 end-to-end encryption over a WebRTC room mesh},
154
154
  url = {https://github.com/p2party/p2party-js},
155
- note = {Version 0.14.1}
155
+ note = {Version 0.14.2}
156
156
  }
157
157
  ```
package/lib/db/api.d.ts CHANGED
@@ -18,6 +18,7 @@ export declare const getAllDBUniqueRooms: () => Promise<import("./types").Unique
18
18
  export declare const setDBUniqueRoom: (roomUrl: string, roomId: string, roomPolicy: ArrayBuffer) => Promise<undefined>;
19
19
  export declare const getDBMessageData: (merkleRootHex?: string, hashHex?: string) => Promise<import("./types").MessageData | undefined>;
20
20
  export declare const getDBRoomMessageData: (roomId: string) => Promise<import("./types").MessageData[]>;
21
+ export declare const getDBRoomStats: (roomId: string) => Promise<import("./types").RoomStats>;
21
22
  export declare const setDBRoomMessageData: (roomId: string, merkleRootHex: string, sha512Hex: string, fromPeerId: string, chunkSize: number, totalSize: number, messageType: number, // MessageType,
22
23
  filename: string, channelLabel: string, timestamp: number, transferId?: string) => Promise<undefined>;
23
24
  export declare const getDBChunk: (merkleRootHex: string, chunkIndex: number) => Promise<ArrayBuffer | undefined>;
package/lib/db/types.d.ts CHANGED
@@ -21,6 +21,25 @@ export interface UniqueRoom {
21
21
  createdAt: number;
22
22
  updatedAt: number;
23
23
  }
24
+ /**
25
+ * Aggregate history for one saved room, computed inside the database worker.
26
+ *
27
+ * Sizes are logical message bytes, not wire bytes: p2party pads everything to
28
+ * uniform 65,490-byte cells, so what actually crossed the network is always
29
+ * larger and is a property of the padding policy rather than of the
30
+ * conversation. Reporting the padded figure would describe the cover traffic,
31
+ * not what the user sent.
32
+ */
33
+ export interface RoomStats {
34
+ messageCount: number;
35
+ messagesSent: number;
36
+ messagesReceived: number;
37
+ bytesSent: number;
38
+ bytesReceived: number;
39
+ bytesTotal: number;
40
+ /** Distinct peers this device has received from, ever. */
41
+ peerIds: string[];
42
+ }
24
43
  export interface MessageData {
25
44
  /** Sender-only random logical-send identity; absent on received/legacy rows. */
26
45
  transferId?: string;
@@ -211,6 +230,10 @@ export type WorkerMessages = {
211
230
  id: number;
212
231
  method: "getDBRoomMessageData";
213
232
  args: [roomId: string];
233
+ } | {
234
+ id: number;
235
+ method: "getDBRoomStats";
236
+ args: [roomId: string];
214
237
  } | {
215
238
  id: number;
216
239
  method: "setDBRoomMessageData";
@@ -410,6 +433,7 @@ export interface WorkerMethodReturnTypes {
410
433
  deleteDBPeerFromBlacklist: undefined;
411
434
  getDBMessageData: MessageData | undefined;
412
435
  getDBRoomMessageData: MessageData[];
436
+ getDBRoomStats: RoomStats;
413
437
  getDBChunk: ArrayBuffer | undefined;
414
438
  existsDBChunk: boolean;
415
439
  getDBNewChunk: NewChunk | undefined;
package/lib/db.worker.js CHANGED
@@ -1 +1 @@
1
- const e=(e,t)=>t.some(t=>e instanceof t);let t,a;const n=new WeakMap,r=new WeakMap,o=new WeakMap;let i={get(e,t,a){if(e instanceof IDBTransaction){if("done"===t)return n.get(e);if("store"===t)return a.objectStoreNames[1]?void 0:a.objectStore(a.objectStoreNames[0])}return d(e[t])},set:(e,t,a)=>(e[t]=a,!0),has:(e,t)=>e instanceof IDBTransaction&&("done"===t||"store"===t)||t in e};function s(e){i=e(i)}function c(e){return(a||(a=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(e)?function(...t){return e.apply(u(this),t),d(this.request)}:function(...t){return d(e.apply(u(this),t))}}function l(a){return"function"==typeof a?c(a):(a instanceof IDBTransaction&&function(e){if(n.has(e))return;const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("complete",r),e.removeEventListener("error",o),e.removeEventListener("abort",o)},r=()=>{t(),n()},o=()=>{a(e.error||new DOMException("AbortError","AbortError")),n()};e.addEventListener("complete",r),e.addEventListener("error",o),e.addEventListener("abort",o)});n.set(e,t)}(a),e(a,t||(t=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]))?new Proxy(a,i):a)}function d(e){if(e instanceof IDBRequest)return function(e){const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("success",r),e.removeEventListener("error",o)},r=()=>{t(d(e.result)),n()},o=()=>{a(e.error),n()};e.addEventListener("success",r),e.addEventListener("error",o)});return o.set(t,e),t}(e);if(r.has(e))return r.get(e);const t=l(e);return t!==e&&(r.set(e,t),o.set(t,e)),t}const u=e=>o.get(e);const h=["get","getKey","getAll","getAllKeys","count"],y=["put","add","delete","clear"],w=new Map;function g(e,t){if(!(e instanceof IDBDatabase)||t in e||"string"!=typeof t)return;if(w.get(t))return w.get(t);const a=t.replace(/FromIndex$/,""),n=t!==a,r=y.includes(a);if(!(a in(n?IDBIndex:IDBObjectStore).prototype)||!r&&!h.includes(a))return;const o=async function(e,...t){const o=this.transaction(e,r?"readwrite":"readonly");let i=o.store;return n&&(i=i.index(t.shift())),(await Promise.all([i[a](...t),r&&o.done]))[0]};return w.set(t,o),o}s(e=>({...e,get:(t,a,n)=>g(t,a)||e.get(t,a,n),has:(t,a)=>!!g(t,a)||e.has(t,a)}));const f=["continue","continuePrimaryKey","advance"],m={},p=new WeakMap,b=new WeakMap,k={get(e,t){if(!f.includes(t))return e[t];let a=m[t];return a||(a=m[t]=function(...e){p.set(this,b.get(this)[t](...e))}),a}};async function*S(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;const a=new Proxy(t,k);for(b.set(a,t),o.set(a,u(t));t;)yield a,t=await(p.get(a)||t.continue()),p.delete(a)}function I(t,a){return a===Symbol.asyncIterator&&e(t,[IDBIndex,IDBObjectStore,IDBCursor])||"iterate"===a&&e(t,[IDBIndex,IDBObjectStore])}s(e=>({...e,get:(t,a,n)=>I(t,a)?S:e.get(t,a,n),has:(t,a)=>I(t,a)||e.has(t,a)}));const x=64*Uint8Array.BYTES_PER_ELEMENT,K=65405-(9+x+8+8+256+8+8+8+(4+48*(x+1)));(new TextEncoder).encode("p2party-x25519-idsig-v1");const v=["hybrid-3dh-mlkem512-cpace21-v4","hybrid-3dh-mlkem768-cpace21-v4","hybrid-3dh-mlkem1024-cpace21-v4"],C="p2party-reassembled",A="p2party";async function R(){return function(e,t,{blocked:a,upgrade:n,blocking:r,terminated:o}={}){const i=indexedDB.open(e,t),s=d(i);return n&&i.addEventListener("upgradeneeded",e=>{n(d(i.result),e.oldVersion,e.newVersion,d(i.transaction),e)}),a&&i.addEventListener("blocked",e=>a(e.oldVersion,e.newVersion,e)),s.then(e=>{o&&e.addEventListener("close",()=>o()),r&&e.addEventListener("versionchange",e=>r(e.oldVersion,e.newVersion,e))}).catch(()=>{}),s}(A,19,{upgrade(e,t,a,n){if(e.objectStoreNames.contains("addressBook")){const e=n.objectStore("addressBook");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("addressBook",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("blacklist")){const e=n.objectStore("blacklist");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("blacklist",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("uniqueRoom")){const e=n.objectStore("uniqueRoom");e.indexNames.contains("roomUrl")||e.createIndex("roomUrl","roomUrl",{unique:!0}),e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!0})}else{const t=e.createObjectStore("uniqueRoom",{keyPath:["roomId"]});t.createIndex("roomUrl","roomUrl",{unique:!0}),t.createIndex("roomId","roomId",{unique:!0})}if(e.objectStoreNames.contains("messageData")){const e=n.objectStore("messageData");e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!0}),e.indexNames.contains("fromPeerId")||e.createIndex("fromPeerId","fromPeerId",{unique:!1})}else{const t=e.createObjectStore("messageData",{keyPath:["timestamp","roomId","merkleRoot"]});t.createIndex("roomId","roomId",{unique:!1}),t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!0}),t.createIndex("fromPeerId","fromPeerId",{unique:!1})}if(e.objectStoreNames.contains("chunks")){const e=n.objectStore("chunks");e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1})}else{const t=e.createObjectStore("chunks",{keyPath:["merkleRoot","chunkIndex"]});t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("hash","hash",{unique:!1})}if(t<18&&e.objectStoreNames.contains("newChunks")&&e.deleteObjectStore("newChunks"),e.objectStoreNames.contains("newChunks")){const e=n.objectStore("newChunks");e.indexNames.contains("transferId")||e.createIndex("transferId","transferId",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("receiptScope")||e.createIndex("receiptScope",["merkleRoot","receiptToken"],{unique:!1})}else{const t=e.createObjectStore("newChunks",{keyPath:["transferId","chunkIndex"]});t.createIndex("transferId","transferId",{unique:!1}),t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("receiptScope",["merkleRoot","receiptToken"],{unique:!1})}if(e.objectStoreNames.contains("sendQueue")){const e=n.objectStore("sendQueue");e.indexNames.contains("labelPeer")||e.createIndex("labelPeer",["label","toPeerId"],{unique:!1})}else{e.createObjectStore("sendQueue",{keyPath:["position","label","toPeerId"]}).createIndex("labelPeer",["label","toPeerId"],{unique:!1})}if(!e.objectStoreNames.contains("ratchetSessions")){const t=e.createObjectStore("ratchetSessions",{keyPath:["roomId","peerPublicKey"]});t.createIndex("peerId","peerId",{unique:!1}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!1}),t.createIndex("roomId","roomId",{unique:!1})}t>0&&t<19&&(n.objectStore("ratchetSessions").clear(),n.objectStore("sendQueue").clear()),e.objectStoreNames.contains("meta")||e.createObjectStore("meta")}})}const D="ratchetWrapKey",P=12,E=16,L=16,B=Uint8Array.of(80,50,82,87),j=B.byteLength+1+L+P,M=262144,N=(new TextEncoder).encode("p2party-edge-crypto-at-rest-aad-v2");var U;!function(e){e[e.RootKey=1]="RootKey",e[e.SendingChainKey=2]="SendingChainKey",e[e.ReceivingChainKey=3]="ReceivingChainKey",e[e.DhSelfSecret=4]="DhSelfSecret",e[e.SkippedMessageKey=5]="SkippedMessageKey",e[e.EdgeCryptoState=6]="EdgeCryptoState"}(U||(U={}));const q=e=>e.slice(0),$=(e,t,a)=>{if(!(e instanceof ArrayBuffer))throw new Error(`${t} must be an ArrayBuffer`);if(void 0!==a&&e.byteLength!==a)throw new Error(`${t} must be ${String(a)} bytes`);return e},T=(e,t)=>{if("number"!=typeof e||!Number.isSafeInteger(e)||e<0)throw new Error(`${t} must be a safe unsigned integer`);return e},z=(e,t)=>{if("string"!=typeof e||0===e.length)throw new Error(`${t} must be a non-empty string`);const a=(new TextEncoder).encode(e);if(a.byteLength>1048576)throw new Error(`${t} is too long`);if((new TextDecoder).decode(a)!==e)throw new Error(`${t} is not canonical Unicode`);return e},F=e=>{if(!Number.isInteger(e)||e<0||e>4294967295)throw new Error("ratchet wrap: value exceeds uint32");const t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!1),t},H=e=>{T(e,"ratchet wrap counter");const t=new Uint8Array(8);return new DataView(t.buffer).setBigUint64(0,BigInt(e),!1),t},O=e=>{const t=e.reduce((e,t)=>e+t.byteLength,0),a=new Uint8Array(t);let n=0;for(const t of e)a.set(t,n),n+=t.byteLength;return a},Q=e=>O([F(e.byteLength),e]),V=e=>Q((new TextEncoder).encode(e)),W=e=>{const t=e.rootSuite;if("string"!=typeof(a=t)||!v.includes(a))throw new Error("Unsupported ratchet root suite");var a;if(z(e.roomId,"ratchet roomId"),z(e.peerPublicKey,"ratchet peerPublicKey"),!/^[0-9a-f]{64}$/.test(e.peerPublicKey))throw new Error("ratchet peerPublicKey must be 32-byte lowercase hex");if(z(e.peerId,"ratchet peerId"),$(e.dhSelfPub,"ratchet dhSelfPub",32),null!==e.dhRemotePub&&$(e.dhRemotePub,"ratchet dhRemotePub",32),T(e.Ns,"ratchet Ns"),T(e.Nr,"ratchet Nr"),T(e.PN,"ratchet PN"),T(e.updatedAt,"ratchet updatedAt"),!Array.isArray(e.skippedMessageKeys)||e.skippedMessageKeys.length>2e3)throw new Error("ratchet skipped-message-key count is invalid");if(e.skippedMessageKeys.forEach((e,t)=>{$(e.dhPub,`ratchet skipped[${String(t)}].dhPub`,32),T(e.n,`ratchet skipped[${String(t)}].n`)}),null!==e.edgeCryptoState){const t=$(e.edgeCryptoState,"ratchet edge crypto state");if(t.byteLength<1||t.byteLength>M+j+E)throw new Error("ratchet edge crypto state length is invalid")}},X=e=>({rootSuite:e.rootSuite,roomId:e.roomId,peerPublicKey:e.peerPublicKey,peerId:e.peerId,rootKey:q($(e.rootKey,"ratchet rootKey")),sendingChainKey:null===e.sendingChainKey?null:q($(e.sendingChainKey,"ratchet sendingChainKey")),receivingChainKey:null===e.receivingChainKey?null:q($(e.receivingChainKey,"ratchet receivingChainKey")),dhSelfPub:q($(e.dhSelfPub,"ratchet dhSelfPub")),dhSelfSec:q($(e.dhSelfSec,"ratchet dhSelfSec")),dhRemotePub:null===e.dhRemotePub?null:q($(e.dhRemotePub,"ratchet dhRemotePub")),Ns:e.Ns,Nr:e.Nr,PN:e.PN,skippedMessageKeys:(()=>{if(!Array.isArray(e.skippedMessageKeys))throw new Error("ratchet skippedMessageKeys must be an array");return e.skippedMessageKeys.map((e,t)=>({dhPub:q($(e.dhPub,`ratchet skipped[${String(t)}].dhPub`)),n:e.n,messageKey:q($(e.messageKey,`ratchet skipped[${String(t)}].messageKey`))}))})(),edgeCryptoState:null===e.edgeCryptoState?null:q($(e.edgeCryptoState,"ratchet edge crypto state")),updatedAt:e.updatedAt}),G=e=>{new Uint8Array(e.rootKey).fill(0),e.sendingChainKey&&new Uint8Array(e.sendingChainKey).fill(0),e.receivingChainKey&&new Uint8Array(e.receivingChainKey).fill(0),new Uint8Array(e.dhSelfSec).fill(0);for(const t of e.skippedMessageKeys)new Uint8Array(t.messageKey).fill(0);e.edgeCryptoState&&new Uint8Array(e.edgeCryptoState).fill(0)},_=(e,t,a,n=0)=>{if(W(e),a.byteLength!==L)throw new Error("ratchet wrap: invalid record ID");const r=(null===e.sendingChainKey?0:1)|(null===e.receivingChainKey?0:2)|(null===e.dhRemotePub?0:4)|(null===e.edgeCryptoState?0:8),o=[Q(N),Uint8Array.of(2,t),Q(a),F(n),V(e.rootSuite),V(e.roomId),V(e.peerPublicKey),V(e.peerId),Q(new Uint8Array(e.dhSelfPub)),Uint8Array.of(r)];null!==e.dhRemotePub&&o.push(Q(new Uint8Array(e.dhRemotePub))),o.push(H(e.Ns),H(e.Nr),H(e.PN),H(e.updatedAt),F(e.skippedMessageKeys.length));for(const t of e.skippedMessageKeys)o.push(Q(new Uint8Array(t.dhPub)),H(t.n));return O(o)},Y=(e,t=32)=>{const a=new Uint8Array(e),n=j+1+E,r=j+M+E;if(null===t&&(a.byteLength<n||a.byteLength>r)||null!==t&&a.byteLength!==j+t+E)throw new Error("Unsupported or malformed ratchet wrap envelope");for(let e=0;e<B.byteLength;e++)if(a[e]!==B[e])throw new Error("Unsupported or malformed ratchet wrap envelope");if(2!==a[B.byteLength])throw new Error("Unsupported or malformed ratchet wrap envelope");return Uint8Array.from(a.subarray(B.byteLength+1,B.byteLength+1+L))},J=async(e,t,a,n,r=32)=>{if($(t,"ratchet secret",null===r?void 0:r),null===r&&(t.byteLength<1||t.byteLength>M))throw new Error("ratchet variable secret length is invalid");if(n.byteLength!==L)throw new Error("ratchet wrap: invalid record ID");const o=crypto.getRandomValues(new Uint8Array(P)),i=await crypto.subtle.encrypt({name:"AES-GCM",iv:o,additionalData:a,tagLength:128},e,t),s=new Uint8Array(j+i.byteLength);return s.set(B,0),s[B.byteLength]=2,s.set(n,B.byteLength+1),s.set(o,B.byteLength+1+L),s.set(new Uint8Array(i),j),s.buffer},Z=async(e,t,a,n,r=32)=>{$(t,"ratchet wrapped secret");const o=Y(t,r);if(!te(o,n))throw new Error("Ratchet wrap record ID mismatch");const i=new Uint8Array(t),s=await crypto.subtle.decrypt({name:"AES-GCM",iv:i.subarray(B.byteLength+1+L,j),additionalData:a,tagLength:128},e,i.subarray(j));if(null!==r&&s.byteLength!==r||null===r&&(s.byteLength<1||s.byteLength>M))throw new Uint8Array(s).fill(0),new Error("Ratchet wrapped secret has an invalid plaintext length");return s},ee=async e=>{W(e);const t=Y(e.rootKey),a=[e.sendingChainKey,e.receivingChainKey,e.dhSelfSec,...e.skippedMessageKeys.map(e=>e.messageKey)];for(const e of a)if(null!==e&&!te(Y(e),t))throw new Error("Ratchet wrap record ID mismatch");if(null!==e.edgeCryptoState&&!te(Y(e.edgeCryptoState,null),t))throw new Error("Ratchet wrap record ID mismatch");const n=[_(e,U.RootKey,t),Q(new Uint8Array(e.rootKey)),Q(e.sendingChainKey?new Uint8Array(e.sendingChainKey):new Uint8Array),Q(e.receivingChainKey?new Uint8Array(e.receivingChainKey):new Uint8Array),Q(new Uint8Array(e.dhSelfSec))];for(const t of e.skippedMessageKeys)n.push(Q(new Uint8Array(t.messageKey)));n.push(Q(e.edgeCryptoState?new Uint8Array(e.edgeCryptoState):new Uint8Array));const r=O(n);try{return new Uint8Array(await crypto.subtle.digest("SHA-256",r))}finally{r.fill(0)}},te=(e,t)=>{if(e.byteLength!==t.byteLength)return!1;let a=0;for(let n=0;n<e.byteLength;n++)a|=e[n]^t[n];return 0===a};async function ae(){const e=await R();try{const t=await e.get("meta",D);if(t)return t;const a=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),n=e.transaction("meta","readwrite"),r=n.objectStore("meta"),o=await r.get(D);return o?(await n.done,o):(await r.put(a,D),await n.done,a)}finally{e.close()}}async function ne(e,t){const a=crypto.getRandomValues(new Uint8Array(P)),n=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e,t),r=new Uint8Array(P+n.byteLength);return r.set(a,0),r.set(new Uint8Array(n),P),r.buffer}async function re(e,t){const a=new Uint8Array(t);if(a.byteLength<28)throw new Error("Malformed wrapped secret");return crypto.subtle.decrypt({name:"AES-GCM",iv:a.subarray(0,P)},e,a.subarray(P))}const oe=()=>globalThis.navigator?.storage,ie=new Map,se=e=>e.createSyncAccessHandle,ce=(e,t,a,n)=>new File([e],t.length>0?t:a,{type:n});async function le(e,t,a,n){if(e.length!==2*x)return null;const r=ie.get(e);if(r)return r;const o=async function(e,t,a,n){try{const r=oe();if(!r||"function"!=typeof r.getDirectory)return console.warn("OPFS unavailable — reassembling file in memory"),null;const o=await r.getDirectory(),i=await o.getDirectoryHandle(C,{create:!0}),s=await i.getFileHandle(e,{create:!0}),c=await s.getFile();if(t>0&&c.size===t)return ce(c,a,e,n);const l=s.createSyncAccessHandle;if("function"!=typeof l)return console.warn("OPFS sync access handle unavailable — reassembling in memory"),null;const d=await l.call(s);let u;try{u=await R(),d.truncate(0);let t=0;const a=u.transaction("chunks","readonly"),n=a.objectStore("chunks").index("merkleRoot");let r=await n.openCursor(e);for(;r;){const e=new Uint8Array(r.value.data??new ArrayBuffer(0));let a=0;for(;a<e.length;){const n=d.write(e.subarray(a),{at:t+a});if(n<=0)throw new Error("OPFS short write");a+=n}t+=e.length,r=await r.continue()}await a.done,d.flush()}catch(t){try{d.close()}catch{}if(u)try{u.close()}catch{}throw await i.removeEntry(e).catch(()=>{}),t}return d.close(),u.close(),ce(await s.getFile(),a,e,n)}catch(e){return console.error(e),null}}(e,t,a,n);ie.set(e,o);try{return await o}finally{ie.delete(e)}}async function de(e){try{const t=oe();if(!t||"function"!=typeof t.getDirectory)return;const a=await t.getDirectory(),n=await a.getDirectoryHandle(C).catch(()=>null);n&&await n.removeEntry(e).catch(()=>{})}catch{}}const ue=new Map,he=new Map,ye=new Map,we=new Map;async function ge(e,t){const a=we.get(e)??Promise.resolve();let n;const r=new Promise(e=>{n=e}),o=a.then(()=>r);we.set(e,o),await a;try{return await t()}finally{n(),we.get(e)===o&&we.delete(e)}}async function fe(e,t){const a=ue.get(e);if(a)return a;const n=he.get(e);if(n)return n;if(ue.size>=8)for(const t of ue.keys())if(t!==e){await be(t);break}const r=async function(e,t){const a=oe();if(!a||"function"!=typeof a.getDirectory)return null;const n=await a.getDirectory(),r=await n.getDirectoryHandle(C,{create:!0}),o=await r.getFileHandle(e,{create:!0}),i=se(o);if("function"!=typeof i)return null;const s=await i.call(o);try{return t>0&&s.getSize()!==t&&s.truncate(t),{access:s,uniformSize:0,uniformKnown:!1,maxRealLen:0,seenCount:0}}catch(e){try{s.close()}catch{}throw e}}(e,t).catch(e=>(console.error(e),null));he.set(e,r);try{const t=await r;return t&&ue.set(e,t),t}finally{he.delete(e)}}function me(e,t,a){const n=new Uint8Array(a);let r=0;for(;r<n.length;){const a=e.write(n.subarray(r),{at:t+r});if(a<=0)throw new Error("OPFS short write");r+=a}}async function pe(e){const{schemaVersion:t,roomId:a,fromPeerId:n,channelLabel:r,timestamp:o,merkleRoot:i,hash:s,filename:c,messageType:l,chunkIndex:d,mimeType:u,leafHash:h,realLen:y,totalSize:w,data:g,storage:f}=e;if(1!==t||!Number.isSafeInteger(l)||l<1||l>64||!Number.isSafeInteger(d)||d<0||!Number.isSafeInteger(y)||y<=0||y>K||!Number.isSafeInteger(w)||w<=0||w>10737418240||y>w||d>=w||g.byteLength!==y||!Number.isSafeInteger(o))throw new Error("invalid receive chunk bounds");const m=e=>{if(e&&(e.roomId!==a||e.fromPeerId!==n||e.hash!==s||e.totalSize!==w||e.messageType!==l||e.filename!==c||e.channelLabel!==r||e.timestamp!==o))throw new Error("receive chunk metadata conflicts with message")},p=e=>{const t=e.map(e=>({chunkIndex:e.chunkIndex,realLen:e.realLen??0})).sort((e,t)=>e.chunkIndex-t.chunkIndex);let a=0;for(let e=0;e<t.length;e++){const n=t[e];if(!Number.isSafeInteger(n.chunkIndex)||n.chunkIndex<0||!Number.isSafeInteger(n.realLen)||n.realLen<=0||n.realLen>K||n.realLen>w||n.chunkIndex>=w||e>0&&t[e-1].chunkIndex===n.chunkIndex)throw new Error("invalid receive chunk layout");if(a+=n.realLen,!Number.isSafeInteger(a)||a>w)throw new Error("receive chunks exceed declared total")}const n=t.find(e=>0===e.chunkIndex);let r;if(n)r=n.realLen;else if(t.length>=2){r=0;for(const e of t)r=Math.max(r,e.realLen)}if(void 0!==r){const e=Math.ceil(w/r),n=e-1,o=w-r*n;for(const a of t){if(a.chunkIndex>=e)throw new Error("receive chunk index exceeds canonical manifest");const t=a.chunkIndex===n?o:r;if(a.realLen!==t)throw new Error("receive chunk length conflicts with manifest")}const i=a===w&&t.length===e&&t.every((e,t)=>e.chunkIndex===t);if(a===w&&!i)throw new Error("receive completion has a chunk-index gap");return{savedSize:a,complete:i}}if(a===w)throw new Error("receive completion is missing chunk zero");return{savedSize:a,complete:!1}},b=await R();let k;try{const e=b.transaction(["chunks","messageData"],"readonly");k=await e.objectStore("chunks").count([i,d]);m(await e.objectStore("messageData").index("merkleRoot").get(i)),await e.done}finally{b.close()}if(k>0){const e=await R();try{const t=e.transaction(["chunks","messageData"],"readonly"),a=t.objectStore("chunks").index("merkleRoot"),n=[];let r=await a.openCursor(i);for(;r;)n.push(r.value),r=await r.continue();m(await t.objectStore("messageData").index("merkleRoot").get(i));const o=p(n);return await t.done,{stored:!1,...o}}finally{e.close()}}const S=await R();try{const e=S.transaction(["chunks","messageData"],"readonly"),t=[];let a=await e.objectStore("chunks").index("merkleRoot").openCursor(i);for(;a;)t.push(a.value),a=await a.continue();m(await e.objectStore("messageData").index("merkleRoot").get(i)),p([...t,{chunkIndex:d,realLen:y}]),await e.done}finally{S.close()}let I=!1;if("opfs"===f)try{I=await async function(e,t,a,n,r){const o=await fe(e,n);if(!o)return!1;if(o.maxRealLen=Math.max(o.maxRealLen,a),o.seenCount+=1,o.uniformKnown||(0===t?(a<n&&(o.uniformSize=a),o.uniformKnown=!0):o.seenCount>=2&&(o.uniformSize=o.maxRealLen,o.uniformKnown=!0)),!o.uniformKnown)return!1;const i=0===t?0:t*o.uniformSize;return me(o.access,i,r),o.access.flush(),!0}(i,d,y,w,g)}catch(e){console.error(e),I=!1}const x="opfs"===f&&I?{merkleRoot:i,hash:s,chunkIndex:d,mimeType:u,realLen:y,leafHash:h}:{merkleRoot:i,hash:s,chunkIndex:d,mimeType:u,realLen:y,leafHash:h,data:g},v=await R();try{const e=v.transaction(["chunks","messageData","uniqueRoom"],"readwrite"),t=e.objectStore("chunks"),u=await t.getKey([i,d]);let h=!1;const g=[];let f=await t.index("merkleRoot").openCursor(i);for(;f;)g.push(f.value),f=await f.continue();void 0===u&&(p([...g,{chunkIndex:d,realLen:y}]),await t.add(x),g.push(x),h=!0);const b=p(g);if(h){const t=e.objectStore("messageData"),d=await t.index("merkleRoot").get(i);m(d),await t.put({roomId:a,timestamp:d?.timestamp??o,merkleRoot:i,hash:s,fromPeerId:n,filename:c,messageType:l,savedSize:b.savedSize,totalSize:w,channelLabel:r});const u=e.objectStore("uniqueRoom"),h=await u.index("roomId").get(a);h&&h.lastMessageMerkleRoot!==i&&await u.put({...h,lastMessageMerkleRoot:i,messageCount:h.messageCount+1,updatedAt:o})}return await e.done,{stored:h,...b}}finally{v.close()}}async function be(e){const t=he.get(e);if(t)try{await t}catch{}const a=ue.get(e);if(a){ue.delete(e);try{a.access.flush(),a.access.close()}catch{}}}async function ke(e,t,a,n){if(e.length!==2*x)return null;await be(e);const r=ye.get(e);if(r)return r;const o=async function(e,t,a,n){try{const r=oe();if(!r||"function"!=typeof r.getDirectory)return null;const o=await r.getDirectory(),i=await o.getDirectoryHandle(C,{create:!0}),s=await i.getFileHandle(e,{create:!0}),c=await R(),l=[];let d=0;try{const t=c.transaction("chunks","readonly"),a=t.objectStore("chunks").index("merkleRoot");let n=await a.openCursor(e);for(;n;){const e=n.value;e.realLen&&e.realLen>d&&(d=e.realLen),e.data&&e.data.byteLength>0&&l.push(e),n=await n.continue()}await t.done}catch(e){return console.error(e),c.close(),null}const u=await s.getFile();if(t>0&&u.size===t&&0===l.length)return c.close(),ce(u,a,e,n);if(l.length>0&&(0===d||l.some(e=>null==e.realLen)))return c.close(),null;const h=se(s);if("function"!=typeof h)return c.close(),null;const y=await h.call(s);try{t>0&&y.getSize()!==t&&y.truncate(t);for(let e=0;e<l.length;e++){const t=l[e];me(y,0===t.chunkIndex?0:t.chunkIndex*d,t.data)}y.flush()}finally{y.close()}if(l.length>0)try{const e=c.transaction("chunks","readwrite"),t=e.objectStore("chunks");for(let e=0;e<l.length;e++){const a=l[e];await t.put({merkleRoot:a.merkleRoot,hash:a.hash,chunkIndex:a.chunkIndex,mimeType:a.mimeType,realLen:a.realLen,leafHash:a.leafHash})}await e.done}catch(e){console.error(e)}c.close();const w=await s.getFile();return t>0&&w.size!==t?null:ce(w,a,e,n)}catch(e){return console.error(e),null}}(e,t,a,n);ye.set(e,o);try{return await o}finally{ye.delete(e)}}const Se=new class{#e=new Map;#t(e,t){const a=(e=>`${String(e.roomId.length)}:${e.roomId}${String(e.peerPublicKey.length)}:${e.peerPublicKey}`)(e),n=this.#e.get(a);if(n&&e.updatedAt<n.updatedAt)throw t.fill(0),new Error("Ratchet persistence rollback detected");if(e.updatedAt===n?.updatedAt&&!te(t,n.fingerprint))throw t.fill(0),new Error("Ratchet persistence equivocation detected");!n||e.updatedAt>n.updatedAt?(n?.fingerprint.fill(0),this.#e.set(a,{updatedAt:e.updatedAt,fingerprint:t})):t.fill(0)}async acceptAuthenticated(e){const t=await ee(e);this.#t(e,t)}async rememberTrustedWrite(e){const t=await ee(e);this.#t(e,t)}forget(e,t){const a=`${String(e.length)}:${e}${String(t.length)}:${t}`;this.#e.get(a)?.fingerprint.fill(0),this.#e.delete(a)}clear(){for(const e of this.#e.values())e.fingerprint.fill(0);this.#e.clear()}},Ie=new Map,xe=new Map,Ke=(e,t)=>`${String(e.length)}:${e}${String(t.length)}:${t}`,ve=async(e,t,a)=>{const n=Ke(e,t),r=xe.get(n)??Promise.resolve();let o;const i=new Promise(e=>{o=e}),s=r.catch(()=>{}).then(()=>i);xe.set(n,s),await r.catch(()=>{});try{return await a()}finally{o(),xe.get(n)===s&&xe.delete(n)}};async function Ce(e,t){return ve(e,t,async()=>{try{const a=await R();let n;try{n=await a.get("ratchetSessions",[e,t])}finally{a.close()}if(!n)return;const r=await ae(),o=await async function(e,t,a){const n=X(e);W(n);const r=[];try{const e=Y(n.rootKey),o=await Z(t,n.rootKey,_(n,U.RootKey,e),e);r.push(o);const i=n.sendingChainKey?await Z(t,n.sendingChainKey,_(n,U.SendingChainKey,e),e):null;i&&r.push(i);const s=n.receivingChainKey?await Z(t,n.receivingChainKey,_(n,U.ReceivingChainKey,e),e):null;s&&r.push(s);const c=await Z(t,n.dhSelfSec,_(n,U.DhSelfSecret,e),e);r.push(c);const l=[];for(let a=0;a<n.skippedMessageKeys.length;a++){const o=n.skippedMessageKeys[a],i=await Z(t,o.messageKey,_(n,U.SkippedMessageKey,e,a),e);r.push(i),l.push({dhPub:o.dhPub,n:o.n,messageKey:i})}const d=n.edgeCryptoState?await Z(t,n.edgeCryptoState,_(n,U.EdgeCryptoState,e),e,null):null;return d&&r.push(d),a&&await a.acceptAuthenticated(n),{...n,rootKey:o,sendingChainKey:i,receivingChainKey:s,dhSelfSec:c,skippedMessageKeys:l,edgeCryptoState:d}}catch(e){for(const e of r)new Uint8Array(e).fill(0);throw e}finally{G(n)}}(n,r,Se),i=Ke(e,t);return Ie.set(i,Math.max(Ie.get(i)??0,o.updatedAt)),o}catch(e){return void console.error(e)}})}async function Ae(e){await ve(e.roomId,e.peerPublicKey,async()=>{const t=Ke(e.roomId,e.peerPublicKey),a=Ie.get(t)??0,n=Math.max(Date.now(),e.updatedAt),r=n>a?n:a+1;if(!Number.isSafeInteger(r))throw new Error("Ratchet persistence timestamp exhausted");const o={...e,updatedAt:r};try{const e=await ae(),a=await async function(e,t){const a=X(e);if(W(a),$(a.rootKey,"ratchet rootKey",32),a.sendingChainKey&&$(a.sendingChainKey,"ratchet sendingChainKey",32),a.receivingChainKey&&$(a.receivingChainKey,"ratchet receivingChainKey",32),$(a.dhSelfSec,"ratchet dhSelfSec",32),a.skippedMessageKeys.forEach((e,t)=>$(e.messageKey,`ratchet skipped[${String(t)}].messageKey`,32)),a.edgeCryptoState&&($(a.edgeCryptoState,"ratchet edge crypto state"),a.edgeCryptoState.byteLength<1||a.edgeCryptoState.byteLength>M))throw new Error("ratchet edge crypto state length is invalid");try{const e=crypto.getRandomValues(new Uint8Array(L)),n=await J(t,a.rootKey,_(a,U.RootKey,e),e),r=a.sendingChainKey?await J(t,a.sendingChainKey,_(a,U.SendingChainKey,e),e):null,o=a.receivingChainKey?await J(t,a.receivingChainKey,_(a,U.ReceivingChainKey,e),e):null,i=await J(t,a.dhSelfSec,_(a,U.DhSelfSecret,e),e),s=[];for(let n=0;n<a.skippedMessageKeys.length;n++){const r=a.skippedMessageKeys[n];s.push({dhPub:r.dhPub,n:r.n,messageKey:await J(t,r.messageKey,_(a,U.SkippedMessageKey,e,n),e)})}const c=a.edgeCryptoState?await J(t,a.edgeCryptoState,_(a,U.EdgeCryptoState,e),e,null):null;return{...a,rootKey:n,sendingChainKey:r,receivingChainKey:o,dhSelfSec:i,skippedMessageKeys:s,edgeCryptoState:c}}finally{G(a)}}(o,e),n=await R();try{await n.put("ratchetSessions",a)}finally{n.close()}await Se.rememberTrustedWrite(a),Ie.set(t,r)}finally{(e=>{new Uint8Array(e.rootKey).fill(0),e.sendingChainKey&&new Uint8Array(e.sendingChainKey).fill(0),e.receivingChainKey&&new Uint8Array(e.receivingChainKey).fill(0),new Uint8Array(e.dhSelfSec).fill(0);for(const t of e.skippedMessageKeys)new Uint8Array(t.messageKey).fill(0);e.edgeCryptoState&&new Uint8Array(e.edgeCryptoState).fill(0)})(o)}})}const Re=/^[0-9a-f]{64}$/,De=(e,t)=>{if("string"!=typeof e||0===e.length)throw new Error("PIN attempt room ID must not be empty");if(void 0!==t&&!Re.test(t))throw new Error("PIN attempt peer identity must be 32-byte lowercase hexadecimal")},Pe=e=>`pinAttempts:v2:${e.length}:${e}:`,Ee=(e,t)=>`${Pe(e)}${t}`;const Le="identityX25519";const Be="identityEd25519";async function je(){try{await async function(){const e=[...he.values()];for(let t=0;t<e.length;t++)try{await e[t]}catch{}const t=[...ue.keys()];for(let e=0;e<t.length;e++)await be(t[e])}();const e=oe();if(e&&"function"==typeof e.getDirectory){const t=await e.getDirectory();await t.removeEntry(C,{recursive:!0}).catch(()=>{})}}catch{}await function(e,{blocked:t}={}){const a=indexedDB.deleteDatabase(e);return t&&a.addEventListener("blocked",e=>t(e.oldVersion,e)),d(a).then(()=>{})}(A,{blocked(){console.error("DB deletion BLOCKED")}}),Se.clear(),Ie.clear()}onmessage=async e=>{const t=e.data,{id:a,method:n}=t;try{let e;switch(n){case"getDBAddressBookEntry":e=await async function(e,t){if(!e&&!t)return;if(e&&e.length<10&&!t)return;if(t&&64!==t.length&&!e)return;const a=await R();try{const n=a.transaction("addressBook","readonly"),r=e?n.objectStore("addressBook").index("peerId"):n.objectStore("addressBook").index("peerPublicKey"),o=e?await r.get(e):await r.get(t??"");return await n.done,a.close(),o?{username:o.username,peerId:o.peerId,peerPublicKey:o.peerPublicKey}:void 0}catch{return void a.close()}}(...t.args);break;case"getAllDBAddressBookEntries":e=await async function(){try{const e=await R(),t=await e.getAll("addressBook");return e.close(),t}catch{return[]}}(...t.args);break;case"setDBAddressBookEntry":await async function(e,t,a){try{const n=await R(),r=n.transaction(["addressBook"],"readwrite"),o=r.objectStore("addressBook"),i=o.index("peerId"),s=o.index("peerPublicKey"),c=await i.get(t),l=await s.get(a);(!c&&!l||c&&!l||!c&&l)&&await o.put({username:e,peerId:t,peerPublicKey:a,dateAdded:Date.now()}),await r.done,n.close()}catch(e){console.error(e)}}(...t.args),e=void 0;break;case"deleteDBAddressBookEntry":e=await async function(e,t,a){const n=!e||0===e.length,r=!t||t.length<10,o=64!==a?.length;if(n&&r&&o)throw new Error("Cannot delete address book with no data");let i=t??"";try{const n=await R(),s=n.transaction("addressBook","readwrite"),c=s.objectStore("addressBook");if(r)if(o){const t=c.index("username"),a=await t.getKey(e??"");if(a){const n=await t.get(e??"");i=n?.peerId??"",await c.delete(a)}}else{const e=c.index("peerPublicKey"),t=await e.getKey(a);if(t){const n=await e.get(a);i=n?.peerId??"",await c.delete(t)}}else{const e=c.index("peerId"),a=await e.getKey(t);a&&await c.delete(a)}await s.done,n.close()}catch{}return i}(...t.args);break;case"getDBPeerIsBlacklisted":e=await async function(e,t){if(!e&&!t)return!1;if(e&&e.length<10&&!t)return!1;if(t&&64!==t.length&&!e)return!1;const a=await R();try{const n=a.transaction("blacklist","readonly"),r=e?n.objectStore("blacklist").index("peerId"):n.objectStore("blacklist").index("peerPublicKey"),o=e?await r.get(e):await r.get(t??"");return await n.done,!!o}finally{a.close()}}(...t.args);break;case"getAllDBBlacklisted":e=await async function(){const e=await R();try{const t=await e.getAll("blacklist");return e.close(),t}catch{return e.close(),[]}}(...t.args);break;case"setDBPeerInBlacklist":await async function(e,t){try{const a=await R(),n=a.transaction(["blacklist"],"readwrite"),r=n.objectStore("blacklist"),o=r.index("peerId"),i=r.index("peerPublicKey"),s=await o.get(e),c=await i.get(t);(!s&&!c||s&&!c||!s&&c)&&await r.put({peerId:e,peerPublicKey:t,dateAdded:Date.now()}),await n.done,a.close()}catch(e){throw console.error(e),e}}(...t.args),e=void 0;break;case"deleteDBPeerFromBlacklist":await async function(e,t){const a=!e||e.length<10;if(a&&64!==t?.length)throw new Error("Cannot delete blacklisted with no data");try{const n=await R(),r=n.transaction("blacklist","readwrite"),o=r.objectStore("blacklist");if(a){const e=o.index("peerPublicKey"),a=await e.getKey(t??"");a&&await o.delete(a)}else{const t=o.index("peerId"),a=await t.getKey(e);a&&await o.delete(a)}await r.done,n.close()}catch(e){console.error(e)}}(...t.args),e=void 0;break;case"getAllDBUniqueRooms":e=await async function(){const e=await R();try{const t=await e.getAll("uniqueRoom");return e.close(),t}catch{return e.close(),[]}}(...t.args);break;case"setDBUniqueRoom":await async function(e,t,a){if(32!==a.byteLength)throw new Error("Room policy must be the canonical 32-byte descriptor");const n=await R();try{const r=n.transaction(["uniqueRoom"],"readwrite"),o=r.objectStore("uniqueRoom"),i=o.index("roomUrl"),s=o.index("roomId"),c=await i.get(e),l=await s.get(t),d=c??l;if(d)await o.put({...d,roomId:t,roomUrl:e,roomPolicy:a,updatedAt:Date.now()});else{const n=Date.now();await o.put({roomId:t,roomUrl:e,roomPolicy:a,messageCount:0,lastMessageMerkleRoot:"",createdAt:n,updatedAt:n})}await r.done}finally{n.close()}}(...t.args),e=void 0;break;case"getDBMessageData":e=await async function(e,t){try{const a=await R(),n=a.transaction(["messageData"],"readonly"),r=n.objectStore("messageData"),o=r.index("merkleRoot"),i=r.index("hash");if(e?.length===2*x){const r=await o.get(e);if(r)return await n.done,a.close(),r;if(t?.length===2*x){const e=await i.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}if(t?.length===2*x){const e=await i.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}catch(e){return void console.error(e)}}(...t.args);break;case"getDBRoomMessageData":e=await async function(e){const t=await R(),a=await t.getAllFromIndex("messageData","roomId",e);t.close();const n=a.length,r=[];for(let t=0;t<n;t++)r.push({transferId:a[t].transferId,roomId:e,merkleRoot:a[t].merkleRoot,hash:a[t].hash,fromPeerId:a[t].fromPeerId,filename:a[t].filename,messageType:a[t].messageType,savedSize:a[t].savedSize,totalSize:a[t].totalSize,channelLabel:a[t].channelLabel,timestamp:a[t].timestamp});return r}(...t.args);break;case"setDBRoomMessageData":await async function(e,t,a,n,r,o,i,s,c,l,d){try{const u=await R(),h=u.transaction(["messageData","uniqueRoom"],"readwrite"),y=h.objectStore("messageData"),w=await y.index("merkleRoot").get(t),g=w?.savedSize??0;try{await y.put({transferId:d,roomId:e,timestamp:l,merkleRoot:t,hash:a,fromPeerId:n,filename:s,messageType:i,savedSize:g+r<=o?g+r:o,totalSize:o,channelLabel:c})}catch(e){throw await h.done,u.close(),e}const f=h.objectStore("uniqueRoom"),m=await f.index("roomId").get(e);if(m&&m.lastMessageMerkleRoot!==t)try{await f.put({...m,lastMessageMerkleRoot:t,messageCount:m.messageCount+1,updatedAt:l})}catch(e){throw await h.done,u.close(),e}await h.done,u.close()}catch(e){throw console.error(e),e}}(...t.args),e=void 0;break;case"getDBChunk":e=await async function(e,t){const a=await R(),n=await a.get("chunks",[e,t]);return a.close(),n?.data}(...t.args);break;case"existsDBChunk":e=await async function(e,t){const a=await R(),n=await a.count("chunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBNewChunk":e=await async function(e,t){const a=await R();try{return await a.get("newChunks",[e,t])}finally{a.close()}}(...t.args);break;case"getDBNewChunkByReceipt":e=await async function(e,t){if(e.length!==2*x||t.length!==2*x)return;const a=await R();try{return await a.getFromIndex("newChunks","receiptScope",[e,t])}finally{a.close()}}(...t.args);break;case"existsDBNewChunk":e=await async function(e,t){const a=await R(),n=await a.count("newChunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBSendQueue":e=await async function(e,t,a){const n=await R();if(a){const r=await n.get("sendQueue",[a,e,t]);return n.close(),r?[r]:[]}const r=n.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),o=IDBKeyRange.only([e,t]),i=await r.getAll(o);return n.close(),i}(...t.args);break;case"getDBAllChunks":e=await async function(e,t){try{const a=await R(),n=a.transaction("chunks","readonly"),r=n.objectStore("chunks"),o=r.index("hash"),i=r.index("merkleRoot");if(e?.length===2*x){const t=await i.getAll(e);return 0===t.length?(await n.done,a.close(),[]):(await n.done,a.close(),t)}if(t?.length===2*x){const e=await o.getAll(t);return await n.done,a.close(),e.length>0?e.filter(t=>t.merkleRoot===e[0].merkleRoot):e}return await n.done,a.close(),[]}catch(e){return console.error(e),[]}}(...t.args);break;case"getDBAllChunkLeafHashes":e=await async function(e){if(e.length!==2*x)return[];try{const t=await R(),a=t.transaction("chunks","readonly"),n=a.objectStore("chunks").index("merkleRoot"),r=[];let o=await n.openCursor(e);for(;o;)r.push({chunkIndex:o.value.chunkIndex,leafHash:o.value.leafHash}),o=await o.continue();return await a.done,t.close(),r}catch(e){return console.error(e),[]}}(...t.args);break;case"assembleToOPFS":e=await le(...t.args);break;case"getDBAllChunksCount":e=await async function(e,t){try{const a=await R(),n=a.transaction(["chunks"],"readonly"),r=n.objectStore("chunks"),o=r.index("hash"),i=r.index("merkleRoot");if(t?.length===2*x){const r=await o.count(t);if(0===r){if(e?.length===2*x){const t=await i.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}return await n.done,a.close(),r}if(e?.length===2*x){const t=await i.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}catch{return 0}}(...t.args);break;case"setDBChunk":await async function(e){const t=await R();try{await t.add("chunks",e)}finally{t.close()}}(...t.args),e=void 0;break;case"storeReceiveChunk":{const a=t.args[0];e=await ge(a.merkleRoot,()=>async function(e){return pe(e)}(a));break}case"getReceiveFile":{const a=t.args;e=await ge(a[0],()=>ke(...a));break}case"closeReceiveFile":await ge(t.args[0],()=>be(...t.args)),e=void 0;break;case"deleteReceiveTransfer":await ge(t.args[0],()=>async function(e){if(e.length!==2*x||!/^[0-9a-f]+$/.test(e))throw new Error("invalid receive transfer Merkle root");await be(e);const t=await R();try{const a=t.transaction(["chunks","messageData","uniqueRoom"],"readwrite"),n=a.objectStore("chunks"),r=a.objectStore("messageData"),o=a.objectStore("uniqueRoom"),i=await n.index("merkleRoot").getAllKeys(e);for(const e of i)await n.delete(e);const s=await r.index("merkleRoot").getAllKeys(e);let c="";for(const e of s){const t=await r.get(e);!c&&t&&(c=t.roomId),await r.delete(e)}if(c){const e=await o.index("roomId").get(c);if(e){const t=r.index("roomId"),a=await t.count(c),n=await t.openCursor(IDBKeyRange.only(c),"prev");await o.put({...e,messageCount:a,updatedAt:n?.value.timestamp??Date.now(),lastMessageMerkleRoot:n?.value.merkleRoot??""})}}await a.done}finally{t.close()}await de(e)}(...t.args)),e=void 0;break;case"getDBAllNewChunks":e=await async function(e){const{transferId:t,merkleRootHex:a,hashHex:n}=e,r=t?"transferId":a?"merkleRoot":n?"hash":void 0,o=t??a??n;if(!r||!o)return[];const i=await R();try{return await i.getAllFromIndex("newChunks",r,o)}finally{i.close()}}(...t.args);break;case"getDBAllNewChunksCount":e=await async function(e){const t=await R();try{return await t.countFromIndex("newChunks","transferId",e)}finally{t.close()}}(...t.args);break;case"setDBNewChunk":await async function(e){const t=await R();try{await t.put("newChunks",e)}finally{t.close()}}(...t.args),e=void 0;break;case"setDBSendQueue":await async function(e){const t=await R();await t.put("sendQueue",e),t.close()}(...t.args),e=void 0;break;case"countDBSendQueue":e=await async function(e,t){const a=await R(),n=a.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),r=IDBKeyRange.only([e,t]),o=await n.count(r);return a.close(),o}(...t.args);break;case"deleteDBChunk":await async function(e,t){try{const a=await R(),n=a.transaction("chunks","readwrite"),r=n.objectStore("chunks");if(void 0!==t){const a=IDBKeyRange.only([e,t]);await r.delete(a)}else{const t=r.index("hash"),a=await t.getAllKeys(e),n=a.length;if(0===n){const t=r.index("merkleRoot"),a=await t.getAllKeys(e),n=a.length;for(let e=0;e<n;e++)await r.delete(a[e])}else for(let e=0;e<n;e++)await r.delete(a[e])}await n.done,a.close()}catch{}}(...t.args),e=void 0;break;case"deleteDBNewChunk":await async function(e){const{transferId:t,merkleRootHex:a,hashHex:n,chunkIndex:r}=e,o=await R();try{const e=o.transaction("newChunks","readwrite"),i=e.objectStore("newChunks");if(t&&void 0!==r)await i.delete([t,r]);else if(t){const e=await i.index("transferId").getAllKeys(t);for(const t of e)await i.delete(t)}else if(a){const e=await i.index("merkleRoot").getAllKeys(a);for(const t of e)await i.delete(t)}else if(n){const e=await i.index("hash").getAllKeys(n);for(const t of e)await i.delete(t)}await e.done}catch(e){throw console.error(e),e}finally{o.close()}}(...t.args),e=void 0;break;case"deleteDBMessageData":await async function(e){try{const t=await R(),a=t.transaction(["messageData","uniqueRoom"],"readwrite"),n=a.objectStore("messageData"),r=a.objectStore("uniqueRoom"),o=n.index("merkleRoot"),i=await o.getAllKeys(e),s=i.length;let c="";for(let e=0;e<s;e++){if(0===e||0===c.length){const t=await n.get(i[e]);c=t?.roomId??""}await n.delete(i[e])}if(c.length>0){const e=r.index("roomId"),t=await e.get(c);if(t){const e=n.index("roomId"),a=await e.getAllKeys(c),o=a.length,i=o>0?await n.get(a[o-1]):void 0;await r.put({...t,messageCount:t.messageCount>0?t.messageCount-1:0,updatedAt:i?.timestamp??Date.now(),lastMessageMerkleRoot:i?.merkleRoot??""})}}await a.done,t.close(),await ge(e,async()=>{await be(e),await de(e)})}catch{}}(...t.args),e=void 0;break;case"deleteDBUniqueRoom":await async function(e){try{const t=await R(),a=t.transaction(["uniqueRoom","ratchetSessions"],"readwrite"),n=a.objectStore("uniqueRoom"),r=n.index("roomId"),o=await r.getKey(e);void 0!==o&&await n.delete(o);const i=a.objectStore("ratchetSessions"),s=await i.index("roomId").getAllKeys(e);for(const t of s)await i.delete(t),Array.isArray(t)&&"string"==typeof t[1]&&(Se.forget(e,t[1]),Ie.delete(Ke(e,t[1])));await a.done,t.close()}catch{}}(...t.args),e=void 0;break;case"deleteDBSendQueue":await async function(e,t,a){try{const n=await R();if(void 0!==a)await n.delete("sendQueue",[a,e,t]);else{const a=IDBKeyRange.only([e,t]);await n.delete("sendQueue",a)}n.close()}catch{}}(...t.args),e=void 0;break;case"getRatchetSession":e=await Ce(...t.args);break;case"setRatchetSession":await Ae(...t.args),e=void 0;break;case"deleteRatchetSession":await async function(e,t){await ve(e,t,async()=>{try{const a=await R();await a.delete("ratchetSessions",[e,t]),a.close(),Se.forget(e,t),Ie.delete(Ke(e,t))}catch(e){console.error(e)}})}(...t.args),e=void 0;break;case"getPinAttemptState":e=await async function(e,t){De(e,t);const a=await R();try{return await a.get("meta",Ee(e,t))}finally{a.close()}}(...t.args);break;case"incrementPinAttemptState":e=await async function(e,t,a,n,r,o){if(De(e,t),!Number.isSafeInteger(a)||!Number.isSafeInteger(n)||!Number.isSafeInteger(r)||!Number.isSafeInteger(o)||a<0||n<1||r<1||o<r)throw new Error("Invalid PIN backoff parameters");const i=await R();try{const s=i.transaction("meta","readwrite"),c=s.objectStore("meta"),l=Ee(e,t),d=await c.get(l),u=(d?.failures??0)+1,h={failures:u,retryAfter:a+(u<n?0:Math.min(r*2**(u-n),o))};return await c.put(h,l),await s.done,h}finally{i.close()}}(...t.args);break;case"deletePinAttemptState":await async function(e,t){De(e,t);const a=await R();try{if(void 0!==t)return void await a.delete("meta",Ee(e,t));const n=a.transaction("meta","readwrite"),r=n.objectStore("meta"),o=Pe(e),i=await r.getAllKeys();await Promise.all(i.filter(e=>"string"==typeof e&&e.startsWith(o)).map(e=>r.delete(e))),await r.delete(`pinAttempts:${e}`),await n.done}finally{a.close()}}(...t.args),e=void 0;break;case"getIdentityX25519":e=await async function(){const e=await R();let t;try{t=await e.get("meta",Le)}finally{e.close()}if(!t)return;if(32!==t.pub.byteLength||64!==t.crossSig.byteLength)throw new Error("Stored X25519 identity has invalid public fields");const a=await ae(),n=await re(a,t.wrappedSecret);if(32!==n.byteLength)throw new Error("Stored X25519 identity has an invalid secret length");return{pub:t.pub,secret:n,crossSig:t.crossSig}}();break;case"setIdentityX25519":await async function(e){if(32!==e.pub.byteLength||32!==e.secret.byteLength||64!==e.crossSig.byteLength)throw new Error("X25519 identity has invalid field lengths");const t=await ae(),a=await ne(t,e.secret),n={pub:e.pub,wrappedSecret:a,crossSig:e.crossSig},r=await R();try{await r.put("meta",n,Le)}finally{r.close()}}(...t.args),e=void 0;break;case"deleteIdentityX25519":await async function(){const e=await R();try{const t=e.transaction(["meta","ratchetSessions"],"readwrite");await t.objectStore("meta").delete(Le),await t.objectStore("ratchetSessions").clear(),await t.done}finally{e.close()}Se.clear(),Ie.clear()}(),e=void 0;break;case"getIdentityEd25519":e=await async function(){const e=await R();let t;try{t=await e.get("meta",Be)}finally{e.close()}if(!t)return;if(32!==t.pub.byteLength)throw new Error("Stored Ed25519 public key has an invalid length");const a=await ae(),n=await re(a,t.wrappedSecret);if(64!==n.byteLength)throw new Error("Stored Ed25519 secret key has an invalid length");return{pub:t.pub,secret:n}}();break;case"setIdentityEd25519":await async function(e){if(32!==e.pub.byteLength||64!==e.secret.byteLength)throw new Error("Ed25519 identity has invalid key lengths");const t=await ae(),a=await ne(t,e.secret),n={pub:e.pub,wrappedSecret:a},r=await R();try{await r.put("meta",n,Be)}finally{r.close()}}(...t.args),e=void 0;break;case"deleteIdentityEd25519":await async function(){const e=await R();try{const t=e.transaction(["meta","ratchetSessions"],"readwrite");await t.objectStore("meta").delete(Be),await t.objectStore("ratchetSessions").clear(),await t.done}finally{e.close()}Se.clear(),Ie.clear()}(),e=void 0;break;case"deleteDB":await je(),e=void 0;break;default:return void postMessage({id:a,error:"Method not found"})}postMessage({id:a,result:e})}catch(e){postMessage({id:a,error:String(e)})}};
1
+ const e=(e,t)=>t.some(t=>e instanceof t);let t,a;const n=new WeakMap,r=new WeakMap,o=new WeakMap;let i={get(e,t,a){if(e instanceof IDBTransaction){if("done"===t)return n.get(e);if("store"===t)return a.objectStoreNames[1]?void 0:a.objectStore(a.objectStoreNames[0])}return d(e[t])},set:(e,t,a)=>(e[t]=a,!0),has:(e,t)=>e instanceof IDBTransaction&&("done"===t||"store"===t)||t in e};function s(e){i=e(i)}function c(e){return(a||(a=[IDBCursor.prototype.advance,IDBCursor.prototype.continue,IDBCursor.prototype.continuePrimaryKey])).includes(e)?function(...t){return e.apply(u(this),t),d(this.request)}:function(...t){return d(e.apply(u(this),t))}}function l(a){return"function"==typeof a?c(a):(a instanceof IDBTransaction&&function(e){if(n.has(e))return;const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("complete",r),e.removeEventListener("error",o),e.removeEventListener("abort",o)},r=()=>{t(),n()},o=()=>{a(e.error||new DOMException("AbortError","AbortError")),n()};e.addEventListener("complete",r),e.addEventListener("error",o),e.addEventListener("abort",o)});n.set(e,t)}(a),e(a,t||(t=[IDBDatabase,IDBObjectStore,IDBIndex,IDBCursor,IDBTransaction]))?new Proxy(a,i):a)}function d(e){if(e instanceof IDBRequest)return function(e){const t=new Promise((t,a)=>{const n=()=>{e.removeEventListener("success",r),e.removeEventListener("error",o)},r=()=>{t(d(e.result)),n()},o=()=>{a(e.error),n()};e.addEventListener("success",r),e.addEventListener("error",o)});return o.set(t,e),t}(e);if(r.has(e))return r.get(e);const t=l(e);return t!==e&&(r.set(e,t),o.set(t,e)),t}const u=e=>o.get(e);const h=["get","getKey","getAll","getAllKeys","count"],y=["put","add","delete","clear"],w=new Map;function g(e,t){if(!(e instanceof IDBDatabase)||t in e||"string"!=typeof t)return;if(w.get(t))return w.get(t);const a=t.replace(/FromIndex$/,""),n=t!==a,r=y.includes(a);if(!(a in(n?IDBIndex:IDBObjectStore).prototype)||!r&&!h.includes(a))return;const o=async function(e,...t){const o=this.transaction(e,r?"readwrite":"readonly");let i=o.store;return n&&(i=i.index(t.shift())),(await Promise.all([i[a](...t),r&&o.done]))[0]};return w.set(t,o),o}s(e=>({...e,get:(t,a,n)=>g(t,a)||e.get(t,a,n),has:(t,a)=>!!g(t,a)||e.has(t,a)}));const f=["continue","continuePrimaryKey","advance"],m={},p=new WeakMap,b=new WeakMap,k={get(e,t){if(!f.includes(t))return e[t];let a=m[t];return a||(a=m[t]=function(...e){p.set(this,b.get(this)[t](...e))}),a}};async function*S(...e){let t=this;if(t instanceof IDBCursor||(t=await t.openCursor(...e)),!t)return;const a=new Proxy(t,k);for(b.set(a,t),o.set(a,u(t));t;)yield a,t=await(p.get(a)||t.continue()),p.delete(a)}function I(t,a){return a===Symbol.asyncIterator&&e(t,[IDBIndex,IDBObjectStore,IDBCursor])||"iterate"===a&&e(t,[IDBIndex,IDBObjectStore])}s(e=>({...e,get:(t,a,n)=>I(t,a)?S:e.get(t,a,n),has:(t,a)=>I(t,a)||e.has(t,a)}));const x=64*Uint8Array.BYTES_PER_ELEMENT,K=65405-(9+x+8+8+256+8+8+8+(4+48*(x+1)));(new TextEncoder).encode("p2party-x25519-idsig-v1");const v=["hybrid-3dh-mlkem512-cpace21-v4","hybrid-3dh-mlkem768-cpace21-v4","hybrid-3dh-mlkem1024-cpace21-v4"],C="p2party-reassembled",R="p2party";async function A(){return function(e,t,{blocked:a,upgrade:n,blocking:r,terminated:o}={}){const i=indexedDB.open(e,t),s=d(i);return n&&i.addEventListener("upgradeneeded",e=>{n(d(i.result),e.oldVersion,e.newVersion,d(i.transaction),e)}),a&&i.addEventListener("blocked",e=>a(e.oldVersion,e.newVersion,e)),s.then(e=>{o&&e.addEventListener("close",()=>o()),r&&e.addEventListener("versionchange",e=>r(e.oldVersion,e.newVersion,e))}).catch(()=>{}),s}(R,19,{upgrade(e,t,a,n){if(e.objectStoreNames.contains("addressBook")){const e=n.objectStore("addressBook");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("addressBook",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("blacklist")){const e=n.objectStore("blacklist");e.indexNames.contains("username")||e.createIndex("username","username",{unique:!1}),e.indexNames.contains("peerId")||e.createIndex("peerId","peerId",{unique:!0}),e.indexNames.contains("peerPublicKey")||e.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}else{const t=e.createObjectStore("blacklist",{keyPath:["peerId"]});t.createIndex("username","username",{unique:!1}),t.createIndex("peerId","peerId",{unique:!0}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!0})}if(e.objectStoreNames.contains("uniqueRoom")){const e=n.objectStore("uniqueRoom");e.indexNames.contains("roomUrl")||e.createIndex("roomUrl","roomUrl",{unique:!0}),e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!0})}else{const t=e.createObjectStore("uniqueRoom",{keyPath:["roomId"]});t.createIndex("roomUrl","roomUrl",{unique:!0}),t.createIndex("roomId","roomId",{unique:!0})}if(e.objectStoreNames.contains("messageData")){const e=n.objectStore("messageData");e.indexNames.contains("roomId")||e.createIndex("roomId","roomId",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!0}),e.indexNames.contains("fromPeerId")||e.createIndex("fromPeerId","fromPeerId",{unique:!1})}else{const t=e.createObjectStore("messageData",{keyPath:["timestamp","roomId","merkleRoot"]});t.createIndex("roomId","roomId",{unique:!1}),t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!0}),t.createIndex("fromPeerId","fromPeerId",{unique:!1})}if(e.objectStoreNames.contains("chunks")){const e=n.objectStore("chunks");e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1})}else{const t=e.createObjectStore("chunks",{keyPath:["merkleRoot","chunkIndex"]});t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("hash","hash",{unique:!1})}if(t<18&&e.objectStoreNames.contains("newChunks")&&e.deleteObjectStore("newChunks"),e.objectStoreNames.contains("newChunks")){const e=n.objectStore("newChunks");e.indexNames.contains("transferId")||e.createIndex("transferId","transferId",{unique:!1}),e.indexNames.contains("hash")||e.createIndex("hash","hash",{unique:!1}),e.indexNames.contains("merkleRoot")||e.createIndex("merkleRoot","merkleRoot",{unique:!1}),e.indexNames.contains("receiptScope")||e.createIndex("receiptScope",["merkleRoot","receiptToken"],{unique:!1})}else{const t=e.createObjectStore("newChunks",{keyPath:["transferId","chunkIndex"]});t.createIndex("transferId","transferId",{unique:!1}),t.createIndex("hash","hash",{unique:!1}),t.createIndex("merkleRoot","merkleRoot",{unique:!1}),t.createIndex("receiptScope",["merkleRoot","receiptToken"],{unique:!1})}if(e.objectStoreNames.contains("sendQueue")){const e=n.objectStore("sendQueue");e.indexNames.contains("labelPeer")||e.createIndex("labelPeer",["label","toPeerId"],{unique:!1})}else{e.createObjectStore("sendQueue",{keyPath:["position","label","toPeerId"]}).createIndex("labelPeer",["label","toPeerId"],{unique:!1})}if(!e.objectStoreNames.contains("ratchetSessions")){const t=e.createObjectStore("ratchetSessions",{keyPath:["roomId","peerPublicKey"]});t.createIndex("peerId","peerId",{unique:!1}),t.createIndex("peerPublicKey","peerPublicKey",{unique:!1}),t.createIndex("roomId","roomId",{unique:!1})}t>0&&t<19&&(n.objectStore("ratchetSessions").clear(),n.objectStore("sendQueue").clear()),e.objectStoreNames.contains("meta")||e.createObjectStore("meta")}})}const D="ratchetWrapKey",P=12,E=16,L=16,B=Uint8Array.of(80,50,82,87),j=B.byteLength+1+L+P,M=262144,N=(new TextEncoder).encode("p2party-edge-crypto-at-rest-aad-v2");var U;!function(e){e[e.RootKey=1]="RootKey",e[e.SendingChainKey=2]="SendingChainKey",e[e.ReceivingChainKey=3]="ReceivingChainKey",e[e.DhSelfSecret=4]="DhSelfSecret",e[e.SkippedMessageKey=5]="SkippedMessageKey",e[e.EdgeCryptoState=6]="EdgeCryptoState"}(U||(U={}));const q=e=>e.slice(0),$=(e,t,a)=>{if(!(e instanceof ArrayBuffer))throw new Error(`${t} must be an ArrayBuffer`);if(void 0!==a&&e.byteLength!==a)throw new Error(`${t} must be ${String(a)} bytes`);return e},T=(e,t)=>{if("number"!=typeof e||!Number.isSafeInteger(e)||e<0)throw new Error(`${t} must be a safe unsigned integer`);return e},z=(e,t)=>{if("string"!=typeof e||0===e.length)throw new Error(`${t} must be a non-empty string`);const a=(new TextEncoder).encode(e);if(a.byteLength>1048576)throw new Error(`${t} is too long`);if((new TextDecoder).decode(a)!==e)throw new Error(`${t} is not canonical Unicode`);return e},F=e=>{if(!Number.isInteger(e)||e<0||e>4294967295)throw new Error("ratchet wrap: value exceeds uint32");const t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!1),t},H=e=>{T(e,"ratchet wrap counter");const t=new Uint8Array(8);return new DataView(t.buffer).setBigUint64(0,BigInt(e),!1),t},O=e=>{const t=e.reduce((e,t)=>e+t.byteLength,0),a=new Uint8Array(t);let n=0;for(const t of e)a.set(t,n),n+=t.byteLength;return a},Q=e=>O([F(e.byteLength),e]),V=e=>Q((new TextEncoder).encode(e)),W=e=>{const t=e.rootSuite;if("string"!=typeof(a=t)||!v.includes(a))throw new Error("Unsupported ratchet root suite");var a;if(z(e.roomId,"ratchet roomId"),z(e.peerPublicKey,"ratchet peerPublicKey"),!/^[0-9a-f]{64}$/.test(e.peerPublicKey))throw new Error("ratchet peerPublicKey must be 32-byte lowercase hex");if(z(e.peerId,"ratchet peerId"),$(e.dhSelfPub,"ratchet dhSelfPub",32),null!==e.dhRemotePub&&$(e.dhRemotePub,"ratchet dhRemotePub",32),T(e.Ns,"ratchet Ns"),T(e.Nr,"ratchet Nr"),T(e.PN,"ratchet PN"),T(e.updatedAt,"ratchet updatedAt"),!Array.isArray(e.skippedMessageKeys)||e.skippedMessageKeys.length>2e3)throw new Error("ratchet skipped-message-key count is invalid");if(e.skippedMessageKeys.forEach((e,t)=>{$(e.dhPub,`ratchet skipped[${String(t)}].dhPub`,32),T(e.n,`ratchet skipped[${String(t)}].n`)}),null!==e.edgeCryptoState){const t=$(e.edgeCryptoState,"ratchet edge crypto state");if(t.byteLength<1||t.byteLength>M+j+E)throw new Error("ratchet edge crypto state length is invalid")}},X=e=>({rootSuite:e.rootSuite,roomId:e.roomId,peerPublicKey:e.peerPublicKey,peerId:e.peerId,rootKey:q($(e.rootKey,"ratchet rootKey")),sendingChainKey:null===e.sendingChainKey?null:q($(e.sendingChainKey,"ratchet sendingChainKey")),receivingChainKey:null===e.receivingChainKey?null:q($(e.receivingChainKey,"ratchet receivingChainKey")),dhSelfPub:q($(e.dhSelfPub,"ratchet dhSelfPub")),dhSelfSec:q($(e.dhSelfSec,"ratchet dhSelfSec")),dhRemotePub:null===e.dhRemotePub?null:q($(e.dhRemotePub,"ratchet dhRemotePub")),Ns:e.Ns,Nr:e.Nr,PN:e.PN,skippedMessageKeys:(()=>{if(!Array.isArray(e.skippedMessageKeys))throw new Error("ratchet skippedMessageKeys must be an array");return e.skippedMessageKeys.map((e,t)=>({dhPub:q($(e.dhPub,`ratchet skipped[${String(t)}].dhPub`)),n:e.n,messageKey:q($(e.messageKey,`ratchet skipped[${String(t)}].messageKey`))}))})(),edgeCryptoState:null===e.edgeCryptoState?null:q($(e.edgeCryptoState,"ratchet edge crypto state")),updatedAt:e.updatedAt}),G=e=>{new Uint8Array(e.rootKey).fill(0),e.sendingChainKey&&new Uint8Array(e.sendingChainKey).fill(0),e.receivingChainKey&&new Uint8Array(e.receivingChainKey).fill(0),new Uint8Array(e.dhSelfSec).fill(0);for(const t of e.skippedMessageKeys)new Uint8Array(t.messageKey).fill(0);e.edgeCryptoState&&new Uint8Array(e.edgeCryptoState).fill(0)},_=(e,t,a,n=0)=>{if(W(e),a.byteLength!==L)throw new Error("ratchet wrap: invalid record ID");const r=(null===e.sendingChainKey?0:1)|(null===e.receivingChainKey?0:2)|(null===e.dhRemotePub?0:4)|(null===e.edgeCryptoState?0:8),o=[Q(N),Uint8Array.of(2,t),Q(a),F(n),V(e.rootSuite),V(e.roomId),V(e.peerPublicKey),V(e.peerId),Q(new Uint8Array(e.dhSelfPub)),Uint8Array.of(r)];null!==e.dhRemotePub&&o.push(Q(new Uint8Array(e.dhRemotePub))),o.push(H(e.Ns),H(e.Nr),H(e.PN),H(e.updatedAt),F(e.skippedMessageKeys.length));for(const t of e.skippedMessageKeys)o.push(Q(new Uint8Array(t.dhPub)),H(t.n));return O(o)},Y=(e,t=32)=>{const a=new Uint8Array(e),n=j+1+E,r=j+M+E;if(null===t&&(a.byteLength<n||a.byteLength>r)||null!==t&&a.byteLength!==j+t+E)throw new Error("Unsupported or malformed ratchet wrap envelope");for(let e=0;e<B.byteLength;e++)if(a[e]!==B[e])throw new Error("Unsupported or malformed ratchet wrap envelope");if(2!==a[B.byteLength])throw new Error("Unsupported or malformed ratchet wrap envelope");return Uint8Array.from(a.subarray(B.byteLength+1,B.byteLength+1+L))},J=async(e,t,a,n,r=32)=>{if($(t,"ratchet secret",null===r?void 0:r),null===r&&(t.byteLength<1||t.byteLength>M))throw new Error("ratchet variable secret length is invalid");if(n.byteLength!==L)throw new Error("ratchet wrap: invalid record ID");const o=crypto.getRandomValues(new Uint8Array(P)),i=await crypto.subtle.encrypt({name:"AES-GCM",iv:o,additionalData:a,tagLength:128},e,t),s=new Uint8Array(j+i.byteLength);return s.set(B,0),s[B.byteLength]=2,s.set(n,B.byteLength+1),s.set(o,B.byteLength+1+L),s.set(new Uint8Array(i),j),s.buffer},Z=async(e,t,a,n,r=32)=>{$(t,"ratchet wrapped secret");const o=Y(t,r);if(!te(o,n))throw new Error("Ratchet wrap record ID mismatch");const i=new Uint8Array(t),s=await crypto.subtle.decrypt({name:"AES-GCM",iv:i.subarray(B.byteLength+1+L,j),additionalData:a,tagLength:128},e,i.subarray(j));if(null!==r&&s.byteLength!==r||null===r&&(s.byteLength<1||s.byteLength>M))throw new Uint8Array(s).fill(0),new Error("Ratchet wrapped secret has an invalid plaintext length");return s},ee=async e=>{W(e);const t=Y(e.rootKey),a=[e.sendingChainKey,e.receivingChainKey,e.dhSelfSec,...e.skippedMessageKeys.map(e=>e.messageKey)];for(const e of a)if(null!==e&&!te(Y(e),t))throw new Error("Ratchet wrap record ID mismatch");if(null!==e.edgeCryptoState&&!te(Y(e.edgeCryptoState,null),t))throw new Error("Ratchet wrap record ID mismatch");const n=[_(e,U.RootKey,t),Q(new Uint8Array(e.rootKey)),Q(e.sendingChainKey?new Uint8Array(e.sendingChainKey):new Uint8Array),Q(e.receivingChainKey?new Uint8Array(e.receivingChainKey):new Uint8Array),Q(new Uint8Array(e.dhSelfSec))];for(const t of e.skippedMessageKeys)n.push(Q(new Uint8Array(t.messageKey)));n.push(Q(e.edgeCryptoState?new Uint8Array(e.edgeCryptoState):new Uint8Array));const r=O(n);try{return new Uint8Array(await crypto.subtle.digest("SHA-256",r))}finally{r.fill(0)}},te=(e,t)=>{if(e.byteLength!==t.byteLength)return!1;let a=0;for(let n=0;n<e.byteLength;n++)a|=e[n]^t[n];return 0===a};async function ae(){const e=await A();try{const t=await e.get("meta",D);if(t)return t;const a=await crypto.subtle.generateKey({name:"AES-GCM",length:256},!1,["encrypt","decrypt"]),n=e.transaction("meta","readwrite"),r=n.objectStore("meta"),o=await r.get(D);return o?(await n.done,o):(await r.put(a,D),await n.done,a)}finally{e.close()}}async function ne(e,t){const a=crypto.getRandomValues(new Uint8Array(P)),n=await crypto.subtle.encrypt({name:"AES-GCM",iv:a},e,t),r=new Uint8Array(P+n.byteLength);return r.set(a,0),r.set(new Uint8Array(n),P),r.buffer}async function re(e,t){const a=new Uint8Array(t);if(a.byteLength<28)throw new Error("Malformed wrapped secret");return crypto.subtle.decrypt({name:"AES-GCM",iv:a.subarray(0,P)},e,a.subarray(P))}const oe=()=>globalThis.navigator?.storage,ie=new Map,se=e=>e.createSyncAccessHandle,ce=(e,t,a,n)=>new File([e],t.length>0?t:a,{type:n});async function le(e,t,a,n){if(e.length!==2*x)return null;const r=ie.get(e);if(r)return r;const o=async function(e,t,a,n){try{const r=oe();if(!r||"function"!=typeof r.getDirectory)return console.warn("OPFS unavailable — reassembling file in memory"),null;const o=await r.getDirectory(),i=await o.getDirectoryHandle(C,{create:!0}),s=await i.getFileHandle(e,{create:!0}),c=await s.getFile();if(t>0&&c.size===t)return ce(c,a,e,n);const l=s.createSyncAccessHandle;if("function"!=typeof l)return console.warn("OPFS sync access handle unavailable — reassembling in memory"),null;const d=await l.call(s);let u;try{u=await A(),d.truncate(0);let t=0;const a=u.transaction("chunks","readonly"),n=a.objectStore("chunks").index("merkleRoot");let r=await n.openCursor(e);for(;r;){const e=new Uint8Array(r.value.data??new ArrayBuffer(0));let a=0;for(;a<e.length;){const n=d.write(e.subarray(a),{at:t+a});if(n<=0)throw new Error("OPFS short write");a+=n}t+=e.length,r=await r.continue()}await a.done,d.flush()}catch(t){try{d.close()}catch{}if(u)try{u.close()}catch{}throw await i.removeEntry(e).catch(()=>{}),t}return d.close(),u.close(),ce(await s.getFile(),a,e,n)}catch(e){return console.error(e),null}}(e,t,a,n);ie.set(e,o);try{return await o}finally{ie.delete(e)}}async function de(e){try{const t=oe();if(!t||"function"!=typeof t.getDirectory)return;const a=await t.getDirectory(),n=await a.getDirectoryHandle(C).catch(()=>null);n&&await n.removeEntry(e).catch(()=>{})}catch{}}const ue=new Map,he=new Map,ye=new Map,we=new Map;async function ge(e,t){const a=we.get(e)??Promise.resolve();let n;const r=new Promise(e=>{n=e}),o=a.then(()=>r);we.set(e,o),await a;try{return await t()}finally{n(),we.get(e)===o&&we.delete(e)}}async function fe(e,t){const a=ue.get(e);if(a)return a;const n=he.get(e);if(n)return n;if(ue.size>=8)for(const t of ue.keys())if(t!==e){await be(t);break}const r=async function(e,t){const a=oe();if(!a||"function"!=typeof a.getDirectory)return null;const n=await a.getDirectory(),r=await n.getDirectoryHandle(C,{create:!0}),o=await r.getFileHandle(e,{create:!0}),i=se(o);if("function"!=typeof i)return null;const s=await i.call(o);try{return t>0&&s.getSize()!==t&&s.truncate(t),{access:s,uniformSize:0,uniformKnown:!1,maxRealLen:0,seenCount:0}}catch(e){try{s.close()}catch{}throw e}}(e,t).catch(e=>(console.error(e),null));he.set(e,r);try{const t=await r;return t&&ue.set(e,t),t}finally{he.delete(e)}}function me(e,t,a){const n=new Uint8Array(a);let r=0;for(;r<n.length;){const a=e.write(n.subarray(r),{at:t+r});if(a<=0)throw new Error("OPFS short write");r+=a}}async function pe(e){const{schemaVersion:t,roomId:a,fromPeerId:n,channelLabel:r,timestamp:o,merkleRoot:i,hash:s,filename:c,messageType:l,chunkIndex:d,mimeType:u,leafHash:h,realLen:y,totalSize:w,data:g,storage:f}=e;if(1!==t||!Number.isSafeInteger(l)||l<1||l>64||!Number.isSafeInteger(d)||d<0||!Number.isSafeInteger(y)||y<=0||y>K||!Number.isSafeInteger(w)||w<=0||w>10737418240||y>w||d>=w||g.byteLength!==y||!Number.isSafeInteger(o))throw new Error("invalid receive chunk bounds");const m=e=>{if(e&&(e.roomId!==a||e.fromPeerId!==n||e.hash!==s||e.totalSize!==w||e.messageType!==l||e.filename!==c||e.channelLabel!==r||e.timestamp!==o))throw new Error("receive chunk metadata conflicts with message")},p=e=>{const t=e.map(e=>({chunkIndex:e.chunkIndex,realLen:e.realLen??0})).sort((e,t)=>e.chunkIndex-t.chunkIndex);let a=0;for(let e=0;e<t.length;e++){const n=t[e];if(!Number.isSafeInteger(n.chunkIndex)||n.chunkIndex<0||!Number.isSafeInteger(n.realLen)||n.realLen<=0||n.realLen>K||n.realLen>w||n.chunkIndex>=w||e>0&&t[e-1].chunkIndex===n.chunkIndex)throw new Error("invalid receive chunk layout");if(a+=n.realLen,!Number.isSafeInteger(a)||a>w)throw new Error("receive chunks exceed declared total")}const n=t.find(e=>0===e.chunkIndex);let r;if(n)r=n.realLen;else if(t.length>=2){r=0;for(const e of t)r=Math.max(r,e.realLen)}if(void 0!==r){const e=Math.ceil(w/r),n=e-1,o=w-r*n;for(const a of t){if(a.chunkIndex>=e)throw new Error("receive chunk index exceeds canonical manifest");const t=a.chunkIndex===n?o:r;if(a.realLen!==t)throw new Error("receive chunk length conflicts with manifest")}const i=a===w&&t.length===e&&t.every((e,t)=>e.chunkIndex===t);if(a===w&&!i)throw new Error("receive completion has a chunk-index gap");return{savedSize:a,complete:i}}if(a===w)throw new Error("receive completion is missing chunk zero");return{savedSize:a,complete:!1}},b=await A();let k;try{const e=b.transaction(["chunks","messageData"],"readonly");k=await e.objectStore("chunks").count([i,d]);m(await e.objectStore("messageData").index("merkleRoot").get(i)),await e.done}finally{b.close()}if(k>0){const e=await A();try{const t=e.transaction(["chunks","messageData"],"readonly"),a=t.objectStore("chunks").index("merkleRoot"),n=[];let r=await a.openCursor(i);for(;r;)n.push(r.value),r=await r.continue();m(await t.objectStore("messageData").index("merkleRoot").get(i));const o=p(n);return await t.done,{stored:!1,...o}}finally{e.close()}}const S=await A();try{const e=S.transaction(["chunks","messageData"],"readonly"),t=[];let a=await e.objectStore("chunks").index("merkleRoot").openCursor(i);for(;a;)t.push(a.value),a=await a.continue();m(await e.objectStore("messageData").index("merkleRoot").get(i)),p([...t,{chunkIndex:d,realLen:y}]),await e.done}finally{S.close()}let I=!1;if("opfs"===f)try{I=await async function(e,t,a,n,r){const o=await fe(e,n);if(!o)return!1;if(o.maxRealLen=Math.max(o.maxRealLen,a),o.seenCount+=1,o.uniformKnown||(0===t?(a<n&&(o.uniformSize=a),o.uniformKnown=!0):o.seenCount>=2&&(o.uniformSize=o.maxRealLen,o.uniformKnown=!0)),!o.uniformKnown)return!1;const i=0===t?0:t*o.uniformSize;return me(o.access,i,r),o.access.flush(),!0}(i,d,y,w,g)}catch(e){console.error(e),I=!1}const x="opfs"===f&&I?{merkleRoot:i,hash:s,chunkIndex:d,mimeType:u,realLen:y,leafHash:h}:{merkleRoot:i,hash:s,chunkIndex:d,mimeType:u,realLen:y,leafHash:h,data:g},v=await A();try{const e=v.transaction(["chunks","messageData","uniqueRoom"],"readwrite"),t=e.objectStore("chunks"),u=await t.getKey([i,d]);let h=!1;const g=[];let f=await t.index("merkleRoot").openCursor(i);for(;f;)g.push(f.value),f=await f.continue();void 0===u&&(p([...g,{chunkIndex:d,realLen:y}]),await t.add(x),g.push(x),h=!0);const b=p(g);if(h){const t=e.objectStore("messageData"),d=await t.index("merkleRoot").get(i);m(d),await t.put({roomId:a,timestamp:d?.timestamp??o,merkleRoot:i,hash:s,fromPeerId:n,filename:c,messageType:l,savedSize:b.savedSize,totalSize:w,channelLabel:r});const u=e.objectStore("uniqueRoom"),h=await u.index("roomId").get(a);h&&h.lastMessageMerkleRoot!==i&&await u.put({...h,lastMessageMerkleRoot:i,messageCount:h.messageCount+1,updatedAt:o})}return await e.done,{stored:h,...b}}finally{v.close()}}async function be(e){const t=he.get(e);if(t)try{await t}catch{}const a=ue.get(e);if(a){ue.delete(e);try{a.access.flush(),a.access.close()}catch{}}}async function ke(e,t,a,n){if(e.length!==2*x)return null;await be(e);const r=ye.get(e);if(r)return r;const o=async function(e,t,a,n){try{const r=oe();if(!r||"function"!=typeof r.getDirectory)return null;const o=await r.getDirectory(),i=await o.getDirectoryHandle(C,{create:!0}),s=await i.getFileHandle(e,{create:!0}),c=await A(),l=[];let d=0;try{const t=c.transaction("chunks","readonly"),a=t.objectStore("chunks").index("merkleRoot");let n=await a.openCursor(e);for(;n;){const e=n.value;e.realLen&&e.realLen>d&&(d=e.realLen),e.data&&e.data.byteLength>0&&l.push(e),n=await n.continue()}await t.done}catch(e){return console.error(e),c.close(),null}const u=await s.getFile();if(t>0&&u.size===t&&0===l.length)return c.close(),ce(u,a,e,n);if(l.length>0&&(0===d||l.some(e=>null==e.realLen)))return c.close(),null;const h=se(s);if("function"!=typeof h)return c.close(),null;const y=await h.call(s);try{t>0&&y.getSize()!==t&&y.truncate(t);for(let e=0;e<l.length;e++){const t=l[e];me(y,0===t.chunkIndex?0:t.chunkIndex*d,t.data)}y.flush()}finally{y.close()}if(l.length>0)try{const e=c.transaction("chunks","readwrite"),t=e.objectStore("chunks");for(let e=0;e<l.length;e++){const a=l[e];await t.put({merkleRoot:a.merkleRoot,hash:a.hash,chunkIndex:a.chunkIndex,mimeType:a.mimeType,realLen:a.realLen,leafHash:a.leafHash})}await e.done}catch(e){console.error(e)}c.close();const w=await s.getFile();return t>0&&w.size!==t?null:ce(w,a,e,n)}catch(e){return console.error(e),null}}(e,t,a,n);ye.set(e,o);try{return await o}finally{ye.delete(e)}}const Se=new class{#e=new Map;#t(e,t){const a=(e=>`${String(e.roomId.length)}:${e.roomId}${String(e.peerPublicKey.length)}:${e.peerPublicKey}`)(e),n=this.#e.get(a);if(n&&e.updatedAt<n.updatedAt)throw t.fill(0),new Error("Ratchet persistence rollback detected");if(e.updatedAt===n?.updatedAt&&!te(t,n.fingerprint))throw t.fill(0),new Error("Ratchet persistence equivocation detected");!n||e.updatedAt>n.updatedAt?(n?.fingerprint.fill(0),this.#e.set(a,{updatedAt:e.updatedAt,fingerprint:t})):t.fill(0)}async acceptAuthenticated(e){const t=await ee(e);this.#t(e,t)}async rememberTrustedWrite(e){const t=await ee(e);this.#t(e,t)}forget(e,t){const a=`${String(e.length)}:${e}${String(t.length)}:${t}`;this.#e.get(a)?.fingerprint.fill(0),this.#e.delete(a)}clear(){for(const e of this.#e.values())e.fingerprint.fill(0);this.#e.clear()}},Ie=new Map,xe=new Map,Ke=(e,t)=>`${String(e.length)}:${e}${String(t.length)}:${t}`,ve=async(e,t,a)=>{const n=Ke(e,t),r=xe.get(n)??Promise.resolve();let o;const i=new Promise(e=>{o=e}),s=r.catch(()=>{}).then(()=>i);xe.set(n,s),await r.catch(()=>{});try{return await a()}finally{o(),xe.get(n)===s&&xe.delete(n)}};async function Ce(e,t){return ve(e,t,async()=>{try{const a=await A();let n;try{n=await a.get("ratchetSessions",[e,t])}finally{a.close()}if(!n)return;const r=await ae(),o=await async function(e,t,a){const n=X(e);W(n);const r=[];try{const e=Y(n.rootKey),o=await Z(t,n.rootKey,_(n,U.RootKey,e),e);r.push(o);const i=n.sendingChainKey?await Z(t,n.sendingChainKey,_(n,U.SendingChainKey,e),e):null;i&&r.push(i);const s=n.receivingChainKey?await Z(t,n.receivingChainKey,_(n,U.ReceivingChainKey,e),e):null;s&&r.push(s);const c=await Z(t,n.dhSelfSec,_(n,U.DhSelfSecret,e),e);r.push(c);const l=[];for(let a=0;a<n.skippedMessageKeys.length;a++){const o=n.skippedMessageKeys[a],i=await Z(t,o.messageKey,_(n,U.SkippedMessageKey,e,a),e);r.push(i),l.push({dhPub:o.dhPub,n:o.n,messageKey:i})}const d=n.edgeCryptoState?await Z(t,n.edgeCryptoState,_(n,U.EdgeCryptoState,e),e,null):null;return d&&r.push(d),a&&await a.acceptAuthenticated(n),{...n,rootKey:o,sendingChainKey:i,receivingChainKey:s,dhSelfSec:c,skippedMessageKeys:l,edgeCryptoState:d}}catch(e){for(const e of r)new Uint8Array(e).fill(0);throw e}finally{G(n)}}(n,r,Se),i=Ke(e,t);return Ie.set(i,Math.max(Ie.get(i)??0,o.updatedAt)),o}catch(e){return void console.error(e)}})}async function Re(e){await ve(e.roomId,e.peerPublicKey,async()=>{const t=Ke(e.roomId,e.peerPublicKey),a=Ie.get(t)??0,n=Math.max(Date.now(),e.updatedAt),r=n>a?n:a+1;if(!Number.isSafeInteger(r))throw new Error("Ratchet persistence timestamp exhausted");const o={...e,updatedAt:r};try{const e=await ae(),a=await async function(e,t){const a=X(e);if(W(a),$(a.rootKey,"ratchet rootKey",32),a.sendingChainKey&&$(a.sendingChainKey,"ratchet sendingChainKey",32),a.receivingChainKey&&$(a.receivingChainKey,"ratchet receivingChainKey",32),$(a.dhSelfSec,"ratchet dhSelfSec",32),a.skippedMessageKeys.forEach((e,t)=>$(e.messageKey,`ratchet skipped[${String(t)}].messageKey`,32)),a.edgeCryptoState&&($(a.edgeCryptoState,"ratchet edge crypto state"),a.edgeCryptoState.byteLength<1||a.edgeCryptoState.byteLength>M))throw new Error("ratchet edge crypto state length is invalid");try{const e=crypto.getRandomValues(new Uint8Array(L)),n=await J(t,a.rootKey,_(a,U.RootKey,e),e),r=a.sendingChainKey?await J(t,a.sendingChainKey,_(a,U.SendingChainKey,e),e):null,o=a.receivingChainKey?await J(t,a.receivingChainKey,_(a,U.ReceivingChainKey,e),e):null,i=await J(t,a.dhSelfSec,_(a,U.DhSelfSecret,e),e),s=[];for(let n=0;n<a.skippedMessageKeys.length;n++){const r=a.skippedMessageKeys[n];s.push({dhPub:r.dhPub,n:r.n,messageKey:await J(t,r.messageKey,_(a,U.SkippedMessageKey,e,n),e)})}const c=a.edgeCryptoState?await J(t,a.edgeCryptoState,_(a,U.EdgeCryptoState,e),e,null):null;return{...a,rootKey:n,sendingChainKey:r,receivingChainKey:o,dhSelfSec:i,skippedMessageKeys:s,edgeCryptoState:c}}finally{G(a)}}(o,e),n=await A();try{await n.put("ratchetSessions",a)}finally{n.close()}await Se.rememberTrustedWrite(a),Ie.set(t,r)}finally{(e=>{new Uint8Array(e.rootKey).fill(0),e.sendingChainKey&&new Uint8Array(e.sendingChainKey).fill(0),e.receivingChainKey&&new Uint8Array(e.receivingChainKey).fill(0),new Uint8Array(e.dhSelfSec).fill(0);for(const t of e.skippedMessageKeys)new Uint8Array(t.messageKey).fill(0);e.edgeCryptoState&&new Uint8Array(e.edgeCryptoState).fill(0)})(o)}})}const Ae=/^[0-9a-f]{64}$/,De=(e,t)=>{if("string"!=typeof e||0===e.length)throw new Error("PIN attempt room ID must not be empty");if(void 0!==t&&!Ae.test(t))throw new Error("PIN attempt peer identity must be 32-byte lowercase hexadecimal")},Pe=e=>`pinAttempts:v2:${e.length}:${e}:`,Ee=(e,t)=>`${Pe(e)}${t}`;const Le="identityX25519";const Be="identityEd25519";async function je(){try{await async function(){const e=[...he.values()];for(let t=0;t<e.length;t++)try{await e[t]}catch{}const t=[...ue.keys()];for(let e=0;e<t.length;e++)await be(t[e])}();const e=oe();if(e&&"function"==typeof e.getDirectory){const t=await e.getDirectory();await t.removeEntry(C,{recursive:!0}).catch(()=>{})}}catch{}await function(e,{blocked:t}={}){const a=indexedDB.deleteDatabase(e);return t&&a.addEventListener("blocked",e=>t(e.oldVersion,e)),d(a).then(()=>{})}(R,{blocked(){console.error("DB deletion BLOCKED")}}),Se.clear(),Ie.clear()}onmessage=async e=>{const t=e.data,{id:a,method:n}=t;try{let e;switch(n){case"getDBAddressBookEntry":e=await async function(e,t){if(!e&&!t)return;if(e&&e.length<10&&!t)return;if(t&&64!==t.length&&!e)return;const a=await A();try{const n=a.transaction("addressBook","readonly"),r=e?n.objectStore("addressBook").index("peerId"):n.objectStore("addressBook").index("peerPublicKey"),o=e?await r.get(e):await r.get(t??"");return await n.done,a.close(),o?{username:o.username,peerId:o.peerId,peerPublicKey:o.peerPublicKey}:void 0}catch{return void a.close()}}(...t.args);break;case"getAllDBAddressBookEntries":e=await async function(){try{const e=await A(),t=await e.getAll("addressBook");return e.close(),t}catch{return[]}}(...t.args);break;case"setDBAddressBookEntry":await async function(e,t,a){try{const n=await A(),r=n.transaction(["addressBook"],"readwrite"),o=r.objectStore("addressBook"),i=o.index("peerId"),s=o.index("peerPublicKey"),c=await i.get(t),l=await s.get(a);(!c&&!l||c&&!l||!c&&l)&&await o.put({username:e,peerId:t,peerPublicKey:a,dateAdded:Date.now()}),await r.done,n.close()}catch(e){console.error(e)}}(...t.args),e=void 0;break;case"deleteDBAddressBookEntry":e=await async function(e,t,a){const n=!e||0===e.length,r=!t||t.length<10,o=64!==a?.length;if(n&&r&&o)throw new Error("Cannot delete address book with no data");let i=t??"";try{const n=await A(),s=n.transaction("addressBook","readwrite"),c=s.objectStore("addressBook");if(r)if(o){const t=c.index("username"),a=await t.getKey(e??"");if(a){const n=await t.get(e??"");i=n?.peerId??"",await c.delete(a)}}else{const e=c.index("peerPublicKey"),t=await e.getKey(a);if(t){const n=await e.get(a);i=n?.peerId??"",await c.delete(t)}}else{const e=c.index("peerId"),a=await e.getKey(t);a&&await c.delete(a)}await s.done,n.close()}catch{}return i}(...t.args);break;case"getDBPeerIsBlacklisted":e=await async function(e,t){if(!e&&!t)return!1;if(e&&e.length<10&&!t)return!1;if(t&&64!==t.length&&!e)return!1;const a=await A();try{const n=a.transaction("blacklist","readonly"),r=e?n.objectStore("blacklist").index("peerId"):n.objectStore("blacklist").index("peerPublicKey"),o=e?await r.get(e):await r.get(t??"");return await n.done,!!o}finally{a.close()}}(...t.args);break;case"getAllDBBlacklisted":e=await async function(){const e=await A();try{const t=await e.getAll("blacklist");return e.close(),t}catch{return e.close(),[]}}(...t.args);break;case"setDBPeerInBlacklist":await async function(e,t){try{const a=await A(),n=a.transaction(["blacklist"],"readwrite"),r=n.objectStore("blacklist"),o=r.index("peerId"),i=r.index("peerPublicKey"),s=await o.get(e),c=await i.get(t);(!s&&!c||s&&!c||!s&&c)&&await r.put({peerId:e,peerPublicKey:t,dateAdded:Date.now()}),await n.done,a.close()}catch(e){throw console.error(e),e}}(...t.args),e=void 0;break;case"deleteDBPeerFromBlacklist":await async function(e,t){const a=!e||e.length<10;if(a&&64!==t?.length)throw new Error("Cannot delete blacklisted with no data");try{const n=await A(),r=n.transaction("blacklist","readwrite"),o=r.objectStore("blacklist");if(a){const e=o.index("peerPublicKey"),a=await e.getKey(t??"");a&&await o.delete(a)}else{const t=o.index("peerId"),a=await t.getKey(e);a&&await o.delete(a)}await r.done,n.close()}catch(e){console.error(e)}}(...t.args),e=void 0;break;case"getAllDBUniqueRooms":e=await async function(){const e=await A();try{const t=await e.getAll("uniqueRoom");return e.close(),t}catch{return e.close(),[]}}(...t.args);break;case"setDBUniqueRoom":await async function(e,t,a){if(32!==a.byteLength)throw new Error("Room policy must be the canonical 32-byte descriptor");const n=await A();try{const r=n.transaction(["uniqueRoom"],"readwrite"),o=r.objectStore("uniqueRoom"),i=o.index("roomUrl"),s=o.index("roomId"),c=await i.get(e),l=await s.get(t),d=c??l;if(d)await o.put({...d,roomId:t,roomUrl:e,roomPolicy:a,updatedAt:Date.now()});else{const n=Date.now();await o.put({roomId:t,roomUrl:e,roomPolicy:a,messageCount:0,lastMessageMerkleRoot:"",createdAt:n,updatedAt:n})}await r.done}finally{n.close()}}(...t.args),e=void 0;break;case"getDBMessageData":e=await async function(e,t){try{const a=await A(),n=a.transaction(["messageData"],"readonly"),r=n.objectStore("messageData"),o=r.index("merkleRoot"),i=r.index("hash");if(e?.length===2*x){const r=await o.get(e);if(r)return await n.done,a.close(),r;if(t?.length===2*x){const e=await i.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}if(t?.length===2*x){const e=await i.get(t);return await n.done,a.close(),e}return await n.done,void a.close()}catch(e){return void console.error(e)}}(...t.args);break;case"getDBRoomMessageData":e=await async function(e){const t=await A(),a=await t.getAllFromIndex("messageData","roomId",e);t.close();const n=a.length,r=[];for(let t=0;t<n;t++)r.push({transferId:a[t].transferId,roomId:e,merkleRoot:a[t].merkleRoot,hash:a[t].hash,fromPeerId:a[t].fromPeerId,filename:a[t].filename,messageType:a[t].messageType,savedSize:a[t].savedSize,totalSize:a[t].totalSize,channelLabel:a[t].channelLabel,timestamp:a[t].timestamp});return r}(...t.args);break;case"getDBRoomStats":e=await async function(e){const t=await A(),a=await t.getAllFromIndex("messageData","roomId",e);t.close();const n=new Set;let r=0,o=0,i=0,s=0;for(const e of a){const t=void 0!==e.transferId,a=t?e.totalSize:e.savedSize;t?(r+=a,i+=1):(o+=a,s+=1,e.fromPeerId.length>0&&n.add(e.fromPeerId))}return{messageCount:a.length,messagesSent:i,messagesReceived:s,bytesSent:r,bytesReceived:o,bytesTotal:r+o,peerIds:[...n]}}(...t.args);break;case"setDBRoomMessageData":await async function(e,t,a,n,r,o,i,s,c,l,d){try{const u=await A(),h=u.transaction(["messageData","uniqueRoom"],"readwrite"),y=h.objectStore("messageData"),w=await y.index("merkleRoot").get(t),g=w?.savedSize??0;try{await y.put({transferId:d,roomId:e,timestamp:l,merkleRoot:t,hash:a,fromPeerId:n,filename:s,messageType:i,savedSize:g+r<=o?g+r:o,totalSize:o,channelLabel:c})}catch(e){throw await h.done,u.close(),e}const f=h.objectStore("uniqueRoom"),m=await f.index("roomId").get(e);if(m&&m.lastMessageMerkleRoot!==t)try{await f.put({...m,lastMessageMerkleRoot:t,messageCount:m.messageCount+1,updatedAt:l})}catch(e){throw await h.done,u.close(),e}await h.done,u.close()}catch(e){throw console.error(e),e}}(...t.args),e=void 0;break;case"getDBChunk":e=await async function(e,t){const a=await A(),n=await a.get("chunks",[e,t]);return a.close(),n?.data}(...t.args);break;case"existsDBChunk":e=await async function(e,t){const a=await A(),n=await a.count("chunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBNewChunk":e=await async function(e,t){const a=await A();try{return await a.get("newChunks",[e,t])}finally{a.close()}}(...t.args);break;case"getDBNewChunkByReceipt":e=await async function(e,t){if(e.length!==2*x||t.length!==2*x)return;const a=await A();try{return await a.getFromIndex("newChunks","receiptScope",[e,t])}finally{a.close()}}(...t.args);break;case"existsDBNewChunk":e=await async function(e,t){const a=await A(),n=await a.count("newChunks",[e,t]);return a.close(),n>0}(...t.args);break;case"getDBSendQueue":e=await async function(e,t,a){const n=await A();if(a){const r=await n.get("sendQueue",[a,e,t]);return n.close(),r?[r]:[]}const r=n.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),o=IDBKeyRange.only([e,t]),i=await r.getAll(o);return n.close(),i}(...t.args);break;case"getDBAllChunks":e=await async function(e,t){try{const a=await A(),n=a.transaction("chunks","readonly"),r=n.objectStore("chunks"),o=r.index("hash"),i=r.index("merkleRoot");if(e?.length===2*x){const t=await i.getAll(e);return 0===t.length?(await n.done,a.close(),[]):(await n.done,a.close(),t)}if(t?.length===2*x){const e=await o.getAll(t);return await n.done,a.close(),e.length>0?e.filter(t=>t.merkleRoot===e[0].merkleRoot):e}return await n.done,a.close(),[]}catch(e){return console.error(e),[]}}(...t.args);break;case"getDBAllChunkLeafHashes":e=await async function(e){if(e.length!==2*x)return[];try{const t=await A(),a=t.transaction("chunks","readonly"),n=a.objectStore("chunks").index("merkleRoot"),r=[];let o=await n.openCursor(e);for(;o;)r.push({chunkIndex:o.value.chunkIndex,leafHash:o.value.leafHash}),o=await o.continue();return await a.done,t.close(),r}catch(e){return console.error(e),[]}}(...t.args);break;case"assembleToOPFS":e=await le(...t.args);break;case"getDBAllChunksCount":e=await async function(e,t){try{const a=await A(),n=a.transaction(["chunks"],"readonly"),r=n.objectStore("chunks"),o=r.index("hash"),i=r.index("merkleRoot");if(t?.length===2*x){const r=await o.count(t);if(0===r){if(e?.length===2*x){const t=await i.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}return await n.done,a.close(),r}if(e?.length===2*x){const t=await i.count(e);return await n.done,a.close(),t}return await n.done,a.close(),0}catch{return 0}}(...t.args);break;case"setDBChunk":await async function(e){const t=await A();try{await t.add("chunks",e)}finally{t.close()}}(...t.args),e=void 0;break;case"storeReceiveChunk":{const a=t.args[0];e=await ge(a.merkleRoot,()=>async function(e){return pe(e)}(a));break}case"getReceiveFile":{const a=t.args;e=await ge(a[0],()=>ke(...a));break}case"closeReceiveFile":await ge(t.args[0],()=>be(...t.args)),e=void 0;break;case"deleteReceiveTransfer":await ge(t.args[0],()=>async function(e){if(e.length!==2*x||!/^[0-9a-f]+$/.test(e))throw new Error("invalid receive transfer Merkle root");await be(e);const t=await A();try{const a=t.transaction(["chunks","messageData","uniqueRoom"],"readwrite"),n=a.objectStore("chunks"),r=a.objectStore("messageData"),o=a.objectStore("uniqueRoom"),i=await n.index("merkleRoot").getAllKeys(e);for(const e of i)await n.delete(e);const s=await r.index("merkleRoot").getAllKeys(e);let c="";for(const e of s){const t=await r.get(e);!c&&t&&(c=t.roomId),await r.delete(e)}if(c){const e=await o.index("roomId").get(c);if(e){const t=r.index("roomId"),a=await t.count(c),n=await t.openCursor(IDBKeyRange.only(c),"prev");await o.put({...e,messageCount:a,updatedAt:n?.value.timestamp??Date.now(),lastMessageMerkleRoot:n?.value.merkleRoot??""})}}await a.done}finally{t.close()}await de(e)}(...t.args)),e=void 0;break;case"getDBAllNewChunks":e=await async function(e){const{transferId:t,merkleRootHex:a,hashHex:n}=e,r=t?"transferId":a?"merkleRoot":n?"hash":void 0,o=t??a??n;if(!r||!o)return[];const i=await A();try{return await i.getAllFromIndex("newChunks",r,o)}finally{i.close()}}(...t.args);break;case"getDBAllNewChunksCount":e=await async function(e){const t=await A();try{return await t.countFromIndex("newChunks","transferId",e)}finally{t.close()}}(...t.args);break;case"setDBNewChunk":await async function(e){const t=await A();try{await t.put("newChunks",e)}finally{t.close()}}(...t.args),e=void 0;break;case"setDBSendQueue":await async function(e){const t=await A();await t.put("sendQueue",e),t.close()}(...t.args),e=void 0;break;case"countDBSendQueue":e=await async function(e,t){const a=await A(),n=a.transaction("sendQueue","readonly").objectStore("sendQueue").index("labelPeer"),r=IDBKeyRange.only([e,t]),o=await n.count(r);return a.close(),o}(...t.args);break;case"deleteDBChunk":await async function(e,t){try{const a=await A(),n=a.transaction("chunks","readwrite"),r=n.objectStore("chunks");if(void 0!==t){const a=IDBKeyRange.only([e,t]);await r.delete(a)}else{const t=r.index("hash"),a=await t.getAllKeys(e),n=a.length;if(0===n){const t=r.index("merkleRoot"),a=await t.getAllKeys(e),n=a.length;for(let e=0;e<n;e++)await r.delete(a[e])}else for(let e=0;e<n;e++)await r.delete(a[e])}await n.done,a.close()}catch{}}(...t.args),e=void 0;break;case"deleteDBNewChunk":await async function(e){const{transferId:t,merkleRootHex:a,hashHex:n,chunkIndex:r}=e,o=await A();try{const e=o.transaction("newChunks","readwrite"),i=e.objectStore("newChunks");if(t&&void 0!==r)await i.delete([t,r]);else if(t){const e=await i.index("transferId").getAllKeys(t);for(const t of e)await i.delete(t)}else if(a){const e=await i.index("merkleRoot").getAllKeys(a);for(const t of e)await i.delete(t)}else if(n){const e=await i.index("hash").getAllKeys(n);for(const t of e)await i.delete(t)}await e.done}catch(e){throw console.error(e),e}finally{o.close()}}(...t.args),e=void 0;break;case"deleteDBMessageData":await async function(e){try{const t=await A(),a=t.transaction(["messageData","uniqueRoom"],"readwrite"),n=a.objectStore("messageData"),r=a.objectStore("uniqueRoom"),o=n.index("merkleRoot"),i=await o.getAllKeys(e),s=i.length;let c="";for(let e=0;e<s;e++){if(0===e||0===c.length){const t=await n.get(i[e]);c=t?.roomId??""}await n.delete(i[e])}if(c.length>0){const e=r.index("roomId"),t=await e.get(c);if(t){const e=n.index("roomId"),a=await e.getAllKeys(c),o=a.length,i=o>0?await n.get(a[o-1]):void 0;await r.put({...t,messageCount:t.messageCount>0?t.messageCount-1:0,updatedAt:i?.timestamp??Date.now(),lastMessageMerkleRoot:i?.merkleRoot??""})}}await a.done,t.close(),await ge(e,async()=>{await be(e),await de(e)})}catch{}}(...t.args),e=void 0;break;case"deleteDBUniqueRoom":await async function(e){try{const t=await A(),a=t.transaction(["uniqueRoom","ratchetSessions"],"readwrite"),n=a.objectStore("uniqueRoom"),r=n.index("roomId"),o=await r.getKey(e);void 0!==o&&await n.delete(o);const i=a.objectStore("ratchetSessions"),s=await i.index("roomId").getAllKeys(e);for(const t of s)await i.delete(t),Array.isArray(t)&&"string"==typeof t[1]&&(Se.forget(e,t[1]),Ie.delete(Ke(e,t[1])));await a.done,t.close()}catch{}}(...t.args),e=void 0;break;case"deleteDBSendQueue":await async function(e,t,a){try{const n=await A();if(void 0!==a)await n.delete("sendQueue",[a,e,t]);else{const a=IDBKeyRange.only([e,t]);await n.delete("sendQueue",a)}n.close()}catch{}}(...t.args),e=void 0;break;case"getRatchetSession":e=await Ce(...t.args);break;case"setRatchetSession":await Re(...t.args),e=void 0;break;case"deleteRatchetSession":await async function(e,t){await ve(e,t,async()=>{try{const a=await A();await a.delete("ratchetSessions",[e,t]),a.close(),Se.forget(e,t),Ie.delete(Ke(e,t))}catch(e){console.error(e)}})}(...t.args),e=void 0;break;case"getPinAttemptState":e=await async function(e,t){De(e,t);const a=await A();try{return await a.get("meta",Ee(e,t))}finally{a.close()}}(...t.args);break;case"incrementPinAttemptState":e=await async function(e,t,a,n,r,o){if(De(e,t),!Number.isSafeInteger(a)||!Number.isSafeInteger(n)||!Number.isSafeInteger(r)||!Number.isSafeInteger(o)||a<0||n<1||r<1||o<r)throw new Error("Invalid PIN backoff parameters");const i=await A();try{const s=i.transaction("meta","readwrite"),c=s.objectStore("meta"),l=Ee(e,t),d=await c.get(l),u=(d?.failures??0)+1,h={failures:u,retryAfter:a+(u<n?0:Math.min(r*2**(u-n),o))};return await c.put(h,l),await s.done,h}finally{i.close()}}(...t.args);break;case"deletePinAttemptState":await async function(e,t){De(e,t);const a=await A();try{if(void 0!==t)return void await a.delete("meta",Ee(e,t));const n=a.transaction("meta","readwrite"),r=n.objectStore("meta"),o=Pe(e),i=await r.getAllKeys();await Promise.all(i.filter(e=>"string"==typeof e&&e.startsWith(o)).map(e=>r.delete(e))),await r.delete(`pinAttempts:${e}`),await n.done}finally{a.close()}}(...t.args),e=void 0;break;case"getIdentityX25519":e=await async function(){const e=await A();let t;try{t=await e.get("meta",Le)}finally{e.close()}if(!t)return;if(32!==t.pub.byteLength||64!==t.crossSig.byteLength)throw new Error("Stored X25519 identity has invalid public fields");const a=await ae(),n=await re(a,t.wrappedSecret);if(32!==n.byteLength)throw new Error("Stored X25519 identity has an invalid secret length");return{pub:t.pub,secret:n,crossSig:t.crossSig}}();break;case"setIdentityX25519":await async function(e){if(32!==e.pub.byteLength||32!==e.secret.byteLength||64!==e.crossSig.byteLength)throw new Error("X25519 identity has invalid field lengths");const t=await ae(),a=await ne(t,e.secret),n={pub:e.pub,wrappedSecret:a,crossSig:e.crossSig},r=await A();try{await r.put("meta",n,Le)}finally{r.close()}}(...t.args),e=void 0;break;case"deleteIdentityX25519":await async function(){const e=await A();try{const t=e.transaction(["meta","ratchetSessions"],"readwrite");await t.objectStore("meta").delete(Le),await t.objectStore("ratchetSessions").clear(),await t.done}finally{e.close()}Se.clear(),Ie.clear()}(),e=void 0;break;case"getIdentityEd25519":e=await async function(){const e=await A();let t;try{t=await e.get("meta",Be)}finally{e.close()}if(!t)return;if(32!==t.pub.byteLength)throw new Error("Stored Ed25519 public key has an invalid length");const a=await ae(),n=await re(a,t.wrappedSecret);if(64!==n.byteLength)throw new Error("Stored Ed25519 secret key has an invalid length");return{pub:t.pub,secret:n}}();break;case"setIdentityEd25519":await async function(e){if(32!==e.pub.byteLength||64!==e.secret.byteLength)throw new Error("Ed25519 identity has invalid key lengths");const t=await ae(),a=await ne(t,e.secret),n={pub:e.pub,wrappedSecret:a},r=await A();try{await r.put("meta",n,Be)}finally{r.close()}}(...t.args),e=void 0;break;case"deleteIdentityEd25519":await async function(){const e=await A();try{const t=e.transaction(["meta","ratchetSessions"],"readwrite");await t.objectStore("meta").delete(Be),await t.objectStore("ratchetSessions").clear(),await t.done}finally{e.close()}Se.clear(),Ie.clear()}(),e=void 0;break;case"deleteDB":await je(),e=void 0;break;default:return void postMessage({id:a,error:"Method not found"})}postMessage({id:a,result:e})}catch(e){postMessage({id:a,error:String(e)})}};
package/lib/index.d.ts CHANGED
@@ -9,7 +9,7 @@ import type { SignalingState } from "./reducers/signalingServerSlice";
9
9
  import type { MimeType, FileExtension } from "./utils/messageTypes";
10
10
  import type { WebSocketMessageRoomIdRequest, WebSocketMessageRoomIdResponse, WebSocketMessageChallengeRequest, WebSocketMessageChallengeResponse, WebSocketMessageDescriptionSend, WebSocketMessageDescriptionReceive, WebSocketMessageCandidateSend, WebSocketMessageCandidateReceive, WebSocketMessageError } from "./utils/interfaces";
11
11
  import type { RoomData } from "./api/webrtc/interfaces";
12
- import type { BlacklistedPeer, UsernamedPeer, UniqueRoom } from "./db/types";
12
+ import type { BlacklistedPeer, UsernamedPeer, UniqueRoom, RoomStats } from "./db/types";
13
13
  import type { KeyPair } from "./reducers/keyPairSlice";
14
14
  import type { RoomPolicyV1 } from "./roomPolicy";
15
15
  import type { SendMessageResult } from "./handlers/handleSendMessage";
@@ -194,6 +194,7 @@ export declare const p2party: {
194
194
  getPeerIsBlacklisted: (peerId?: string, peerPublicKey?: string) => Promise<boolean>;
195
195
  removePeerFromBlacklist: (peerId?: string, peerPublicKey?: string) => Promise<undefined>;
196
196
  getAllExistingRooms: () => Promise<UniqueRoom[]>;
197
+ getRoomStats: (roomId: string) => Promise<RoomStats>;
197
198
  sendMessage: (data: string | File, toChannel: string, roomId: string, percentageFilledChunk?: number, minChunks?: number, chunkSize?: number, metadataSchemaVersion?: number, transferId?: string) => MessageTransferHandle;
198
199
  readMessage: (merkleRootHex: string, hashHex?: string, materialize?: boolean) => Promise<{
199
200
  message: string | Blob;
@@ -346,7 +347,7 @@ declare global {
346
347
  p2party: typeof p2party;
347
348
  }
348
349
  }
349
- export type { State, Room, Peer, Channel, Message, RoomData, MimeType, FileExtension, UsernamedPeer, BlacklistedPeer, UniqueRoom, SignalingState, KeyPair, RoomPolicyV1, WebSocketMessageRoomIdRequest, WebSocketMessageRoomIdResponse, WebSocketMessageChallengeRequest, WebSocketMessageChallengeResponse, WebSocketMessageDescriptionSend, WebSocketMessageDescriptionReceive, WebSocketMessageCandidateSend, WebSocketMessageCandidateReceive, WebSocketMessageError, };
350
+ export type { State, Room, Peer, Channel, Message, RoomData, MimeType, FileExtension, UsernamedPeer, BlacklistedPeer, UniqueRoom, RoomStats, SignalingState, KeyPair, RoomPolicyV1, WebSocketMessageRoomIdRequest, WebSocketMessageRoomIdResponse, WebSocketMessageChallengeRequest, WebSocketMessageChallengeResponse, WebSocketMessageDescriptionSend, WebSocketMessageDescriptionReceive, WebSocketMessageCandidateSend, WebSocketMessageCandidateReceive, WebSocketMessageError, };
350
351
  export { createSession, restoreSession, generateSessionIdentity, setWasmSourceUrl, MessageDeliveryError, joinRoom, waitForRoom, waitForPeers, onMessage, setDebugLogging, };
351
352
  export { DEFAULT_ROOM_POLICY_V1, canonicalizeRoomPolicyV1, decodeRoomPolicyV1, encodeRoomPolicyV1, hashRoomPolicyV1, roomPoliciesEqualV1, };
352
353
  export { MIN_COVER_CADENCE_MS, MAX_COVER_CADENCE_MS, MAX_COVER_LANES, MAX_COVER_FRAMES_PER_CELL, MIN_COVER_SLOT_MS, validateRoomPolicyV1, WIRE_CHUNK_FRAME_LEN, };