@hashtree/worker 0.1.26 → 0.2.1
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 +16 -16
- package/package.json +23 -19
- package/src/app-runtime.ts +393 -0
- package/src/capabilities/blossomBandwidthTracker.ts +74 -0
- package/src/capabilities/blossomTransport.ts +179 -0
- package/src/capabilities/connectivity.ts +54 -0
- package/src/capabilities/idbStorage.ts +94 -0
- package/src/capabilities/meshRouterStore.ts +426 -0
- package/src/capabilities/rootResolver.ts +497 -0
- package/src/client-id.ts +137 -0
- package/src/client.ts +501 -0
- package/{dist/entry.js → src/entry.ts} +1 -1
- package/src/htree-path.ts +53 -0
- package/src/htree-url.ts +156 -0
- package/src/index.ts +76 -0
- package/src/mediaStreaming.ts +64 -0
- package/src/p2p/boundedQueue.ts +168 -0
- package/src/p2p/errorMessage.ts +6 -0
- package/src/p2p/index.ts +48 -0
- package/src/p2p/lruCache.ts +78 -0
- package/src/p2p/meshQueryRouter.ts +361 -0
- package/src/p2p/protocol.ts +11 -0
- package/src/p2p/queryForwardingMachine.ts +197 -0
- package/src/p2p/signaling.ts +284 -0
- package/src/p2p/uploadRateLimiter.ts +85 -0
- package/src/p2p/webrtcController.ts +1168 -0
- package/src/p2p/webrtcProxy.ts +519 -0
- package/src/privacyGuards.ts +31 -0
- package/src/protocol.ts +124 -0
- package/src/relay/identity.ts +86 -0
- package/src/relay/mediaHandler.ts +1633 -0
- package/src/relay/ndk.ts +590 -0
- package/{dist/iris/nostr-wasm.js → src/relay/nostr-wasm.ts} +4 -1
- package/src/relay/nostr.ts +249 -0
- package/src/relay/protocol.ts +361 -0
- package/src/relay/publicAssetUrl.ts +25 -0
- package/src/relay/rootPathResolver.ts +50 -0
- package/src/relay/shims.d.ts +17 -0
- package/src/relay/signing.ts +332 -0
- package/src/relay/treeRootCache.ts +354 -0
- package/src/relay/treeRootSubscription.ts +577 -0
- package/src/relay/utils/constants.ts +139 -0
- package/src/relay/utils/errorMessage.ts +7 -0
- package/src/relay/utils/lruCache.ts +79 -0
- package/src/relay/webrtc.ts +5 -0
- package/src/relay/webrtcSignaling.ts +108 -0
- package/src/relay/worker.ts +1787 -0
- package/src/relay-client.ts +265 -0
- package/src/relay-entry.ts +1 -0
- package/src/runtime-network.ts +134 -0
- package/src/runtime.ts +153 -0
- package/src/transferableBytes.ts +5 -0
- package/src/tree-root.ts +851 -0
- package/src/types.ts +8 -0
- package/src/worker.ts +975 -0
- package/LICENSE +0 -21
- package/dist/app-runtime.d.ts +0 -60
- package/dist/app-runtime.d.ts.map +0 -1
- package/dist/app-runtime.js +0 -271
- package/dist/app-runtime.js.map +0 -1
- package/dist/capabilities/blossomBandwidthTracker.d.ts +0 -26
- package/dist/capabilities/blossomBandwidthTracker.d.ts.map +0 -1
- package/dist/capabilities/blossomBandwidthTracker.js +0 -53
- package/dist/capabilities/blossomBandwidthTracker.js.map +0 -1
- package/dist/capabilities/blossomTransport.d.ts +0 -22
- package/dist/capabilities/blossomTransport.d.ts.map +0 -1
- package/dist/capabilities/blossomTransport.js +0 -144
- package/dist/capabilities/blossomTransport.js.map +0 -1
- package/dist/capabilities/connectivity.d.ts +0 -3
- package/dist/capabilities/connectivity.d.ts.map +0 -1
- package/dist/capabilities/connectivity.js +0 -49
- package/dist/capabilities/connectivity.js.map +0 -1
- package/dist/capabilities/idbStorage.d.ts +0 -25
- package/dist/capabilities/idbStorage.d.ts.map +0 -1
- package/dist/capabilities/idbStorage.js +0 -73
- package/dist/capabilities/idbStorage.js.map +0 -1
- package/dist/capabilities/meshRouterStore.d.ts +0 -71
- package/dist/capabilities/meshRouterStore.d.ts.map +0 -1
- package/dist/capabilities/meshRouterStore.js +0 -316
- package/dist/capabilities/meshRouterStore.js.map +0 -1
- package/dist/capabilities/rootResolver.d.ts +0 -10
- package/dist/capabilities/rootResolver.d.ts.map +0 -1
- package/dist/capabilities/rootResolver.js +0 -393
- package/dist/capabilities/rootResolver.js.map +0 -1
- package/dist/client-id.d.ts +0 -18
- package/dist/client-id.d.ts.map +0 -1
- package/dist/client-id.js +0 -98
- package/dist/client-id.js.map +0 -1
- package/dist/client.d.ts +0 -61
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js +0 -417
- package/dist/client.js.map +0 -1
- package/dist/entry.d.ts +0 -2
- package/dist/entry.d.ts.map +0 -1
- package/dist/entry.js.map +0 -1
- package/dist/htree-path.d.ts +0 -13
- package/dist/htree-path.d.ts.map +0 -1
- package/dist/htree-path.js +0 -38
- package/dist/htree-path.js.map +0 -1
- package/dist/htree-url.d.ts +0 -22
- package/dist/htree-url.d.ts.map +0 -1
- package/dist/htree-url.js +0 -118
- package/dist/htree-url.js.map +0 -1
- package/dist/index.d.ts +0 -17
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -8
- package/dist/index.js.map +0 -1
- package/dist/iris/identity.d.ts +0 -36
- package/dist/iris/identity.d.ts.map +0 -1
- package/dist/iris/identity.js +0 -78
- package/dist/iris/identity.js.map +0 -1
- package/dist/iris/mediaHandler.d.ts +0 -64
- package/dist/iris/mediaHandler.d.ts.map +0 -1
- package/dist/iris/mediaHandler.js +0 -1285
- package/dist/iris/mediaHandler.js.map +0 -1
- package/dist/iris/ndk.d.ts +0 -96
- package/dist/iris/ndk.d.ts.map +0 -1
- package/dist/iris/ndk.js +0 -502
- package/dist/iris/ndk.js.map +0 -1
- package/dist/iris/nostr-wasm.d.ts +0 -14
- package/dist/iris/nostr-wasm.d.ts.map +0 -1
- package/dist/iris/nostr-wasm.js.map +0 -1
- package/dist/iris/nostr.d.ts +0 -60
- package/dist/iris/nostr.d.ts.map +0 -1
- package/dist/iris/nostr.js +0 -207
- package/dist/iris/nostr.js.map +0 -1
- package/dist/iris/protocol.d.ts +0 -583
- package/dist/iris/protocol.d.ts.map +0 -1
- package/dist/iris/protocol.js +0 -16
- package/dist/iris/protocol.js.map +0 -1
- package/dist/iris/publicAssetUrl.d.ts +0 -6
- package/dist/iris/publicAssetUrl.d.ts.map +0 -1
- package/dist/iris/publicAssetUrl.js +0 -14
- package/dist/iris/publicAssetUrl.js.map +0 -1
- package/dist/iris/rootPathResolver.d.ts +0 -9
- package/dist/iris/rootPathResolver.d.ts.map +0 -1
- package/dist/iris/rootPathResolver.js +0 -32
- package/dist/iris/rootPathResolver.js.map +0 -1
- package/dist/iris/signing.d.ts +0 -50
- package/dist/iris/signing.d.ts.map +0 -1
- package/dist/iris/signing.js +0 -299
- package/dist/iris/signing.js.map +0 -1
- package/dist/iris/treeRootCache.d.ts +0 -86
- package/dist/iris/treeRootCache.d.ts.map +0 -1
- package/dist/iris/treeRootCache.js +0 -269
- package/dist/iris/treeRootCache.js.map +0 -1
- package/dist/iris/treeRootSubscription.d.ts +0 -55
- package/dist/iris/treeRootSubscription.d.ts.map +0 -1
- package/dist/iris/treeRootSubscription.js +0 -479
- package/dist/iris/treeRootSubscription.js.map +0 -1
- package/dist/iris/utils/constants.d.ts +0 -76
- package/dist/iris/utils/constants.d.ts.map +0 -1
- package/dist/iris/utils/constants.js +0 -113
- package/dist/iris/utils/constants.js.map +0 -1
- package/dist/iris/utils/errorMessage.d.ts +0 -5
- package/dist/iris/utils/errorMessage.d.ts.map +0 -1
- package/dist/iris/utils/errorMessage.js +0 -8
- package/dist/iris/utils/errorMessage.js.map +0 -1
- package/dist/iris/utils/lruCache.d.ts +0 -26
- package/dist/iris/utils/lruCache.d.ts.map +0 -1
- package/dist/iris/utils/lruCache.js +0 -66
- package/dist/iris/utils/lruCache.js.map +0 -1
- package/dist/iris/webrtc.d.ts +0 -2
- package/dist/iris/webrtc.d.ts.map +0 -1
- package/dist/iris/webrtc.js +0 -3
- package/dist/iris/webrtc.js.map +0 -1
- package/dist/iris/webrtcSignaling.d.ts +0 -37
- package/dist/iris/webrtcSignaling.d.ts.map +0 -1
- package/dist/iris/webrtcSignaling.js +0 -86
- package/dist/iris/webrtcSignaling.js.map +0 -1
- package/dist/iris/worker.d.ts +0 -12
- package/dist/iris/worker.d.ts.map +0 -1
- package/dist/iris/worker.js +0 -1529
- package/dist/iris/worker.js.map +0 -1
- package/dist/iris-client.d.ts +0 -31
- package/dist/iris-client.d.ts.map +0 -1
- package/dist/iris-client.js +0 -197
- package/dist/iris-client.js.map +0 -1
- package/dist/iris-entry.d.ts +0 -2
- package/dist/iris-entry.d.ts.map +0 -1
- package/dist/iris-entry.js +0 -2
- package/dist/iris-entry.js.map +0 -1
- package/dist/mediaStreaming.d.ts +0 -7
- package/dist/mediaStreaming.d.ts.map +0 -1
- package/dist/mediaStreaming.js +0 -48
- package/dist/mediaStreaming.js.map +0 -1
- package/dist/p2p/boundedQueue.d.ts +0 -79
- package/dist/p2p/boundedQueue.d.ts.map +0 -1
- package/dist/p2p/boundedQueue.js +0 -134
- package/dist/p2p/boundedQueue.js.map +0 -1
- package/dist/p2p/errorMessage.d.ts +0 -5
- package/dist/p2p/errorMessage.d.ts.map +0 -1
- package/dist/p2p/errorMessage.js +0 -7
- package/dist/p2p/errorMessage.js.map +0 -1
- package/dist/p2p/index.d.ts +0 -8
- package/dist/p2p/index.d.ts.map +0 -1
- package/dist/p2p/index.js +0 -6
- package/dist/p2p/index.js.map +0 -1
- package/dist/p2p/lruCache.d.ts +0 -26
- package/dist/p2p/lruCache.d.ts.map +0 -1
- package/dist/p2p/lruCache.js +0 -65
- package/dist/p2p/lruCache.js.map +0 -1
- package/dist/p2p/meshQueryRouter.d.ts +0 -44
- package/dist/p2p/meshQueryRouter.d.ts.map +0 -1
- package/dist/p2p/meshQueryRouter.js +0 -228
- package/dist/p2p/meshQueryRouter.js.map +0 -1
- package/dist/p2p/protocol.d.ts +0 -10
- package/dist/p2p/protocol.d.ts.map +0 -1
- package/dist/p2p/protocol.js +0 -2
- package/dist/p2p/protocol.js.map +0 -1
- package/dist/p2p/queryForwardingMachine.d.ts +0 -46
- package/dist/p2p/queryForwardingMachine.d.ts.map +0 -1
- package/dist/p2p/queryForwardingMachine.js +0 -144
- package/dist/p2p/queryForwardingMachine.js.map +0 -1
- package/dist/p2p/signaling.d.ts +0 -63
- package/dist/p2p/signaling.d.ts.map +0 -1
- package/dist/p2p/signaling.js +0 -185
- package/dist/p2p/signaling.js.map +0 -1
- package/dist/p2p/uploadRateLimiter.d.ts +0 -21
- package/dist/p2p/uploadRateLimiter.d.ts.map +0 -1
- package/dist/p2p/uploadRateLimiter.js +0 -62
- package/dist/p2p/uploadRateLimiter.js.map +0 -1
- package/dist/p2p/webrtcController.d.ts +0 -168
- package/dist/p2p/webrtcController.d.ts.map +0 -1
- package/dist/p2p/webrtcController.js +0 -902
- package/dist/p2p/webrtcController.js.map +0 -1
- package/dist/p2p/webrtcProxy.d.ts +0 -62
- package/dist/p2p/webrtcProxy.d.ts.map +0 -1
- package/dist/p2p/webrtcProxy.js +0 -447
- package/dist/p2p/webrtcProxy.js.map +0 -1
- package/dist/privacyGuards.d.ts +0 -14
- package/dist/privacyGuards.d.ts.map +0 -1
- package/dist/privacyGuards.js +0 -27
- package/dist/privacyGuards.js.map +0 -1
- package/dist/protocol.d.ts +0 -225
- package/dist/protocol.d.ts.map +0 -1
- package/dist/protocol.js +0 -2
- package/dist/protocol.js.map +0 -1
- package/dist/runtime-network.d.ts +0 -23
- package/dist/runtime-network.d.ts.map +0 -1
- package/dist/runtime-network.js +0 -105
- package/dist/runtime-network.js.map +0 -1
- package/dist/runtime.d.ts +0 -23
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -122
- package/dist/runtime.js.map +0 -1
- package/dist/tree-root.d.ts +0 -201
- package/dist/tree-root.d.ts.map +0 -1
- package/dist/tree-root.js +0 -632
- package/dist/tree-root.js.map +0 -1
- package/dist/types.d.ts +0 -2
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/worker.d.ts +0 -9
- package/dist/worker.d.ts.map +0 -1
- package/dist/worker.js +0 -797
- package/dist/worker.js.map +0 -1
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Tree Root Subscription Handler
|
|
4
|
+
*
|
|
5
|
+
* Worker subscribes directly to tree root events (kind 30078 with #l=hashtree).
|
|
6
|
+
* Updates local cache and notifies main thread of changes.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CID } from '@hashtree/core';
|
|
10
|
+
import { SimplePool, type Event as NostrEvent } from 'nostr-tools';
|
|
11
|
+
import { storeTreeEventSnapshot, type StoredNostrEvent } from '@hashtree/nostr';
|
|
12
|
+
import { getNdk, subscribe as ndkSubscribe, unsubscribe as ndkUnsubscribe } from './ndk';
|
|
13
|
+
import { getCachedRoot, getTreeRootCacheStore, setCachedRoot } from './treeRootCache';
|
|
14
|
+
import type { SignedEvent, TreeVisibility } from './protocol';
|
|
15
|
+
import { nip19 } from 'nostr-tools';
|
|
16
|
+
import { NDKSubscriptionCacheUsage } from 'ndk';
|
|
17
|
+
|
|
18
|
+
// Active subscriptions by pubkey
|
|
19
|
+
const activeSubscriptions = new Map<string, string>(); // pubkeyHex -> subId
|
|
20
|
+
const inFlightRootResolutions = new Map<string, Promise<Uint8Array | null>>();
|
|
21
|
+
const inFlightHistoricalRootLists = new Map<string, Promise<CID[]>>();
|
|
22
|
+
const historicalRootListCache = new Map<string, { roots: CID[]; expiresAt: number }>();
|
|
23
|
+
const MAX_HISTORICAL_TREE_ROOT_EVENTS = 20;
|
|
24
|
+
const HISTORICAL_TREE_ROOT_CACHE_TTL_MS = 30_000;
|
|
25
|
+
|
|
26
|
+
const DEFAULT_TREE_ROOT_RELAYS = [
|
|
27
|
+
'wss://relay.damus.io',
|
|
28
|
+
'wss://relay.primal.net',
|
|
29
|
+
'wss://relay.nostr.band',
|
|
30
|
+
'wss://relay.snort.social',
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
// Callback to notify main thread
|
|
34
|
+
let notifyCallback: ((npub: string, treeName: string, record: TreeRootRecord) => void) | null = null;
|
|
35
|
+
|
|
36
|
+
export interface TreeRootRecord {
|
|
37
|
+
hash: Uint8Array;
|
|
38
|
+
key?: Uint8Array;
|
|
39
|
+
visibility: TreeVisibility;
|
|
40
|
+
labels?: string[];
|
|
41
|
+
updatedAt: number;
|
|
42
|
+
snapshotNhash?: string;
|
|
43
|
+
encryptedKey?: string;
|
|
44
|
+
keyId?: string;
|
|
45
|
+
selfEncryptedKey?: string;
|
|
46
|
+
selfEncryptedLinkKey?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
interface LegacyContentPayload {
|
|
50
|
+
hash?: string;
|
|
51
|
+
key?: string;
|
|
52
|
+
visibility?: TreeVisibility;
|
|
53
|
+
encryptedKey?: string;
|
|
54
|
+
keyId?: string;
|
|
55
|
+
selfEncryptedKey?: string;
|
|
56
|
+
selfEncryptedLinkKey?: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface ParsedTreeRootEvent {
|
|
60
|
+
hash: string;
|
|
61
|
+
key?: string;
|
|
62
|
+
visibility: TreeVisibility;
|
|
63
|
+
labels?: string[];
|
|
64
|
+
encryptedKey?: string;
|
|
65
|
+
keyId?: string;
|
|
66
|
+
selfEncryptedKey?: string;
|
|
67
|
+
selfEncryptedLinkKey?: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function storeSnapshotNhash(event: SignedEvent): Promise<string | undefined> {
|
|
71
|
+
const snapshotTarget = getTreeRootCacheStore();
|
|
72
|
+
if (!snapshotTarget) {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const snapshot = await storeTreeEventSnapshot(
|
|
77
|
+
snapshotTarget,
|
|
78
|
+
nip19,
|
|
79
|
+
event as StoredNostrEvent,
|
|
80
|
+
);
|
|
81
|
+
return snapshot?.snapshotNhash;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T | null> {
|
|
85
|
+
return Promise.race([
|
|
86
|
+
promise,
|
|
87
|
+
new Promise<null>((resolve) => setTimeout(() => resolve(null), timeoutMs)),
|
|
88
|
+
]);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getHistoryRelayUrls(): string[] {
|
|
92
|
+
const urls = new Set<string>(DEFAULT_TREE_ROOT_RELAYS);
|
|
93
|
+
const ndk = getNdk();
|
|
94
|
+
const connected = typeof ndk?.pool?.connectedRelays === 'function'
|
|
95
|
+
? Array.from(ndk.pool.connectedRelays()).map((relay) => relay.url)
|
|
96
|
+
: [];
|
|
97
|
+
for (const url of connected) {
|
|
98
|
+
urls.add(url);
|
|
99
|
+
}
|
|
100
|
+
if (typeof ndk?.pool?.urls === 'function') {
|
|
101
|
+
for (const url of ndk.pool.urls()) {
|
|
102
|
+
urls.add(url);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return Array.from(urls);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function toSignedEvent(event: NostrEvent): SignedEvent {
|
|
109
|
+
return {
|
|
110
|
+
id: event.id,
|
|
111
|
+
pubkey: event.pubkey,
|
|
112
|
+
kind: event.kind,
|
|
113
|
+
content: event.content,
|
|
114
|
+
tags: event.tags,
|
|
115
|
+
created_at: event.created_at,
|
|
116
|
+
sig: event.sig,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function uniqueEvents(events: SignedEvent[]): SignedEvent[] {
|
|
121
|
+
const seen = new Set<string>();
|
|
122
|
+
const result: SignedEvent[] = [];
|
|
123
|
+
for (const event of events) {
|
|
124
|
+
const eventKey = event.id || `${event.created_at}:${event.pubkey}:${event.tags.find((tag) => tag[0] === 'd')?.[1] ?? ''}`;
|
|
125
|
+
if (seen.has(eventKey)) continue;
|
|
126
|
+
seen.add(eventKey);
|
|
127
|
+
result.push(event);
|
|
128
|
+
}
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function compareReplaceableEvents(left: SignedEvent, right: SignedEvent): number {
|
|
133
|
+
const leftCreatedAt = left.created_at ?? 0;
|
|
134
|
+
const rightCreatedAt = right.created_at ?? 0;
|
|
135
|
+
if (leftCreatedAt !== rightCreatedAt) {
|
|
136
|
+
return rightCreatedAt - leftCreatedAt;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const leftId = left.id ?? '';
|
|
140
|
+
const rightId = right.id ?? '';
|
|
141
|
+
if (leftId === rightId) {
|
|
142
|
+
return 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!leftId) return 1;
|
|
146
|
+
if (!rightId) return -1;
|
|
147
|
+
return rightId.localeCompare(leftId);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function parseLabels(event: SignedEvent): string[] | undefined {
|
|
151
|
+
const seen = new Set<string>();
|
|
152
|
+
const labels: string[] = [];
|
|
153
|
+
for (const tag of event.tags) {
|
|
154
|
+
if (tag[0] !== 'l' || !tag[1] || seen.has(tag[1])) continue;
|
|
155
|
+
seen.add(tag[1]);
|
|
156
|
+
labels.push(tag[1]);
|
|
157
|
+
}
|
|
158
|
+
return labels.length > 0 ? labels : undefined;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function parseLegacyContent(event: SignedEvent): LegacyContentPayload | null {
|
|
162
|
+
const content = event.content?.trim();
|
|
163
|
+
if (!content) return null;
|
|
164
|
+
|
|
165
|
+
try {
|
|
166
|
+
const parsed = JSON.parse(content);
|
|
167
|
+
if (parsed && typeof parsed === 'object') {
|
|
168
|
+
const payload = parsed as Record<string, unknown>;
|
|
169
|
+
return {
|
|
170
|
+
hash: typeof payload.hash === 'string' ? payload.hash : undefined,
|
|
171
|
+
key: typeof payload.key === 'string' ? payload.key : undefined,
|
|
172
|
+
visibility: typeof payload.visibility === 'string' ? payload.visibility as TreeVisibility : undefined,
|
|
173
|
+
encryptedKey: typeof payload.encryptedKey === 'string' ? payload.encryptedKey : undefined,
|
|
174
|
+
keyId: typeof payload.keyId === 'string' ? payload.keyId : undefined,
|
|
175
|
+
selfEncryptedKey: typeof payload.selfEncryptedKey === 'string' ? payload.selfEncryptedKey : undefined,
|
|
176
|
+
selfEncryptedLinkKey: typeof payload.selfEncryptedLinkKey === 'string' ? payload.selfEncryptedLinkKey : undefined,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
// Ignore JSON parse errors.
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (/^[0-9a-fA-F]{64}$/.test(content)) {
|
|
184
|
+
return { hash: content };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export function parseTreeRootEvent(event: SignedEvent): ParsedTreeRootEvent | null {
|
|
191
|
+
const hashTag = event.tags.find(t => t[0] === 'hash')?.[1];
|
|
192
|
+
const legacyContent = hashTag ? null : parseLegacyContent(event);
|
|
193
|
+
const hash = hashTag ?? legacyContent?.hash;
|
|
194
|
+
if (!hash) return null;
|
|
195
|
+
|
|
196
|
+
const keyTag = event.tags.find(t => t[0] === 'key')?.[1];
|
|
197
|
+
const encryptedKeyTag = event.tags.find(t => t[0] === 'encryptedKey')?.[1];
|
|
198
|
+
const keyIdTag = event.tags.find(t => t[0] === 'keyId')?.[1];
|
|
199
|
+
const selfEncryptedKeyTag = event.tags.find(t => t[0] === 'selfEncryptedKey')?.[1];
|
|
200
|
+
const selfEncryptedLinkKeyTag = event.tags.find(t => t[0] === 'selfEncryptedLinkKey')?.[1];
|
|
201
|
+
|
|
202
|
+
const key = keyTag ?? legacyContent?.key;
|
|
203
|
+
const encryptedKey = encryptedKeyTag ?? legacyContent?.encryptedKey;
|
|
204
|
+
const keyId = keyIdTag ?? legacyContent?.keyId;
|
|
205
|
+
const selfEncryptedKey = selfEncryptedKeyTag ?? legacyContent?.selfEncryptedKey;
|
|
206
|
+
const selfEncryptedLinkKey = selfEncryptedLinkKeyTag ?? legacyContent?.selfEncryptedLinkKey;
|
|
207
|
+
|
|
208
|
+
let visibility: TreeVisibility;
|
|
209
|
+
if (encryptedKey) {
|
|
210
|
+
visibility = 'link-visible';
|
|
211
|
+
} else if (selfEncryptedKey) {
|
|
212
|
+
visibility = 'private';
|
|
213
|
+
} else {
|
|
214
|
+
visibility = legacyContent?.visibility ?? 'public';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return {
|
|
218
|
+
hash,
|
|
219
|
+
key,
|
|
220
|
+
visibility,
|
|
221
|
+
labels: parseLabels(event),
|
|
222
|
+
encryptedKey,
|
|
223
|
+
keyId,
|
|
224
|
+
selfEncryptedKey,
|
|
225
|
+
selfEncryptedLinkKey,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function fetchTreeRootEventsFromNdk(
|
|
230
|
+
pubkeyHex: string,
|
|
231
|
+
treeName: string,
|
|
232
|
+
timeoutMs: number
|
|
233
|
+
): Promise<SignedEvent[]> {
|
|
234
|
+
const ndk = getNdk();
|
|
235
|
+
if (!ndk) return [];
|
|
236
|
+
|
|
237
|
+
try {
|
|
238
|
+
const events = await withTimeout(
|
|
239
|
+
ndk.fetchEvents({
|
|
240
|
+
kinds: [30078],
|
|
241
|
+
authors: [pubkeyHex],
|
|
242
|
+
'#d': [treeName],
|
|
243
|
+
limit: MAX_HISTORICAL_TREE_ROOT_EVENTS,
|
|
244
|
+
}, {
|
|
245
|
+
cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY,
|
|
246
|
+
}),
|
|
247
|
+
timeoutMs,
|
|
248
|
+
);
|
|
249
|
+
if (!events) return [];
|
|
250
|
+
return uniqueEvents(Array.from(events).map((event) => toSignedEvent(event.rawEvent?.() ?? event)))
|
|
251
|
+
.sort(compareReplaceableEvents);
|
|
252
|
+
} catch {
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
async function fetchTreeRootEventsFromRelays(
|
|
258
|
+
pubkeyHex: string,
|
|
259
|
+
treeName: string,
|
|
260
|
+
timeoutMs: number
|
|
261
|
+
): Promise<SignedEvent[]> {
|
|
262
|
+
const relayUrls = getHistoryRelayUrls();
|
|
263
|
+
if (relayUrls.length === 0) return [];
|
|
264
|
+
|
|
265
|
+
const pool = new SimplePool();
|
|
266
|
+
try {
|
|
267
|
+
const events = await withTimeout(
|
|
268
|
+
pool.querySync(relayUrls, {
|
|
269
|
+
kinds: [30078],
|
|
270
|
+
authors: [pubkeyHex],
|
|
271
|
+
'#d': [treeName],
|
|
272
|
+
limit: MAX_HISTORICAL_TREE_ROOT_EVENTS,
|
|
273
|
+
}, {
|
|
274
|
+
maxWait: timeoutMs,
|
|
275
|
+
}),
|
|
276
|
+
timeoutMs + 500,
|
|
277
|
+
);
|
|
278
|
+
if (!events) return [];
|
|
279
|
+
return uniqueEvents(Array.from(events).map((event) => toSignedEvent(event)))
|
|
280
|
+
.sort(compareReplaceableEvents);
|
|
281
|
+
} catch {
|
|
282
|
+
return [];
|
|
283
|
+
} finally {
|
|
284
|
+
try {
|
|
285
|
+
pool.close(relayUrls);
|
|
286
|
+
} catch {}
|
|
287
|
+
try {
|
|
288
|
+
pool.destroy();
|
|
289
|
+
} catch {}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function cidKey(cid: CID): string {
|
|
294
|
+
const hash = Array.from(cid.hash, (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
295
|
+
const key = cid.key
|
|
296
|
+
? Array.from(cid.key, (byte) => byte.toString(16).padStart(2, '0')).join('')
|
|
297
|
+
: '';
|
|
298
|
+
return `${hash}:${key}`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function dedupeRoots(roots: CID[]): CID[] {
|
|
302
|
+
const seen = new Set<string>();
|
|
303
|
+
const result: CID[] = [];
|
|
304
|
+
for (const root of roots) {
|
|
305
|
+
const key = cidKey(root);
|
|
306
|
+
if (seen.has(key)) continue;
|
|
307
|
+
seen.add(key);
|
|
308
|
+
result.push(root);
|
|
309
|
+
}
|
|
310
|
+
return result;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export async function getHistoricalTreeRoots(
|
|
314
|
+
npub: string,
|
|
315
|
+
treeName: string,
|
|
316
|
+
timeoutMs: number = 8000,
|
|
317
|
+
): Promise<CID[]> {
|
|
318
|
+
const cacheKey = `${npub}/${treeName}`;
|
|
319
|
+
const cached = historicalRootListCache.get(cacheKey);
|
|
320
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
321
|
+
return cached.roots;
|
|
322
|
+
}
|
|
323
|
+
if (cached) {
|
|
324
|
+
historicalRootListCache.delete(cacheKey);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const inFlight = inFlightHistoricalRootLists.get(cacheKey);
|
|
328
|
+
if (inFlight) {
|
|
329
|
+
return await inFlight;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const lookup = (async (): Promise<CID[]> => {
|
|
333
|
+
let pubkeyHex: string;
|
|
334
|
+
try {
|
|
335
|
+
const decoded = nip19.decode(npub);
|
|
336
|
+
if (decoded.type !== 'npub') return [];
|
|
337
|
+
pubkeyHex = decoded.data as string;
|
|
338
|
+
} catch {
|
|
339
|
+
return [];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
const [ndkEvents, relayEvents] = await Promise.all([
|
|
343
|
+
fetchTreeRootEventsFromNdk(pubkeyHex, treeName, timeoutMs),
|
|
344
|
+
fetchTreeRootEventsFromRelays(pubkeyHex, treeName, timeoutMs),
|
|
345
|
+
]);
|
|
346
|
+
|
|
347
|
+
const roots = dedupeRoots(
|
|
348
|
+
uniqueEvents([...ndkEvents, ...relayEvents])
|
|
349
|
+
.sort(compareReplaceableEvents)
|
|
350
|
+
.map((event) => {
|
|
351
|
+
const parsed = parseTreeRootEvent(event);
|
|
352
|
+
if (!parsed) return null;
|
|
353
|
+
try {
|
|
354
|
+
return {
|
|
355
|
+
hash: hexToBytes(parsed.hash),
|
|
356
|
+
key: parsed.key ? hexToBytes(parsed.key) : undefined,
|
|
357
|
+
} as CID;
|
|
358
|
+
} catch {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
.filter((root): root is CID => !!root),
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
historicalRootListCache.set(cacheKey, {
|
|
366
|
+
roots,
|
|
367
|
+
expiresAt: Date.now() + HISTORICAL_TREE_ROOT_CACHE_TTL_MS,
|
|
368
|
+
});
|
|
369
|
+
return roots;
|
|
370
|
+
})();
|
|
371
|
+
|
|
372
|
+
inFlightHistoricalRootLists.set(cacheKey, lookup);
|
|
373
|
+
try {
|
|
374
|
+
return await lookup;
|
|
375
|
+
} finally {
|
|
376
|
+
inFlightHistoricalRootLists.delete(cacheKey);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
export async function resolveTreeRootNow(
|
|
381
|
+
npub: string,
|
|
382
|
+
treeName: string,
|
|
383
|
+
timeoutMs: number = 8000,
|
|
384
|
+
): Promise<CID | null> {
|
|
385
|
+
const cached = await getCachedRoot(npub, treeName);
|
|
386
|
+
if (cached) {
|
|
387
|
+
return cached;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const cacheKey = `${npub}/${treeName}`;
|
|
391
|
+
const inFlight = inFlightRootResolutions.get(cacheKey);
|
|
392
|
+
if (inFlight) {
|
|
393
|
+
return await inFlight;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const lookup = (async (): Promise<CID | null> => {
|
|
397
|
+
let pubkeyHex: string;
|
|
398
|
+
try {
|
|
399
|
+
const decoded = nip19.decode(npub);
|
|
400
|
+
if (decoded.type !== 'npub') return null;
|
|
401
|
+
pubkeyHex = decoded.data as string;
|
|
402
|
+
} catch {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const fetched = (
|
|
407
|
+
await fetchTreeRootEventsFromNdk(pubkeyHex, treeName, timeoutMs)
|
|
408
|
+
)[0] ?? (
|
|
409
|
+
await fetchTreeRootEventsFromRelays(pubkeyHex, treeName, timeoutMs)
|
|
410
|
+
)[0];
|
|
411
|
+
if (!fetched) {
|
|
412
|
+
return null;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const parsed = parseTreeRootEvent(fetched);
|
|
416
|
+
if (!parsed) {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const hash = hexToBytes(parsed.hash);
|
|
421
|
+
const key = parsed.key ? hexToBytes(parsed.key) : undefined;
|
|
422
|
+
const { applied, record } = await setCachedRoot(npub, treeName, { hash, key }, parsed.visibility, {
|
|
423
|
+
updatedAt: fetched.created_at,
|
|
424
|
+
eventId: fetched.id,
|
|
425
|
+
labels: parsed.labels,
|
|
426
|
+
snapshotNhash: await storeSnapshotNhash(fetched),
|
|
427
|
+
encryptedKey: parsed.encryptedKey,
|
|
428
|
+
keyId: parsed.keyId,
|
|
429
|
+
selfEncryptedKey: parsed.selfEncryptedKey,
|
|
430
|
+
selfEncryptedLinkKey: parsed.selfEncryptedLinkKey,
|
|
431
|
+
});
|
|
432
|
+
historicalRootListCache.delete(cacheKey);
|
|
433
|
+
|
|
434
|
+
if (notifyCallback && applied) {
|
|
435
|
+
notifyCallback(npub, treeName, {
|
|
436
|
+
hash: record.hash,
|
|
437
|
+
key: record.key,
|
|
438
|
+
visibility: record.visibility,
|
|
439
|
+
labels: record.labels,
|
|
440
|
+
updatedAt: record.updatedAt,
|
|
441
|
+
snapshotNhash: record.snapshotNhash,
|
|
442
|
+
encryptedKey: record.encryptedKey,
|
|
443
|
+
keyId: record.keyId,
|
|
444
|
+
selfEncryptedKey: record.selfEncryptedKey,
|
|
445
|
+
selfEncryptedLinkKey: record.selfEncryptedLinkKey,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return { hash: record.hash, key: record.key };
|
|
450
|
+
})();
|
|
451
|
+
|
|
452
|
+
inFlightRootResolutions.set(cacheKey, lookup);
|
|
453
|
+
try {
|
|
454
|
+
return await lookup;
|
|
455
|
+
} finally {
|
|
456
|
+
inFlightRootResolutions.delete(cacheKey);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Set callback to notify main thread of tree root updates
|
|
462
|
+
*/
|
|
463
|
+
export function setNotifyCallback(
|
|
464
|
+
callback: (npub: string, treeName: string, record: TreeRootRecord) => void
|
|
465
|
+
): void {
|
|
466
|
+
notifyCallback = callback;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* Subscribe to tree roots for a specific pubkey
|
|
471
|
+
*/
|
|
472
|
+
export function subscribeToTreeRoots(pubkeyHex: string): () => void {
|
|
473
|
+
// Already subscribed?
|
|
474
|
+
if (activeSubscriptions.has(pubkeyHex)) {
|
|
475
|
+
return () => unsubscribeFromTreeRoots(pubkeyHex);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const subId = `tree-${pubkeyHex.slice(0, 8)}`;
|
|
479
|
+
activeSubscriptions.set(pubkeyHex, subId);
|
|
480
|
+
|
|
481
|
+
ndkSubscribe(subId, [{
|
|
482
|
+
kinds: [30078],
|
|
483
|
+
authors: [pubkeyHex],
|
|
484
|
+
}], {
|
|
485
|
+
cacheUsage: NDKSubscriptionCacheUsage.ONLY_RELAY,
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
return () => unsubscribeFromTreeRoots(pubkeyHex);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Unsubscribe from tree roots for a specific pubkey
|
|
493
|
+
*/
|
|
494
|
+
export function unsubscribeFromTreeRoots(pubkeyHex: string): void {
|
|
495
|
+
const subId = activeSubscriptions.get(pubkeyHex);
|
|
496
|
+
if (subId) {
|
|
497
|
+
ndkUnsubscribe(subId);
|
|
498
|
+
activeSubscriptions.delete(pubkeyHex);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Handle incoming tree root event (kind 30078 with #l=hashtree)
|
|
504
|
+
* Called from worker.ts event router
|
|
505
|
+
*/
|
|
506
|
+
function hasLabel(event: SignedEvent, label: string): boolean {
|
|
507
|
+
return event.tags.some(tag => tag[0] === 'l' && tag[1] === label);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
function hasAnyLabel(event: SignedEvent): boolean {
|
|
511
|
+
return event.tags.some(tag => tag[0] === 'l');
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export async function handleTreeRootEvent(event: SignedEvent): Promise<void> {
|
|
515
|
+
// Extract tree name from #d tag
|
|
516
|
+
const dTag = event.tags.find(t => t[0] === 'd');
|
|
517
|
+
if (!dTag || !dTag[1]) return;
|
|
518
|
+
const treeName = dTag[1];
|
|
519
|
+
|
|
520
|
+
// Accept unlabeled legacy events, ignore other labeled apps.
|
|
521
|
+
if (hasAnyLabel(event) && !hasLabel(event, 'hashtree')) return;
|
|
522
|
+
|
|
523
|
+
const parsed = parseTreeRootEvent(event);
|
|
524
|
+
if (!parsed) return;
|
|
525
|
+
|
|
526
|
+
// Convert pubkey to npub
|
|
527
|
+
const npub = nip19.npubEncode(event.pubkey);
|
|
528
|
+
|
|
529
|
+
// Parse hash and optional key
|
|
530
|
+
const hash = hexToBytes(parsed.hash);
|
|
531
|
+
const key = parsed.key ? hexToBytes(parsed.key) : undefined;
|
|
532
|
+
const visibility: TreeVisibility = parsed.visibility || 'public';
|
|
533
|
+
|
|
534
|
+
// Update cache
|
|
535
|
+
const { applied, record } = await setCachedRoot(npub, treeName, { hash, key }, visibility, {
|
|
536
|
+
updatedAt: event.created_at,
|
|
537
|
+
eventId: event.id,
|
|
538
|
+
labels: parsed.labels,
|
|
539
|
+
snapshotNhash: await storeSnapshotNhash(event),
|
|
540
|
+
encryptedKey: parsed.encryptedKey,
|
|
541
|
+
keyId: parsed.keyId,
|
|
542
|
+
selfEncryptedKey: parsed.selfEncryptedKey,
|
|
543
|
+
selfEncryptedLinkKey: parsed.selfEncryptedLinkKey,
|
|
544
|
+
});
|
|
545
|
+
if (!applied) return;
|
|
546
|
+
historicalRootListCache.delete(`${npub}/${treeName}`);
|
|
547
|
+
|
|
548
|
+
// Notify main thread
|
|
549
|
+
if (notifyCallback) {
|
|
550
|
+
notifyCallback(npub, treeName, record);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Check if an event is a tree root event
|
|
556
|
+
*/
|
|
557
|
+
export function isTreeRootEvent(event: SignedEvent): boolean {
|
|
558
|
+
if (event.kind !== 30078) return false;
|
|
559
|
+
if (hasLabel(event, 'hashtree')) return true;
|
|
560
|
+
return !hasAnyLabel(event);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Get all active subscription pubkeys
|
|
565
|
+
*/
|
|
566
|
+
export function getActiveSubscriptions(): string[] {
|
|
567
|
+
return Array.from(activeSubscriptions.keys());
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// Helper: hex string to Uint8Array
|
|
571
|
+
function hexToBytes(hex: string): Uint8Array {
|
|
572
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
573
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
574
|
+
bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
575
|
+
}
|
|
576
|
+
return bytes;
|
|
577
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// Nostr Event Kinds Constants
|
|
3
|
+
// Based on NIPs (Nostr Implementation Possibilities)
|
|
4
|
+
// Only includes constants that are actually used in the codebase
|
|
5
|
+
|
|
6
|
+
const TEST_BOOTSTRAP_PUBKEY = import.meta.env.VITE_TEST_BOOTSTRAP_PUBKEY as string | undefined;
|
|
7
|
+
// Default content/social graph bootstrap pubkey (sirius)
|
|
8
|
+
export const DEFAULT_BOOTSTRAP_PUBKEY =
|
|
9
|
+
import.meta.env.VITE_TEST_MODE && TEST_BOOTSTRAP_PUBKEY
|
|
10
|
+
? TEST_BOOTSTRAP_PUBKEY
|
|
11
|
+
: '4523be58d395b1b196a9b8c82b038b6895cb02b683d0c253a955068dba1facd0';
|
|
12
|
+
|
|
13
|
+
// Seed pubkeys to populate the video feed when follows are empty.
|
|
14
|
+
export const DEFAULT_VIDEO_FEED_PUBKEYS = [
|
|
15
|
+
'feb535ca427f7ab7551adfc5fcc39132b10cbc11ce5841f05588680e94f4e71a',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
// NIP-01: Basic protocol
|
|
19
|
+
export const KIND_METADATA = 0 // User profile metadata
|
|
20
|
+
export const KIND_TEXT_NOTE = 1 // Text note
|
|
21
|
+
export const KIND_CONTACTS = 3 // Contact list (follows)
|
|
22
|
+
|
|
23
|
+
// NIP-18: Reposts
|
|
24
|
+
export const KIND_REPOST = 6
|
|
25
|
+
|
|
26
|
+
// NIP-25: Reactions
|
|
27
|
+
export const KIND_REACTION = 7
|
|
28
|
+
|
|
29
|
+
// NIP-16: Event Treatment
|
|
30
|
+
export const KIND_EPHEMERAL = 20000 // Ephemeral events
|
|
31
|
+
|
|
32
|
+
// NIP-04: Encrypted Direct Messages
|
|
33
|
+
export const KIND_CHAT_MESSAGE = 14 // Encrypted direct message (double-ratchet)
|
|
34
|
+
|
|
35
|
+
// NIP-28: Public chat
|
|
36
|
+
export const KIND_CHANNEL_CREATE = 40 // Channel creation
|
|
37
|
+
export const KIND_CHANNEL_MESSAGE = 42 // Channel message
|
|
38
|
+
|
|
39
|
+
// NIP-57: Lightning zaps
|
|
40
|
+
export const KIND_ZAP_RECEIPT = 9735
|
|
41
|
+
|
|
42
|
+
// NIP-51: Lists
|
|
43
|
+
export const KIND_MUTE_LIST = 10000 // Mute list (deprecated, use 30000)
|
|
44
|
+
export const KIND_FLAG_LIST = 16463 // Flagged/reported users list
|
|
45
|
+
|
|
46
|
+
// NIP-78: App-specific data
|
|
47
|
+
export const KIND_APP_DATA = 30078
|
|
48
|
+
|
|
49
|
+
// Long-form content
|
|
50
|
+
export const KIND_LONG_FORM_CONTENT = 30023
|
|
51
|
+
|
|
52
|
+
// HTTP authentication
|
|
53
|
+
export const KIND_HTTP_AUTH = 27235
|
|
54
|
+
|
|
55
|
+
// Blossom authorization
|
|
56
|
+
export const KIND_BLOSSOM_AUTH = 24242
|
|
57
|
+
|
|
58
|
+
// Debug/development
|
|
59
|
+
export const KIND_DEBUG_DATA = 30000 // Used for encrypted debug key-value storage
|
|
60
|
+
|
|
61
|
+
// Classified listings
|
|
62
|
+
export const KIND_CLASSIFIED = 30402
|
|
63
|
+
|
|
64
|
+
// Highlights
|
|
65
|
+
export const KIND_HIGHLIGHT = 9802
|
|
66
|
+
|
|
67
|
+
// NIP-68: Picture-first feeds
|
|
68
|
+
export const KIND_PICTURE_FIRST = 20
|
|
69
|
+
|
|
70
|
+
// Additional kinds found in codebase
|
|
71
|
+
export const KIND_WALLET_CONNECT = 6927
|
|
72
|
+
|
|
73
|
+
// NIP-34: Git Repositories
|
|
74
|
+
export const KIND_REPO_ANNOUNCEMENT = 30617 // Repository announcement
|
|
75
|
+
export const KIND_REPO_STATE = 30618 // Repository state (branch/tag tracking)
|
|
76
|
+
export const KIND_PATCH = 1617 // Patch (code changes under 60kb)
|
|
77
|
+
export const KIND_PULL_REQUEST = 1618 // Pull request
|
|
78
|
+
export const KIND_PR_UPDATE = 1619 // PR update (revision)
|
|
79
|
+
export const KIND_ISSUE = 1621 // Issue (bug report, feature request)
|
|
80
|
+
// Status events (1630-1633)
|
|
81
|
+
export const KIND_STATUS_OPEN = 1630 // Open/default
|
|
82
|
+
export const KIND_STATUS_APPLIED = 1631 // Applied/Merged/Resolved
|
|
83
|
+
export const KIND_STATUS_CLOSED = 1632 // Closed
|
|
84
|
+
export const KIND_STATUS_DRAFT = 1633 // Draft
|
|
85
|
+
|
|
86
|
+
// Debug namespaces for debug pkg
|
|
87
|
+
export const DEBUG_NAMESPACES = {
|
|
88
|
+
// NDK
|
|
89
|
+
NDK_RELAY: "ndk:relay",
|
|
90
|
+
NDK_RELAY_CONN: "ndk:relay:conn",
|
|
91
|
+
NDK_RELAY_ERROR: "ndk:relay:error",
|
|
92
|
+
NDK_RELAY_WARN: "ndk:relay:warn",
|
|
93
|
+
NDK_SUBSCRIPTION: "ndk:subscription",
|
|
94
|
+
NDK_SUBSCRIPTION_ERROR: "ndk:subscription:error",
|
|
95
|
+
NDK_SUBSCRIPTION_WARN: "ndk:subscription:warn",
|
|
96
|
+
NDK_CACHE: "ndk:cache",
|
|
97
|
+
NDK_CACHE_ERROR: "ndk:cache:error",
|
|
98
|
+
NDK_CACHE_WARN: "ndk:cache:warn",
|
|
99
|
+
NDK_POOL: "ndk:pool",
|
|
100
|
+
NDK_POOL_ERROR: "ndk:pool:error",
|
|
101
|
+
NDK_POOL_WARN: "ndk:pool:warn",
|
|
102
|
+
NDK_WORKER: "ndk:worker",
|
|
103
|
+
NDK_WORKER_ERROR: "ndk:worker:error",
|
|
104
|
+
NDK_WORKER_WARN: "ndk:worker:warn",
|
|
105
|
+
NDK_TRANSPORT: "ndk:transport",
|
|
106
|
+
|
|
107
|
+
// WebRTC
|
|
108
|
+
WEBRTC_PEER: "webrtc:peer",
|
|
109
|
+
WEBRTC_PEER_LIFECYCLE: "webrtc:peer:lifecycle", // connect/disconnect/state changes
|
|
110
|
+
WEBRTC_PEER_MESSAGES: "webrtc:peer:messages", // offer/answer/ICE candidates
|
|
111
|
+
WEBRTC_PEER_DATA: "webrtc:peer:data", // data channel events
|
|
112
|
+
WEBRTC_SIGNALING: "webrtc:signaling",
|
|
113
|
+
|
|
114
|
+
// Cashu
|
|
115
|
+
CASHU_WALLET: "cashu:wallet",
|
|
116
|
+
CASHU_WALLET_ERROR: "cashu:wallet:error",
|
|
117
|
+
CASHU_WALLET_WARN: "cashu:wallet:warn",
|
|
118
|
+
CASHU_MINT: "cashu:mint",
|
|
119
|
+
CASHU_MINT_ERROR: "cashu:mint:error",
|
|
120
|
+
CASHU_MINT_WARN: "cashu:mint:warn",
|
|
121
|
+
|
|
122
|
+
// UI
|
|
123
|
+
UI_FEED: "ui:feed",
|
|
124
|
+
UI_FEED_ERROR: "ui:feed:error",
|
|
125
|
+
UI_FEED_WARN: "ui:feed:warn",
|
|
126
|
+
UI_CHAT: "ui:chat",
|
|
127
|
+
UI_CHAT_ERROR: "ui:chat:error",
|
|
128
|
+
UI_CHAT_WARN: "ui:chat:warn",
|
|
129
|
+
|
|
130
|
+
// Hooks
|
|
131
|
+
HOOKS: "hooks",
|
|
132
|
+
HOOKS_ERROR: "hooks:error",
|
|
133
|
+
HOOKS_WARN: "hooks:warn",
|
|
134
|
+
|
|
135
|
+
// Utils
|
|
136
|
+
UTILS: "utils",
|
|
137
|
+
UTILS_ERROR: "utils:error",
|
|
138
|
+
UTILS_WARN: "utils:warn",
|
|
139
|
+
} as const
|