@candypoets/nipworker 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +341 -0
  3. package/dist/hooks.d.ts +6 -0
  4. package/dist/hooks.d.ts.map +1 -0
  5. package/dist/hooks.js +33 -0
  6. package/dist/hooks.js.map +1 -0
  7. package/dist/index.d.ts +81 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +13 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/index2.js +8 -0
  12. package/dist/index2.js.map +1 -0
  13. package/dist/index3.js +270 -0
  14. package/dist/index3.js.map +1 -0
  15. package/dist/lib/sharedBuffer.d.ts +50 -0
  16. package/dist/lib/sharedBuffer.d.ts.map +1 -0
  17. package/dist/nostr_worker.js +1001 -0
  18. package/dist/nostr_worker.js.map +1 -0
  19. package/dist/types/index.d.ts +53 -0
  20. package/dist/types/index.d.ts.map +1 -0
  21. package/dist/types/kind0.d.ts +24 -0
  22. package/dist/types/kind0.d.ts.map +1 -0
  23. package/dist/types/kind1.d.ts +17 -0
  24. package/dist/types/kind1.d.ts.map +1 -0
  25. package/dist/types/kind10002.d.ts +7 -0
  26. package/dist/types/kind10002.d.ts.map +1 -0
  27. package/dist/types/kind10019.d.ts +9 -0
  28. package/dist/types/kind10019.d.ts.map +1 -0
  29. package/dist/types/kind17.d.ts +4 -0
  30. package/dist/types/kind17.d.ts.map +1 -0
  31. package/dist/types/kind17375.d.ts +7 -0
  32. package/dist/types/kind17375.d.ts.map +1 -0
  33. package/dist/types/kind3.d.ts +7 -0
  34. package/dist/types/kind3.d.ts.map +1 -0
  35. package/dist/types/kind39089.d.ts +11 -0
  36. package/dist/types/kind39089.d.ts.map +1 -0
  37. package/dist/types/kind4.d.ts +9 -0
  38. package/dist/types/kind4.d.ts.map +1 -0
  39. package/dist/types/kind6.d.ts +6 -0
  40. package/dist/types/kind6.d.ts.map +1 -0
  41. package/dist/types/kind7.d.ts +18 -0
  42. package/dist/types/kind7.d.ts.map +1 -0
  43. package/dist/types/kind7374.d.ts +6 -0
  44. package/dist/types/kind7374.d.ts.map +1 -0
  45. package/dist/types/kind7375.d.ts +9 -0
  46. package/dist/types/kind7375.d.ts.map +1 -0
  47. package/dist/types/kind7376.d.ts +16 -0
  48. package/dist/types/kind7376.d.ts.map +1 -0
  49. package/dist/types/kind9321.d.ts +11 -0
  50. package/dist/types/kind9321.d.ts.map +1 -0
  51. package/dist/types/kind9735.d.ts +15 -0
  52. package/dist/types/kind9735.d.ts.map +1 -0
  53. package/dist/types/proofs.d.ts +21 -0
  54. package/dist/types/proofs.d.ts.map +1 -0
  55. package/dist/utils.d.ts +23 -0
  56. package/dist/utils.d.ts.map +1 -0
  57. package/dist/utils.js +56 -0
  58. package/dist/utils.js.map +1 -0
  59. package/dist/wasm/main/nostr_main.d.ts +74 -0
  60. package/dist/wasm/main/nostr_main_bg.wasm.d.ts +20 -0
  61. package/dist/wasm/worker/nostr_worker.d.ts +45 -0
  62. package/dist/wasm/worker/nostr_worker_bg.wasm.d.ts +41 -0
  63. package/dist/worker.d.ts +3 -0
  64. package/dist/worker.d.ts.map +1 -0
  65. package/dist/worker.js +13 -0
  66. package/dist/worker.js.map +1 -0
  67. package/package.json +71 -0
