@qntx/nostr 0.5.0 → 0.6.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.
- package/dist/{client-BtIAtxrL.mjs → client-CadO5fAX.mjs} +2 -2
- package/dist/{client-BtIAtxrL.mjs.map → client-CadO5fAX.mjs.map} +1 -1
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/{index-QxvrpMfF.d.mts → index-CNl2q67H.d.mts} +3 -3
- package/dist/{index-Dmc8FJgO.d.mts → index-lvXeER5t.d.mts} +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +2 -2
- package/dist/instance-CIca-ynn.d.mts +15 -0
- package/dist/instance-DQE8BoWt.mjs +221 -0
- package/dist/instance-DQE8BoWt.mjs.map +1 -0
- package/dist/loaders.d.mts +1 -1
- package/dist/nostr_crypto_wasm_bg.wasm +0 -0
- package/dist/{reactive-DFpqtIf_.d.mts → reactive-7aqeip4A.d.mts} +3 -1
- package/dist/{reactive-DDlThDSZ.mjs → reactive-BfhPp9a3.mjs} +38 -4
- package/dist/reactive-BfhPp9a3.mjs.map +1 -0
- package/dist/store.d.mts +1 -1
- package/dist/store.mjs +1 -1
- package/dist/wasm.browser.d.mts +8 -0
- package/dist/wasm.browser.mjs +19 -0
- package/dist/wasm.browser.mjs.map +1 -0
- package/dist/wasm.d.mts +1 -11
- package/dist/wasm.mjs +6 -207
- package/dist/wasm.mjs.map +1 -1
- package/package.json +10 -3
- package/dist/reactive-DDlThDSZ.mjs.map +0 -1
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { f as CryptoError, v as WasmVerifyPoisonedError } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { t as createEventVerifier } from "./verifier-t5WoWbtY.mjs";
|
|
3
|
+
//#region src/wasm/abi.ts
|
|
4
|
+
/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */
|
|
5
|
+
const ALLOWED_WASM_IMPORTS = [{
|
|
6
|
+
module: "wbg",
|
|
7
|
+
name: "__wbindgen_throw"
|
|
8
|
+
}, {
|
|
9
|
+
module: "./nostr_crypto_wasm_bg.js",
|
|
10
|
+
name: "__wbindgen_throw"
|
|
11
|
+
}];
|
|
12
|
+
const utf8 = new TextDecoder();
|
|
13
|
+
function decodeUtf8(memory, ptr, len) {
|
|
14
|
+
return utf8.decode(new Uint8Array(memory.buffer, ptr, len));
|
|
15
|
+
}
|
|
16
|
+
function makeWbgImports(holder) {
|
|
17
|
+
const throwRuntime = (ptr, len) => {
|
|
18
|
+
const mem = holder.exports?.memory;
|
|
19
|
+
const msg = mem ? decodeUtf8(mem, ptr, len) : "wasm panic";
|
|
20
|
+
throw new WebAssembly.RuntimeError(msg);
|
|
21
|
+
};
|
|
22
|
+
const wbg = { __wbindgen_throw: throwRuntime };
|
|
23
|
+
return {
|
|
24
|
+
wbg,
|
|
25
|
+
"./nostr_crypto_wasm_bg.js": wbg
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */
|
|
29
|
+
function assertAllowedWasmImports(mod) {
|
|
30
|
+
const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\0${item.name}`));
|
|
31
|
+
for (const imp of WebAssembly.Module.imports(mod)) {
|
|
32
|
+
if (imp.kind !== "function") throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);
|
|
33
|
+
if (!allowed.has(`${imp.module}\0${imp.name}`)) throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function requireMemory(value) {
|
|
37
|
+
if (!(value instanceof WebAssembly.Memory)) throw new TypeError("wasm missing memory export");
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function requireFn(value, name) {
|
|
41
|
+
if (typeof value !== "function") throw new TypeError(`wasm missing ${name} export`);
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
function asExports(raw) {
|
|
45
|
+
const exports = {
|
|
46
|
+
memory: requireMemory(raw["memory"]),
|
|
47
|
+
verify: requireFn(raw["verify"], "verify"),
|
|
48
|
+
verify_serialized: requireFn(raw["verify_serialized"], "verify_serialized"),
|
|
49
|
+
sign: requireFn(raw["sign"], "sign"),
|
|
50
|
+
public_key: requireFn(raw["public_key"], "public_key"),
|
|
51
|
+
__wbindgen_export: requireFn(raw["__wbindgen_export"], "__wbindgen_export"),
|
|
52
|
+
__wbindgen_export2: requireFn(raw["__wbindgen_export2"], "__wbindgen_export2"),
|
|
53
|
+
__wbindgen_add_to_stack_pointer: requireFn(raw["__wbindgen_add_to_stack_pointer"], "__wbindgen_add_to_stack_pointer")
|
|
54
|
+
};
|
|
55
|
+
const start = raw["__wbindgen_start"];
|
|
56
|
+
if (typeof start === "function") exports.__wbindgen_start = requireFn(start, "__wbindgen_start");
|
|
57
|
+
return exports;
|
|
58
|
+
}
|
|
59
|
+
function passBytes(exports, bytes) {
|
|
60
|
+
const len = bytes.length;
|
|
61
|
+
const ptr = exports.__wbindgen_export(len, 1) >>> 0;
|
|
62
|
+
new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);
|
|
63
|
+
return {
|
|
64
|
+
ptr,
|
|
65
|
+
len
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function wasmVerify(exports, id, pubkey, sig) {
|
|
69
|
+
const idP = passBytes(exports, id);
|
|
70
|
+
const pkP = passBytes(exports, pubkey);
|
|
71
|
+
const sigP = passBytes(exports, sig);
|
|
72
|
+
return exports.verify(idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;
|
|
73
|
+
}
|
|
74
|
+
function wasmVerifySerialized(exports, serialized, id, pubkey, sig) {
|
|
75
|
+
const serP = passBytes(exports, serialized);
|
|
76
|
+
const idP = passBytes(exports, id);
|
|
77
|
+
const pkP = passBytes(exports, pubkey);
|
|
78
|
+
const sigP = passBytes(exports, sig);
|
|
79
|
+
return exports.verify_serialized(serP.ptr, serP.len, idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;
|
|
80
|
+
}
|
|
81
|
+
function takeBytes(exports, ptr, len) {
|
|
82
|
+
const out = new Uint8Array(len);
|
|
83
|
+
if (len > 0) {
|
|
84
|
+
out.set(new Uint8Array(exports.memory.buffer, ptr, len));
|
|
85
|
+
exports.__wbindgen_export2(ptr, len, 1);
|
|
86
|
+
}
|
|
87
|
+
return out;
|
|
88
|
+
}
|
|
89
|
+
function callReturningBytes(exports, invoke) {
|
|
90
|
+
const retptr = exports.__wbindgen_add_to_stack_pointer(-16);
|
|
91
|
+
try {
|
|
92
|
+
invoke(retptr);
|
|
93
|
+
const view = new DataView(exports.memory.buffer);
|
|
94
|
+
return takeBytes(exports, view.getUint32(retptr, true), view.getUint32(retptr + 4, true));
|
|
95
|
+
} finally {
|
|
96
|
+
exports.__wbindgen_add_to_stack_pointer(16);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function wasmSign(exports, id, seckey, aux) {
|
|
100
|
+
const idP = passBytes(exports, id);
|
|
101
|
+
const skP = passBytes(exports, seckey);
|
|
102
|
+
const auxP = passBytes(exports, aux);
|
|
103
|
+
return callReturningBytes(exports, (retptr) => {
|
|
104
|
+
exports.sign(retptr, idP.ptr, idP.len, skP.ptr, skP.len, auxP.ptr, auxP.len);
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function wasmPublicKey(exports, seckey) {
|
|
108
|
+
const skP = passBytes(exports, seckey);
|
|
109
|
+
return callReturningBytes(exports, (retptr) => {
|
|
110
|
+
exports.public_key(retptr, skP.ptr, skP.len);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async function instantiateCryptoWasm(bytes) {
|
|
114
|
+
const holder = {};
|
|
115
|
+
const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));
|
|
116
|
+
assertAllowedWasmImports(module);
|
|
117
|
+
holder.exports = asExports(instance.exports);
|
|
118
|
+
holder.exports.__wbindgen_start?.();
|
|
119
|
+
return holder.exports;
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
//#region src/wasm/adapter.ts
|
|
123
|
+
/**
|
|
124
|
+
* Build the WASM event verifier on {@link createEventVerifier}. A `WebAssembly.RuntimeError` from
|
|
125
|
+
* the module means the instance aborted — it poisons every later call with the same
|
|
126
|
+
* `WasmVerifyPoisonedError`; any other backend error verifies `false` (the event is marked
|
|
127
|
+
* failed).
|
|
128
|
+
*/
|
|
129
|
+
function createWasmEventVerifier(verifySerialized, poison) {
|
|
130
|
+
const backend = (serializedUtf8, id, pubkey, sig) => {
|
|
131
|
+
if (poison.error !== void 0) throw poison.error;
|
|
132
|
+
try {
|
|
133
|
+
return verifySerialized(serializedUtf8, id, pubkey, sig);
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (error instanceof WebAssembly.RuntimeError) {
|
|
136
|
+
poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: error });
|
|
137
|
+
throw poison.error;
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
return createEventVerifier(backend);
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/wasm/instance.ts
|
|
146
|
+
function isWasmBytes(value) {
|
|
147
|
+
return value instanceof ArrayBuffer || ArrayBuffer.isView(value);
|
|
148
|
+
}
|
|
149
|
+
async function fetchWasmUrl(url) {
|
|
150
|
+
const res = await fetch(url);
|
|
151
|
+
if (!res.ok) throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);
|
|
152
|
+
return new Uint8Array(await res.arrayBuffer());
|
|
153
|
+
}
|
|
154
|
+
function requireByteLength(bytes, expected, label) {
|
|
155
|
+
if (bytes.length !== expected) throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);
|
|
156
|
+
}
|
|
157
|
+
function wrapPoison(poison, fn) {
|
|
158
|
+
if (poison.error) throw poison.error;
|
|
159
|
+
try {
|
|
160
|
+
return fn();
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error instanceof WebAssembly.RuntimeError) {
|
|
163
|
+
poison.error = new WasmVerifyPoisonedError("wasm verify aborted the instance", { cause: error });
|
|
164
|
+
throw poison.error;
|
|
165
|
+
}
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function bindExports(exports) {
|
|
170
|
+
const poison = {};
|
|
171
|
+
const rawSerialized = (serializedUtf8, id, pubkey, sig) => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);
|
|
172
|
+
return {
|
|
173
|
+
verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),
|
|
174
|
+
verifySerialized: (serializedUtf8, id, pubkey, sig) => wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),
|
|
175
|
+
verifyEvent: createWasmEventVerifier(rawSerialized, poison),
|
|
176
|
+
sign: (id, seckey, aux) => wrapPoison(poison, () => {
|
|
177
|
+
requireByteLength(id, 32, "id");
|
|
178
|
+
requireByteLength(seckey, 32, "secret key");
|
|
179
|
+
requireByteLength(aux, 32, "aux");
|
|
180
|
+
const sig = wasmSign(exports, id, seckey, aux);
|
|
181
|
+
if (sig.length !== 64) throw new CryptoError("wasm sign failed");
|
|
182
|
+
return sig;
|
|
183
|
+
}),
|
|
184
|
+
publicKey: (seckey) => wrapPoison(poison, () => {
|
|
185
|
+
requireByteLength(seckey, 32, "secret key");
|
|
186
|
+
const pk = wasmPublicKey(exports, seckey);
|
|
187
|
+
if (pk.length !== 32) throw new CryptoError("wasm publicKey failed");
|
|
188
|
+
return pk;
|
|
189
|
+
})
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** Builds a loader that interns a single instance per module slot. */
|
|
193
|
+
function createNostrWasmLoader(wasmBytes) {
|
|
194
|
+
let interned;
|
|
195
|
+
async function instantiate(opts) {
|
|
196
|
+
return bindExports(await instantiateCryptoWasm(await wasmBytes(opts)));
|
|
197
|
+
}
|
|
198
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
199
|
+
async function loadNostrWasm(opts) {
|
|
200
|
+
if (interned) return interned;
|
|
201
|
+
const pending = instantiate(opts);
|
|
202
|
+
interned = pending;
|
|
203
|
+
try {
|
|
204
|
+
return await pending;
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (interned === pending) interned = void 0;
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function resetNostrWasm() {
|
|
211
|
+
interned = void 0;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
loadNostrWasm,
|
|
215
|
+
resetNostrWasm
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
//#endregion
|
|
219
|
+
export { fetchWasmUrl as n, isWasmBytes as r, createNostrWasmLoader as t };
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=instance-DQE8BoWt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instance-DQE8BoWt.mjs","names":[],"sources":["../src/wasm/abi.ts","../src/wasm/adapter.ts","../src/wasm/instance.ts"],"sourcesContent":["/** Wasm-bindgen 0.2.122 bundler-produced exports used by interned TS glue. */\nexport type CryptoWasmExports = {\n memory: WebAssembly.Memory;\n verify: (\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n verify_serialized: (\n serPtr: number,\n serLen: number,\n idPtr: number,\n idLen: number,\n pkPtr: number,\n pkLen: number,\n sigPtr: number,\n sigLen: number,\n ) => number;\n sign: (\n retptr: number,\n idPtr: number,\n idLen: number,\n skPtr: number,\n skLen: number,\n auxPtr: number,\n auxLen: number,\n ) => void;\n public_key: (retptr: number, skPtr: number, skLen: number) => void;\n /** 0.2.122 name for `__wbindgen_malloc(size, align)`. */\n __wbindgen_export: (size: number, align: number) => number;\n /** 0.2.122 name for `__wbindgen_free(ptr, size, align)` after malloc claimed `__wbindgen_export`. */\n __wbindgen_export2: (ptr: number, size: number, align: number) => void;\n __wbindgen_add_to_stack_pointer: (delta: number) => number;\n __wbindgen_start?: () => void;\n};\n\n/** Imports 0.2.122 may request. Instantiation fails if anything else appears. */\nexport const ALLOWED_WASM_IMPORTS: ReadonlyArray<{ module: string; name: string }> = [\n { module: \"wbg\", name: \"__wbindgen_throw\" },\n { module: \"./nostr_crypto_wasm_bg.js\", name: \"__wbindgen_throw\" },\n];\n\nconst utf8 = new TextDecoder();\n\nfunction decodeUtf8(memory: WebAssembly.Memory, ptr: number, len: number): string {\n return utf8.decode(new Uint8Array(memory.buffer, ptr, len));\n}\n\nfunction makeWbgImports(holder: { exports?: CryptoWasmExports }): WebAssembly.Imports {\n const throwRuntime = (ptr: number, len: number): never => {\n const mem = holder.exports?.memory;\n const msg = mem ? decodeUtf8(mem, ptr, len) : \"wasm panic\";\n throw new WebAssembly.RuntimeError(msg);\n };\n const wbg = {\n __wbindgen_throw: throwRuntime,\n };\n return {\n wbg,\n \"./nostr_crypto_wasm_bg.js\": wbg,\n };\n}\n\n/** Fail if the module imports anything outside {@link ALLOWED_WASM_IMPORTS}. */\nexport function assertAllowedWasmImports(mod: WebAssembly.Module): void {\n const allowed = new Set(ALLOWED_WASM_IMPORTS.map((item) => `${item.module}\\0${item.name}`));\n for (const imp of WebAssembly.Module.imports(mod)) {\n if (imp.kind !== \"function\") {\n throw new TypeError(`unexpected wasm import kind ${imp.kind}: ${imp.module}.${imp.name}`);\n }\n if (!allowed.has(`${imp.module}\\0${imp.name}`)) {\n throw new TypeError(`unexpected wasm import ${imp.module}.${imp.name}`);\n }\n }\n}\n\nfunction requireMemory(value: WebAssembly.ExportValue | undefined): WebAssembly.Memory {\n if (!(value instanceof WebAssembly.Memory)) {\n throw new TypeError(\"wasm missing memory export\");\n }\n return value;\n}\n\n// oxlint-disable-next-line no-unnecessary-type-parameters -- T binds the declared ABI signature at each call site\nfunction requireFn<T extends (...args: number[]) => unknown>(\n value: WebAssembly.ExportValue | undefined,\n name: string,\n): T {\n if (typeof value !== \"function\") {\n throw new TypeError(`wasm missing ${name} export`);\n }\n // oxlint-disable-next-line no-unsafe-type-assertion -- wasm exports are opaque; each name is bound to the signature the ABI contract requires\n return value as T;\n}\n\nfunction asExports(raw: WebAssembly.Exports): CryptoWasmExports {\n const exports: CryptoWasmExports = {\n memory: requireMemory(raw[\"memory\"]),\n verify: requireFn(raw[\"verify\"], \"verify\"),\n verify_serialized: requireFn(raw[\"verify_serialized\"], \"verify_serialized\"),\n sign: requireFn(raw[\"sign\"], \"sign\"),\n public_key: requireFn(raw[\"public_key\"], \"public_key\"),\n __wbindgen_export: requireFn(raw[\"__wbindgen_export\"], \"__wbindgen_export\"),\n __wbindgen_export2: requireFn(raw[\"__wbindgen_export2\"], \"__wbindgen_export2\"),\n __wbindgen_add_to_stack_pointer: requireFn(\n raw[\"__wbindgen_add_to_stack_pointer\"],\n \"__wbindgen_add_to_stack_pointer\",\n ),\n };\n const start = raw[\"__wbindgen_start\"];\n if (typeof start === \"function\") {\n exports.__wbindgen_start = requireFn<() => void>(start, \"__wbindgen_start\");\n }\n return exports;\n}\n\nfunction passBytes(exports: CryptoWasmExports, bytes: Uint8Array): { ptr: number; len: number } {\n const len = bytes.length;\n const ptr = exports.__wbindgen_export(len, 1) >>> 0;\n new Uint8Array(exports.memory.buffer, ptr, len).set(bytes);\n return { ptr, len };\n}\n\nexport function wasmVerify(\n exports: CryptoWasmExports,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return exports.verify(idP.ptr, idP.len, pkP.ptr, pkP.len, sigP.ptr, sigP.len) !== 0;\n}\n\nexport function wasmVerifySerialized(\n exports: CryptoWasmExports,\n serialized: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n): boolean {\n const serP = passBytes(exports, serialized);\n const idP = passBytes(exports, id);\n const pkP = passBytes(exports, pubkey);\n const sigP = passBytes(exports, sig);\n return (\n exports.verify_serialized(\n serP.ptr,\n serP.len,\n idP.ptr,\n idP.len,\n pkP.ptr,\n pkP.len,\n sigP.ptr,\n sigP.len,\n ) !== 0\n );\n}\n\nfunction takeBytes(exports: CryptoWasmExports, ptr: number, len: number): Uint8Array {\n const out = new Uint8Array(len);\n if (len > 0) {\n out.set(new Uint8Array(exports.memory.buffer, ptr, len));\n exports.__wbindgen_export2(ptr, len, 1);\n }\n return out;\n}\n\nfunction callReturningBytes(\n exports: CryptoWasmExports,\n invoke: (retptr: number) => void,\n): Uint8Array {\n const retptr = exports.__wbindgen_add_to_stack_pointer(-16);\n try {\n invoke(retptr);\n const view = new DataView(exports.memory.buffer);\n const ptr = view.getUint32(retptr, true);\n const len = view.getUint32(retptr + 4, true);\n return takeBytes(exports, ptr, len);\n } finally {\n exports.__wbindgen_add_to_stack_pointer(16);\n }\n}\n\nexport function wasmSign(\n exports: CryptoWasmExports,\n id: Uint8Array,\n seckey: Uint8Array,\n aux: Uint8Array,\n): Uint8Array {\n const idP = passBytes(exports, id);\n const skP = passBytes(exports, seckey);\n const auxP = passBytes(exports, aux);\n return callReturningBytes(exports, (retptr) => {\n exports.sign(retptr, idP.ptr, idP.len, skP.ptr, skP.len, auxP.ptr, auxP.len);\n });\n}\n\nexport function wasmPublicKey(exports: CryptoWasmExports, seckey: Uint8Array): Uint8Array {\n const skP = passBytes(exports, seckey);\n return callReturningBytes(exports, (retptr) => {\n exports.public_key(retptr, skP.ptr, skP.len);\n });\n}\n\nexport async function instantiateCryptoWasm(\n bytes: ArrayBuffer | ArrayBufferView,\n): Promise<CryptoWasmExports> {\n const holder: { exports?: CryptoWasmExports } = {};\n const { module, instance } = await WebAssembly.instantiate(bytes, makeWbgImports(holder));\n assertAllowedWasmImports(module);\n holder.exports = asExports(instance.exports);\n holder.exports.__wbindgen_start?.();\n return holder.exports;\n}\n","import { WasmVerifyPoisonedError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport { createEventVerifier } from \"../core/verifier.ts\";\nimport type { SerializedEventVerifier } from \"../core/verifier.ts\";\n\nexport { WasmVerifyPoisonedError } from \"../core/error.ts\";\n\n/**\n * Build the WASM event verifier on {@link createEventVerifier}. A `WebAssembly.RuntimeError` from\n * the module means the instance aborted — it poisons every later call with the same\n * `WasmVerifyPoisonedError`; any other backend error verifies `false` (the event is marked\n * failed).\n */\nexport function createWasmEventVerifier(\n verifySerialized: SerializedEventVerifier,\n poison: { error?: Error },\n): (event: Event) => boolean {\n const backend: SerializedEventVerifier = (serializedUtf8, id, pubkey, sig) => {\n if (poison.error !== undefined) {\n throw poison.error;\n }\n try {\n return verifySerialized(serializedUtf8, id, pubkey, sig);\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n return false;\n }\n };\n return createEventVerifier(backend);\n}\n","import { CryptoError } from \"../core/error.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport type { SigningBackend } from \"../core/key.ts\";\nimport {\n instantiateCryptoWasm,\n wasmPublicKey,\n wasmSign,\n wasmVerify,\n wasmVerifySerialized,\n} from \"./abi.ts\";\nimport type { CryptoWasmExports } from \"./abi.ts\";\nimport { createWasmEventVerifier, WasmVerifyPoisonedError } from \"./adapter.ts\";\n\nexport type LoadNostrWasmOptions = {\n /** Bytes, or a URL whose bytes will be read by the platform loader. */\n module?: ArrayBuffer | ArrayBufferView | URL;\n};\n\nexport type NostrWasm = SigningBackend & {\n verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;\n verifySerialized: (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ) => boolean;\n verifyEvent: (event: Event) => boolean;\n};\n\nexport function isWasmBytes(value: unknown): value is ArrayBuffer | ArrayBufferView {\n return value instanceof ArrayBuffer || ArrayBuffer.isView(value);\n}\n\nexport async function fetchWasmUrl(url: URL): Promise<Uint8Array> {\n const res = await fetch(url);\n if (!res.ok) {\n throw new CryptoError(`failed to fetch wasm: ${res.status} ${url.href}`);\n }\n return new Uint8Array(await res.arrayBuffer());\n}\n\nfunction requireByteLength(bytes: Uint8Array, expected: number, label: string): void {\n if (bytes.length !== expected) {\n throw new CryptoError(`invalid ${label} length: expected ${expected}, got ${bytes.length}`);\n }\n}\n\nfunction wrapPoison<T>(poison: { error?: Error }, fn: () => T): T {\n if (poison.error) {\n throw poison.error;\n }\n try {\n return fn();\n } catch (error) {\n if (error instanceof WebAssembly.RuntimeError) {\n poison.error = new WasmVerifyPoisonedError(\"wasm verify aborted the instance\", {\n cause: error,\n });\n throw poison.error;\n }\n throw error;\n }\n}\n\nfunction bindExports(exports: CryptoWasmExports): NostrWasm {\n const poison: { error?: Error } = {};\n const rawSerialized = (\n serializedUtf8: Uint8Array,\n id: Uint8Array,\n pubkey: Uint8Array,\n sig: Uint8Array,\n ): boolean => wasmVerifySerialized(exports, serializedUtf8, id, pubkey, sig);\n return {\n verify: (id, pubkey, sig) => wrapPoison(poison, () => wasmVerify(exports, id, pubkey, sig)),\n verifySerialized: (serializedUtf8, id, pubkey, sig) =>\n wrapPoison(poison, () => rawSerialized(serializedUtf8, id, pubkey, sig)),\n verifyEvent: createWasmEventVerifier(rawSerialized, poison),\n sign: (id, seckey, aux) =>\n wrapPoison(poison, () => {\n requireByteLength(id, 32, \"id\");\n requireByteLength(seckey, 32, \"secret key\");\n requireByteLength(aux, 32, \"aux\");\n const sig = wasmSign(exports, id, seckey, aux);\n if (sig.length !== 64) {\n throw new CryptoError(\"wasm sign failed\");\n }\n return sig;\n }),\n publicKey: (seckey) =>\n wrapPoison(poison, () => {\n requireByteLength(seckey, 32, \"secret key\");\n const pk = wasmPublicKey(exports, seckey);\n if (pk.length !== 32) {\n throw new CryptoError(\"wasm publicKey failed\");\n }\n return pk;\n }),\n };\n}\n\n/** Builds a loader that interns a single instance per module slot. */\nexport function createNostrWasmLoader(\n wasmBytes: (opts?: LoadNostrWasmOptions) => Promise<ArrayBuffer | ArrayBufferView>,\n): {\n loadNostrWasm: (opts?: LoadNostrWasmOptions) => Promise<NostrWasm>;\n resetNostrWasm: () => void;\n} {\n let interned: Promise<NostrWasm> | undefined;\n\n async function instantiate(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n const bytes = await wasmBytes(opts);\n const exports = await instantiateCryptoWasm(bytes);\n return bindExports(exports);\n }\n\n /** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\n async function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n if (interned) {\n return interned;\n }\n const pending = instantiate(opts);\n interned = pending;\n try {\n return await pending;\n } catch (error) {\n if (interned === pending) {\n interned = undefined;\n }\n throw error;\n }\n }\n\n function resetNostrWasm(): void {\n interned = undefined;\n }\n\n return { loadNostrWasm, resetNostrWasm };\n}\n"],"mappings":"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"}
|
package/dist/loaders.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { r as OutboxBound } from "./types-2pCUprRU.mjs";
|
|
2
|
-
import { _ as ReplaceableLoader, a as OutboxFeed, c as groupAuthorsByOutboxRelay, d as bareNostrUser, f as ListLoaders, g as ReplaceableLoadResult, h as LoadStyle, i as OutboxError, l as NostrUser, m as MutedEntity, n as Loaders, o as OutboxFeedOptions, p as ListResult, r as createLoaders, s as createOutboxFeed, t as CreateLoadersOptions, u as ProfileLoader, v as EventLoader, y as EventRef } from "./index-
|
|
2
|
+
import { _ as ReplaceableLoader, a as OutboxFeed, c as groupAuthorsByOutboxRelay, d as bareNostrUser, f as ListLoaders, g as ReplaceableLoadResult, h as LoadStyle, i as OutboxError, l as NostrUser, m as MutedEntity, n as Loaders, o as OutboxFeedOptions, p as ListResult, r as createLoaders, s as createOutboxFeed, t as CreateLoadersOptions, u as ProfileLoader, v as EventLoader, y as EventRef } from "./index-lvXeER5t.mjs";
|
|
3
3
|
export { CreateLoadersOptions, type EventLoader, type EventRef, type ListLoaders, type ListResult, type LoadStyle, Loaders, type MutedEntity, type NostrUser, type OutboxBound, OutboxError, OutboxFeed, type OutboxFeedOptions, type ProfileLoader, type ReplaceableLoadResult, type ReplaceableLoader, bareNostrUser, createLoaders, createOutboxFeed, groupAuthorsByOutboxRelay };
|
|
Binary file
|
|
@@ -58,9 +58,11 @@ declare class ReactiveEventStore {
|
|
|
58
58
|
watchQuery(filters: ReadonlyArray<Filter>): Watch<ReadonlyArray<Event>>;
|
|
59
59
|
/** Synchronous listener for every physical index insert (after update). */
|
|
60
60
|
onInsert(listener: (event: Event) => void): () => void;
|
|
61
|
+
/** Synchronous listener for every physical index remove (after watch invalidation). */
|
|
62
|
+
onRemove(listener: (event: Event) => void): () => void;
|
|
61
63
|
_register(watch: WatchHandle): void;
|
|
62
64
|
_unregister(watch: WatchHandle): void;
|
|
63
65
|
}
|
|
64
66
|
//#endregion
|
|
65
67
|
export { ReactiveEventStoreOptions as n, Watch as r, ReactiveEventStore as t };
|
|
66
|
-
//# sourceMappingURL=reactive-
|
|
68
|
+
//# sourceMappingURL=reactive-7aqeip4A.d.mts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { l as normalizeURL } from "./util-LfQirgDk.mjs";
|
|
2
|
-
import { _ as formatEventAddress, g as eventAddress, o as itemCompare } from "./event-D8Nfoh4K.mjs";
|
|
2
|
+
import { _ as formatEventAddress, b as parseEventAddress, g as eventAddress, o as itemCompare } from "./event-D8Nfoh4K.mjs";
|
|
3
3
|
import { o as matchFilters, r as filterFingerprint } from "./filter-BQl3GlHt.mjs";
|
|
4
4
|
import { t as invokeSafely } from "./report-CHld4uWj.mjs";
|
|
5
5
|
import { t as MemoryIndex } from "./memory-index-Do1mz0WF.mjs";
|
|
@@ -91,11 +91,14 @@ var ReactiveEventStore = class {
|
|
|
91
91
|
#seenOn = /* @__PURE__ */ new Map();
|
|
92
92
|
#idWatches = /* @__PURE__ */ new Map();
|
|
93
93
|
#addressWatches = /* @__PURE__ */ new Map();
|
|
94
|
+
#eventCache = /* @__PURE__ */ new Map();
|
|
95
|
+
#addressCache = /* @__PURE__ */ new Map();
|
|
94
96
|
#queryCache = /* @__PURE__ */ new Map();
|
|
95
97
|
#queryRegistry = /* @__PURE__ */ new Set();
|
|
96
98
|
#dirty = /* @__PURE__ */ new Set();
|
|
97
99
|
#flushScheduled = false;
|
|
98
100
|
#insertListeners = /* @__PURE__ */ new Set();
|
|
101
|
+
#removeListeners = /* @__PURE__ */ new Set();
|
|
99
102
|
constructor(opts) {
|
|
100
103
|
this.#maxEvents = opts?.maxEvents ?? 5e4;
|
|
101
104
|
this.#maxSeenOnEntries = opts?.maxSeenOnEntries ?? 2e4;
|
|
@@ -170,11 +173,21 @@ var ReactiveEventStore = class {
|
|
|
170
173
|
}
|
|
171
174
|
watchEvent(id) {
|
|
172
175
|
const key = id.toLowerCase();
|
|
173
|
-
|
|
176
|
+
let watch = this.#eventCache.get(key);
|
|
177
|
+
if (!watch) {
|
|
178
|
+
watch = new WatchImpl(this, "event", key, () => this.get(key), sameRef, EVENT_IDS);
|
|
179
|
+
this.#eventCache.set(key, watch);
|
|
180
|
+
}
|
|
181
|
+
return watch;
|
|
174
182
|
}
|
|
175
183
|
watchReplaceable(kind, pubkey, d) {
|
|
176
184
|
const address = formatEventAddress(kind, pubkey, d ?? "");
|
|
177
|
-
|
|
185
|
+
let watch = this.#addressCache.get(address);
|
|
186
|
+
if (!watch) {
|
|
187
|
+
watch = new WatchImpl(this, "replaceable", address, () => this.getByAddress(address), sameRef, EVENT_IDS);
|
|
188
|
+
this.#addressCache.set(address, watch);
|
|
189
|
+
}
|
|
190
|
+
return watch;
|
|
178
191
|
}
|
|
179
192
|
watchQuery(filters) {
|
|
180
193
|
const key = filterFingerprint(filters);
|
|
@@ -193,6 +206,13 @@ var ReactiveEventStore = class {
|
|
|
193
206
|
this.#insertListeners.delete(listener);
|
|
194
207
|
};
|
|
195
208
|
}
|
|
209
|
+
/** Synchronous listener for every physical index remove (after watch invalidation). */
|
|
210
|
+
onRemove(listener) {
|
|
211
|
+
this.#removeListeners.add(listener);
|
|
212
|
+
return () => {
|
|
213
|
+
this.#removeListeners.delete(listener);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
196
216
|
_register(watch) {
|
|
197
217
|
switch (watch.kind) {
|
|
198
218
|
case "event":
|
|
@@ -209,9 +229,11 @@ var ReactiveEventStore = class {
|
|
|
209
229
|
switch (watch.kind) {
|
|
210
230
|
case "event":
|
|
211
231
|
removeWatch(this.#idWatches, watch.key, watch);
|
|
232
|
+
if (this.#eventCache.get(watch.key) === watch) this.#eventCache.delete(watch.key);
|
|
212
233
|
return;
|
|
213
234
|
case "replaceable":
|
|
214
235
|
removeWatch(this.#addressWatches, watch.key, watch);
|
|
236
|
+
if (this.#addressCache.get(watch.key) === watch) this.#addressCache.delete(watch.key);
|
|
215
237
|
return;
|
|
216
238
|
case "query":
|
|
217
239
|
this.#queryRegistry.delete(watch);
|
|
@@ -246,6 +268,7 @@ var ReactiveEventStore = class {
|
|
|
246
268
|
this._version += 1;
|
|
247
269
|
this.#recency.delete(event.id);
|
|
248
270
|
this.#invalidateByEvent(event);
|
|
271
|
+
for (const listener of this.#removeListeners) invokeSafely(() => listener(event));
|
|
249
272
|
}
|
|
250
273
|
#invalidateByEvent(event) {
|
|
251
274
|
const byId = this.#idWatches.get(event.id);
|
|
@@ -255,6 +278,17 @@ var ReactiveEventStore = class {
|
|
|
255
278
|
const byAddress = this.#addressWatches.get(address);
|
|
256
279
|
if (byAddress) for (const watch of byAddress) this.#markDirty(watch);
|
|
257
280
|
}
|
|
281
|
+
if (event.kind === 5) {
|
|
282
|
+
for (const tag of event.tags) if (tag[0] === "e" && tag[1] !== void 0) {
|
|
283
|
+
const watches = this.#idWatches.get(tag[1].toLowerCase());
|
|
284
|
+
if (watches) for (const watch of watches) this.#markDirty(watch);
|
|
285
|
+
} else if (tag[0] === "a" && tag[1] !== void 0) {
|
|
286
|
+
const coord = parseEventAddress(tag[1]);
|
|
287
|
+
if (coord === void 0) continue;
|
|
288
|
+
const watches = this.#addressWatches.get(formatEventAddress(coord.kind, coord.pubkey, coord.identifier));
|
|
289
|
+
if (watches) for (const watch of watches) this.#markDirty(watch);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
258
292
|
for (const watch of this.#queryRegistry) if (watch.filters !== void 0 && matchFilters(watch.filters, event)) this.#markDirty(watch);
|
|
259
293
|
}
|
|
260
294
|
#invalidateAll() {
|
|
@@ -321,4 +355,4 @@ function removeWatch(map, key, watch) {
|
|
|
321
355
|
//#endregion
|
|
322
356
|
export { ReactiveEventStore as t };
|
|
323
357
|
|
|
324
|
-
//# sourceMappingURL=reactive-
|
|
358
|
+
//# sourceMappingURL=reactive-BfhPp9a3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reactive-BfhPp9a3.mjs","names":[],"sources":["../src/store/reactive.ts"],"sourcesContent":["import { itemCompare } from \"../core/event.ts\";\nimport type { Event } from \"../core/event.ts\";\nimport type { Filter } from \"../core/filter.ts\";\nimport { filterFingerprint, matchFilters } from \"../core/filter.ts\";\nimport { invokeSafely } from \"../core/report.ts\";\nimport { formatEventAddress, eventAddress, parseEventAddress } from \"../core/tag.ts\";\nimport { normalizeURL } from \"../core/util.ts\";\nimport { MemoryIndex } from \"../storage/memory-index.ts\";\nimport type { PutResult } from \"../storage/types.ts\";\n\n/** A reactive snapshot source compatible with `useSyncExternalStore`. */\nexport type Watch<T> = {\n subscribe: (onChange: () => void) => () => void;\n getSnapshot: () => T;\n};\n\n/** Capacity options for {@link ReactiveEventStore}. */\nexport type ReactiveEventStoreOptions = {\n /** Max stored events before LRU eviction. Default 50_000. */\n maxEvents?: number;\n /** Max ids tracked by `seenOn`. Default 20_000. */\n maxSeenOnEntries?: number;\n /** FIFO cap on tombstoned deletion ids. Default 100_000. */\n maxTombstones?: number;\n};\n\nconst SEEN_ON_PER_ID = 16;\n\n/** Category of a {@link Watch} subscription. */\ntype WatchKind = \"event\" | \"replaceable\" | \"query\";\n\n/** Structural handle the store needs for invalidation; implemented by WatchImpl. */\ntype WatchHandle = {\n readonly kind: WatchKind;\n readonly key: string;\n readonly filters: ReadonlyArray<Filter> | undefined;\n readonly subscribed: boolean;\n readonly pinnedIds: ReadonlyArray<string>;\n _markDirty: () => void;\n _notify: () => void;\n};\n\nclass WatchImpl<T> implements Watch<T>, WatchHandle {\n readonly store: ReactiveEventStore;\n readonly kind: WatchKind;\n readonly key: string;\n readonly filters: ReadonlyArray<Filter> | undefined;\n readonly compute: () => T;\n readonly equal: (a: T, b: T) => boolean;\n readonly snapshotIds: (snapshot: T) => ReadonlyArray<string>;\n readonly #subscribers = new Set<() => void>();\n #snapshot: T;\n #version = -1;\n #dirty = false;\n #pendingRemove = false;\n\n constructor(\n store: ReactiveEventStore,\n kind: WatchKind,\n key: string,\n compute: () => T,\n equal: (a: T, b: T) => boolean,\n snapshotIds: (snapshot: T) => ReadonlyArray<string>,\n filters?: ReadonlyArray<Filter>,\n ) {\n this.store = store;\n this.kind = kind;\n this.key = key;\n this.filters = filters;\n this.compute = compute;\n this.equal = equal;\n this.snapshotIds = snapshotIds;\n this.#snapshot = compute();\n this.#version = store._version;\n }\n\n get subscribed(): boolean {\n return this.#subscribers.size > 0;\n }\n\n get pinnedIds(): ReadonlyArray<string> {\n return this.snapshotIds(this.#snapshot);\n }\n\n subscribe(onChange: () => void): () => void {\n const wasUnsubscribed = this.#subscribers.size === 0;\n this.#subscribers.add(onChange);\n this.#pendingRemove = false;\n // Writes that landed while unregistered must not be lost.\n if (wasUnsubscribed && this.#version !== this.store._version) {\n this.#dirty = true;\n }\n this.store._register(this);\n return () => {\n this.#subscribers.delete(onChange);\n if (this.#subscribers.size > 0 || this.#pendingRemove) {\n return;\n }\n this.#pendingRemove = true;\n queueMicrotask(() => {\n if (this.#pendingRemove) {\n this.store._unregister(this);\n }\n });\n };\n }\n\n getSnapshot(): T {\n if (this.subscribed ? this.#dirty : this.#version !== this.store._version) {\n const next = this.compute();\n if (!this.equal(next, this.#snapshot)) {\n this.#snapshot = next;\n }\n this.#version = this.store._version;\n this.#dirty = false;\n }\n return this.#snapshot;\n }\n\n _markDirty(): void {\n this.#dirty = true;\n }\n\n _notify(): void {\n // Do not sync #version here: subscribers will call getSnapshot, which\n // recomputes against the bumped store version and keeps the reference\n // when the result is element-wise identical. A throwing subscriber is\n // reported and never aborts the remaining notifications.\n for (const onChange of this.#subscribers) {\n invokeSafely(onChange);\n }\n }\n}\n\nconst EVENT_IDS = (e: Event | undefined): ReadonlyArray<string> => (e ? [e.id] : []);\nconst LIST_IDS = (events: ReadonlyArray<Event>): ReadonlyArray<string> => events.map((e) => e.id);\n\nfunction sameRef(a: Event | undefined, b: Event | undefined): boolean {\n return a === b;\n}\n\nfunction sameList(a: ReadonlyArray<Event>, b: ReadonlyArray<Event>): boolean {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Synchronous reactive in-memory event store backed by {@link MemoryIndex}. The single read source\n * for Nostr events on the UI side: `Watch` snapshots keep referential stability for\n * `useSyncExternalStore` and are invalidated on matching writes, deletions and tombstones. Writes\n * batch notifications into one microtask flush.\n */\nexport class ReactiveEventStore {\n readonly #index: MemoryIndex;\n readonly #maxEvents: number;\n readonly #maxSeenOnEntries: number;\n\n _version = 0;\n\n // id -> recency-ordered access order (delete+add moves to the newest end)\n readonly #recency = new Set<string>();\n // id -> relay urls (≤ SEEN_ON_PER_ID); Map insertion order for eviction\n readonly #seenOn = new Map<string, string[]>();\n\n readonly #idWatches = new Map<string, Set<WatchHandle>>();\n readonly #addressWatches = new Map<string, Set<WatchHandle>>();\n readonly #eventCache = new Map<string, WatchImpl<Event | undefined>>();\n readonly #addressCache = new Map<string, WatchImpl<Event | undefined>>();\n readonly #queryCache = new Map<string, WatchImpl<ReadonlyArray<Event>>>();\n readonly #queryRegistry = new Set<WatchHandle>();\n\n readonly #dirty = new Set<WatchHandle>();\n #flushScheduled = false;\n readonly #insertListeners = new Set<(event: Event) => void>();\n readonly #removeListeners = new Set<(event: Event) => void>();\n\n constructor(opts?: ReactiveEventStoreOptions) {\n this.#maxEvents = opts?.maxEvents ?? 50_000;\n this.#maxSeenOnEntries = opts?.maxSeenOnEntries ?? 20_000;\n this.#index = new MemoryIndex({\n maxTombstones: opts?.maxTombstones ?? 100_000,\n // Keep evicted replaceable winners rejectable while their body is gone.\n maxWatermarks: this.#maxEvents,\n onInsert: (event) => this.#onInsert(event),\n onRemove: (event) => this.#onRemove(event),\n });\n }\n\n add(event: Event, relayUrl?: string): PutResult {\n const result = this.#index.put(event);\n // Stored events are canonical; seenOn keys are their lowercase ids.\n const { id } = event;\n if (\n relayUrl !== undefined &&\n result !== \"ephemeral\" &&\n result !== \"rejected\" &&\n result !== \"invalid\"\n ) {\n this.#recordSeen(id, relayUrl);\n }\n // The just-inserted event must survive its own eviction pass even when\n // every older entry is pinned by a subscribed watch snapshot.\n this.#evictIfNeeded(id);\n return result;\n }\n\n addMany(events: ReadonlyArray<Event>, relayUrl?: string): PutResult[] {\n const results: PutResult[] = [];\n for (const event of events) {\n results.push(this.add(event, relayUrl));\n }\n return results;\n }\n\n /** Record a relay sighting for an id already in the index. No notification. */\n markSeen(id: string, relayUrl: string): boolean {\n const key = id.toLowerCase();\n if (this.#index.get(key) === undefined) {\n return false;\n }\n this.#recordSeen(key, relayUrl);\n return true;\n }\n\n /** Bulk load (initial hydration): no seenOn, one batched notification. */\n hydrate(events: ReadonlyArray<Event>): void {\n // Insert oldest-first so recency ends with the newest entries hottest.\n const sorted = [...events].sort(itemCompare);\n for (const event of sorted) {\n this.#index.put(event);\n }\n this.#evictIfNeeded();\n }\n\n remove(ids: ReadonlyArray<string>): number {\n return this.#index.remove(ids);\n }\n\n clear(): void {\n this.#index.clear();\n this.#seenOn.clear();\n this.#recency.clear();\n this._version += 1;\n this.#invalidateAll();\n }\n\n get(id: string): Event | undefined {\n const event = this.#index.get(id);\n if (event) {\n this.#touch(event.id);\n }\n return event;\n }\n\n getReplaceable(kind: number, pubkey: string, d?: string): Event | undefined {\n return this.getByAddress(formatEventAddress(kind, pubkey, d ?? \"\"));\n }\n\n getByAddress(address: string): Event | undefined {\n const event = this.#index.getByAddress(address);\n if (event) {\n this.#touch(event.id);\n }\n return event;\n }\n\n query(filters: ReadonlyArray<Filter>): ReadonlyArray<Event> {\n const events = this.#index.query(filters);\n // Results come back newest-first; touch oldest→newest so the newest\n // entries end up hottest in the recency order.\n for (const event of [...events].reverse()) {\n this.#touch(event.id);\n }\n return events;\n }\n\n isDeleted(idOrAddress: string): boolean {\n return this.#index.isDeleted(idOrAddress);\n }\n\n seenOn(id: string): ReadonlyArray<string> {\n return this.#seenOn.get(id.toLowerCase()) ?? [];\n }\n\n get size(): number {\n return this.#index.size;\n }\n\n watchEvent(id: string): Watch<Event | undefined> {\n const key = id.toLowerCase();\n let watch = this.#eventCache.get(key);\n if (!watch) {\n watch = new WatchImpl(this, \"event\", key, () => this.get(key), sameRef, EVENT_IDS);\n this.#eventCache.set(key, watch);\n }\n return watch;\n }\n\n watchReplaceable(kind: number, pubkey: string, d?: string): Watch<Event | undefined> {\n const address = formatEventAddress(kind, pubkey, d ?? \"\");\n let watch = this.#addressCache.get(address);\n if (!watch) {\n watch = new WatchImpl(\n this,\n \"replaceable\",\n address,\n () => this.getByAddress(address),\n sameRef,\n EVENT_IDS,\n );\n this.#addressCache.set(address, watch);\n }\n return watch;\n }\n\n watchQuery(filters: ReadonlyArray<Filter>): Watch<ReadonlyArray<Event>> {\n const key = filterFingerprint(filters);\n let watch = this.#queryCache.get(key);\n if (!watch) {\n const list = [...filters];\n watch = new WatchImpl(this, \"query\", key, () => this.query(list), sameList, LIST_IDS, list);\n this.#queryCache.set(key, watch);\n }\n return watch;\n }\n\n /** Synchronous listener for every physical index insert (after update). */\n onInsert(listener: (event: Event) => void): () => void {\n this.#insertListeners.add(listener);\n return () => {\n this.#insertListeners.delete(listener);\n };\n }\n\n /** Synchronous listener for every physical index remove (after watch invalidation). */\n onRemove(listener: (event: Event) => void): () => void {\n this.#removeListeners.add(listener);\n return () => {\n this.#removeListeners.delete(listener);\n };\n }\n\n _register(watch: WatchHandle): void {\n switch (watch.kind) {\n case \"event\":\n addWatch(this.#idWatches, watch.key, watch);\n return;\n case \"replaceable\":\n addWatch(this.#addressWatches, watch.key, watch);\n return;\n case \"query\":\n this.#queryRegistry.add(watch);\n }\n }\n\n _unregister(watch: WatchHandle): void {\n if (watch.subscribed) {\n return;\n }\n switch (watch.kind) {\n case \"event\":\n removeWatch(this.#idWatches, watch.key, watch);\n if (this.#eventCache.get(watch.key) === watch) {\n this.#eventCache.delete(watch.key);\n }\n return;\n case \"replaceable\":\n removeWatch(this.#addressWatches, watch.key, watch);\n if (this.#addressCache.get(watch.key) === watch) {\n this.#addressCache.delete(watch.key);\n }\n return;\n case \"query\":\n this.#queryRegistry.delete(watch);\n if (this.#queryCache.get(watch.key) === watch) {\n this.#queryCache.delete(watch.key);\n }\n }\n }\n\n #touch(id: string): void {\n if (this.#recency.delete(id)) {\n this.#recency.add(id);\n } else {\n this.#recency.add(id);\n }\n }\n\n #recordSeen(id: string, relayUrl: string): void {\n const url = normalizeURL(relayUrl);\n let urls = this.#seenOn.get(id);\n if (!urls) {\n urls = [];\n this.#seenOn.set(id, urls);\n }\n if (!urls.includes(url) && urls.length < SEEN_ON_PER_ID) {\n urls.push(url);\n }\n while (this.#seenOn.size > this.#maxSeenOnEntries) {\n const oldest = this.#seenOn.keys().next().value;\n if (oldest === undefined) {\n break;\n }\n this.#seenOn.delete(oldest);\n }\n }\n\n #onInsert(event: Event): void {\n this._version += 1;\n this.#touch(event.id);\n this.#invalidateByEvent(event);\n for (const listener of this.#insertListeners) {\n invokeSafely(() => listener(event));\n }\n }\n\n #onRemove(event: Event): void {\n this._version += 1;\n this.#recency.delete(event.id);\n this.#invalidateByEvent(event);\n for (const listener of this.#removeListeners) {\n invokeSafely(() => listener(event));\n }\n }\n\n #invalidateByEvent(event: Event): void {\n const byId = this.#idWatches.get(event.id);\n if (byId) {\n for (const watch of byId) {\n this.#markDirty(watch);\n }\n }\n const address = eventAddress(event);\n if (address !== undefined) {\n const byAddress = this.#addressWatches.get(address);\n if (byAddress) {\n for (const watch of byAddress) {\n this.#markDirty(watch);\n }\n }\n }\n // A kind-5 deletion marks its targets tombstoned even when they are not in\n // the index, so nothing else invalidates a watch keyed on the target.\n if (event.kind === 5) {\n for (const tag of event.tags) {\n if (tag[0] === \"e\" && tag[1] !== undefined) {\n const watches = this.#idWatches.get(tag[1].toLowerCase());\n if (watches) {\n for (const watch of watches) {\n this.#markDirty(watch);\n }\n }\n } else if (tag[0] === \"a\" && tag[1] !== undefined) {\n const coord = parseEventAddress(tag[1]);\n if (coord === undefined) {\n continue;\n }\n const watches = this.#addressWatches.get(\n formatEventAddress(coord.kind, coord.pubkey, coord.identifier),\n );\n if (watches) {\n for (const watch of watches) {\n this.#markDirty(watch);\n }\n }\n }\n }\n }\n for (const watch of this.#queryRegistry) {\n if (watch.filters !== undefined && matchFilters(watch.filters, event)) {\n this.#markDirty(watch);\n }\n }\n }\n\n #invalidateAll(): void {\n for (const watches of this.#idWatches.values()) {\n for (const watch of watches) {\n this.#markDirty(watch);\n }\n }\n for (const watches of this.#addressWatches.values()) {\n for (const watch of watches) {\n this.#markDirty(watch);\n }\n }\n for (const watch of this.#queryRegistry) {\n this.#markDirty(watch);\n }\n this.#scheduleFlush();\n }\n\n #markDirty(watch: WatchHandle): void {\n watch._markDirty();\n this.#dirty.add(watch);\n this.#scheduleFlush();\n }\n\n #scheduleFlush(): void {\n if (this.#flushScheduled) {\n return;\n }\n this.#flushScheduled = true;\n queueMicrotask(() => {\n // Keep the flag set while flushing: writes re-entered from a\n // subscriber land in #dirty and are notified in the same pass.\n while (this.#dirty.size > 0) {\n const batch = [...this.#dirty];\n this.#dirty.clear();\n for (const watch of batch) {\n watch._notify();\n }\n }\n this.#flushScheduled = false;\n });\n }\n\n #pinnedIds(): Set<string> {\n const pinned = new Set<string>();\n const collect = (watch: WatchHandle): void => {\n for (const id of watch.pinnedIds) {\n pinned.add(id);\n }\n };\n for (const watches of this.#idWatches.values()) {\n for (const watch of watches) {\n collect(watch);\n }\n }\n for (const watches of this.#addressWatches.values()) {\n for (const watch of watches) {\n collect(watch);\n }\n }\n for (const watch of this.#queryRegistry) {\n collect(watch);\n }\n return pinned;\n }\n\n #evictIfNeeded(protectedId?: string): void {\n if (this.#index.size <= this.#maxEvents) {\n return;\n }\n const pinned = this.#pinnedIds();\n const evicting: string[] = [];\n for (const id of this.#recency) {\n if (this.#index.size - evicting.length <= this.#maxEvents) {\n break;\n }\n if (pinned.has(id) || id === protectedId) {\n continue;\n }\n const event = this.#index.get(id);\n if (event === undefined) {\n continue;\n }\n // Replaceable/addressable winners evict like any other event; the index\n // records a watermark so stale versions stay rejected afterwards.\n evicting.push(id);\n }\n this.#index.evict(evicting);\n for (const id of evicting) {\n this.#recency.delete(id);\n }\n }\n}\n\nfunction addWatch(map: Map<string, Set<WatchHandle>>, key: string, watch: WatchHandle): void {\n let set = map.get(key);\n if (!set) {\n set = new Set();\n map.set(key, set);\n }\n set.add(watch);\n}\n\nfunction removeWatch(map: Map<string, Set<WatchHandle>>, key: string, watch: WatchHandle): void {\n const set = map.get(key);\n if (!set) {\n return;\n }\n set.delete(watch);\n if (set.size === 0) {\n map.delete(key);\n }\n}\n"],"mappings":"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"}
|
package/dist/store.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as ReactiveEventStoreOptions, r as Watch, t as ReactiveEventStore } from "./reactive-
|
|
1
|
+
import { n as ReactiveEventStoreOptions, r as Watch, t as ReactiveEventStore } from "./reactive-7aqeip4A.mjs";
|
|
2
2
|
export { ReactiveEventStore, type ReactiveEventStoreOptions, type Watch };
|
package/dist/store.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as ReactiveEventStore } from "./reactive-
|
|
1
|
+
import { t as ReactiveEventStore } from "./reactive-BfhPp9a3.mjs";
|
|
2
2
|
export { ReactiveEventStore };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { s as WasmVerifyPoisonedError } from "./error-CR8Urc84.mjs";
|
|
2
|
+
import { n as NostrWasm, t as LoadNostrWasmOptions } from "./instance-CIca-ynn.mjs";
|
|
3
|
+
//#region src/wasm/load.browser.d.ts
|
|
4
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
5
|
+
export declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { type LoadNostrWasmOptions, type NostrWasm, WasmVerifyPoisonedError };
|
|
8
|
+
//# sourceMappingURL=wasm.browser.d.mts.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { f as CryptoError, v as WasmVerifyPoisonedError } from "./util-LfQirgDk.mjs";
|
|
2
|
+
import { n as fetchWasmUrl, r as isWasmBytes, t as createNostrWasmLoader } from "./instance-DQE8BoWt.mjs";
|
|
3
|
+
//#region src/wasm/load.browser.ts
|
|
4
|
+
async function wasmBytes(opts) {
|
|
5
|
+
const source = opts?.module;
|
|
6
|
+
if (source !== void 0 && isWasmBytes(source)) return source;
|
|
7
|
+
if (source instanceof URL && source.protocol !== "file:") return fetchWasmUrl(source);
|
|
8
|
+
if (source instanceof URL) throw new CryptoError(`cannot fetch wasm from ${source.href}`);
|
|
9
|
+
return fetchWasmUrl(new URL("nostr_crypto_wasm_bg.wasm", import.meta.url));
|
|
10
|
+
}
|
|
11
|
+
const loader = createNostrWasmLoader(wasmBytes);
|
|
12
|
+
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
13
|
+
async function loadNostrWasm(opts) {
|
|
14
|
+
return loader.loadNostrWasm(opts);
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { WasmVerifyPoisonedError, loadNostrWasm };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=wasm.browser.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wasm.browser.mjs","names":[],"sources":["../src/wasm/load.browser.ts"],"sourcesContent":["import { CryptoError } from \"../core/error.ts\";\nimport { createNostrWasmLoader, fetchWasmUrl, isWasmBytes } from \"./instance.ts\";\nimport type { LoadNostrWasmOptions, NostrWasm } from \"./instance.ts\";\n\nexport type { LoadNostrWasmOptions, NostrWasm } from \"./instance.ts\";\n\nasync function wasmBytes(opts?: LoadNostrWasmOptions): Promise<ArrayBuffer | ArrayBufferView> {\n const source = opts?.module;\n if (source !== undefined && isWasmBytes(source)) {\n return source;\n }\n if (source instanceof URL && source.protocol !== \"file:\") {\n return fetchWasmUrl(source);\n }\n if (source instanceof URL) {\n throw new CryptoError(`cannot fetch wasm from ${source.href}`);\n }\n return fetchWasmUrl(new URL(\"nostr_crypto_wasm_bg.wasm\", import.meta.url));\n}\n\nconst loader = createNostrWasmLoader(wasmBytes);\n\n/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */\nexport async function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm> {\n return loader.loadNostrWasm(opts);\n}\n"],"mappings":";;;AAMA,eAAe,UAAU,MAAqE;CAC5F,MAAM,SAAS,MAAM;CACrB,IAAI,WAAW,KAAA,KAAa,YAAY,MAAM,GAC5C,OAAO;CAET,IAAI,kBAAkB,OAAO,OAAO,aAAa,SAC/C,OAAO,aAAa,MAAM;CAE5B,IAAI,kBAAkB,KACpB,MAAM,IAAI,YAAY,0BAA0B,OAAO,MAAM;CAE/D,OAAO,aAAa,IAAI,IAAI,6BAA6B,YAAY,GAAG,CAAC;AAC3E;AAEA,MAAM,SAAS,sBAAsB,SAAS;;AAG9C,eAAsB,cAAc,MAAiD;CACnF,OAAO,OAAO,cAAc,IAAI;AAClC"}
|
package/dist/wasm.d.mts
CHANGED
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
import { t as Event } from "./event-fU3Y01PR.mjs";
|
|
2
|
-
import { i as SigningBackend } from "./key-Cv4_pN3x.mjs";
|
|
3
1
|
import { s as WasmVerifyPoisonedError } from "./error-CR8Urc84.mjs";
|
|
2
|
+
import { n as NostrWasm, t as LoadNostrWasmOptions } from "./instance-CIca-ynn.mjs";
|
|
4
3
|
//#region src/wasm/load.d.ts
|
|
5
|
-
type LoadNostrWasmOptions = {
|
|
6
|
-
/** Bytes, or a URL whose bytes will be read (Node fs for file:; fetch otherwise). */
|
|
7
|
-
module?: ArrayBuffer | ArrayBufferView | URL;
|
|
8
|
-
};
|
|
9
|
-
type NostrWasm = SigningBackend & {
|
|
10
|
-
verify: (id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
11
|
-
verifySerialized: (serializedUtf8: Uint8Array, id: Uint8Array, pubkey: Uint8Array, sig: Uint8Array) => boolean;
|
|
12
|
-
verifyEvent: (event: Event) => boolean;
|
|
13
|
-
};
|
|
14
4
|
/** Instantiate once. Repeats reuse the same module. Failure throws; no noble fallback. */
|
|
15
5
|
export declare function loadNostrWasm(opts?: LoadNostrWasmOptions): Promise<NostrWasm>;
|
|
16
6
|
//#endregion
|