@hashtree/nostr 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +51 -0
  2. package/dist/events.d.ts +66 -0
  3. package/dist/events.d.ts.map +1 -0
  4. package/dist/events.js +426 -0
  5. package/dist/events.js.map +1 -0
  6. package/dist/index.d.ts +4 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +6 -2
  9. package/dist/index.js.map +1 -1
  10. package/dist/resolver/nostr.d.ts +2 -0
  11. package/dist/resolver/nostr.d.ts.map +1 -1
  12. package/dist/resolver/nostr.js +122 -31
  13. package/dist/resolver/nostr.js.map +1 -1
  14. package/dist/snapshot.d.ts +30 -0
  15. package/dist/snapshot.d.ts.map +1 -0
  16. package/dist/snapshot.js +157 -0
  17. package/dist/snapshot.js.map +1 -0
  18. package/dist/treeEventSnapshots.d.ts +30 -0
  19. package/dist/treeEventSnapshots.d.ts.map +1 -0
  20. package/dist/treeEventSnapshots.js +186 -0
  21. package/dist/treeEventSnapshots.js.map +1 -0
  22. package/dist/webrtc/index.d.ts +3 -2
  23. package/dist/webrtc/index.d.ts.map +1 -1
  24. package/dist/webrtc/index.js +3 -2
  25. package/dist/webrtc/index.js.map +1 -1
  26. package/dist/webrtc/peer.d.ts +12 -1
  27. package/dist/webrtc/peer.d.ts.map +1 -1
  28. package/dist/webrtc/peer.js +39 -5
  29. package/dist/webrtc/peer.js.map +1 -1
  30. package/dist/webrtc/peerSelector.d.ts +31 -0
  31. package/dist/webrtc/peerSelector.d.ts.map +1 -0
  32. package/dist/webrtc/peerSelector.js +348 -0
  33. package/dist/webrtc/peerSelector.js.map +1 -0
  34. package/dist/webrtc/protocol.d.ts +15 -4
  35. package/dist/webrtc/protocol.d.ts.map +1 -1
  36. package/dist/webrtc/protocol.js +31 -17
  37. package/dist/webrtc/protocol.js.map +1 -1
  38. package/dist/webrtc/store.d.ts +31 -4
  39. package/dist/webrtc/store.d.ts.map +1 -1
  40. package/dist/webrtc/store.js +362 -99
  41. package/dist/webrtc/store.js.map +1 -1
  42. package/dist/webrtc/types.d.ts +66 -4
  43. package/dist/webrtc/types.d.ts.map +1 -1
  44. package/dist/webrtc/types.js +71 -9
  45. package/dist/webrtc/types.js.map +1 -1
  46. package/package.json +8 -2