package/dist/index3.js ADDED
@@ -0,0 +1,270 @@
1
+ import { unpack as b } from "msgpackr";
2
+ import { decode as S, encode as h } from "@msgpack/msgpack";
3
+ import "./index2.js";
4
+ class w {
5
+ /**
6
+ * Read new messages from SharedArrayBuffer since last read position
7
+ * @param buffer The SharedArrayBuffer to read from
8
+ * @param lastReadPosition Last position read (default: 0, meaning read from beginning)
9
+ * @returns Object containing new messages and updated read position
10
+ */
11
+ static readMessages(e, t = 0) {
12
+ const s = new DataView(e), r = new Uint8Array(e), i = s.getUint32(0, !0), c = Math.max(t, 4);
13
+ if (i <= c)
14
+ return {
15
+ messages: [],
16
+ newReadPosition: c,
17
+ hasNewData: !1
18
+ };
19
+ const u = [];
20
+ let o = c;
21
+ try {
22
+ for (; o < i && !(o + 4 > i); ) {
23
+ const l = s.getUint32(o, !0);
24
+ if (o += 4, o + l > i) break;
25
+ const g = r.slice(o, o + l), a = b(g);
26
+ u.push(a), o += l;
27
+ }
28
+ return {
29
+ messages: u,
30
+ newReadPosition: o,
31
+ hasNewData: u.length > 0
32
+ };
33
+ } catch (l) {
34
+ return console.error(
35
+ "Failed to decode length-prefixed msgpack data from SharedArrayBuffer:",
36
+ l
37
+ ), {
38
+ messages: u,
39
+ newReadPosition: c,
40
+ hasNewData: !1
41
+ };
42
+ }
43
+ }
44
+ /**
45
+ * Read all messages from SharedArrayBuffer from the beginning (ignores lastReadPosition)
46
+ * @param buffer The SharedArrayBuffer to read from
47
+ * @returns Object containing all messages in the buffer
48
+ */
49
+ static readAllMessages(e) {
50
+ const t = this.readMessages(e, 0);
51
+ return {
52
+ messages: t.messages,
53
+ totalMessages: t.messages.length
54
+ };
55
+ }
56
+ /**
57
+ * Get current write position from buffer header
58
+ * @param buffer The SharedArrayBuffer to read from
59
+ * @returns Current write position
60
+ */
61
+ static getCurrentWritePosition(e) {
62
+ return new DataView(e).getUint32(0, !0);
63
+ }
64
+ /**
65
+ * Check if buffer has new data since last read
66
+ * @param buffer The SharedArrayBuffer to check
67
+ * @param lastReadPosition Last position read
68
+ * @returns True if there's new data to read
69
+ */
70
+ static hasNewData(e, t) {
71
+ const s = this.getCurrentWritePosition(e), i = Math.max(t, 4);
72
+ return s > i;
73
+ }
74
+ /**
75
+ * Calculate recommended buffer size based on request limits
76
+ * @param totalEventLimit Total expected events across all requests
77
+ * @param bytesPerEvent Estimated bytes per event (default: 2048)
78
+ * @returns Recommended buffer size in bytes
79
+ */
80
+ static calculateBufferSize(e = 100, t = 3072) {
81
+ const r = e * t, i = Math.floor(r * 0.25);
82
+ return 4 + r + i;
83
+ }
84
+ }
85
+ function U(n) {
86
+ return n.kind === 39089;
87
+ }
88
+ var k = /* @__PURE__ */ ((n) => (n.LIKE = "+", n.DISLIKE = "-", n.EMOJI = "emoji", n.CUSTOM = "custom", n))(k || {}), m = /* @__PURE__ */ ((n) => (n.StatusPending = "pending", n.StatusSent = "sent", n.StatusSuccess = "success", n.StatusFailed = "failed", n.StatusRejected = "rejected", n.StatusConnError = "connection_error", n))(m || {});
89
+ class f {
90
+ constructor(e = {}) {
91
+ this.subscriptions = /* @__PURE__ */ new Map(), this.publishes = /* @__PURE__ */ new Map(), this.signers = /* @__PURE__ */ new Map(), this.PERPETUAL_SUBSCRIPTIONS = ["notifications", "starterpack"], this.worker = this.createWorker(e), this.setupWorkerListener();
92
+ }
93
+ createWorker(e) {
94
+ const t = new URL("./worker.js", import.meta.url);
95
+ return console.log(import.meta.url, t), new Worker(t);
96
+ }
97
+ setupWorkerListener() {
98
+ this.worker.onmessage = async (e) => {
99
+ if (e.data instanceof Uint8Array) {
100
+ let t = e.data;
101
+ try {
102
+ const s = S(t);
103
+ this.handleWorkerMessage(s);
104
+ } catch (s) {
105
+ console.error("Failed to decode worker message:", s);
106
+ } finally {
107
+ t && (t.fill(0), t = null);
108
+ }
109
+ } else
110
+ console.log("Received non-arrayBuffer message:", e.data);
111
+ }, this.worker.onerror = (e) => {
112
+ console.error("Worker error:", e);
113
+ };
114
+ }
115
+ handleWorkerMessage(e) {
116
+ "PublishStatus" in e ? this.handlePublishStatus(
117
+ e.PublishStatus.publish_id,
118
+ e.PublishStatus.status
119
+ ) : "Count" in e || ("SignedEvent" in e ? this.handleSignedEvent(
120
+ e.SignedEvent.content,
121
+ e.SignedEvent.signed_event
122
+ ) : "PublicKey" in e ? this.handlePublicKey(e.PublicKey.public_key) : "Debug" in e ? console.debug("Worker debug:", e.Debug.message, e.Debug.data) : console.warn("Unknown message type from worker:", e));
123
+ }
124
+ handlePublishStatus(e, t) {
125
+ const s = this.publishes.get(e);
126
+ if (t[0]) {
127
+ if (!s) {
128
+ const r = this.publishes.get("*");
129
+ return r && r(t[0], "PUBLISH_STATUS");
130
+ }
131
+ t.length > 0 && s(t[0], "PUBLISH_STATUS");
132
+ }
133
+ }
134
+ handleSignedEvent(e, t) {
135
+ console.log("Signed event received:", e, t);
136
+ }
137
+ handlePublicKey(e) {
138
+ console.log("Public key received:", e);
139
+ }
140
+ createShortId(e) {
141
+ let t = 0;
142
+ for (let r = 0; r < e.length; r++) {
143
+ const i = e.charCodeAt(r);
144
+ t = (t << 5) - t + i, t = t & t;
145
+ }
146
+ return Math.abs(t).toString(36).substring(0, 63);
147
+ }
148
+ subscribe(e, t, s = {}) {
149
+ const r = e.length < 64 ? e : this.createShortId(e), i = this.subscriptions.get(r);
150
+ if (i)
151
+ return i.refCount++, i.buffer;
152
+ const d = {
153
+ closeOnEose: !1,
154
+ skipCache: !1,
155
+ force: !1,
156
+ ...s
157
+ }, c = t.reduce(
158
+ (a, p) => a + (p.limit || 100),
159
+ 0
160
+ ), u = w.calculateBufferSize(c), o = new SharedArrayBuffer(u);
161
+ new DataView(o).setUint32(0, 4, !0), this.subscriptions.set(r, {
162
+ buffer: o,
163
+ options: d,
164
+ refCount: 1
165
+ });
166
+ const g = {
167
+ Subscribe: {
168
+ subscription_id: r,
169
+ requests: t
170
+ }
171
+ };
172
+ try {
173
+ const a = h(g);
174
+ return this.worker.postMessage({
175
+ serializedMessage: a,
176
+ sharedBuffer: o
177
+ }), o;
178
+ } catch (a) {
179
+ throw this.subscriptions.delete(r), a;
180
+ }
181
+ }
182
+ getBuffer(e) {
183
+ const t = this.subscriptions.get(e);
184
+ if (t)
185
+ return t.refCount++, t.buffer;
186
+ }
187
+ unsubscribe(e) {
188
+ const t = e.length < 64 ? e : this.createShortId(e), s = this.subscriptions.get(t);
189
+ s && s.refCount--;
190
+ }
191
+ publish(e, t, s) {
192
+ try {
193
+ s && this.publishes.set(e, s);
194
+ const r = {
195
+ kind: t.kind,
196
+ content: t.content,
197
+ tags: t.tags || []
198
+ }, d = h({
199
+ Publish: {
200
+ publish_id: e,
201
+ template: r
202
+ }
203
+ });
204
+ this.worker.postMessage(d);
205
+ } catch (r) {
206
+ throw console.error("Failed to publish event:", r), r;
207
+ }
208
+ }
209
+ setSigner(e, t) {
210
+ const r = h({
211
+ SetSigner: {
212
+ signer_type: e,
213
+ private_key: t
214
+ }
215
+ });
216
+ this.worker.postMessage(r), this.signers.set(e, t);
217
+ }
218
+ signEvent(e) {
219
+ const s = {
220
+ SignEvent: {
221
+ template: {
222
+ kind: e.kind,
223
+ content: e.content,
224
+ tags: e.tags
225
+ }
226
+ }
227
+ }, r = h(s);
228
+ this.worker.postMessage(r);
229
+ }
230
+ getPublicKey() {
231
+ const t = h({
232
+ GetPublicKey: {}
233
+ });
234
+ this.worker.postMessage(t);
235
+ }
236
+ addPublishCallbackAll(e) {
237
+ this.publishes.set("*", e);
238
+ }
239
+ cleanup() {
240
+ const e = [];
241
+ for (const [t, s] of this.subscriptions.entries())
242
+ s.refCount <= 0 && !this.PERPETUAL_SUBSCRIPTIONS.includes(t) && e.push(t);
243
+ for (const t of e)
244
+ if (this.subscriptions.get(t)) {
245
+ const i = h({
246
+ Unsubscribe: {
247
+ subscription_id: t
248
+ }
249
+ });
250
+ this.worker.postMessage(i), this.subscriptions.delete(t);
251
+ }
252
+ }
253
+ }
254
+ function C(n = {}) {
255
+ return new f(n);
256
+ }
257
+ const P = new f();
258
+ function E() {
259
+ P.cleanup();
260
+ }
261
+ export {
262
+ m as P,
263
+ k as R,
264
+ w as S,
265
+ E as a,
266
+ C as c,
267
+ U as i,
268
+ P as n
269
+ };
270
+ //# sourceMappingURL=index3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index3.js","sources":["../src/lib/sharedBuffer.ts","../src/types/kind39089.ts","../src/types/kind7.ts","../src/index.ts"],"sourcesContent":["import { unpack } from \"msgpackr\";\nimport type { WorkerToMainMessage } from \"src/types\";\n\n/**\n * Utility library for reading from SharedArrayBuffer with 4-byte header approach\n * Header format: [0-3]: Write position (4 bytes, little endian)\n * Data format: [4+]: [4-byte length][msgpack event][4-byte length][msgpack event]...\n */\nexport class SharedBufferReader {\n /**\n * Read new messages from SharedArrayBuffer since last read position\n * @param buffer The SharedArrayBuffer to read from\n * @param lastReadPosition Last position read (default: 0, meaning read from beginning)\n * @returns Object containing new messages and updated read position\n */\n static readMessages(\n buffer: SharedArrayBuffer,\n lastReadPosition: number = 0,\n ): {\n messages: WorkerToMainMessage[];\n newReadPosition: number;\n hasNewData: boolean;\n } {\n const view = new DataView(buffer);\n const uint8View = new Uint8Array(buffer);\n\n // Read current write position from header (first 4 bytes, little endian)\n const currentWritePosition = view.getUint32(0, true);\n\n // Check if there's new data to read\n const dataStartOffset = 4; // Skip 4-byte write position header\n const actualLastReadPosition = Math.max(lastReadPosition, dataStartOffset);\n\n if (currentWritePosition <= actualLastReadPosition) {\n return {\n messages: [],\n newReadPosition: actualLastReadPosition,\n hasNewData: false,\n };\n }\n\n const messages: WorkerToMainMessage[] = [];\n let currentPos = actualLastReadPosition;\n\n try {\n // Read length-prefixed events\n while (currentPos < currentWritePosition) {\n // Read 4-byte length prefix (little endian)\n if (currentPos + 4 > currentWritePosition) break;\n const eventLength = view.getUint32(currentPos, true);\n currentPos += 4;\n\n // Read the event data\n if (currentPos + eventLength > currentWritePosition) break;\n const eventData = uint8View.slice(currentPos, currentPos + eventLength);\n\n // Decode the event\n const message = unpack(eventData) as WorkerToMainMessage;\n messages.push(message);\n\n currentPos += eventLength;\n }\n\n return {\n messages,\n newReadPosition: currentPos,\n hasNewData: messages.length > 0,\n };\n } catch (error) {\n console.error(\n \"Failed to decode length-prefixed msgpack data from SharedArrayBuffer:\",\n error,\n );\n return {\n messages,\n newReadPosition: actualLastReadPosition,\n hasNewData: false,\n };\n }\n }\n\n /**\n * Read all messages from SharedArrayBuffer from the beginning (ignores lastReadPosition)\n * @param buffer The SharedArrayBuffer to read from\n * @returns Object containing all messages in the buffer\n */\n static readAllMessages(buffer: SharedArrayBuffer): {\n messages: WorkerToMainMessage[];\n totalMessages: number;\n } {\n const result = this.readMessages(buffer, 0); // Always start from beginning\n return {\n messages: result.messages,\n totalMessages: result.messages.length,\n };\n }\n\n /**\n * Get current write position from buffer header\n * @param buffer The SharedArrayBuffer to read from\n * @returns Current write position\n */\n static getCurrentWritePosition(buffer: SharedArrayBuffer): number {\n const view = new DataView(buffer);\n return view.getUint32(0, true);\n }\n\n /**\n * Check if buffer has new data since last read\n * @param buffer The SharedArrayBuffer to check\n * @param lastReadPosition Last position read\n * @returns True if there's new data to read\n */\n static hasNewData(\n buffer: SharedArrayBuffer,\n lastReadPosition: number,\n ): boolean {\n const currentWritePosition = this.getCurrentWritePosition(buffer);\n const dataStartOffset = 4;\n const actualLastReadPosition = Math.max(lastReadPosition, dataStartOffset);\n return currentWritePosition > actualLastReadPosition;\n }\n\n /**\n * Calculate recommended buffer size based on request limits\n * @param totalEventLimit Total expected events across all requests\n * @param bytesPerEvent Estimated bytes per event (default: 2048)\n * @returns Recommended buffer size in bytes\n */\n static calculateBufferSize(\n totalEventLimit: number = 100,\n bytesPerEvent: number = 3072,\n ): number {\n const headerSize = 4;\n const dataSize = totalEventLimit * bytesPerEvent;\n const overhead = Math.floor(dataSize * 0.25); // 25% overhead\n return headerSize + dataSize + overhead;\n }\n}\n","import type { ParsedEvent } from 'src/types';\n\nexport interface Kind39089Parsed {\n\tlist_identifier: string;\n\tpeople: string[];\n\ttitle?: string;\n\tdescription?: string;\n\timage?: string;\n}\n\nexport function isKind39089(event: ParsedEvent<unknown>): event is ParsedEvent<Kind39089Parsed> {\n\treturn event.kind === 39089;\n}\n","export enum ReactionType {\n\tLIKE = '+',\n\tDISLIKE = '-',\n\tEMOJI = 'emoji',\n\tCUSTOM = 'custom'\n}\n\nexport type Kind7Parsed = {\n\ttype: ReactionType;\n\teventId: string; // The id of the event being reacted to\n\tpubkey: string; // The pubkey of the author of the reacted event\n\teventKind?: number; // The kind of the event being reacted to (from k tag)\n\temoji?: {\n\t\tshortcode: string;\n\t\turl: string;\n\t};\n\ttargetCoordinates?: string; // For addressable events (from a tag)\n};\n","import { SharedBufferReader } from \"src/lib/sharedBuffer\";\nimport {\n type MainToWorkerMessage,\n type RelayStatusUpdate,\n type Request,\n type WorkerToMainMessage,\n} from \"src/wasm/main/nostr_main.js\";\n// import mainWasmUrl from \"src/wasm/main/nostr_main_bg.wasm?url\";\n\nimport type { AnyKind, ParsedEvent } from \"src/types\";\n\nimport { decode, encode } from \"@msgpack/msgpack\";\nimport type { NostrEvent } from \"nostr-tools\";\nimport type { SubscribeKind, PublishKind } from \"src/types\";\n\n// Re-export types for external use\nexport type { Request };\n\n// Callback for subscription events\nexport type SubscriptionCallback = (\n data: ParsedEvent<AnyKind>[] | number,\n type: SubscribeKind,\n) => void;\ntype PublishCallback = (data: RelayStatusUpdate, type: PublishKind) => void;\n\nexport enum PublishStatus {\n StatusPending = \"pending\",\n StatusSent = \"sent\",\n StatusSuccess = \"success\",\n StatusFailed = \"failed\",\n StatusRejected = \"rejected\",\n StatusConnError = \"connection_error\",\n}\n\nexport type RelayStatus = {\n relay: string;\n status: PublishStatus;\n message: string;\n timestamp: number;\n};\n\nexport interface SubscriptionOptions {\n closeOnEose?: boolean;\n skipCache?: boolean;\n force?: boolean;\n}\n\n/**\n * Configuration for the Nostr Manager\n */\nexport interface NostrManagerConfig {\n /**\n * Custom worker URL. If not provided, uses the bundled worker.\n */\n workerUrl?: string;\n /**\n * Custom worker instance. If provided, workerUrl is ignored.\n */\n worker?: Worker;\n}\n\n// const wasmReady = init(mainWasmUrl);\n\n/**\n * Pure TypeScript NostrClient that manages worker communication and state.\n * Uses WASM utilities for heavy lifting (encoding, decoding, crypto).\n */\nclass NostrManager {\n private worker: Worker;\n private subscriptions = new Map<\n string,\n {\n buffer: SharedArrayBuffer;\n options: SubscriptionOptions;\n refCount: number;\n }\n >();\n private publishes = new Map<string, PublishCallback>();\n private signers = new Map<string, string>(); // name -> secret key hex\n\n public PERPETUAL_SUBSCRIPTIONS = [\"notifications\", \"starterpack\"];\n\n constructor(config: NostrManagerConfig = {}) {\n this.worker = this.createWorker(config);\n this.setupWorkerListener();\n }\n\n private createWorker(config: NostrManagerConfig): Worker {\n const workerUrl = new URL(\"./worker.js\", import.meta.url);\n console.log(import.meta.url, workerUrl);\n\n return new Worker(workerUrl);\n }\n\n private setupWorkerListener() {\n this.worker.onmessage = async (event) => {\n // await wasmReady;\n if (event.data instanceof Uint8Array) {\n let uint8Array = event.data;\n try {\n const message: any = decode(uint8Array);\n this.handleWorkerMessage(message);\n } catch (error) {\n console.error(\"Failed to decode worker message:\", error);\n } finally {\n // Aggressively clear memory references\n if (uint8Array) {\n uint8Array.fill(0);\n (uint8Array as any) = null;\n }\n }\n } else {\n console.log(\"Received non-arrayBuffer message:\", event.data);\n }\n };\n\n this.worker.onerror = (error) => {\n console.error(\"Worker error:\", error);\n };\n }\n\n private handleWorkerMessage(message: WorkerToMainMessage) {\n if (\"PublishStatus\" in message) {\n this.handlePublishStatus(\n message.PublishStatus.publish_id,\n message.PublishStatus.status,\n );\n } else if (\"Count\" in message) {\n // this.handleSubscriptionCount(message.Count.subscription_id, message.Count.count);\n } else if (\"SignedEvent\" in message) {\n this.handleSignedEvent(\n message.SignedEvent.content,\n message.SignedEvent.signed_event,\n );\n } else if (\"PublicKey\" in message) {\n this.handlePublicKey(message.PublicKey.public_key);\n } else if (\"Debug\" in message) {\n console.debug(\"Worker debug:\", message.Debug.message, message.Debug.data);\n } else {\n console.warn(\"Unknown message type from worker:\", message);\n }\n }\n\n private handlePublishStatus(\n publishId: string,\n statuses: RelayStatusUpdate[],\n ) {\n const publishCallback = this.publishes.get(publishId);\n if (!statuses[0]) return;\n if (!publishCallback) {\n const publishAllCallback = this.publishes.get(\"*\");\n return (\n publishAllCallback && publishAllCallback(statuses[0], \"PUBLISH_STATUS\")\n );\n }\n\n if (statuses.length > 0) {\n publishCallback(statuses[0], \"PUBLISH_STATUS\");\n }\n }\n\n private handleSignedEvent(content: string, signedEvent: any) {\n console.log(\"Signed event received:\", content, signedEvent);\n }\n\n private handlePublicKey(publicKey: string) {\n console.log(\"Public key received:\", publicKey);\n }\n\n private createShortId(input: string): string {\n let hash = 0;\n for (let i = 0; i < input.length; i++) {\n const char = input.charCodeAt(i);\n hash = (hash << 5) - hash + char;\n hash = hash & hash;\n }\n const shortId = Math.abs(hash).toString(36);\n return shortId.substring(0, 63);\n }\n\n subscribe(\n subscriptionId: string,\n requests: Request[],\n options: SubscriptionOptions = {},\n ): SharedArrayBuffer {\n const subId =\n subscriptionId.length < 64\n ? subscriptionId\n : this.createShortId(subscriptionId);\n\n const existingSubscription = this.subscriptions.get(subId);\n if (existingSubscription) {\n existingSubscription.refCount++;\n return existingSubscription.buffer;\n }\n\n const defaultOptions: SubscriptionOptions = {\n closeOnEose: false,\n skipCache: false,\n force: false,\n ...options,\n };\n\n const totalLimit = requests.reduce(\n (sum, req) => sum + (req.limit || 100),\n 0,\n );\n const bufferSize = SharedBufferReader.calculateBufferSize(totalLimit);\n const buffer = new SharedArrayBuffer(bufferSize);\n\n const view = new DataView(buffer);\n view.setUint32(0, 4, true);\n\n this.subscriptions.set(subId, {\n buffer,\n options: defaultOptions,\n refCount: 1,\n });\n\n const message: MainToWorkerMessage = {\n Subscribe: {\n subscription_id: subId,\n requests: requests,\n },\n };\n\n try {\n const pack = encode(message);\n this.worker.postMessage({\n serializedMessage: pack,\n sharedBuffer: buffer,\n });\n return buffer;\n } catch (error) {\n this.subscriptions.delete(subId);\n throw error;\n }\n }\n\n getBuffer(subId: string): SharedArrayBuffer | undefined {\n const existingSubscription = this.subscriptions.get(subId);\n if (existingSubscription) {\n existingSubscription.refCount++;\n return existingSubscription.buffer;\n }\n return undefined;\n }\n\n unsubscribe(subscriptionId: string): void {\n const subId =\n subscriptionId.length < 64\n ? subscriptionId\n : this.createShortId(subscriptionId);\n const subscription = this.subscriptions.get(subId);\n if (subscription) {\n subscription.refCount--;\n }\n }\n\n publish(publish_id: string, event: NostrEvent, callback?: PublishCallback) {\n try {\n if (callback) {\n this.publishes.set(publish_id, callback);\n }\n\n const template = {\n kind: event.kind,\n content: event.content,\n tags: event.tags || [],\n };\n\n const message: MainToWorkerMessage = {\n Publish: {\n publish_id: publish_id,\n template,\n },\n };\n\n const p = encode(message);\n this.worker.postMessage(p);\n } catch (error) {\n console.error(\"Failed to publish event:\", error);\n throw error;\n }\n }\n\n setSigner(name: string, secretKeyHex: string): void {\n const message: MainToWorkerMessage = {\n SetSigner: {\n signer_type: name,\n private_key: secretKeyHex,\n },\n };\n\n const pack = encode(message);\n this.worker.postMessage(pack);\n this.signers.set(name, secretKeyHex);\n }\n\n signEvent(event: NostrEvent) {\n const template = {\n kind: event.kind,\n content: event.content,\n tags: event.tags,\n };\n\n const message: MainToWorkerMessage = {\n SignEvent: {\n template: template,\n },\n };\n const pack = encode(message);\n this.worker.postMessage(pack);\n }\n\n getPublicKey() {\n const message: MainToWorkerMessage = {\n GetPublicKey: {},\n };\n const pack = encode(message);\n this.worker.postMessage(pack);\n }\n\n addPublishCallbackAll(\n callback: (status: RelayStatusUpdate, eventId: string) => void,\n ) {\n this.publishes.set(\"*\", callback as any);\n }\n\n cleanup(): void {\n const subscriptionsToDelete: string[] = [];\n\n for (const [subId, subscription] of this.subscriptions.entries()) {\n if (\n subscription.refCount <= 0 &&\n !this.PERPETUAL_SUBSCRIPTIONS.includes(subId)\n ) {\n subscriptionsToDelete.push(subId);\n }\n }\n\n for (const subId of subscriptionsToDelete) {\n const subscription = this.subscriptions.get(subId);\n if (subscription) {\n const message: MainToWorkerMessage = {\n Unsubscribe: {\n subscription_id: subId,\n },\n };\n const pack = encode(message);\n this.worker.postMessage(pack);\n this.subscriptions.delete(subId);\n }\n }\n }\n}\n\n/**\n * Factory function to create a new NostrManager instance.\n * @param config - Configuration for the NostrManager.\n * @returns A new instance of NostrManager.\n */\nexport function createNostrManager(\n config: NostrManagerConfig = {},\n): NostrManager {\n return new NostrManager(config);\n}\n\n/**\n * Default singleton instance of the NostrManager.\n * Useful for applications that only need one instance.\n */\nexport const nostrManager = new NostrManager();\n\nexport function cleanup(): void {\n nostrManager.cleanup();\n}\n\nexport * from \"./types\";\n"],"names":["SharedBufferReader","buffer","lastReadPosition","view","uint8View","currentWritePosition","actualLastReadPosition","messages","currentPos","eventLength","eventData","message","unpack","error","result","totalEventLimit","bytesPerEvent","dataSize","overhead","isKind39089","event","ReactionType","PublishStatus","NostrManager","config","workerUrl","uint8Array","decode","publishId","statuses","publishCallback","publishAllCallback","content","signedEvent","publicKey","input","hash","i","char","subscriptionId","requests","options","subId","existingSubscription","defaultOptions","totalLimit","sum","req","bufferSize","pack","encode","subscription","publish_id","callback","template","p","name","secretKeyHex","subscriptionsToDelete","createNostrManager","nostrManager","cleanup"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { WorkerToMainMessage } from '../types';
2
+
3
+ /**
4
+ * Utility library for reading from SharedArrayBuffer with 4-byte header approach
5
+ * Header format: [0-3]: Write position (4 bytes, little endian)
6
+ * Data format: [4+]: [4-byte length][msgpack event][4-byte length][msgpack event]...
7
+ */
8
+ export declare class SharedBufferReader {
9
+ /**
10
+ * Read new messages from SharedArrayBuffer since last read position
11
+ * @param buffer The SharedArrayBuffer to read from
12
+ * @param lastReadPosition Last position read (default: 0, meaning read from beginning)
13
+ * @returns Object containing new messages and updated read position
14
+ */
15
+ static readMessages(buffer: SharedArrayBuffer, lastReadPosition?: number): {
16
+ messages: WorkerToMainMessage[];
17
+ newReadPosition: number;
18
+ hasNewData: boolean;
19
+ };
20
+ /**
21
+ * Read all messages from SharedArrayBuffer from the beginning (ignores lastReadPosition)
22
+ * @param buffer The SharedArrayBuffer to read from
23
+ * @returns Object containing all messages in the buffer
24
+ */
25
+ static readAllMessages(buffer: SharedArrayBuffer): {
26
+ messages: WorkerToMainMessage[];
27
+ totalMessages: number;
28
+ };
29
+ /**
30
+ * Get current write position from buffer header
31
+ * @param buffer The SharedArrayBuffer to read from
32
+ * @returns Current write position
33
+ */
34
+ static getCurrentWritePosition(buffer: SharedArrayBuffer): number;
35
+ /**
36
+ * Check if buffer has new data since last read
37
+ * @param buffer The SharedArrayBuffer to check
38
+ * @param lastReadPosition Last position read
39
+ * @returns True if there's new data to read
40
+ */
41
+ static hasNewData(buffer: SharedArrayBuffer, lastReadPosition: number): boolean;
42
+ /**
43
+ * Calculate recommended buffer size based on request limits
44
+ * @param totalEventLimit Total expected events across all requests
45
+ * @param bytesPerEvent Estimated bytes per event (default: 2048)
46
+ * @returns Recommended buffer size in bytes
47
+ */
48
+ static calculateBufferSize(totalEventLimit?: number, bytesPerEvent?: number): number;
49
+ }
50
+ //# sourceMappingURL=sharedBuffer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedBuffer.d.ts","sourceRoot":"","sources":["../../src/lib/sharedBuffer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAErD;;;;GAIG;AACH,qBAAa,kBAAkB;IAC7B;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CACjB,MAAM,EAAE,iBAAiB,EACzB,gBAAgB,GAAE,MAAU,GAC3B;QACD,QAAQ,EAAE,mBAAmB,EAAE,CAAC;QAChC,eAAe,EAAE,MAAM,CAAC;QACxB,UAAU,EAAE,OAAO,CAAC;KACrB;IA2DD;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,iBAAiB,GAAG;QACjD,QAAQ,EAAE,mBAAmB,EAAE,CAAC;QAChC,aAAa,EAAE,MAAM,CAAC;KACvB;IAQD;;;;OAIG;IACH,MAAM,CAAC,uBAAuB,CAAC,MAAM,EAAE,iBAAiB,GAAG,MAAM;IAKjE;;;;;OAKG;IACH,MAAM,CAAC,UAAU,CACf,MAAM,EAAE,iBAAiB,EACzB,gBAAgB,EAAE,MAAM,GACvB,OAAO;IAOV;;;;;OAKG;IACH,MAAM,CAAC,mBAAmB,CACxB,eAAe,GAAE,MAAY,EAC7B,aAAa,GAAE,MAAa,GAC3B,MAAM;CAMV"}