@qntx/nostr 0.4.1 → 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-C6EultPx.mjs → client-CadO5fAX.mjs} +33 -3
- package/dist/client-CadO5fAX.mjs.map +1 -0
- package/dist/client.d.mts +2 -2
- package/dist/client.mjs +1 -1
- package/dist/{index-BP4UmZKF.d.mts → index-CNl2q67H.d.mts} +20 -5
- package/dist/{index-skvsYz00.d.mts → index-lvXeER5t.d.mts} +3 -3
- package/dist/{index-D-TK_KJG.d.mts → index-q4MDce_r.d.mts} +2 -2
- package/dist/index.d.mts +6 -6
- package/dist/index.mjs +3 -3
- 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/{pool-BGVx59yd.mjs → pool-As20OGxB.mjs} +95 -34
- package/dist/pool-As20OGxB.mjs.map +1 -0
- package/dist/{pool-B7p_reAm.d.mts → pool-DBIYMtwy.d.mts} +42 -4
- 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/relay.d.mts +3 -3
- package/dist/relay.mjs +1 -1
- 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/client-C6EultPx.mjs.map +0 -1
- package/dist/pool-BGVx59yd.mjs.map +0 -1
- 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
|
|
@@ -441,11 +441,14 @@ function openExclusive(ctx, filters, opts) {
|
|
|
441
441
|
function subscribeLive(ctx, filters, opts) {
|
|
442
442
|
const fp = filterFingerprint(filters);
|
|
443
443
|
let group = ctx.liveByFp.get(fp);
|
|
444
|
+
if (group?.sub.eosed === true) group = void 0;
|
|
444
445
|
let created = false;
|
|
445
446
|
if (!group) {
|
|
446
447
|
created = true;
|
|
448
|
+
const slot = { group: void 0 };
|
|
447
449
|
const wire = new Subscription(filters, { id: opts.id }, () => {
|
|
448
|
-
|
|
450
|
+
const g = slot.group;
|
|
451
|
+
if (g) endLiveGroup(ctx, g, {
|
|
449
452
|
sendClose: true,
|
|
450
453
|
reason: "closed by client"
|
|
451
454
|
});
|
|
@@ -455,18 +458,20 @@ function subscribeLive(ctx, filters, opts) {
|
|
|
455
458
|
sub: wire,
|
|
456
459
|
attachments: /* @__PURE__ */ new Set()
|
|
457
460
|
};
|
|
461
|
+
slot.group = group;
|
|
458
462
|
ctx.liveByFp.set(fp, group);
|
|
459
463
|
ctx.liveBySubId.set(wire.id, group);
|
|
460
464
|
ctx.subs.set(wire.id, wire);
|
|
461
465
|
}
|
|
462
466
|
const slot = { handle: void 0 };
|
|
467
|
+
const attached = group;
|
|
463
468
|
const handle = new Subscription(filters, {
|
|
464
469
|
...opts,
|
|
465
470
|
id: group.sub.id
|
|
466
471
|
}, () => {
|
|
467
472
|
const current = slot.handle;
|
|
468
473
|
if (!current) return;
|
|
469
|
-
detachLive(ctx,
|
|
474
|
+
detachLive(ctx, attached, current);
|
|
470
475
|
});
|
|
471
476
|
slot.handle = handle;
|
|
472
477
|
if (handle.closed) {
|
|
@@ -483,32 +488,23 @@ function subscribeLive(ctx, filters, opts) {
|
|
|
483
488
|
else if (ctx.enableReconnect()) ctx.scheduleReconnect();
|
|
484
489
|
}
|
|
485
490
|
if (opts.eoseTimeoutMs !== void 0) ctx.armEoseTimeout(handle, opts.eoseTimeoutMs);
|
|
486
|
-
if (group.sub.eosed) queueMicrotask(() => {
|
|
487
|
-
if (handle.closed || handle.eosed) return;
|
|
488
|
-
handle.eosed = true;
|
|
489
|
-
invokeSafely(() => handle.handlers.oneose?.());
|
|
490
|
-
});
|
|
491
491
|
return handle;
|
|
492
492
|
}
|
|
493
493
|
function forgetLiveGroup(ctx, group) {
|
|
494
|
-
ctx.liveByFp.delete(group.fp);
|
|
494
|
+
if (ctx.liveByFp.get(group.fp) === group) ctx.liveByFp.delete(group.fp);
|
|
495
495
|
ctx.liveBySubId.delete(group.sub.id);
|
|
496
496
|
ctx.subs.delete(group.sub.id);
|
|
497
497
|
group.sub.closed = true;
|
|
498
498
|
}
|
|
499
|
-
function detachLive(ctx,
|
|
500
|
-
const group = ctx.liveByFp.get(fp);
|
|
501
|
-
if (!group) return;
|
|
499
|
+
function detachLive(ctx, group, handle) {
|
|
502
500
|
if (!group.attachments.delete(handle)) return;
|
|
503
501
|
if (group.attachments.size > 0) return;
|
|
504
|
-
endLiveGroup(ctx,
|
|
502
|
+
endLiveGroup(ctx, group, {
|
|
505
503
|
sendClose: true,
|
|
506
504
|
reason: "closed by client"
|
|
507
505
|
});
|
|
508
506
|
}
|
|
509
|
-
function endLiveGroup(ctx,
|
|
510
|
-
const group = ctx.liveByFp.get(fp);
|
|
511
|
-
if (!group) return;
|
|
507
|
+
function endLiveGroup(ctx, group, opts) {
|
|
512
508
|
const { id } = group.sub;
|
|
513
509
|
const remaining = [...group.attachments];
|
|
514
510
|
group.attachments.clear();
|
|
@@ -555,9 +551,9 @@ function deliverLiveEose(group) {
|
|
|
555
551
|
}
|
|
556
552
|
}
|
|
557
553
|
function closeAllSubscriptions(ctx, reason) {
|
|
558
|
-
const
|
|
559
|
-
for (const
|
|
560
|
-
endLiveGroup(ctx,
|
|
554
|
+
const groups = [...ctx.liveBySubId.values()];
|
|
555
|
+
for (const group of groups) invokeSafely(() => {
|
|
556
|
+
endLiveGroup(ctx, group, {
|
|
561
557
|
sendClose: false,
|
|
562
558
|
reason
|
|
563
559
|
});
|
|
@@ -575,7 +571,7 @@ function closeAllSubscriptions(ctx, reason) {
|
|
|
575
571
|
function dropSubscription(ctx, sub, reason) {
|
|
576
572
|
const group = ctx.liveBySubId.get(sub.id);
|
|
577
573
|
if (group) {
|
|
578
|
-
endLiveGroup(ctx, group
|
|
574
|
+
endLiveGroup(ctx, group, {
|
|
579
575
|
sendClose: false,
|
|
580
576
|
reason
|
|
581
577
|
});
|
|
@@ -654,6 +650,7 @@ async function fetchFilters(subscribe, filters, opts) {
|
|
|
654
650
|
throwIfAborted(opts.signal);
|
|
655
651
|
const events = [];
|
|
656
652
|
const seen = /* @__PURE__ */ new Set();
|
|
653
|
+
let end = { type: "timeout" };
|
|
657
654
|
await new Promise((resolve, reject) => {
|
|
658
655
|
let settled = false;
|
|
659
656
|
const done = (err) => {
|
|
@@ -667,7 +664,10 @@ async function fetchFilters(subscribe, filters, opts) {
|
|
|
667
664
|
if (err === void 0) resolve();
|
|
668
665
|
else reject(err);
|
|
669
666
|
};
|
|
670
|
-
const timer = setTimeout(() =>
|
|
667
|
+
const timer = setTimeout(() => {
|
|
668
|
+
end = { type: "timeout" };
|
|
669
|
+
done();
|
|
670
|
+
}, opts.timeoutMs);
|
|
671
671
|
const sub = subscribe(filters, {
|
|
672
672
|
id: opts.id,
|
|
673
673
|
signal: opts.signal,
|
|
@@ -678,15 +678,28 @@ async function fetchFilters(subscribe, filters, opts) {
|
|
|
678
678
|
events.push(event);
|
|
679
679
|
},
|
|
680
680
|
oneose() {
|
|
681
|
+
end = { type: "eose" };
|
|
681
682
|
done();
|
|
682
683
|
},
|
|
683
|
-
onclose() {
|
|
684
|
-
if (
|
|
684
|
+
onclose(reason) {
|
|
685
|
+
if (settled) return;
|
|
686
|
+
if (opts.signal?.aborted === true) {
|
|
687
|
+
done(abortReason(opts.signal));
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
end = {
|
|
691
|
+
type: "closed",
|
|
692
|
+
reason
|
|
693
|
+
};
|
|
694
|
+
done();
|
|
685
695
|
}
|
|
686
696
|
});
|
|
687
697
|
opts.signal?.addEventListener("abort", () => done(opts.signal ? abortReason(opts.signal) : void 0), { once: true });
|
|
688
698
|
});
|
|
689
|
-
return
|
|
699
|
+
return {
|
|
700
|
+
events,
|
|
701
|
+
end
|
|
702
|
+
};
|
|
690
703
|
}
|
|
691
704
|
function armEoseTimeout(sub, eoseTimeoutMs) {
|
|
692
705
|
const timer = setTimeout(() => {
|
|
@@ -1264,7 +1277,11 @@ var Relay = class Relay {
|
|
|
1264
1277
|
stream(filters, opts) {
|
|
1265
1278
|
return streamFilters((f, o) => this.subscribe(f, o), filters, opts);
|
|
1266
1279
|
}
|
|
1267
|
-
/**
|
|
1280
|
+
/**
|
|
1281
|
+
* One-shot query: collect events until the REQ ends, then close. `end` reports how it ended —
|
|
1282
|
+
* relay `EOSE`, relay `CLOSED` (with its reason), or the local timeout; events received before a
|
|
1283
|
+
* CLOSED or the deadline are still returned. Abort rejects; a failed (re)connect rejects.
|
|
1284
|
+
*/
|
|
1268
1285
|
async fetch(filters, opts) {
|
|
1269
1286
|
if (filters.length === 0) throw new MessageError("REQ requires at least one filter");
|
|
1270
1287
|
const canonical = canonicalizeFilters(filters);
|
|
@@ -1272,8 +1289,7 @@ var Relay = class Relay {
|
|
|
1272
1289
|
return fetchFilters((f, o) => this.subscribe(f, o), canonical, {
|
|
1273
1290
|
timeoutMs: opts?.timeoutMs ?? 4400,
|
|
1274
1291
|
signal: opts?.signal,
|
|
1275
|
-
id: opts?.id
|
|
1276
|
-
url: this.url
|
|
1292
|
+
id: opts?.id
|
|
1277
1293
|
});
|
|
1278
1294
|
}
|
|
1279
1295
|
/** Publish an event and wait for OK. */
|
|
@@ -1596,6 +1612,7 @@ function fanIn(pool, jobs, opts = {}) {
|
|
|
1596
1612
|
const closers = [];
|
|
1597
1613
|
let closed = false;
|
|
1598
1614
|
let eoseFired = false;
|
|
1615
|
+
let sawEose = false;
|
|
1599
1616
|
let eoseTimer;
|
|
1600
1617
|
const eoseDone = /* @__PURE__ */ new Set();
|
|
1601
1618
|
const eoseAttempted = /* @__PURE__ */ new Set();
|
|
@@ -1610,12 +1627,18 @@ function fanIn(pool, jobs, opts = {}) {
|
|
|
1610
1627
|
}
|
|
1611
1628
|
invokeSafely(() => opts.oneose?.());
|
|
1612
1629
|
};
|
|
1613
|
-
|
|
1630
|
+
/**
|
|
1631
|
+
* Remove one relay from the pending-EOSE set. `eosed` credits a real EOSE; a CLOSED or a connect
|
|
1632
|
+
* failure only drops the wait — the aggregate `oneose` fires once every remaining relay ended AND
|
|
1633
|
+
* at least one actually EOSE'd.
|
|
1634
|
+
*/
|
|
1635
|
+
const settleEose = (jobIndex, url, eosed) => {
|
|
1614
1636
|
const key = `${jobIndex}:${url}`;
|
|
1615
1637
|
if (eoseDone.has(key)) return;
|
|
1616
1638
|
eoseDone.add(key);
|
|
1639
|
+
if (eosed) sawEose = true;
|
|
1617
1640
|
pendingEose -= 1;
|
|
1618
|
-
if (pendingEose === 0) fireEose();
|
|
1641
|
+
if (pendingEose === 0 && sawEose) fireEose();
|
|
1619
1642
|
};
|
|
1620
1643
|
const settleClose = () => {
|
|
1621
1644
|
closed = true;
|
|
@@ -1637,7 +1660,7 @@ function fanIn(pool, jobs, opts = {}) {
|
|
|
1637
1660
|
}
|
|
1638
1661
|
opts.signal?.addEventListener("abort", () => closeAll("aborted"), { once: true });
|
|
1639
1662
|
const failUrl = (jobIndex, key) => {
|
|
1640
|
-
|
|
1663
|
+
settleEose(jobIndex, key, false);
|
|
1641
1664
|
pending -= 1;
|
|
1642
1665
|
if (pending <= 0 && closers.length === 0 && !closed) {
|
|
1643
1666
|
settleClose();
|
|
@@ -1662,9 +1685,9 @@ function fanIn(pool, jobs, opts = {}) {
|
|
|
1662
1685
|
seen.add(event.id);
|
|
1663
1686
|
invokeSafely(() => opts.onevent?.(event, relay.url));
|
|
1664
1687
|
},
|
|
1665
|
-
oneose: () =>
|
|
1688
|
+
oneose: () => settleEose(jobIndex, relay.url, true),
|
|
1666
1689
|
onclose: (reason) => {
|
|
1667
|
-
|
|
1690
|
+
settleEose(jobIndex, relay.url, false);
|
|
1668
1691
|
pending -= 1;
|
|
1669
1692
|
if (pending <= 0 && !closed) {
|
|
1670
1693
|
settleClose();
|
|
@@ -1756,10 +1779,10 @@ async function fetchRouted(pool, jobs, opts = {}) {
|
|
|
1756
1779
|
timeoutMs: opts.connectTimeoutMs
|
|
1757
1780
|
});
|
|
1758
1781
|
relayUrl = relay.url;
|
|
1759
|
-
batch = await relay.fetch([...job.filters], {
|
|
1782
|
+
batch = (await relay.fetch([...job.filters], {
|
|
1760
1783
|
timeoutMs: opts.timeoutMs,
|
|
1761
1784
|
signal: opts.signal
|
|
1762
|
-
});
|
|
1785
|
+
})).events;
|
|
1763
1786
|
} catch {
|
|
1764
1787
|
if (opts.signal?.aborted === true) throw abortReason(opts.signal);
|
|
1765
1788
|
return;
|
|
@@ -2002,6 +2025,44 @@ var Pool = class {
|
|
|
2002
2025
|
connectTimeoutMs: this.#opts.connectTimeoutMs
|
|
2003
2026
|
});
|
|
2004
2027
|
}
|
|
2028
|
+
/**
|
|
2029
|
+
* One-shot fetch per relay: each entry reports its own events and end reason (`eose`, `closed`,
|
|
2030
|
+
* `timeout`), or `failed` when the connect or REQ itself errored. An abort rejects the whole
|
|
2031
|
+
* call. Events are not deduped across relays — use {@link fetch} for that.
|
|
2032
|
+
*/
|
|
2033
|
+
async fetchEach(relays, filters, opts) {
|
|
2034
|
+
if (filters.length === 0) throw new MessageError("REQ requires at least one filter");
|
|
2035
|
+
throwIfAborted(opts?.signal);
|
|
2036
|
+
const canonical = canonicalizeFilters(filters);
|
|
2037
|
+
return Promise.all(relays.map(async (url) => {
|
|
2038
|
+
try {
|
|
2039
|
+
const relay = await this.ensureRelay(url, {
|
|
2040
|
+
signal: opts?.signal,
|
|
2041
|
+
timeoutMs: this.#opts.connectTimeoutMs
|
|
2042
|
+
});
|
|
2043
|
+
this.#touch(relay.url);
|
|
2044
|
+
const result = await relay.fetch([...canonical], {
|
|
2045
|
+
timeoutMs: opts?.timeoutMs,
|
|
2046
|
+
signal: opts?.signal
|
|
2047
|
+
});
|
|
2048
|
+
return {
|
|
2049
|
+
url: relay.url,
|
|
2050
|
+
events: result.events,
|
|
2051
|
+
end: result.end
|
|
2052
|
+
};
|
|
2053
|
+
} catch (error) {
|
|
2054
|
+
if (opts?.signal?.aborted === true) throw abortReason(opts.signal);
|
|
2055
|
+
return {
|
|
2056
|
+
url,
|
|
2057
|
+
events: [],
|
|
2058
|
+
end: {
|
|
2059
|
+
type: "failed",
|
|
2060
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
2061
|
+
}
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
}));
|
|
2065
|
+
}
|
|
2005
2066
|
/** Fetch events until each connected relay EOSE or timeout; dedupe by id. */
|
|
2006
2067
|
async fetch(relays, filters, opts) {
|
|
2007
2068
|
if (filters.length === 0) throw new MessageError("REQ requires at least one filter");
|
|
@@ -2102,4 +2163,4 @@ var Pool = class {
|
|
|
2102
2163
|
//#endregion
|
|
2103
2164
|
export { RelayStatus as a, isInsecureRelayUrl as c, RelayClosedError as d, RelayConnectionError as f, RelayTimeoutError as g, RelaySuspendedError as h, Relay as i, getWebSocketImplementation as l, RelayPublishError as m, fanIn as n, Subscription as o, RelayError as p, fetchRouted as r, subscriptionToAsyncIterable as s, Pool as t, useWebSocketImplementation as u };
|
|
2104
2165
|
|
|
2105
|
-
//# sourceMappingURL=pool-
|
|
2166
|
+
//# sourceMappingURL=pool-As20OGxB.mjs.map
|