@@ -0,0 +1,157 @@
1
+ import { HashTree, cid, fromHex } from '@hashtree/core';
2
+ const HEX_64 = /^[0-9a-f]{64}$/;
3
+ const HEX_128 = /^[0-9a-f]{128}$/;
4
+ const MAX_SNAPSHOT_BYTES = 256 * 1024;
5
+ const textEncoder = new TextEncoder();
6
+ const textDecoder = new TextDecoder();
7
+ function isSnapshotTreeLike(target) {
8
+ return (typeof target.putFile === 'function' &&
9
+ typeof target.readFileRange === 'function');
10
+ }
11
+ function getSnapshotTree(target) {
12
+ if (isSnapshotTreeLike(target)) {
13
+ return target;
14
+ }
15
+ return new HashTree({ store: target });
16
+ }
17
+ function assertStringTags(tags) {
18
+ if (!Array.isArray(tags)) {
19
+ throw new Error('Nostr event tags must be an array');
20
+ }
21
+ for (const tag of tags) {
22
+ if (!Array.isArray(tag) || tag.some((value) => typeof value !== 'string')) {
23
+ throw new Error('Nostr event tags must be an array of string arrays');
24
+ }
25
+ }
26
+ }
27
+ function uniqueLabels(labels) {
28
+ const seen = new Set();
29
+ const result = [];
30
+ for (const label of labels) {
31
+ if (!label || seen.has(label))
32
+ continue;
33
+ seen.add(label);
34
+ result.push(label);
35
+ }
36
+ return result;
37
+ }
38
+ export function normalizeSignedNostrEvent(event) {
39
+ const { id, pubkey, created_at, kind, tags, content, sig } = event;
40
+ if (!HEX_64.test(id)) {
41
+ throw new Error('Nostr event id must be a lowercase 64-character hex string');
42
+ }
43
+ if (!HEX_64.test(pubkey)) {
44
+ throw new Error('Nostr event pubkey must be a lowercase 64-character hex string');
45
+ }
46
+ if (!Number.isInteger(created_at) || created_at < 0) {
47
+ throw new Error('Nostr event created_at must be a non-negative integer');
48
+ }
49
+ if (!Number.isInteger(kind) || kind < 0) {
50
+ throw new Error('Nostr event kind must be a non-negative integer');
51
+ }
52
+ assertStringTags(tags);
53
+ if (typeof content !== 'string') {
54
+ throw new Error('Nostr event content must be a string');
55
+ }
56
+ if (!HEX_128.test(sig)) {
57
+ throw new Error('Nostr event sig must be a lowercase 128-character hex string');
58
+ }
59
+ return {
60
+ id,
61
+ pubkey,
62
+ created_at,
63
+ kind,
64
+ tags: tags.map((tag) => [...tag]),
65
+ content,
66
+ sig,
67
+ };
68
+ }
69
+ export function encodeSignedNostrEventJson(event) {
70
+ const normalized = normalizeSignedNostrEvent(event);
71
+ return textEncoder.encode(JSON.stringify({
72
+ id: normalized.id,
73
+ pubkey: normalized.pubkey,
74
+ created_at: normalized.created_at,
75
+ kind: normalized.kind,
76
+ tags: normalized.tags,
77
+ content: normalized.content,
78
+ sig: normalized.sig,
79
+ }));
80
+ }
81
+ export function decodeSignedNostrEventJson(data) {
82
+ const parsed = JSON.parse(textDecoder.decode(data));
83
+ return normalizeSignedNostrEvent({
84
+ id: typeof parsed.id === 'string' ? parsed.id : '',
85
+ pubkey: typeof parsed.pubkey === 'string' ? parsed.pubkey : '',
86
+ created_at: typeof parsed.created_at === 'number' ? parsed.created_at : NaN,
87
+ kind: typeof parsed.kind === 'number' ? parsed.kind : NaN,
88
+ tags: parsed.tags,
89
+ content: typeof parsed.content === 'string' ? parsed.content : '',
90
+ sig: typeof parsed.sig === 'string' ? parsed.sig : '',
91
+ });
92
+ }
93
+ export async function storeSignedNostrEventSnapshot(target, event) {
94
+ const tree = getSnapshotTree(target);
95
+ return (await tree.putFile(encodeSignedNostrEventJson(event), { unencrypted: true })).cid;
96
+ }
97
+ export async function readSignedNostrEventSnapshot(target, snapshotCid, maxBytes = MAX_SNAPSHOT_BYTES) {
98
+ const tree = getSnapshotTree(target);
99
+ const bytes = await tree.readFileRange(snapshotCid, 0, maxBytes + 1);
100
+ if (!bytes) {
101
+ throw new Error('Signed Nostr event snapshot is missing');
102
+ }
103
+ if (bytes.length > maxBytes) {
104
+ throw new Error(`Signed Nostr event snapshot exceeds ${maxBytes} bytes`);
105
+ }
106
+ return decodeSignedNostrEventJson(bytes);
107
+ }
108
+ function hasLabel(event, label) {
109
+ return event.tags.some((tag) => tag[0] === 'l' && tag[1] === label);
110
+ }
111
+ function hasAnyLabel(event) {
112
+ return event.tags.some((tag) => tag[0] === 'l');
113
+ }
114
+ export function parseHashtreeRootEvent(event) {
115
+ const normalized = normalizeSignedNostrEvent(event);
116
+ if (normalized.kind !== 30078) {
117
+ return null;
118
+ }
119
+ const treeName = normalized.tags.find((tag) => tag[0] === 'd')?.[1];
120
+ const hashHex = normalized.tags.find((tag) => tag[0] === 'hash')?.[1];
121
+ if (!treeName || !hashHex || !HEX_64.test(hashHex)) {
122
+ return null;
123
+ }
124
+ if (hasAnyLabel(normalized) && !hasLabel(normalized, 'hashtree')) {
125
+ return null;
126
+ }
127
+ const labels = uniqueLabels(normalized.tags
128
+ .filter((tag) => tag[0] === 'l' && typeof tag[1] === 'string' && tag[1].length > 0)
129
+ .map((tag) => tag[1]));
130
+ const keyHex = normalized.tags.find((tag) => tag[0] === 'key')?.[1];
131
+ const encryptedKey = normalized.tags.find((tag) => tag[0] === 'encryptedKey')?.[1];
132
+ const keyId = normalized.tags.find((tag) => tag[0] === 'keyId')?.[1];
133
+ const selfEncryptedKey = normalized.tags.find((tag) => tag[0] === 'selfEncryptedKey')?.[1];
134
+ const selfEncryptedLinkKey = normalized.tags.find((tag) => tag[0] === 'selfEncryptedLinkKey')?.[1];
135
+ const visibility = encryptedKey
136
+ ? 'link-visible'
137
+ : selfEncryptedKey
138
+ ? 'private'
139
+ : 'public';
140
+ try {
141
+ return {
142
+ event: normalized,
143
+ treeName,
144
+ rootCid: cid(fromHex(hashHex), visibility === 'public' && keyHex ? fromHex(keyHex) : undefined),
145
+ visibility,
146
+ labels,
147
+ encryptedKey,
148
+ keyId,
149
+ selfEncryptedKey,
150
+ selfEncryptedLinkKey,
151
+ };
152
+ }
153
+ catch {
154
+ return null;
155
+ }
156
+ }
157
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../src/snapshot.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type CID } from '@hashtree/core';
2
+ import type { StoredNostrEvent } from './events.js';
3
+ import type { Nip19Like, NostrFilter } from './resolver/nostr.js';
4
+ import { type ParsedHashtreeRootEvent, type SnapshotTarget } from './snapshot.js';
5
+ export interface TreeEventSnapshotInfo extends ParsedHashtreeRootEvent {
6
+ snapshotCid: CID;
7
+ snapshotNhash: string;
8
+ npub: string;
9
+ }
10
+ export interface TreeEventSnapshotQuery extends NostrFilter {
11
+ limit?: number;
12
+ }
13
+ export interface FetchLatestTreeEventSnapshotConfig {
14
+ snapshotTarget: SnapshotTarget;
15
+ nip19: Nip19Like;
16
+ fetchEvents: (filter: TreeEventSnapshotQuery) => Promise<StoredNostrEvent[]>;
17
+ snapshotFetchLimit?: number;
18
+ }
19
+ export interface WatchTreeEventSnapshotsConfig extends FetchLatestTreeEventSnapshotConfig {
20
+ subscribeEvents: (filter: TreeEventSnapshotQuery, onEvent: (event: StoredNostrEvent) => void) => () => void;
21
+ }
22
+ export declare function compareTreeEventSnapshots(a: TreeEventSnapshotInfo, b: TreeEventSnapshotInfo): number;
23
+ export declare function isNewerTreeEventSnapshot(candidate: TreeEventSnapshotInfo, current: TreeEventSnapshotInfo): boolean;
24
+ export declare function snapshotMatchesRootCid(snapshot: TreeEventSnapshotInfo | null | undefined, rootCid: CID | null | undefined): boolean;
25
+ export declare function resolveSnapshotRootCid(snapshot: TreeEventSnapshotInfo, linkKey?: string | Uint8Array | null): Promise<CID | null>;
26
+ export declare function storeTreeEventSnapshot(snapshotTarget: SnapshotTarget, nip19: Nip19Like, event: StoredNostrEvent): Promise<TreeEventSnapshotInfo | null>;
27
+ export declare function readTreeEventSnapshot(snapshotTarget: SnapshotTarget, nip19: Nip19Like, snapshotCid: CID, maxBytes?: number): Promise<TreeEventSnapshotInfo | null>;
28
+ export declare function fetchLatestTreeEventSnapshot(config: FetchLatestTreeEventSnapshotConfig, npub: string, treeName: string): Promise<TreeEventSnapshotInfo | null>;
29
+ export declare function watchLatestTreeEventSnapshot(config: WatchTreeEventSnapshotsConfig, npub: string, treeName: string, onSnapshot: (snapshot: TreeEventSnapshotInfo) => void | Promise<void>): () => void;
30
+ //# sourceMappingURL=treeEventSnapshots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeEventSnapshots.d.ts","sourceRoot":"","sources":["../src/treeEventSnapshots.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,GAAG,EACT,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAIL,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAIvB,MAAM,WAAW,qBAAsB,SAAQ,uBAAuB;IACpE,WAAW,EAAE,GAAG,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kCAAkC;IACjD,cAAc,EAAE,cAAc,CAAC;IAC/B,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC7E,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,6BAA8B,SAAQ,kCAAkC;IACvF,eAAe,EAAE,CACf,MAAM,EAAE,sBAAsB,EAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,KACvC,MAAM,IAAI,CAAC;CACjB;AAiDD,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,qBAAqB,EAAE,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAEpG;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,qBAAqB,EAChC,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAET;AAED,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,GAAG,SAAS,EAClD,OAAO,EAAE,GAAG,GAAG,IAAI,GAAG,SAAS,GAC9B,OAAO,CAgBT;AAED,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,GACnC,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAwBrB;AAED,wBAAsB,sBAAsB,CAC1C,cAAc,EAAE,cAAc,EAC9B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAOvC;AAED,wBAAsB,qBAAqB,CACzC,cAAc,EAAE,cAAc,EAC9B,KAAK,EAAE,SAAS,EAChB,WAAW,EAAE,GAAG,EAChB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAWvC;AAED,wBAAsB,4BAA4B,CAChD,MAAM,EAAE,kCAAkC,EAC1C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CA+BvC;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,6BAA6B,EACrC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GACpE,MAAM,IAAI,CA4DZ"}
@@ -0,0 +1,186 @@
1
+ import { decryptKeyFromLink, fromHex, nhashEncode, toHex, } from '@hashtree/core';
2
+ import { parseHashtreeRootEvent, readSignedNostrEventSnapshot, storeSignedNostrEventSnapshot, } from './snapshot.js';
3
+ const DEFAULT_SNAPSHOT_FETCH_LIMIT = 20;
4
+ function compareEvents(a, b) {
5
+ if (a.created_at !== b.created_at) {
6
+ return a.created_at - b.created_at;
7
+ }
8
+ return a.id.localeCompare(b.id);
9
+ }
10
+ function snapshotInfoFromParsed(parsed, snapshotCid, nip19) {
11
+ return {
12
+ ...parsed,
13
+ snapshotCid,
14
+ snapshotNhash: nhashEncode(snapshotCid),
15
+ npub: nip19.npubEncode(parsed.event.pubkey),
16
+ };
17
+ }
18
+ function tryParseHashtreeRootEvent(event) {
19
+ try {
20
+ return parseHashtreeRootEvent(event);
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ function normalizeLinkKey(linkKey) {
27
+ if (!linkKey) {
28
+ return null;
29
+ }
30
+ return typeof linkKey === 'string' ? fromHex(linkKey) : linkKey;
31
+ }
32
+ function isValidTreeEventFor(event, pubkey, treeName) {
33
+ if (event.pubkey !== pubkey) {
34
+ return false;
35
+ }
36
+ const parsed = tryParseHashtreeRootEvent(event);
37
+ return parsed?.treeName === treeName;
38
+ }
39
+ export function compareTreeEventSnapshots(a, b) {
40
+ return compareEvents(a.event, b.event);
41
+ }
42
+ export function isNewerTreeEventSnapshot(candidate, current) {
43
+ return compareTreeEventSnapshots(candidate, current) > 0;
44
+ }
45
+ export function snapshotMatchesRootCid(snapshot, rootCid) {
46
+ if (!snapshot || !rootCid) {
47
+ return false;
48
+ }
49
+ if (toHex(snapshot.rootCid.hash) !== toHex(rootCid.hash)) {
50
+ return false;
51
+ }
52
+ if (snapshot.visibility !== 'public') {
53
+ return true;
54
+ }
55
+ const snapshotKey = snapshot.rootCid.key ? toHex(snapshot.rootCid.key) : null;
56
+ const rootKey = rootCid.key ? toHex(rootCid.key) : null;
57
+ if (snapshotKey === null || rootKey === null) {
58
+ return true;
59
+ }
60
+ return snapshotKey === rootKey;
61
+ }
62
+ export async function resolveSnapshotRootCid(snapshot, linkKey) {
63
+ if (snapshot.visibility === 'public') {
64
+ return snapshot.rootCid;
65
+ }
66
+ if (snapshot.visibility === 'link-visible' && snapshot.encryptedKey) {
67
+ const normalizedLinkKey = normalizeLinkKey(linkKey);
68
+ if (!normalizedLinkKey) {
69
+ return null;
70
+ }
71
+ try {
72
+ const decryptedKey = await decryptKeyFromLink(fromHex(snapshot.encryptedKey), normalizedLinkKey);
73
+ if (decryptedKey) {
74
+ return { hash: snapshot.rootCid.hash, key: decryptedKey };
75
+ }
76
+ }
77
+ catch {
78
+ return null;
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ export async function storeTreeEventSnapshot(snapshotTarget, nip19, event) {
84
+ const parsed = tryParseHashtreeRootEvent(event);
85
+ if (!parsed) {
86
+ return null;
87
+ }
88
+ const snapshotCid = await storeSignedNostrEventSnapshot(snapshotTarget, parsed.event);
89
+ return snapshotInfoFromParsed(parsed, snapshotCid, nip19);
90
+ }
91
+ export async function readTreeEventSnapshot(snapshotTarget, nip19, snapshotCid, maxBytes) {
92
+ try {
93
+ const event = await readSignedNostrEventSnapshot(snapshotTarget, snapshotCid, maxBytes);
94
+ const parsed = tryParseHashtreeRootEvent(event);
95
+ if (!parsed) {
96
+ return null;
97
+ }
98
+ return snapshotInfoFromParsed(parsed, snapshotCid, nip19);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ export async function fetchLatestTreeEventSnapshot(config, npub, treeName) {
105
+ let decoded;
106
+ try {
107
+ decoded = config.nip19.decode(npub);
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ if (decoded.type !== 'npub' || typeof decoded.data !== 'string') {
113
+ return null;
114
+ }
115
+ const events = await config.fetchEvents({
116
+ kinds: [30078],
117
+ authors: [decoded.data],
118
+ '#d': [treeName],
119
+ limit: config.snapshotFetchLimit ?? DEFAULT_SNAPSHOT_FETCH_LIMIT,
120
+ });
121
+ const candidates = [];
122
+ for (const event of events) {
123
+ if (!isValidTreeEventFor(event, decoded.data, treeName)) {
124
+ continue;
125
+ }
126
+ candidates.push(event);
127
+ }
128
+ if (candidates.length === 0) {
129
+ return null;
130
+ }
131
+ candidates.sort(compareEvents);
132
+ return storeTreeEventSnapshot(config.snapshotTarget, config.nip19, candidates[candidates.length - 1]);
133
+ }
134
+ export function watchLatestTreeEventSnapshot(config, npub, treeName, onSnapshot) {
135
+ let decoded;
136
+ try {
137
+ decoded = config.nip19.decode(npub);
138
+ }
139
+ catch {
140
+ return () => { };
141
+ }
142
+ if (decoded.type !== 'npub' || typeof decoded.data !== 'string') {
143
+ return () => { };
144
+ }
145
+ const pubkey = decoded.data;
146
+ let closed = false;
147
+ let latestSnapshot = null;
148
+ const emitIfNewer = async (event) => {
149
+ if (closed || !isValidTreeEventFor(event, pubkey, treeName)) {
150
+ return;
151
+ }
152
+ const snapshot = await storeTreeEventSnapshot(config.snapshotTarget, config.nip19, event);
153
+ if (!snapshot) {
154
+ return;
155
+ }
156
+ if (latestSnapshot && compareTreeEventSnapshots(snapshot, latestSnapshot) <= 0) {
157
+ return;
158
+ }
159
+ latestSnapshot = snapshot;
160
+ await onSnapshot(snapshot);
161
+ };
162
+ fetchLatestTreeEventSnapshot(config, npub, treeName)
163
+ .then(async (snapshot) => {
164
+ if (closed || !snapshot) {
165
+ return;
166
+ }
167
+ if (latestSnapshot && compareTreeEventSnapshots(snapshot, latestSnapshot) <= 0) {
168
+ return;
169
+ }
170
+ latestSnapshot = snapshot;
171
+ await onSnapshot(snapshot);
172
+ })
173
+ .catch(() => { });
174
+ const unsubscribe = config.subscribeEvents({
175
+ kinds: [30078],
176
+ authors: [pubkey],
177
+ '#d': [treeName],
178
+ }, (event) => {
179
+ void emitIfNewer(event);
180
+ });
181
+ return () => {
182
+ closed = true;
183
+ unsubscribe();
184
+ };
185
+ }
186
+ //# sourceMappingURL=treeEventSnapshots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"treeEventSnapshots.js","sourceRoot":"","sources":["../src/treeEventSnapshots.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  export { WebRTCStore, DEFAULT_RELAYS } from './store.js';
2
2
  export { Peer } from './peer.js';
3
- export { PeerId, generateUuid, MAX_HTL, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, type SignalingMessage, type WebRTCStoreConfig, type PeerStatus, type WebRTCStoreEvent, type WebRTCStoreEventHandler, type EventSigner, type EventEncrypter, type EventDecrypter, type GiftWrapper, type GiftUnwrapper, type SignedEvent, type PeerPool, type PeerClassifier, type PoolConfig, type WebRTCStats, type BandwidthSample, type DataRequest, type DataResponse, } from './types.js';
4
- export { encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, hashToKey, verifyHash, generatePeerHTLConfig, decrementHTL, shouldForward, type PeerHTLConfig, type PendingRequest, } from './protocol.js';
3
+ export { PeerSelector, peerPrincipal, normalizeDispatchConfig, buildHedgedWavePlan, syncSelectorPeers, } from './peerSelector.js';
4
+ export { PeerId, generateUuid, WEBRTC_KIND, MAX_HTL, HtlMode, type HtlPolicy, BLOB_REQUEST_POLICY, MESH_EVENT_POLICY, MESH_PROTOCOL, MESH_PROTOCOL_VERSION, MESH_DEFAULT_HTL, MESH_MAX_HTL, PEER_METADATA_SNAPSHOT_VERSION, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, createMeshNostrEventFrame, validateMeshNostrFrame, parseMeshNostrFrameText, type SignalingMessage, type MeshNostrFrame, type MeshNostrPayload, type WebRTCStoreConfig, type PeerStatus, type WebRTCStoreEvent, type WebRTCStoreEventHandler, type EventSigner, type EventEncrypter, type EventDecrypter, type GiftWrapper, type GiftUnwrapper, type SignedEvent, type PeerPool, type PeerClassifier, type PoolConfig, type SelectionStrategy, type RequestDispatchConfig, type PersistedPeerMetadata, type PeerMetadataSnapshot, type MeshStats, type WebRTCStats, type BandwidthSample, type DataRequest, type DataResponse, } from './types.js';
5
+ export { encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, hashToKey, verifyHash, generatePeerHTLConfig, decrementHTLWithPolicy, decrementHTL, shouldForwardHTL, shouldForward, type PeerHTLConfig, type PendingRequest, } from './protocol.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,MAAM,EACN,YAAY,EACZ,WAAW,EACX,OAAO,EACP,OAAO,EACP,KAAK,SAAS,EACd,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,8BAA8B,EAC9B,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,QAAQ,EACb,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC"}
@@ -1,6 +1,7 @@
1
1
  export { WebRTCStore, DEFAULT_RELAYS } from './store.js';
2
2
  export { Peer } from './peer.js';
3
- export { PeerId, generateUuid, MAX_HTL, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, } from './types.js';
3
+ export { PeerSelector, peerPrincipal, normalizeDispatchConfig, buildHedgedWavePlan, syncSelectorPeers, } from './peerSelector.js';
4
+ export { PeerId, generateUuid, WEBRTC_KIND, MAX_HTL, HtlMode, BLOB_REQUEST_POLICY, MESH_EVENT_POLICY, MESH_PROTOCOL, MESH_PROTOCOL_VERSION, MESH_DEFAULT_HTL, MESH_MAX_HTL, PEER_METADATA_SNAPSHOT_VERSION, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, createMeshNostrEventFrame, validateMeshNostrFrame, parseMeshNostrFrameText, } from './types.js';
4
5
  // Protocol functions
5
- export { encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, hashToKey, verifyHash, generatePeerHTLConfig, decrementHTL, shouldForward, } from './protocol.js';
6
+ export { encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, hashToKey, verifyHash, generatePeerHTLConfig, decrementHTLWithPolicy, decrementHTL, shouldForwardHTL, shouldForward, } from './protocol.js';
6
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,MAAM,EACN,YAAY,EACZ,OAAO,EACP,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,GAmBd,MAAM,YAAY,CAAC;AAEpB,qBAAqB;AACrB,OAAO,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,qBAAqB,EACrB,YAAY,EACZ,aAAa,GAGd,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/webrtc/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EACL,YAAY,EACZ,aAAa,EACb,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,MAAM,EACN,YAAY,EACZ,WAAW,EACX,OAAO,EACP,OAAO,EAEP,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,gBAAgB,EAChB,YAAY,EACZ,8BAA8B,EAC9B,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,GA0BxB,MAAM,YAAY,CAAC;AAEpB,qBAAqB;AACrB,OAAO,EACL,aAAa,EACb,cAAc,EACd,YAAY,EACZ,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,SAAS,EACT,UAAU,EACV,qBAAqB,EACrB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,aAAa,GAGd,MAAM,eAAe,CAAC"}
@@ -2,7 +2,8 @@
2
2
  * WebRTC peer connection for hashtree data exchange
3
3
  */
4
4
  import type { Store, Hash } from '@hashtree/core';
5
- import type { SignalingMessage, PeerId } from './types.js';
5
+ import type { SignalingMessage, PeerId, MeshNostrFrame } from './types.js';
6
+ import { PeerHTLConfig } from './protocol.js';
6
7
  export declare class Peer {
7
8
  readonly peerId: string;
8
9
  readonly pubkey: string;
@@ -26,6 +27,7 @@ export declare class Peer {
26
27
  private candidateBatchTimeout;
27
28
  private queuedRemoteCandidates;
28
29
  private onForwardRequest?;
30
+ private onMeshFrame?;
29
31
  private stats;
30
32
  private pendingReassemblies;
31
33
  private reassemblyCleanupInterval?;
@@ -41,6 +43,7 @@ export declare class Peer {
41
43
  onClose: () => void;
42
44
  onConnected?: () => void;
43
45
  onForwardRequest?: (hash: Uint8Array, excludePeerId: string, htl: number) => Promise<Uint8Array | null>;
46
+ onMeshFrame?: (fromPeerId: string, frame: MeshNostrFrame) => Promise<void> | void;
44
47
  requestTimeout?: number;
45
48
  debug?: boolean;
46
49
  });
@@ -89,6 +92,14 @@ export declare class Peer {
89
92
  bytesReceived: number;
90
93
  bytesForwarded: number;
91
94
  };
95
+ /**
96
+ * Get per-peer HTL config used for probabilistic decrements.
97
+ */
98
+ getHTLConfig(): PeerHTLConfig;
99
+ /**
100
+ * Send a relayless mesh signaling frame over text channel.
101
+ */
102
+ sendMeshFrameText(frame: MeshNostrFrame): boolean;
92
103
  /**
93
104
  * Send data to this peer for a hash they previously requested
94
105
  * Returns true if this peer had requested this hash
@@ -1 +1 @@
1
- {"version":3,"file":"peer.d.ts","sourceRoot":"","sources":["../../src/webrtc/peer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EACV,gBAAgB,EAGhB,MAAM,EAEP,MAAM,YAAY,CAAC;AAgDpB,qBAAa,IAAI;IACf,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;IAE3C,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,WAAW,CAA+B;IAClD,OAAO,CAAC,UAAU,CAAe;IACjC,OAAO,CAAC,aAAa,CAA2C;IAChE,OAAO,CAAC,OAAO,CAAa;IAC5B,OAAO,CAAC,WAAW,CAAC,CAAa;IACjC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,KAAK,CAAU;IAGvB,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,QAAQ,CAAU;IAC1B,OAAO,CAAC,QAAQ,CAAS;IAGzB,OAAO,CAAC,WAAW,CAAqC;IAGxD,OAAO,CAAC,aAAa,CAA2D;IAEhF,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,qBAAqB,CAA8C;IAC3E,OAAO,CAAC,sBAAsB,CAA6B;IAI3D,OAAO,CAAC,gBAAgB,CAAC,CAAuF;IAGhH,OAAO,CAAC,KAAK,CAaX;IAGF,OAAO,CAAC,mBAAmB,CAAwC;IACnE,OAAO,CAAC,yBAAyB,CAAC,CAAiC;IAGnE,OAAO,CAAC,SAAS,CAAgB;IAEjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;gBAET,OAAO,EAAE;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,SAAS,GAAG,UAAU,CAAC;QAClC,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC;QACzB,aAAa,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QACxD,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;QACzB,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;QACxG,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB;IA6BD,OAAO,CAAC,GAAG;IAMX,IAAI,KAAK,IAAI,sBAAsB,CAElC;IAED,IAAI,WAAW,IAAI,OAAO,CAGzB;IAED,IAAI,yBAAyB,IAAI,MAAM,CAEtC;IAED,OAAO,CAAC,sBAAsB;IA0B9B,OAAO,CAAC,mBAAmB;IAgC3B,OAAO,CAAC,gBAAgB;YAyBV,aAAa;YA0Db,aAAa;IA6C3B,OAAO,CAAC,YAAY;IA4BpB;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAiD9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IA0BhC;;;OAGG;IACG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,GAAE,MAAgB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAsC5E;;OAEG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,aAAa,EAAE,MAAM,CAAC;QACtB,aAAa,EAAE,MAAM,CAAC;QACtB,iBAAiB,EAAE,MAAM,CAAC;QAC1B,gBAAgB,EAAE,MAAM,CAAC;QACzB,qBAAqB,EAAE,MAAM,CAAC;QAC9B,SAAS,EAAE,MAAM,CAAC;QAClB,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;KACxB;IAID;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO;IAiBrD;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO;IAIvC;;OAEG;IACH,oBAAoB,IAAI,MAAM;IAI9B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAwB9B;;;OAGG;IACG,eAAe,CAAC,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;YA2D7C,kBAAkB;YAclB,uBAAuB;IAarC;;OAEG;IACH,KAAK,IAAI,IAAI;CA8Bd"}
1
+ {"version":3,"file":"peer.d.ts","sourceRoot":"","sources":["../../src/webrtc/peer.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { MAX_HTL, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, FRAGMENT_STALL_TIMEOUT, FRAGMENT_TOTAL_TIMEOUT, MAX_PENDING_REASSEMBLIES, } from './types.js';
1
+ import { BLOB_REQUEST_POLICY, MSG_TYPE_REQUEST, MSG_TYPE_RESPONSE, FRAGMENT_SIZE, FRAGMENT_STALL_TIMEOUT, FRAGMENT_TOTAL_TIMEOUT, MAX_PENDING_REASSEMBLIES, parseMeshNostrFrameText, } from './types.js';
2
2
  import { LRUCache } from './lruCache.js';
3
3
  import { encodeRequest, encodeResponse, parseMessage, createRequest, createResponse, createFragmentResponse, isFragmented, clearPendingRequests, generatePeerHTLConfig, decrementHTL, shouldForward, hashToKey, verifyHash, } from './protocol.js';
4
4
  const ICE_SERVERS = [
@@ -39,6 +39,8 @@ export class Peer {
39
39
  // Callback to forward request to other peers when we don't have data locally
40
40
  // htl parameter is the decremented HTL to use when forwarding
41
41
  onForwardRequest;
42
+ // Callback for relayless mesh signaling frames received over data channel text.
43
+ onMeshFrame;
42
44
  // Per-peer stats tracking
43
45
  stats = {
44
46
  requestsSent: 0,
@@ -70,6 +72,7 @@ export class Peer {
70
72
  this.onClose = options.onClose;
71
73
  this.onConnected = options.onConnected;
72
74
  this.onForwardRequest = options.onForwardRequest;
75
+ this.onMeshFrame = options.onMeshFrame;
73
76
  this.requestTimeout = options.requestTimeout ?? 500;
74
77
  this.debug = options.debug ?? false;
75
78
  this.createdAt = Date.now();
@@ -77,7 +80,7 @@ export class Peer {
77
80
  this.htlConfig = generatePeerHTLConfig();
78
81
  // Perfect negotiation: polite peer (smaller ID) rolls back on collision
79
82
  this.myPeerId = options.myPeerId;
80
- this.isPolite = options.myPeerId < options.peerId.uuid;
83
+ this.isPolite = options.myPeerId < options.peerId.toString();
81
84
  // Start fragment reassembly cleanup interval
82
85
  this.reassemblyCleanupInterval = setInterval(() => this.cleanupStaleReassemblies(), 5000);
83
86
  this.pc = new RTCPeerConnection({ iceServers: ICE_SERVERS });
@@ -165,9 +168,19 @@ export class Peer {
165
168
  this.close();
166
169
  };
167
170
  channel.onmessage = async (event) => {
168
- // All messages are binary with type prefix
171
+ if (typeof event.data === 'string') {
172
+ const frame = parseMeshNostrFrameText(event.data);
173
+ if (frame && this.onMeshFrame) {
174
+ await this.onMeshFrame(this.peerId, frame);
175
+ }
176
+ return;
177
+ }
169
178
  if (event.data instanceof ArrayBuffer) {
170
179
  await this.handleMessage(event.data);
180
+ return;
181
+ }
182
+ if (typeof Blob !== 'undefined' && event.data instanceof Blob) {
183
+ await this.handleMessage(await event.data.arrayBuffer());
171
184
  }
172
185
  };
173
186
  }
@@ -227,7 +240,7 @@ export class Peer {
227
240
  }
228
241
  }
229
242
  async handleRequest(req) {
230
- const htl = req.htl ?? MAX_HTL;
243
+ const htl = req.htl ?? BLOB_REQUEST_POLICY.maxHtl;
231
244
  const hash = req.h;
232
245
  const hashKey = hashToKey(hash);
233
246
  this.stats.requestsReceived++;
@@ -376,7 +389,7 @@ export class Peer {
376
389
  * Request data by hash from this peer
377
390
  * @param htl Hops To Live - decremented before sending
378
391
  */
379
- async request(hash, htl = MAX_HTL) {
392
+ async request(hash, htl = BLOB_REQUEST_POLICY.maxHtl) {
380
393
  if (!this.dataChannel || this.dataChannel.readyState !== 'open') {
381
394
  return null;
382
395
  }
@@ -412,6 +425,27 @@ export class Peer {
412
425
  getStats() {
413
426
  return { ...this.stats };
414
427
  }
428
+ /**
429
+ * Get per-peer HTL config used for probabilistic decrements.
430
+ */
431
+ getHTLConfig() {
432
+ return this.htlConfig;
433
+ }
434
+ /**
435
+ * Send a relayless mesh signaling frame over text channel.
436
+ */
437
+ sendMeshFrameText(frame) {
438
+ if (!this.dataChannel || this.dataChannel.readyState !== 'open') {
439
+ return false;
440
+ }
441
+ try {
442
+ this.dataChannel.send(JSON.stringify(frame));
443
+ return true;
444
+ }
445
+ catch {
446
+ return false;
447
+ }
448
+ }
415
449
  /**
416
450
  * Send data to this peer for a hash they previously requested
417
451
  * Returns true if this peer had requested this hash