Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions src/util/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { modifyMutable, produce } from "solid-js/store";
import { UnsignedEvent, Event, Nostr, VerifiedEvent } from "nostr-tools/core";
import { normalizeURL as nostrNormalizeURL } from "nostr-tools/utils";
import { Filter, matchFilter } from "nostr-tools/filter";
import { SubCloser, AbstractPoolConstructorOptions, SubscribeManyParams as SubscribeManyParamsDefault } from "nostr-tools/pool";
import { SubCloser, SubscribeManyParams as SubscribeManyParamsDefault } from "nostr-tools/pool";
import { AbstractRelay as AbstractRelay, SubscriptionParams, Subscription, type AbstractRelayConstructorOptions } from "nostr-tools/abstract-relay";
import { getEventHash, verifyEvent } from "nostr-tools/pure";
import { Relay, RelayRecord } from "nostr-tools/relay";
Expand Down Expand Up @@ -41,7 +41,7 @@ class PrioritizedPool {
private eventsCount: { [relay: string]: number; } = {};
private eventsTs: { [key: string]: number; } = {};

constructor(opts: AbstractPoolConstructorOptions) {
constructor(opts: AbstractRelayConstructorOptions) {
this.verifyEvent = opts.verifyEvent
this._WebSocket = opts.websocketImplementation
}
Expand All @@ -53,15 +53,14 @@ class PrioritizedPool {
verifyEvent: this.verifyEvent,
websocketImplementation: this._WebSocket,
});
relay.connectionTimeout = SHORT_TIMEOUT;
relay._onauth = _ => {
if (store.readRelays.includes(url)) {
this.updateRelayInfo(url, { readAuth: true });
}
};
this.relays.set(url, relay);
}
await relay.connect()
// The connection timeout is now passed per connect() call, and relays
// that require NIP-42 AUTH to read are detected from the subscription
// close reason (see handleClose) — nostr-tools no longer exposes the
// connectionTimeout property or the private _onauth hook the previous
// detection relied on.
await relay.connect({ timeout: SHORT_TIMEOUT })

return relay
}
Expand Down Expand Up @@ -105,7 +104,7 @@ class PrioritizedPool {

if (loggedIn) {
const pk = signersStore.active!.pk;
externalRelays = await window.nostr!.getRelays();
externalRelays = window.nostr!.getRelays ? await window.nostr!.getRelays() : {};
if (!relaysAreOk(externalRelays)) {
const profileRelays = await find('profileRelays', IDBKeyRange.only(pk));
if (profileRelays) {
Expand Down
50 changes: 50 additions & 0 deletions src/util/nip27.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Minimal NIP-27 reference matcher/replacer.
//
// nostr-tools removed the `matchAll` / `replaceAll` helpers from its `nip27`
// module — current versions export only `parse`. ZapThreads still needs the
// old behaviour (find `nostr:`-prefixed NIP-19 references in text, then decode
// or replace them), so the small amount it used is vendored here.
//
// Behaviour mirrors nostr-tools' pre-removal `nip27`: it matches NIP-21
// `nostr:` URIs only — bare entities are normalised to `nostr:` beforehand
// in `ui.ts` (see BAD_NIP27_REGEX). Decode failures are skipped rather than
// thrown, so a malformed reference can never break comment rendering.

import { decode } from "nostr-tools/nip19";

export type Nip27Match = {
uri: string; // full match, e.g. "nostr:npub1..."
value: string; // the bech32 entity, e.g. "npub1..."
decoded: ReturnType<typeof decode>; // nip19 decode result
};

// NIP-21 `nostr:` URI wrapping a bech32 entity. The bech32 body pattern
// mirrors nostr-tools' own BECH32_REGEX.
const BECH32 = /[\x21-\x7E]{1,83}1[023456789acdefghjklmnpqrstuvwxyz]{6,}/;

// A fresh RegExp per call — global regexes carry `lastIndex` state.
const nostrUriRegex = () => new RegExp(`\\bnostr:(${BECH32.source})\\b`, "g");

export function* matchAll(content: string): Iterable<Nip27Match> {
for (const match of content.matchAll(nostrUriRegex())) {
try {
const [uri, value] = match;
yield { uri, value, decoded: decode(value) };
} catch (_e) {
// not a valid NIP-19 entity — skip
}
}
}

export function replaceAll(
content: string,
replacer: (match: Nip27Match) => string,
): string {
return content.replace(nostrUriRegex(), (uri, value) => {
try {
return replacer({ uri, value, decoded: decode(value) });
} catch (_e) {
return uri;
}
});
}
2 changes: 1 addition & 1 deletion src/util/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { decode } from "nostr-tools/nip19";
import { Filter } from "nostr-tools/filter";
import { Event } from "nostr-tools/core";
import { ShortTextNote, Metadata, Highlights, Reaction, Zap, Report, CommunityDefinition } from "nostr-tools/kinds";
import { matchAll, replaceAll } from "nostr-tools/nip27";
import { matchAll, replaceAll } from "./nip27.ts";
import { Remarkable } from 'remarkable';
import { linkify } from 'remarkable/linkify';
import { findAll, save } from "./db.ts";
Expand Down