chore: upgrade applesauce packages to v4.0.0

- Update all applesauce packages from 3.1.0 to 4.0.0
- Add applesauce-factory dependency
- Version 4.0.0 includes app-data helpers needed for NIP-78
This commit is contained in:
Gigi
2025-10-05 02:35:28 +01:00
parent 1b381a0f8c
commit 1b8c276529
229 changed files with 2533 additions and 7592 deletions

View File

@@ -372,7 +372,10 @@ var AbstractRelay = class {
baseEoseTimeout = 4400;
connectionTimeout = 4400;
publishTimeout = 4400;
pingFrequency = 2e4;
pingTimeout = 2e4;
openSubs = /* @__PURE__ */ new Map();
enablePing;
connectionTimeoutHandle;
connectionPromise;
openCountRequests = /* @__PURE__ */ new Map();
@@ -389,6 +392,7 @@ var AbstractRelay = class {
this.url = normalizeURL(url);
this.verifyEvent = opts.verifyEvent;
this._WebSocket = opts.websocketImplementation || WebSocket;
this.enablePing = opts.enablePing;
}
static async connect(url, opts) {
const relay = new AbstractRelay(url, opts);
@@ -434,7 +438,7 @@ var AbstractRelay = class {
this.ws.onopen = () => {
clearTimeout(this.connectionTimeoutHandle);
this._connected = true;
if (this.ws && this.ws.ping) {
if (this.enablePing) {
this.pingpong();
}
resolve();
@@ -442,45 +446,54 @@ var AbstractRelay = class {
this.ws.onerror = (ev) => {
clearTimeout(this.connectionTimeoutHandle);
reject(ev.message || "websocket error");
if (this._connected) {
this._connected = false;
this.connectionPromise = void 0;
this.onclose?.();
this.closeAllSubscriptions("relay connection errored");
}
this._connected = false;
this.connectionPromise = void 0;
this.onclose?.();
this.closeAllSubscriptions("relay connection errored");
};
this.ws.onclose = (ev) => {
clearTimeout(this.connectionTimeoutHandle);
reject(ev.message || "websocket closed");
if (this._connected) {
this._connected = false;
this.connectionPromise = void 0;
this.onclose?.();
this.closeAllSubscriptions("relay connection closed");
}
this._connected = false;
this.connectionPromise = void 0;
this.onclose?.();
this.closeAllSubscriptions("relay connection closed");
};
this.ws.onmessage = this._onmessage.bind(this);
});
return this.connectionPromise;
}
async receivePong() {
async waitForPingPong() {
return new Promise((res, err) => {
;
this.ws && this.ws.on && this.ws.on("pong", () => res(true)) || err("ws can't listen for pong");
this.ws && this.ws.ping && this.ws.ping();
});
}
async waitForDummyReq() {
return new Promise((resolve, _) => {
const sub = this.subscribe([{ ids: ["a".repeat(64)] }], {
oneose: () => {
sub.close();
resolve(true);
},
eoseTimeout: this.pingTimeout + 1e3
});
});
}
async pingpong() {
if (this.ws?.readyState == 1) {
this.ws && this.ws.ping && this.ws.ping();
if (this.ws?.readyState === 1) {
const result = await Promise.any([
this.receivePong(),
new Promise((res) => setTimeout(() => res(false), 1e4))
this.ws && this.ws.ping && this.ws.on ? this.waitForPingPong() : this.waitForDummyReq(),
new Promise((res) => setTimeout(() => res(false), this.pingTimeout))
]);
console.error("pingpong result", result);
if (result) {
setTimeout(() => this.pingpong(), 1e4);
setTimeout(() => this.pingpong(), this.pingFrequency);
} else {
this.ws && this.ws.close();
this.closeAllSubscriptions("pingpong timed out");
this._connected = false;
this.onclose?.();
this.ws?.close();
}
}
}
@@ -645,8 +658,8 @@ var AbstractRelay = class {
close() {
this.closeAllSubscriptions("relay connection closed by us");
this._connected = false;
this.ws?.close();
this.onclose?.();
this.ws?.close();
}
_onmessage(ev) {
this.incomingMessageQueue.enqueue(ev.data);
@@ -718,11 +731,13 @@ var AbstractSimplePool = class {
seenOn = /* @__PURE__ */ new Map();
trackRelays = false;
verifyEvent;
enablePing;
trustedRelayURLs = /* @__PURE__ */ new Set();
_WebSocket;
constructor(opts) {
this.verifyEvent = opts.verifyEvent;
this._WebSocket = opts.websocketImplementation;
this.enablePing = opts.enablePing;
}
async ensureRelay(url, params) {
url = normalizeURL(url);
@@ -730,7 +745,8 @@ var AbstractSimplePool = class {
if (!relay) {
relay = new AbstractRelay(url, {
verifyEvent: this.trustedRelayURLs.has(url) ? alwaysTrue : this.verifyEvent,
websocketImplementation: this._WebSocket
websocketImplementation: this._WebSocket,
enablePing: this.enablePing
});
relay.onclose = () => {
this.relays.delete(url);
@@ -750,20 +766,38 @@ var AbstractSimplePool = class {
}
subscribe(relays, filter, params) {
params.onauth = params.onauth || params.doauth;
return this.subscribeMap(
relays.map((url) => ({ url, filter })),
params
);
const request = [];
for (let i2 = 0; i2 < relays.length; i2++) {
const url = normalizeURL(relays[i2]);
if (!request.find((r) => r.url === url)) {
request.push({ url, filter });
}
}
return this.subscribeMap(request, params);
}
subscribeMany(relays, filters, params) {
subscribeMany(relays, filter, params) {
params.onauth = params.onauth || params.doauth;
return this.subscribeMap(
relays.flatMap((url) => filters.map((filter) => ({ url, filter }))),
params
);
const request = [];
const uniqUrls = [];
for (let i2 = 0; i2 < relays.length; i2++) {
const url = normalizeURL(relays[i2]);
if (uniqUrls.indexOf(url) === -1) {
uniqUrls.push(url);
request.push({ url, filter });
}
}
return this.subscribeMap(request, params);
}
subscribeMap(requests, params) {
params.onauth = params.onauth || params.doauth;
const grouped = /* @__PURE__ */ new Map();
for (const req of requests) {
const { url, filter } = req;
if (!grouped.has(url))
grouped.set(url, []);
grouped.get(url).push(filter);
}
const groupedRequests = Array.from(grouped.entries()).map(([url, filters]) => ({ url, filters }));
if (this.trackRelays) {
params.receivedEvent = (relay, id) => {
let set = this.seenOn.get(id);
@@ -808,8 +842,7 @@ var AbstractSimplePool = class {
return have;
};
const allOpened = Promise.all(
requests.map(async ({ url, filter }, i2) => {
url = normalizeURL(url);
groupedRequests.map(async ({ url, filters }, i2) => {
let relay;
try {
relay = await this.ensureRelay(url, {
@@ -819,13 +852,13 @@ var AbstractSimplePool = class {
handleClose(i2, err?.message || String(err));
return;
}
let subscription = relay.subscribe([filter], {
let subscription = relay.subscribe(filters, {
...params,
oneose: () => handleEose(i2),
onclose: (reason) => {
if (reason.startsWith("auth-required: ") && params.onauth) {
relay.auth(params.onauth).then(() => {
relay.subscribe([filter], {
relay.subscribe(filters, {
...params,
oneose: () => handleEose(i2),
onclose: (reason2) => {
@@ -866,9 +899,9 @@ var AbstractSimplePool = class {
});
return subcloser;
}
subscribeManyEose(relays, filters, params) {
subscribeManyEose(relays, filter, params) {
params.onauth = params.onauth || params.doauth;
const subcloser = this.subscribeMany(relays, filters, {
const subcloser = this.subscribeMany(relays, filter, {
...params,
oneose() {
subcloser.close("closed automatically on eose");
@@ -939,8 +972,8 @@ try {
} catch {
}
var SimplePool = class extends AbstractSimplePool {
constructor() {
super({ verifyEvent, websocketImplementation: _WebSocket });
constructor(options) {
super({ verifyEvent, websocketImplementation: _WebSocket, ...options });
}
};
@@ -996,6 +1029,75 @@ async function queryBunkerProfile(nip05) {
return null;
}
}
function createNostrConnectURI(params) {
if (!params.clientPubkey) {
throw new Error("clientPubkey is required.");
}
if (!params.relays || params.relays.length === 0) {
throw new Error("At least one relay is required.");
}
if (!params.secret) {
throw new Error("secret is required.");
}
const queryParams = new URLSearchParams();
params.relays.forEach((relay) => {
queryParams.append("relay", relay);
});
queryParams.append("secret", params.secret);
if (params.perms && params.perms.length > 0) {
queryParams.append("perms", params.perms.join(","));
}
if (params.name) {
queryParams.append("name", params.name);
}
if (params.url) {
queryParams.append("url", params.url);
}
if (params.image) {
queryParams.append("image", params.image);
}
return `nostrconnect://${params.clientPubkey}?${queryParams.toString()}`;
}
function parseNostrConnectURI(uri) {
if (!uri.startsWith("nostrconnect://")) {
throw new Error('Invalid nostrconnect URI: Must start with "nostrconnect://".');
}
const [protocolAndPubkey, queryString] = uri.split("?");
if (!protocolAndPubkey || !queryString) {
throw new Error("Invalid nostrconnect URI: Missing query string.");
}
const clientPubkey = protocolAndPubkey.substring("nostrconnect://".length);
if (!clientPubkey) {
throw new Error("Invalid nostrconnect URI: Missing client-pubkey.");
}
const queryParams = new URLSearchParams(queryString);
const relays = queryParams.getAll("relay");
if (relays.length === 0) {
throw new Error('Invalid nostrconnect URI: Missing "relay" parameter.');
}
const secret = queryParams.get("secret");
if (!secret) {
throw new Error('Invalid nostrconnect URI: Missing "secret" parameter.');
}
const permsString = queryParams.get("perms");
const perms = permsString ? permsString.split(",") : void 0;
const name = queryParams.get("name") || void 0;
const url = queryParams.get("url") || void 0;
const image = queryParams.get("image") || void 0;
return {
protocol: "nostrconnect",
clientPubkey,
params: {
relays,
secret,
perms,
name,
url,
image
},
originalString: uri
};
}
var BunkerSigner = class {
params;
pool;
@@ -1009,21 +1111,68 @@ var BunkerSigner = class {
conversationKey;
bp;
cachedPubKey;
constructor(clientSecretKey, bp, params = {}) {
if (bp.relays.length === 0) {
throw new Error("no relays are specified for this bunker");
}
constructor(clientSecretKey, params) {
this.params = params;
this.pool = params.pool || new SimplePool();
this.secretKey = clientSecretKey;
this.conversationKey = getConversationKey(clientSecretKey, bp.pubkey);
this.bp = bp;
this.isOpen = false;
this.idPrefix = Math.random().toString(36).substring(7);
this.serial = 0;
this.listeners = {};
this.waitingForAuth = {};
this.setupSubscription(params);
}
static fromBunker(clientSecretKey, bp, params = {}) {
if (bp.relays.length === 0) {
throw new Error("No relays specified for this bunker");
}
const signer = new BunkerSigner(clientSecretKey, params);
signer.conversationKey = getConversationKey(clientSecretKey, bp.pubkey);
signer.bp = bp;
signer.setupSubscription(params);
return signer;
}
static async fromURI(clientSecretKey, connectionURI, params = {}, maxWait = 3e5) {
const signer = new BunkerSigner(clientSecretKey, params);
const parsedURI = parseNostrConnectURI(connectionURI);
const clientPubkey = getPublicKey(clientSecretKey);
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
sub.close();
reject(new Error(`Connection timed out after ${maxWait / 1e3} seconds`));
}, maxWait);
const sub = signer.pool.subscribe(
parsedURI.params.relays,
{ kinds: [NostrConnect], "#p": [clientPubkey] },
{
onevent: async (event) => {
try {
const tempConvKey = getConversationKey(clientSecretKey, event.pubkey);
const decryptedContent = decrypt(event.content, tempConvKey);
const response = JSON.parse(decryptedContent);
if (response.result === parsedURI.params.secret) {
clearTimeout(timer);
sub.close();
signer.bp = {
pubkey: event.pubkey,
relays: parsedURI.params.relays,
secret: parsedURI.params.secret
};
signer.conversationKey = getConversationKey(clientSecretKey, event.pubkey);
signer.setupSubscription(params);
resolve(signer);
}
} catch (e) {
console.warn("Failed to process potential connection event", e);
}
},
onclose: () => {
clearTimeout(timer);
reject(new Error("Subscription closed before connection was established."));
},
maxWait
}
);
});
}
setupSubscription(params) {
const listeners = this.listeners;
@@ -1133,7 +1282,7 @@ var BunkerSigner = class {
async function createAccount(bunker, params, username, domain, email, localSecretKey = generateSecretKey()) {
if (email && !EMAIL_REGEX.test(email))
throw new Error("Invalid email");
let rpc = new BunkerSigner(localSecretKey, bunker.bunkerPointer, params);
let rpc = BunkerSigner.fromBunker(localSecretKey, bunker.bunkerPointer, params);
let pubkey = await rpc.sendRequest("create_account", [username, domain, email || ""]);
rpc.bp.pubkey = pubkey;
await rpc.connect();
@@ -1178,8 +1327,10 @@ export {
BUNKER_REGEX,
BunkerSigner,
createAccount,
createNostrConnectURI,
fetchBunkerProviders,
parseBunkerInput,
parseNostrConnectURI,
queryBunkerProfile,
toBunkerURL,
useFetchImplementation