Browse Source

Fix warnings and errors thrown be Deno's linter

master
buttercat1791 8 months ago
parent
commit
3b7ffb913f
  1. 1
      playwright.config.ts
  2. 17
      src/app.d.ts
  3. 6
      src/lib/components/publications/PublicationFeed.svelte
  4. 2
      src/lib/components/util/CardActions.svelte
  5. 3
      src/lib/navigator/EventNetwork/utils/forceSimulation.ts
  6. 8
      src/lib/navigator/EventNetwork/utils/networkBuilder.ts
  7. 93
      src/lib/ndk.ts
  8. 16
      src/lib/parser.ts
  9. 10
      src/lib/services/publisher.ts
  10. 2
      src/lib/state.ts
  11. 4
      src/lib/stores.ts
  12. 4
      src/lib/stores/networkStore.ts
  13. 27
      src/lib/stores/userStore.ts
  14. 2
      src/lib/types.ts
  15. 8
      src/lib/utils.ts
  16. 8
      src/lib/utils/ZettelParser.ts
  17. 13
      src/lib/utils/event_input_utils.ts
  18. 18
      src/lib/utils/event_search.ts
  19. 5
      src/lib/utils/indexEventCache.ts
  20. 14
      src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts
  21. 24
      src/lib/utils/markup/advancedMarkupParser.ts
  22. 25
      src/lib/utils/markup/asciidoctorExtensions.ts
  23. 8
      src/lib/utils/markup/basicMarkupParser.ts
  24. 11
      src/lib/utils/network_detection.ts
  25. 21
      src/lib/utils/nostrEventService.ts
  26. 26
      src/lib/utils/nostrUtils.ts
  27. 30
      src/lib/utils/profile_search.ts
  28. 7
      src/lib/utils/relayDiagnostics.ts
  29. 34
      src/lib/utils/relay_management.ts
  30. 5
      src/lib/utils/searchCache.ts
  31. 6
      src/lib/utils/search_types.ts
  32. 7
      src/lib/utils/search_utils.ts
  33. 46
      src/lib/utils/subscription_search.ts
  34. 15
      src/routes/+layout.ts
  35. 6
      src/routes/+page.svelte
  36. 15
      src/routes/publication/+page.ts
  37. 3
      vite.config.ts

1
playwright.config.ts

@ -1,4 +1,5 @@
import { defineConfig, devices } from "@playwright/test"; import { defineConfig, devices } from "@playwright/test";
import process from "node:process";
/** /**
* Read environment variables from file. * Read environment variables from file.

17
src/app.d.ts vendored

@ -1,7 +1,7 @@
// See https://kit.svelte.dev/docs/types#app // See https://kit.svelte.dev/docs/types#app
import NDK, { NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKEvent, NDKNip07Signer } from "@nostr-dev-kit/ndk";
import Pharos from "./lib/parser.ts"; import { HLJSApi } from "highlight.js";
// for information about these interfaces // for information about these interfaces
declare global { declare global {
@ -9,13 +9,24 @@ declare global {
// interface Error {} // interface Error {}
// interface Locals {} // interface Locals {}
interface PageData { interface PageData {
waitable?: Promise<any>; waitable?: Promise<unknown>;
publicationType?: string; publicationType?: string;
indexEvent?: NDKEvent; indexEvent?: NDKEvent;
url?: URL; url?: URL;
} }
// interface Platform {} // interface Platform {}
} }
var hljs: HLJSApi;
// deno-lint-ignore no-explicit-any
var MathJax: any;
var nostr: NDKNip07Signer & {
getRelays: () => Promise<Record<string, Record<string, boolean | undefined>>>;
// deno-lint-ignore no-explicit-any
signEvent: (event: any) => Promise<any>;
};
} }
export {}; export {};

6
src/lib/components/publications/PublicationFeed.svelte

@ -35,10 +35,6 @@
// Event management // Event management
let allIndexEvents: NDKEvent[] = $state([]); let allIndexEvents: NDKEvent[] = $state([]);
let cutoffTimestamp: number = $derived(
eventsInView?.at(eventsInView.length - 1)?.created_at ??
new Date().getTime(),
);
// Initialize relays and fetch events // Initialize relays and fetch events
async function initializeAndFetch() { async function initializeAndFetch() {
@ -371,8 +367,6 @@
</script> </script>
<div class="flex flex-col space-y-4"> <div class="flex flex-col space-y-4">
<div <div
class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 w-full" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 w-full"
> >

2
src/lib/components/util/CardActions.svelte

@ -9,7 +9,7 @@
import { userBadge } from "$lib/snippets/UserSnippets.svelte"; import { userBadge } from "$lib/snippets/UserSnippets.svelte";
import { neventEncode, naddrEncode } from "$lib/utils"; import { neventEncode, naddrEncode } from "$lib/utils";
import { activeInboxRelays } from "$lib/ndk"; import { activeInboxRelays } from "$lib/ndk";
import { userStore } from "$lib/stores/userStore"; import { userStore } from "$lib/stores/userStore";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
import type { NDKEvent } from "$lib/utils/nostrUtils"; import type { NDKEvent } from "$lib/utils/nostrUtils";

3
src/lib/navigator/EventNetwork/utils/forceSimulation.ts

@ -1,3 +1,4 @@
// deno-lint-ignore-file no-explicit-any
/** /**
* D3 Force Simulation Utilities * D3 Force Simulation Utilities
* *
@ -5,7 +6,7 @@
* graph simulations for the event network visualization. * graph simulations for the event network visualization.
*/ */
import type { NetworkNode, NetworkLink } from "../types"; import type { NetworkNode, NetworkLink } from "../types.ts";
import * as d3 from "d3"; import * as d3 from "d3";
// Configuration // Configuration

8
src/lib/navigator/EventNetwork/utils/networkBuilder.ts

@ -6,10 +6,10 @@
*/ */
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import type { NetworkNode, NetworkLink, GraphData, GraphState } from "../types"; import type { NetworkNode, GraphData, GraphState } from "../types.ts";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { activeInboxRelays, activeOutboxRelays } from "../../../ndk.ts";
import { getMatchingTags } from "$lib/utils/nostrUtils"; import { getMatchingTags } from "../../../utils/nostrUtils.ts";
import { get } from "svelte/store"; import { get } from "svelte/store";
// Configuration // Configuration
@ -20,7 +20,7 @@ const CONTENT_EVENT_KIND = 30041;
/** /**
* Debug logging function that only logs when DEBUG is true * Debug logging function that only logs when DEBUG is true
*/ */
function debug(...args: any[]) { function debug(...args: unknown[]) {
if (DEBUG) { if (DEBUG) {
console.log("[NetworkBuilder]", ...args); console.log("[NetworkBuilder]", ...args);
} }

93
src/lib/ndk.ts

@ -8,29 +8,19 @@ import NDK, {
} from "@nostr-dev-kit/ndk"; } from "@nostr-dev-kit/ndk";
import { get, writable, type Writable } from "svelte/store"; import { get, writable, type Writable } from "svelte/store";
import { import {
secondaryRelays,
FeedType,
loginStorageKey, loginStorageKey,
communityRelays, } from "./consts.ts";
anonymousRelays,
searchRelays,
} from "./consts";
import { import {
buildCompleteRelaySet, buildCompleteRelaySet,
testRelayConnection, testRelayConnection,
discoverLocalRelays,
getUserLocalRelays,
getUserBlockedRelays,
getUserOutboxRelays,
deduplicateRelayUrls, deduplicateRelayUrls,
} from "./utils/relay_management"; } from "./utils/relay_management.ts";
// Re-export testRelayConnection for components that need it // Re-export testRelayConnection for components that need it
export { testRelayConnection }; export { testRelayConnection };
import { startNetworkMonitoring, NetworkCondition } from "./utils/network_detection"; import { userStore } from "./stores/userStore.ts";
import { userStore } from "./stores/userStore"; import { userPubkey } from "./stores/authStore.Svelte.ts";
import { userPubkey } from "$lib/stores/authStore.Svelte"; import { startNetworkStatusMonitoring, stopNetworkStatusMonitoring } from "./stores/networkStore.ts";
import { startNetworkStatusMonitoring, stopNetworkStatusMonitoring } from "./stores/networkStore";
export const ndkInstance: Writable<NDK> = writable(); export const ndkInstance: Writable<NDK> = writable();
export const ndkSignedIn = writable(false); export const ndkSignedIn = writable(false);
@ -59,7 +49,7 @@ class CustomRelayAuthPolicy {
* @param relay The relay to authenticate with * @param relay The relay to authenticate with
* @returns Promise that resolves when authentication is complete * @returns Promise that resolves when authentication is complete
*/ */
async authenticate(relay: NDKRelay): Promise<void> { authenticate(relay: NDKRelay): void {
if (!this.ndk.signer || !this.ndk.activeUser) { if (!this.ndk.signer || !this.ndk.activeUser) {
console.warn( console.warn(
"[NDK.ts] No signer or active user available for relay authentication", "[NDK.ts] No signer or active user available for relay authentication",
@ -84,7 +74,7 @@ class CustomRelayAuthPolicy {
relay.on("notice", (message: string) => { relay.on("notice", (message: string) => {
if (message.includes("auth-required")) { if (message.includes("auth-required")) {
console.debug(`[NDK.ts] Auth required from ${relay.url}:`, message); console.debug(`[NDK.ts] Auth required from ${relay.url}:`, message);
this.handleAuthRequired(relay, message); this.handleAuthRequired(relay);
} }
}); });
@ -94,7 +84,7 @@ class CustomRelayAuthPolicy {
}); });
// Listen for authentication failures // Listen for authentication failures
relay.on("auth:failed", (error: any) => { relay.on("auth:failed", (error) => {
console.error( console.error(
`[NDK.ts] Authentication failed for ${relay.url}:`, `[NDK.ts] Authentication failed for ${relay.url}:`,
error, error,
@ -151,10 +141,7 @@ class CustomRelayAuthPolicy {
/** /**
* Handles auth-required error from relay * Handles auth-required error from relay
*/ */
private async handleAuthRequired( private async handleAuthRequired(relay: NDKRelay): Promise<void> {
relay: NDKRelay,
message: string,
): Promise<void> {
const challenge = this.challenges.get(relay.url); const challenge = this.challenges.get(relay.url);
if (challenge) { if (challenge) {
await this.handleAuthChallenge(relay, challenge); await this.handleAuthChallenge(relay, challenge);
@ -173,13 +160,13 @@ export function checkEnvironmentForWebSocketDowngrade(): void {
console.debug("[NDK.ts] Environment Check for WebSocket Protocol:"); console.debug("[NDK.ts] Environment Check for WebSocket Protocol:");
const isLocalhost = const isLocalhost =
window.location.hostname === "localhost" || globalThis.location.hostname === "localhost" ||
window.location.hostname === "127.0.0.1"; globalThis.location.hostname === "127.0.0.1";
const isHttp = window.location.protocol === "http:"; const isHttp = globalThis.location.protocol === "http:";
const isHttps = window.location.protocol === "https:"; const isHttps = globalThis.location.protocol === "https:";
console.debug("[NDK.ts] - Is localhost:", isLocalhost); console.debug("[NDK.ts] - Is localhost:", isLocalhost);
console.debug("[NDK.ts] - Protocol:", window.location.protocol); console.debug("[NDK.ts] - Protocol:", globalThis.location.protocol);
console.debug("[NDK.ts] - Is HTTP:", isHttp); console.debug("[NDK.ts] - Is HTTP:", isHttp);
console.debug("[NDK.ts] - Is HTTPS:", isHttps); console.debug("[NDK.ts] - Is HTTPS:", isHttps);
@ -205,9 +192,9 @@ export function checkEnvironmentForWebSocketDowngrade(): void {
*/ */
export function checkWebSocketSupport(): void { export function checkWebSocketSupport(): void {
console.debug("[NDK.ts] WebSocket Support Diagnostics:"); console.debug("[NDK.ts] WebSocket Support Diagnostics:");
console.debug("[NDK.ts] - Protocol:", window.location.protocol); console.debug("[NDK.ts] - Protocol:", globalThis.location.protocol);
console.debug("[NDK.ts] - Hostname:", window.location.hostname); console.debug("[NDK.ts] - Hostname:", globalThis.location.hostname);
console.debug("[NDK.ts] - Port:", window.location.port); console.debug("[NDK.ts] - Port:", globalThis.location.port);
console.debug("[NDK.ts] - User Agent:", navigator.userAgent); console.debug("[NDK.ts] - User Agent:", navigator.userAgent);
// Test if secure WebSocket is supported // Test if secure WebSocket is supported
@ -266,46 +253,6 @@ function getRelayStorageKey(user: NDKUser, type: "inbox" | "outbox"): string {
return `${loginStorageKey}/${user.pubkey}/${type}`; return `${loginStorageKey}/${user.pubkey}/${type}`;
} }
/**
* Stores the user's relay lists in local storage.
* @param user The user for whom to store the relay lists.
* @param inboxes The user's inbox relays.
* @param outboxes The user's outbox relays.
*/
function persistRelays(
user: NDKUser,
inboxes: Set<NDKRelay>,
outboxes: Set<NDKRelay>,
): void {
localStorage.setItem(
getRelayStorageKey(user, "inbox"),
JSON.stringify(Array.from(inboxes).map((relay) => relay.url)),
);
localStorage.setItem(
getRelayStorageKey(user, "outbox"),
JSON.stringify(Array.from(outboxes).map((relay) => relay.url)),
);
}
/**
* Retrieves the user's relay lists from local storage.
* @param user The user for whom to retrieve the relay lists.
* @returns A tuple of relay sets of the form `[inboxRelays, outboxRelays]`. Either set may be
* empty if no relay lists were stored for the user.
*/
function getPersistedRelays(user: NDKUser): [Set<string>, Set<string>] {
const inboxes = new Set<string>(
JSON.parse(localStorage.getItem(getRelayStorageKey(user, "inbox")) ?? "[]"),
);
const outboxes = new Set<string>(
JSON.parse(
localStorage.getItem(getRelayStorageKey(user, "outbox")) ?? "[]",
),
);
return [inboxes, outboxes];
}
export function clearPersistedRelays(user: NDKUser): void { export function clearPersistedRelays(user: NDKUser): void {
localStorage.removeItem(getRelayStorageKey(user, "inbox")); localStorage.removeItem(getRelayStorageKey(user, "inbox"));
localStorage.removeItem(getRelayStorageKey(user, "outbox")); localStorage.removeItem(getRelayStorageKey(user, "outbox"));
@ -468,7 +415,7 @@ export async function refreshRelayStoresOnNetworkChange(ndk: NDK): Promise<void>
* Starts network monitoring for relay optimization * Starts network monitoring for relay optimization
* @param ndk NDK instance * @param ndk NDK instance
*/ */
export function startNetworkMonitoringForRelays(ndk: NDK): void { export function startNetworkMonitoringForRelays(): void {
// Use centralized network monitoring instead of separate monitoring // Use centralized network monitoring instead of separate monitoring
startNetworkStatusMonitoring(); startNetworkStatusMonitoring();
} }
@ -529,7 +476,7 @@ export function initNdk(): NDK {
// Update relay stores after connection // Update relay stores after connection
await updateActiveRelayStores(ndk); await updateActiveRelayStores(ndk);
// Start network monitoring for relay optimization // Start network monitoring for relay optimization
startNetworkMonitoringForRelays(ndk); startNetworkMonitoringForRelays();
} catch (error) { } catch (error) {
console.warn("[NDK.ts] Failed to connect NDK:", error); console.warn("[NDK.ts] Failed to connect NDK:", error);
@ -543,7 +490,7 @@ export function initNdk(): NDK {
// Still try to update relay stores even if connection failed // Still try to update relay stores even if connection failed
try { try {
await updateActiveRelayStores(ndk); await updateActiveRelayStores(ndk);
startNetworkMonitoringForRelays(ndk); startNetworkMonitoringForRelays();
} catch (storeError) { } catch (storeError) {
console.warn("[NDK.ts] Failed to update relay stores:", storeError); console.warn("[NDK.ts] Failed to update relay stores:", storeError);
} }

16
src/lib/parser.ts

@ -1,9 +1,9 @@
// deno-lint-ignore-file no-this-alias
import NDK, { NDKEvent } from "@nostr-dev-kit/ndk"; import NDK, { NDKEvent } from "@nostr-dev-kit/ndk";
import asciidoctor from "asciidoctor"; import Processor from "asciidoctor";
import type { import type {
AbstractBlock, AbstractBlock,
AbstractNode, AbstractNode,
Asciidoctor,
Block, Block,
Document, Document,
Extensions, Extensions,
@ -13,7 +13,7 @@ import type {
import he from "he"; import he from "he";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import { zettelKinds } from "./consts.ts"; import { zettelKinds } from "./consts.ts";
import { getMatchingTags } from "$lib/utils/nostrUtils"; import { getMatchingTags } from "./utils/nostrUtils.ts";
interface IndexMetadata { interface IndexMetadata {
authors?: string[]; authors?: string[];
@ -65,7 +65,7 @@ export default class Pharos {
* hierarchically to form the Abstract Syntax Tree (AST) representation of the document. * hierarchically to form the Abstract Syntax Tree (AST) representation of the document.
*/ */
private asciidoctor: Asciidoctor; private asciidoctor;
private pharosExtensions: Extensions.Registry; private pharosExtensions: Extensions.Registry;
@ -140,7 +140,7 @@ export default class Pharos {
// #region Public API // #region Public API
constructor(ndk: NDK) { constructor(ndk: NDK) {
this.asciidoctor = asciidoctor(); this.asciidoctor = Processor();
this.pharosExtensions = this.asciidoctor.Extensions.create(); this.pharosExtensions = this.asciidoctor.Extensions.create();
this.ndk = ndk; this.ndk = ndk;
@ -164,9 +164,9 @@ export default class Pharos {
private async loadAdvancedExtensions(): Promise<void> { private async loadAdvancedExtensions(): Promise<void> {
try { try {
const { createAdvancedExtensions } = await import( const { createAdvancedExtensions } = await import(
"./utils/markup/asciidoctorExtensions" "./utils/markup/asciidoctorExtensions.ts"
); );
const advancedExtensions = createAdvancedExtensions(); createAdvancedExtensions();
// Note: Extensions merging might not be available in this version // Note: Extensions merging might not be available in this version
// We'll handle this in the parse method instead // We'll handle this in the parse method instead
} catch (error) { } catch (error) {
@ -549,7 +549,7 @@ export default class Pharos {
* - Each ID of a node containing children is mapped to the set of IDs of its children. * - Each ID of a node containing children is mapped to the set of IDs of its children.
*/ */
private treeProcessor( private treeProcessor(
treeProcessor: Extensions.TreeProcessor, _: Extensions.TreeProcessor,
document: Document, document: Document,
) { ) {
this.rootNodeId = this.generateNodeId(document); this.rootNodeId = this.generateNodeId(document);

10
src/lib/services/publisher.ts

@ -1,12 +1,8 @@
import { get } from "svelte/store"; import { get } from "svelte/store";
import { ndkInstance } from "$lib/ndk"; import { ndkInstance } from "../ndk.ts";
import { getMimeTags } from "$lib/utils/mime"; import { getMimeTags } from "../utils/mime.ts";
import { import { parseAsciiDocSections } from "../utils/ZettelParser.ts";
parseAsciiDocSections,
type ZettelSection,
} from "$lib/utils/ZettelParser";
import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools";
export interface PublishResult { export interface PublishResult {
success: boolean; success: boolean;

2
src/lib/state.ts

@ -1,6 +1,6 @@
import { browser } from "$app/environment"; import { browser } from "$app/environment";
import { writable, type Writable } from "svelte/store"; import { writable, type Writable } from "svelte/store";
import type { Tab } from "./types"; import type { Tab } from "./types.ts";
export const pathLoaded: Writable<boolean> = writable(false); export const pathLoaded: Writable<boolean> = writable(false);

4
src/lib/stores.ts

@ -3,9 +3,9 @@ import { writable } from "svelte/store";
// The old feedType store is no longer needed since we use the new relay management system // The old feedType store is no longer needed since we use the new relay management system
// All relay selection is now handled by the activeInboxRelays and activeOutboxRelays stores in ndk.ts // All relay selection is now handled by the activeInboxRelays and activeOutboxRelays stores in ndk.ts
export let idList = writable<string[]>([]); export const idList = writable<string[]>([]);
export let alexandriaKinds = writable<number[]>([30040, 30041, 30818]); export const alexandriaKinds = writable<number[]>([30040, 30041, 30818]);
export interface PublicationLayoutVisibility { export interface PublicationLayoutVisibility {
toc: boolean; toc: boolean;

4
src/lib/stores/networkStore.ts

@ -1,5 +1,5 @@
import { writable, type Writable } from 'svelte/store'; import { writable } from "svelte/store";
import { detectNetworkCondition, NetworkCondition, startNetworkMonitoring } from '$lib/utils/network_detection'; import { detectNetworkCondition, NetworkCondition, startNetworkMonitoring } from '../utils/network_detection.ts';
// Network status store // Network status store
export const networkCondition = writable<NetworkCondition>(NetworkCondition.ONLINE); export const networkCondition = writable<NetworkCondition>(NetworkCondition.ONLINE);

27
src/lib/stores/userStore.ts

@ -1,17 +1,17 @@
import { writable, get } from "svelte/store"; import { writable, get } from "svelte/store";
import type { NostrProfile } from "$lib/utils/nostrUtils"; import type { NostrProfile } from "../utils/nostrUtils.ts";
import type { NDKUser, NDKSigner } from "@nostr-dev-kit/ndk"; import type { NDKUser, NDKSigner } from "@nostr-dev-kit/ndk";
import { import NDK, {
NDKNip07Signer, NDKNip07Signer,
NDKRelayAuthPolicies, NDKRelayAuthPolicies,
NDKRelaySet, NDKRelaySet,
NDKRelay, NDKRelay,
} from "@nostr-dev-kit/ndk"; } from "@nostr-dev-kit/ndk";
import { getUserMetadata } from "$lib/utils/nostrUtils"; import { getUserMetadata } from "../utils/nostrUtils.ts";
import { ndkInstance, activeInboxRelays, activeOutboxRelays, updateActiveRelayStores } from "$lib/ndk"; import { ndkInstance, activeInboxRelays, activeOutboxRelays, updateActiveRelayStores } from "../ndk.ts";
import { loginStorageKey } from "$lib/consts"; import { loginStorageKey } from "../consts.ts";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { userPubkey } from "$lib/stores/authStore.Svelte"; import { userPubkey } from "../stores/authStore.Svelte.ts";
export interface UserState { export interface UserState {
pubkey: string | null; pubkey: string | null;
@ -69,7 +69,7 @@ function getPersistedRelays(user: NDKUser): [Set<string>, Set<string>] {
} }
async function getUserPreferredRelays( async function getUserPreferredRelays(
ndk: any, ndk: NDK,
user: NDKUser, user: NDKUser,
fallbacks: readonly string[] = [...get(activeInboxRelays), ...get(activeOutboxRelays)], fallbacks: readonly string[] = [...get(activeInboxRelays), ...get(activeOutboxRelays)],
): Promise<[Set<NDKRelay>, Set<NDKRelay>]> { ): Promise<[Set<NDKRelay>, Set<NDKRelay>]> {
@ -90,9 +90,9 @@ async function getUserPreferredRelays(
const outboxRelays = new Set<NDKRelay>(); const outboxRelays = new Set<NDKRelay>();
if (relayList == null) { if (relayList == null) {
const relayMap = await window.nostr?.getRelays?.(); const relayMap = await globalThis.nostr?.getRelays?.();
Object.entries(relayMap ?? {}).forEach( Object.entries(relayMap ?? {}).forEach(
([url, relayType]: [string, any]) => { ([url, relayType]: [string, Record<string, boolean | undefined>]) => {
const relay = new NDKRelay( const relay = new NDKRelay(
url, url,
NDKRelayAuthPolicies.signIn({ ndk }), NDKRelayAuthPolicies.signIn({ ndk }),
@ -139,15 +139,6 @@ function persistLogin(user: NDKUser, method: "extension" | "amber" | "npub") {
localStorage.setItem(loginMethodStorageKey, method); localStorage.setItem(loginMethodStorageKey, method);
} }
function getPersistedLoginMethod(): "extension" | "amber" | "npub" | null {
return (
(localStorage.getItem(loginMethodStorageKey) as
| "extension"
| "amber"
| "npub") ?? null
);
}
function clearLogin() { function clearLogin() {
localStorage.removeItem(loginStorageKey); localStorage.removeItem(loginStorageKey);
localStorage.removeItem(loginMethodStorageKey); localStorage.removeItem(loginMethodStorageKey);

2
src/lib/types.ts

@ -3,7 +3,7 @@ export type Tab = {
type: TabType; type: TabType;
parent?: number; parent?: number;
previous?: Tab; previous?: Tab;
data?: any; data?: unknown;
}; };
export type TabType = export type TabType =

8
src/lib/utils.ts

@ -1,6 +1,6 @@
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { getMatchingTags } from "./utils/nostrUtils"; import { getMatchingTags } from "./utils/nostrUtils.ts";
export function neventEncode(event: NDKEvent, relays: string[]) { export function neventEncode(event: NDKEvent, relays: string[]) {
return nip19.neventEncode({ return nip19.neventEncode({
@ -97,8 +97,8 @@ export function isElementInViewport(el: string | HTMLElement) {
rect.top >= 0 && rect.top >= 0 &&
rect.left >= 0 && rect.left >= 0 &&
rect.bottom <= rect.bottom <=
(window.innerHeight || document.documentElement.clientHeight) && (globalThis.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth) rect.right <= (globalThis.innerWidth || document.documentElement.clientWidth)
); );
} }
@ -169,7 +169,7 @@ Array.prototype.findIndexAsync = function <T>(
* @param wait The number of milliseconds to delay * @param wait The number of milliseconds to delay
* @returns A debounced version of the function * @returns A debounced version of the function
*/ */
export function debounce<T extends (...args: any[]) => any>( export function debounce<T extends (...args: unknown[]) => unknown>(
func: T, func: T,
wait: number, wait: number,
): (...args: Parameters<T>) => void { ): (...args: Parameters<T>) => void {

8
src/lib/utils/ZettelParser.ts

@ -1,9 +1,3 @@
import { ndkInstance } from "$lib/ndk";
import { signEvent, getEventHash } from "$lib/utils/nostrUtils";
import { getMimeTags } from "$lib/utils/mime";
import { communityRelays } from "$lib/consts";
import { nip19 } from "nostr-tools";
export interface ZettelSection { export interface ZettelSection {
title: string; title: string;
content: string; content: string;
@ -37,7 +31,7 @@ export function splitAsciiDocByHeadingLevel(
export function parseZettelSection(section: string): ZettelSection { export function parseZettelSection(section: string): ZettelSection {
const lines = section.split("\n"); const lines = section.split("\n");
let title = "Untitled"; let title = "Untitled";
let contentLines: string[] = []; const contentLines: string[] = [];
let inHeader = true; let inHeader = true;
let tags: string[][] = []; let tags: string[][] = [];
tags = extractTags(section); tags = extractTags(section);

13
src/lib/utils/event_input_utils.ts

@ -1,6 +1,6 @@
import type { NDKEvent } from "./nostrUtils"; import type { NDKEvent } from "./nostrUtils.ts";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { ndkInstance } from "$lib/ndk"; import { ndkInstance } from "../ndk.ts";
import { NDKEvent as NDKEventClass } from "@nostr-dev-kit/ndk"; import { NDKEvent as NDKEventClass } from "@nostr-dev-kit/ndk";
import { EVENT_KINDS } from "./search_constants"; import { EVENT_KINDS } from "./search_constants";
@ -149,13 +149,6 @@ function extractAsciiDocDocumentHeader(content: string): string | null {
return match ? match[1].trim() : null; return match ? match[1].trim() : null;
} }
/**
* Extracts all section headers (lines starting with '== ').
*/
function extractAsciiDocSectionHeaders(content: string): string[] {
return Array.from(content.matchAll(/^==\s+(.+)$/gm)).map((m) => m[1].trim());
}
/** /**
* Extracts the topmost Markdown # header (line starting with '# '). * Extracts the topmost Markdown # header (line starting with '# ').
*/ */
@ -181,7 +174,7 @@ function splitAsciiDocSections(content: string): {
let current: string[] = []; let current: string[] = [];
let foundFirstSection = false; let foundFirstSection = false;
let hasPreamble = false; let hasPreamble = false;
let preambleContent: string[] = []; const preambleContent: string[] = [];
for (const line of lines) { for (const line of lines) {
// Skip document title lines (= header) // Skip document title lines (= header)

18
src/lib/utils/event_search.ts

@ -1,18 +1,18 @@
import { ndkInstance } from "$lib/ndk"; import { ndkInstance } from "../ndk.ts";
import { fetchEventWithFallback } from "$lib/utils/nostrUtils"; import { fetchEventWithFallback } from "./nostrUtils.ts";
import { nip19 } from "$lib/utils/nostrUtils"; import { nip19 } from "nostr-tools";
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { wellKnownUrl, isValidNip05Address } from "./search_utils"; import { wellKnownUrl, isValidNip05Address } from "./search_utils.ts";
import { TIMEOUTS, VALIDATION } from "./search_constants"; import { TIMEOUTS, VALIDATION } from "./search_constants.ts";
/** /**
* Search for a single event by ID or filter * Search for a single event by ID or filter
*/ */
export async function searchEvent(query: string): Promise<NDKEvent | null> { export async function searchEvent(query: string): Promise<NDKEvent | null> {
// Clean the query and normalize to lowercase // Clean the query and normalize to lowercase
let cleanedQuery = query.replace(/^nostr:/, "").toLowerCase(); const cleanedQuery = query.replace(/^nostr:/, "").toLowerCase();
let filterOrId: any = cleanedQuery; let filterOrId: NDKFilter | string = cleanedQuery;
// If it's a valid hex string, try as event id first, then as pubkey (profile) // If it's a valid hex string, try as event id first, then as pubkey (profile)
if ( if (
@ -164,7 +164,7 @@ export async function findContainingIndexEvents(
): Promise<NDKEvent[]> { ): Promise<NDKEvent[]> {
// Support all content event kinds that can be contained in indexes // Support all content event kinds that can be contained in indexes
const contentEventKinds = [30041, 30818, 30040, 30023]; const contentEventKinds = [30041, 30818, 30040, 30023];
if (!contentEventKinds.includes(contentEvent.kind)) { if (!contentEventKinds.includes(contentEvent.kind!)) {
return []; return [];
} }

5
src/lib/utils/indexEventCache.ts

@ -1,5 +1,5 @@
import type { NDKEvent } from "./nostrUtils"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants"; import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants.ts";
export interface IndexEventCacheEntry { export interface IndexEventCacheEntry {
events: NDKEvent[]; events: NDKEvent[];
@ -84,7 +84,6 @@ class IndexEventCache {
* Clear expired entries from cache * Clear expired entries from cache
*/ */
cleanup(): void { cleanup(): void {
const now = Date.now();
for (const [key, entry] of this.cache.entries()) { for (const [key, entry] of this.cache.entries()) {
if (this.isExpired(entry)) { if (this.isExpired(entry)) {
this.cache.delete(key); this.cache.delete(key);

14
src/lib/utils/markup/advancedAsciidoctorPostProcessor.ts

@ -1,4 +1,4 @@
import { postProcessAsciidoctorHtml } from "./asciidoctorPostProcessor"; import { postProcessAsciidoctorHtml } from "./asciidoctorPostProcessor.ts";
import plantumlEncoder from "plantuml-encoder"; import plantumlEncoder from "plantuml-encoder";
/** /**
@ -25,16 +25,16 @@ export async function postProcessAdvancedAsciidoctorHtml(
processedHtml = processTikZBlocks(processedHtml); processedHtml = processTikZBlocks(processedHtml);
// After all processing, apply highlight.js if available // After all processing, apply highlight.js if available
if ( if (
typeof window !== "undefined" && typeof globalThis !== "undefined" &&
typeof window.hljs?.highlightAll === "function" typeof globalThis.hljs?.highlightAll === "function"
) { ) {
setTimeout(() => window.hljs!.highlightAll(), 0); setTimeout(() => globalThis.hljs!.highlightAll(), 0);
} }
if ( if (
typeof window !== "undefined" && typeof globalThis !== "undefined" &&
typeof (window as any).MathJax?.typesetPromise === "function" typeof globalThis.MathJax?.typesetPromise === "function"
) { ) {
setTimeout(() => (window as any).MathJax.typesetPromise(), 0); setTimeout(() => globalThis.MathJax.typesetPromise(), 0);
} }
return processedHtml; return processedHtml;
} catch (error) { } catch (error) {

24
src/lib/utils/markup/advancedMarkupParser.ts

@ -1,4 +1,4 @@
import { parseBasicmarkup } from "./basicMarkupParser"; import { parseBasicmarkup } from "./basicMarkupParser.ts";
import hljs from "highlight.js"; import hljs from "highlight.js";
import "highlight.js/lib/common"; // Import common languages import "highlight.js/lib/common"; // Import common languages
import "highlight.js/styles/github-dark.css"; // Dark theme only import "highlight.js/styles/github-dark.css"; // Dark theme only
@ -35,14 +35,14 @@ const FOOTNOTE_DEFINITION_REGEX = /^\[\^([^\]]+)\]:\s*(.+)$/gm;
const CODE_BLOCK_REGEX = /^```(\w*)$/; const CODE_BLOCK_REGEX = /^```(\w*)$/;
// LaTeX math regex patterns // LaTeX math regex patterns
const INLINE_MATH_REGEX = /\$([^$\n]+?)\$/g; // const INLINE_MATH_REGEX = /\$([^$\n]+?)\$/g;
const DISPLAY_MATH_REGEX = /\$\$([\s\S]*?)\$\$/g; // const DISPLAY_MATH_REGEX = /\$\$([\s\S]*?)\$\$/g;
const LATEX_BLOCK_REGEX = /\\\[([\s\S]*?)\\\]/g; // const LATEX_BLOCK_REGEX = /\\\[([\s\S]*?)\\\]/g;
const LATEX_INLINE_REGEX = /\\\(([^)]+?)\\\)/g; // const LATEX_INLINE_REGEX = /\\\(([^)]+?)\\\)/g;
// Add regex for LaTeX display math environments (e.g., \begin{pmatrix}...\end{pmatrix}) // Add regex for LaTeX display math environments (e.g., \begin{pmatrix}...\end{pmatrix})
// Improved regex: match optional whitespace/linebreaks before and after, and allow for indented environments // Improved regex: match optional whitespace/linebreaks before and after, and allow for indented environments
const LATEX_ENV_BLOCK_REGEX = // const LATEX_ENV_BLOCK_REGEX =
/(?:^|\n)\s*\\begin\{([a-zA-Z*]+)\}([\s\S]*?)\\end\{\1\}\s*(?=\n|$)/gm; // /(?:^|\n)\s*\\begin\{([a-zA-Z*]+)\}([\s\S]*?)\\end\{\1\}\s*(?=\n|$)/gm;
/** /**
* Process headings (both styles) * Process headings (both styles)
@ -290,7 +290,7 @@ function processCodeBlocks(text: string): {
if (currentLanguage.toLowerCase() === "json") { if (currentLanguage.toLowerCase() === "json") {
try { try {
formattedCode = JSON.stringify(JSON.parse(code), null, 2); formattedCode = JSON.stringify(JSON.parse(code), null, 2);
} catch (e: unknown) { } catch {
formattedCode = code; formattedCode = code;
} }
} }
@ -333,7 +333,7 @@ function processCodeBlocks(text: string): {
if (currentLanguage.toLowerCase() === "json") { if (currentLanguage.toLowerCase() === "json") {
try { try {
formattedCode = JSON.stringify(JSON.parse(code), null, 2); formattedCode = JSON.stringify(JSON.parse(code), null, 2);
} catch (e: unknown) { } catch {
formattedCode = code; formattedCode = code;
} }
} }
@ -402,7 +402,7 @@ function restoreCodeBlocks(text: string, blocks: Map<string, string>): string {
*/ */
function processDollarMath(content: string): string { function processDollarMath(content: string): string {
// Display math: $$...$$ (multi-line, not empty) // Display math: $$...$$ (multi-line, not empty)
content = content.replace(/\$\$([\s\S]*?\S[\s\S]*?)\$\$/g, (match, expr) => { content = content.replace(/\$\$([\s\S]*?\S[\s\S]*?)\$\$/g, (_match, expr) => {
if (isLaTeXContent(expr)) { if (isLaTeXContent(expr)) {
return `<div class="math-block">$$${expr}$$</div>`; return `<div class="math-block">$$${expr}$$</div>`;
} else { } else {
@ -412,7 +412,7 @@ function processDollarMath(content: string): string {
} }
}); });
// Inline math: $...$ (not empty, not just whitespace) // Inline math: $...$ (not empty, not just whitespace)
content = content.replace(/\$([^\s$][^$\n]*?)\$/g, (match, expr) => { content = content.replace(/\$([^\s$][^$\n]*?)\$/g, (_match, expr) => {
if (isLaTeXContent(expr)) { if (isLaTeXContent(expr)) {
return `<span class="math-inline">$${expr}$</span>`; return `<span class="math-inline">$${expr}$</span>`;
} else { } else {
@ -428,7 +428,7 @@ function processDollarMath(content: string): string {
*/ */
function processMathExpressions(content: string): string { function processMathExpressions(content: string): string {
// Only process LaTeX within inline code blocks (backticks) // Only process LaTeX within inline code blocks (backticks)
return content.replace(INLINE_CODE_REGEX, (match, code) => { return content.replace(INLINE_CODE_REGEX, (_match, code) => {
const trimmedCode = code.trim(); const trimmedCode = code.trim();
// Check for unsupported LaTeX environments (like tabular) first // Check for unsupported LaTeX environments (like tabular) first

25
src/lib/utils/markup/asciidoctorExtensions.ts

@ -1,17 +1,6 @@
import { renderTikZ } from "./tikzRenderer"; // deno-lint-ignore-file no-this-alias no-explicit-any
import asciidoctor from "asciidoctor"; import Processor from "asciidoctor";
import { renderTikZ } from "./tikzRenderer.ts";
// Simple math rendering using MathJax CDN
function renderMath(content: string): string {
return `<div class="math-block" data-math="${encodeURIComponent(content)}">
<div class="math-content">${content}</div>
<script>
if (typeof MathJax !== 'undefined') {
MathJax.typesetPromise([document.querySelector('.math-content')]);
}
</script>
</div>`;
}
// Simple PlantUML rendering using PlantUML server // Simple PlantUML rendering using PlantUML server
function renderPlantUML(content: string): string { function renderPlantUML(content: string): string {
@ -27,7 +16,7 @@ function renderPlantUML(content: string): string {
* including Asciimath/Latex, PlantUML, BPMN, and TikZ * including Asciimath/Latex, PlantUML, BPMN, and TikZ
*/ */
export function createAdvancedExtensions(): any { export function createAdvancedExtensions(): any {
const Asciidoctor = asciidoctor(); const Asciidoctor = Processor();
const extensions = Asciidoctor.Extensions.create(); const extensions = Asciidoctor.Extensions.create();
// Math rendering extension (Asciimath/Latex) // Math rendering extension (Asciimath/Latex)
@ -95,7 +84,7 @@ export function createAdvancedExtensions(): any {
/** /**
* Processes math blocks (stem blocks) and converts them to rendered HTML * Processes math blocks (stem blocks) and converts them to rendered HTML
*/ */
function processMathBlocks(treeProcessor: any, document: any): void { function processMathBlocks(_: any, document: any): void {
const blocks = document.getBlocks(); const blocks = document.getBlocks();
for (const block of blocks) { for (const block of blocks) {
if (block.getContext() === "stem") { if (block.getContext() === "stem") {
@ -131,7 +120,7 @@ function processMathBlocks(treeProcessor: any, document: any): void {
/** /**
* Processes PlantUML blocks and converts them to rendered SVG * Processes PlantUML blocks and converts them to rendered SVG
*/ */
function processPlantUMLBlocks(treeProcessor: any, document: any): void { function processPlantUMLBlocks(_: any, document: any): void {
const blocks = document.getBlocks(); const blocks = document.getBlocks();
for (const block of blocks) { for (const block of blocks) {
@ -156,7 +145,7 @@ function processPlantUMLBlocks(treeProcessor: any, document: any): void {
/** /**
* Processes TikZ blocks and converts them to rendered SVG * Processes TikZ blocks and converts them to rendered SVG
*/ */
function processTikZBlocks(treeProcessor: any, document: any): void { function processTikZBlocks(_: any, document: any): void {
const blocks = document.getBlocks(); const blocks = document.getBlocks();
for (const block of blocks) { for (const block of blocks) {

8
src/lib/utils/markup/basicMarkupParser.ts

@ -1,4 +1,4 @@
import { processNostrIdentifiers } from "../nostrUtils"; import { processNostrIdentifiers } from "../nostrUtils.ts";
import * as emoji from "node-emoji"; import * as emoji from "node-emoji";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
@ -236,7 +236,7 @@ function processBasicFormatting(content: string): string {
processedText = replaceAlexandriaNostrLinks(processedText); processedText = replaceAlexandriaNostrLinks(processedText);
// Process markup images first // Process markup images first
processedText = processedText.replace(MARKUP_IMAGE, (match, alt, url) => { processedText = processedText.replace(MARKUP_IMAGE, (_match, alt, url) => {
url = stripTrackingParams(url); url = stripTrackingParams(url);
if (YOUTUBE_URL_REGEX.test(url)) { if (YOUTUBE_URL_REGEX.test(url)) {
const videoId = extractYouTubeVideoId(url); const videoId = extractYouTubeVideoId(url);
@ -261,7 +261,7 @@ function processBasicFormatting(content: string): string {
// Process markup links // Process markup links
processedText = processedText.replace( processedText = processedText.replace(
MARKUP_LINK, MARKUP_LINK,
(match, text, url) => (_match, text, url) =>
`<a href="${stripTrackingParams(url)}" class="text-primary-600 dark:text-primary-500 hover:underline" target="_blank" rel="noopener noreferrer">${text}</a>`, `<a href="${stripTrackingParams(url)}" class="text-primary-600 dark:text-primary-500 hover:underline" target="_blank" rel="noopener noreferrer">${text}</a>`,
); );
@ -303,7 +303,7 @@ function processBasicFormatting(content: string): string {
}); });
processedText = processedText.replace( processedText = processedText.replace(
STRIKETHROUGH_REGEX, STRIKETHROUGH_REGEX,
(match, doubleText, singleText) => { (_match, doubleText, singleText) => {
const text = doubleText || singleText; const text = doubleText || singleText;
return `<del class="line-through">${text}</del>`; return `<del class="line-through">${text}</del>`;
}, },

11
src/lib/utils/network_detection.ts

@ -1,4 +1,4 @@
import { deduplicateRelayUrls } from './relay_management'; import { deduplicateRelayUrls } from "./relay_management.ts";
/** /**
* Network conditions for relay selection * Network conditions for relay selection
@ -26,7 +26,7 @@ export async function isNetworkOnline(): Promise<boolean> {
for (const endpoint of NETWORK_ENDPOINTS) { for (const endpoint of NETWORK_ENDPOINTS) {
try { try {
// Use a simple fetch without HEAD method to avoid CORS issues // Use a simple fetch without HEAD method to avoid CORS issues
const response = await fetch(endpoint, { await fetch(endpoint, {
method: 'GET', method: 'GET',
cache: 'no-cache', cache: 'no-cache',
signal: AbortSignal.timeout(3000), signal: AbortSignal.timeout(3000),
@ -127,8 +127,7 @@ export function getRelaySetForNetworkCondition(
outboxRelays: [] outboxRelays: []
}; };
} }
case NetworkCondition.SLOW: {
case NetworkCondition.SLOW:
// Local relays + low bandwidth relays when slow (deduplicated) // Local relays + low bandwidth relays when slow (deduplicated)
console.debug('[network_detection.ts] Using local + low bandwidth relays (slow network)'); console.debug('[network_detection.ts] Using local + low bandwidth relays (slow network)');
const slowInboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...lowbandwidthRelays]); const slowInboxRelays = deduplicateRelayUrls([...discoveredLocalRelays, ...lowbandwidthRelays]);
@ -137,7 +136,7 @@ export function getRelaySetForNetworkCondition(
inboxRelays: slowInboxRelays, inboxRelays: slowInboxRelays,
outboxRelays: slowOutboxRelays outboxRelays: slowOutboxRelays
}; };
}
case NetworkCondition.ONLINE: case NetworkCondition.ONLINE:
default: default:
// Full relay set when online // Full relay set when online
@ -177,7 +176,7 @@ export function startNetworkMonitoring(
checkNetwork(); checkNetwork();
// Set up periodic monitoring // Set up periodic monitoring
intervalId = window.setInterval(checkNetwork, checkInterval); intervalId = globalThis.setInterval(checkNetwork, checkInterval);
// Return function to stop monitoring // Return function to stop monitoring
return () => { return () => {

21
src/lib/utils/nostrEventService.ts

@ -1,10 +1,9 @@
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils"; import { getEventHash, signEvent, prefixNostrAddresses } from "./nostrUtils.ts";
import { get } from "svelte/store"; import { get } from "svelte/store";
import { goto } from "$app/navigation"; import { goto } from "$app/navigation";
import { EVENT_KINDS, TIME_CONSTANTS, TIMEOUTS } from "./search_constants"; import { EVENT_KINDS, TIME_CONSTANTS } from "./search_constants.ts";
import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { ndkInstance } from "../ndk.ts";
import { ndkInstance } from "$lib/ndk";
import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk";
export interface RootEventInfo { export interface RootEventInfo {
@ -139,7 +138,6 @@ export function extractParentEventInfo(parent: NDKEvent): ParentEventInfo {
*/ */
function buildRootScopeTags( function buildRootScopeTags(
rootInfo: RootEventInfo, rootInfo: RootEventInfo,
parentInfo: ParentEventInfo,
): string[][] { ): string[][] {
const tags: string[][] = []; const tags: string[][] = [];
@ -292,7 +290,7 @@ export function buildReplyTags(
// For regular events, use E/e tags // For regular events, use E/e tags
if (isReplyToComment) { if (isReplyToComment) {
// Reply to a comment - distinguish root from parent // Reply to a comment - distinguish root from parent
addTags(tags, ...buildRootScopeTags(rootInfo, parentInfo)); addTags(tags, ...buildRootScopeTags(rootInfo));
addTags( addTags(
tags, tags,
createTag("e", parent.id, parentInfo.parentRelay), createTag("e", parent.id, parentInfo.parentRelay),
@ -301,7 +299,7 @@ export function buildReplyTags(
); );
} else { } else {
// Top-level comment or regular event // Top-level comment or regular event
addTags(tags, ...buildRootScopeTags(rootInfo, parentInfo)); addTags(tags, ...buildRootScopeTags(rootInfo));
addTags(tags, ...buildParentScopeTags(parent, parentInfo, rootInfo)); addTags(tags, ...buildParentScopeTags(parent, parentInfo, rootInfo));
} }
} }
@ -318,6 +316,7 @@ export async function createSignedEvent(
pubkey: string, pubkey: string,
kind: number, kind: number,
tags: string[][], tags: string[][],
// deno-lint-ignore no-explicit-any
): Promise<{ id: string; sig: string; event: any }> { ): Promise<{ id: string; sig: string; event: any }> {
const prefixedContent = prefixNostrAddresses(content); const prefixedContent = prefixNostrAddresses(content);
@ -337,8 +336,8 @@ export async function createSignedEvent(
}; };
let sig, id; let sig, id;
if (typeof window !== "undefined" && window.nostr && window.nostr.signEvent) { if (typeof window !== "undefined" && globalThis.nostr && globalThis.nostr.signEvent) {
const signed = await window.nostr.signEvent(eventToSign); const signed = await globalThis.nostr.signEvent(eventToSign);
sig = signed.sig as string; sig = signed.sig as string;
id = "id" in signed ? (signed.id as string) : getEventHash(eventToSign); id = "id" in signed ? (signed.id as string) : getEventHash(eventToSign);
} else { } else {
@ -364,7 +363,7 @@ export async function createSignedEvent(
* @returns Promise that resolves to array of successful relay URLs * @returns Promise that resolves to array of successful relay URLs
*/ */
export async function publishEvent( export async function publishEvent(
event: NDKEvent | any, event: NDKEvent,
relayUrls: string[], relayUrls: string[],
): Promise<string[]> { ): Promise<string[]> {
const successfulRelays: string[] = []; const successfulRelays: string[] = [];
@ -427,6 +426,7 @@ export function navigateToEvent(eventId: string): void {
} }
// Helper functions to ensure relay and pubkey are always strings // Helper functions to ensure relay and pubkey are always strings
// deno-lint-ignore no-explicit-any
function getRelayString(relay: any): string { function getRelayString(relay: any): string {
if (!relay) return ""; if (!relay) return "";
if (typeof relay === "string") return relay; if (typeof relay === "string") return relay;
@ -434,6 +434,7 @@ function getRelayString(relay: any): string {
return ""; return "";
} }
// deno-lint-ignore no-explicit-any
function getPubkeyString(pubkey: any): string { function getPubkeyString(pubkey: any): string {
if (!pubkey) return ""; if (!pubkey) return "";
if (typeof pubkey === "string") return pubkey; if (typeof pubkey === "string") return pubkey;

26
src/lib/utils/nostrUtils.ts

@ -1,17 +1,17 @@
import { get } from "svelte/store"; import { get } from "svelte/store";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { ndkInstance } from "$lib/ndk"; import { ndkInstance } from "../ndk.ts";
import { npubCache } from "./npubCache"; import { npubCache } from "./npubCache.ts";
import NDK, { NDKEvent, NDKRelaySet, NDKUser } from "@nostr-dev-kit/ndk"; import NDK, { NDKEvent, NDKRelaySet, NDKUser } from "@nostr-dev-kit/ndk";
import type { NDKFilter, NDKKind } from "@nostr-dev-kit/ndk"; import type { NDKFilter, NDKKind, NostrEvent } from "@nostr-dev-kit/ndk";
import { communityRelays, secondaryRelays, anonymousRelays } from "$lib/consts"; import { communityRelays, secondaryRelays } from "../consts.ts";
import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts";
import { NDKRelaySet as NDKRelaySetFromNDK } from "@nostr-dev-kit/ndk"; import { NDKRelaySet as NDKRelaySetFromNDK } from "@nostr-dev-kit/ndk";
import { sha256 } from "@noble/hashes/sha256"; import { sha256 } from "@noble/hashes/sha2.js";
import { schnorr } from "@noble/curves/secp256k1"; import { schnorr } from "@noble/curves/secp256k1";
import { bytesToHex } from "@noble/hashes/utils"; import { bytesToHex } from "@noble/hashes/utils";
import { wellKnownUrl } from "./search_utility"; import { wellKnownUrl } from "./search_utility.ts";
import { TIMEOUTS, VALIDATION } from "./search_constants"; import { VALIDATION } from "./search_constants.ts";
const badgeCheckSvg = const badgeCheckSvg =
'<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M12 2c-.791 0-1.55.314-2.11.874l-.893.893a.985.985 0 0 1-.696.288H7.04A2.984 2.984 0 0 0 4.055 7.04v1.262a.986.986 0 0 1-.288.696l-.893.893a2.984 2.984 0 0 0 0 4.22l.893.893a.985.985 0 0 1 .288.696v1.262a2.984 2.984 0 0 0 2.984 2.984h1.262c.261 0 .512.104.696.288l.893.893a2.984 2.984 0 0 0 4.22 0l.893-.893a.985.985 0 0 1 .696-.288h1.262a2.984 2.984 0 0 0 2.984-2.984V15.7c0-.261.104-.512.288-.696l.893-.893a2.984 2.984 0 0 0 0-4.22l-.893-.893a.985.985 0 0 1-.288-.696V7.04a2.984 2.984 0 0 0-2.984-2.984h-1.262a.985.985 0 0 1-.696-.288l-.893-.893A2.984 2.984 0 0 0 12 2Zm3.683 7.73a1 1 0 1 0-1.414-1.413l-4.253 4.253-1.277-1.277a1 1 0 0 0-1.415 1.414l1.985 1.984a1 1 0 0 0 1.414 0l4.96-4.96Z" clip-rule="evenodd"/></svg>'; '<svg class="w-6 h-6 text-gray-800 dark:text-white" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M12 2c-.791 0-1.55.314-2.11.874l-.893.893a.985.985 0 0 1-.696.288H7.04A2.984 2.984 0 0 0 4.055 7.04v1.262a.986.986 0 0 1-.288.696l-.893.893a2.984 2.984 0 0 0 0 4.22l.893.893a.985.985 0 0 1 .288.696v1.262a2.984 2.984 0 0 0 2.984 2.984h1.262c.261 0 .512.104.696.288l.893.893a2.984 2.984 0 0 0 4.22 0l.893-.893a.985.985 0 0 1 .696-.288h1.262a2.984 2.984 0 0 0 2.984-2.984V15.7c0-.261.104-.512.288-.696l.893-.893a2.984 2.984 0 0 0 0-4.22l-.893-.893a.985.985 0 0 1-.288-.696V7.04a2.984 2.984 0 0 0-2.984-2.984h-1.262a.985.985 0 0 1-.696-.288l-.893-.893A2.984 2.984 0 0 0 12 2Zm3.683 7.73a1 1 0 1 0-1.414-1.413l-4.253 4.253-1.277-1.277a1 1 0 0 0-1.415 1.414l1.985 1.984a1 1 0 0 0 1.414 0l4.96-4.96Z" clip-rule="evenodd"/></svg>';
@ -442,7 +442,7 @@ export async function fetchEventWithFallback(
// Use both inbox and outbox relays for better event discovery // Use both inbox and outbox relays for better event discovery
const inboxRelays = get(activeInboxRelays); const inboxRelays = get(activeInboxRelays);
const outboxRelays = get(activeOutboxRelays); const outboxRelays = get(activeOutboxRelays);
const allRelays = [...(inboxRelays || []), ...(outboxRelays || [])]; const allRelays = [...inboxRelays, ...outboxRelays];
console.log("fetchEventWithFallback: Using inbox relays:", inboxRelays); console.log("fetchEventWithFallback: Using inbox relays:", inboxRelays);
console.log("fetchEventWithFallback: Using outbox relays:", outboxRelays); console.log("fetchEventWithFallback: Using outbox relays:", outboxRelays);
@ -464,7 +464,7 @@ export async function fetchEventWithFallback(
console.log("fetchEventWithFallback: Relay set size:", relaySet.relays.size); console.log("fetchEventWithFallback: Relay set size:", relaySet.relays.size);
console.log("fetchEventWithFallback: Filter:", filterOrId); console.log("fetchEventWithFallback: Filter:", filterOrId);
console.log("fetchEventWithFallback: Relay URLs:", Array.from(relaySet.relays).map((r: any) => r.url)); console.log("fetchEventWithFallback: Relay URLs:", Array.from(relaySet.relays).map((r) => r.url));
let found: NDKEvent | null = null; let found: NDKEvent | null = null;
@ -488,7 +488,7 @@ export async function fetchEventWithFallback(
if (!found) { if (!found) {
const timeoutSeconds = timeoutMs / 1000; const timeoutSeconds = timeoutMs / 1000;
const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); const relayUrls = Array.from(relaySet.relays).map((r) => r.url).join(", ");
console.warn( console.warn(
`fetchEventWithFallback: Event not found after ${timeoutSeconds}s timeout. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, `fetchEventWithFallback: Event not found after ${timeoutSeconds}s timeout. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`,
); );
@ -501,7 +501,7 @@ export async function fetchEventWithFallback(
} catch (err) { } catch (err) {
if (err instanceof Error && err.message === 'Timeout') { if (err instanceof Error && err.message === 'Timeout') {
const timeoutSeconds = timeoutMs / 1000; const timeoutSeconds = timeoutMs / 1000;
const relayUrls = Array.from(relaySet.relays).map((r: any) => r.url).join(", "); const relayUrls = Array.from(relaySet.relays).map((r) => r.url).join(", ");
console.warn( console.warn(
`fetchEventWithFallback: Event fetch timed out after ${timeoutSeconds}s. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`, `fetchEventWithFallback: Event fetch timed out after ${timeoutSeconds}s. Tried inbox relays: ${relayUrls}. Some relays may be offline or slow.`,
); );
@ -536,7 +536,7 @@ export function createRelaySetFromUrls(relayUrls: string[], ndk: NDK) {
return NDKRelaySetFromNDK.fromRelayUrls(relayUrls, ndk); return NDKRelaySetFromNDK.fromRelayUrls(relayUrls, ndk);
} }
export function createNDKEvent(ndk: NDK, rawEvent: any) { export function createNDKEvent(ndk: NDK, rawEvent: NDKEvent | NostrEvent | undefined) {
return new NDKEvent(ndk, rawEvent); return new NDKEvent(ndk, rawEvent);
} }

30
src/lib/utils/profile_search.ts

@ -1,19 +1,16 @@
import { ndkInstance } from "$lib/ndk"; import { ndkInstance } from "../ndk.ts";
import { getUserMetadata, getNpubFromNip05 } from "$lib/utils/nostrUtils"; import { getUserMetadata, getNpubFromNip05 } from "./nostrUtils.ts";
import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; import NDK, { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk";
import { searchCache } from "$lib/utils/searchCache"; import { searchCache } from "./searchCache.ts";
import { communityRelays, secondaryRelays } from "$lib/consts"; import { communityRelays, secondaryRelays } from "../consts.ts";
import { get } from "svelte/store"; import { get } from "svelte/store";
import type { NostrProfile, ProfileSearchResult } from "./search_types"; import type { NostrProfile, ProfileSearchResult } from "./search_types.ts";
import { import {
fieldMatches, fieldMatches,
nip05Matches, nip05Matches,
normalizeSearchTerm, normalizeSearchTerm,
COMMON_DOMAINS,
createProfileFromEvent, createProfileFromEvent,
} from "./search_utils"; } from "./search_utils.ts";
import { checkCommunityStatus } from "./community_checker";
import { TIMEOUTS } from "./search_constants";
/** /**
* Search for profiles by various criteria (display name, name, NIP-05, npub) * Search for profiles by various criteria (display name, name, NIP-05, npub)
@ -92,7 +89,7 @@ export async function searchProfiles(
} else { } else {
// Try NIP-05 search first (faster than relay search) // Try NIP-05 search first (faster than relay search)
console.log("Starting NIP-05 search for:", normalizedSearchTerm); console.log("Starting NIP-05 search for:", normalizedSearchTerm);
foundProfiles = await searchNip05Domains(normalizedSearchTerm, ndk); foundProfiles = await searchNip05Domains(normalizedSearchTerm);
console.log( console.log(
"NIP-05 search completed, found:", "NIP-05 search completed, found:",
foundProfiles.length, foundProfiles.length,
@ -145,7 +142,6 @@ export async function searchProfiles(
*/ */
async function searchNip05Domains( async function searchNip05Domains(
searchTerm: string, searchTerm: string,
ndk: any,
): Promise<NostrProfile[]> { ): Promise<NostrProfile[]> {
const foundProfiles: NostrProfile[] = []; const foundProfiles: NostrProfile[] = [];
@ -260,10 +256,9 @@ async function searchNip05Domains(
*/ */
async function quickRelaySearch( async function quickRelaySearch(
searchTerm: string, searchTerm: string,
ndk: any, ndk: NDK,
): Promise<NostrProfile[]> { ): Promise<NostrProfile[]> {
console.log("quickRelaySearch called with:", searchTerm); console.log("quickRelaySearch called with:", searchTerm);
const foundProfiles: NostrProfile[] = [];
// Normalize the search term for relay search // Normalize the search term for relay search
const normalizedSearchTerm = normalizeSearchTerm(searchTerm); const normalizedSearchTerm = normalizeSearchTerm(searchTerm);
@ -286,7 +281,7 @@ async function quickRelaySearch(
.filter(Boolean); .filter(Boolean);
// Search all relays in parallel with short timeout // Search all relays in parallel with short timeout
const searchPromises = relaySets.map(async (relaySet, index) => { const searchPromises = relaySets.map((relaySet, index) => {
if (!relaySet) return []; if (!relaySet) return [];
return new Promise<NostrProfile[]>((resolve) => { return new Promise<NostrProfile[]>((resolve) => {
@ -299,7 +294,8 @@ async function quickRelaySearch(
const sub = ndk.subscribe( const sub = ndk.subscribe(
{ kinds: [0] }, { kinds: [0] },
{ closeOnEose: true, relaySet }, { closeOnEose: true },
relaySet,
); );
sub.on("event", (event: NDKEvent) => { sub.on("event", (event: NDKEvent) => {
@ -351,7 +347,7 @@ async function quickRelaySearch(
foundInRelay.push(profile); foundInRelay.push(profile);
} }
} }
} catch (e) { } catch {
// Invalid JSON or other error, skip // Invalid JSON or other error, skip
} }
}); });

7
src/lib/utils/relayDiagnostics.ts

@ -1,6 +1,5 @@
import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts";
import NDK from "@nostr-dev-kit/ndk"; import { TIMEOUTS } from "./search_constants.ts";
import { TIMEOUTS } from "./search_constants";
import { get } from "svelte/store"; import { get } from "svelte/store";
export interface RelayDiagnostic { export interface RelayDiagnostic {
@ -14,7 +13,7 @@ export interface RelayDiagnostic {
/** /**
* Tests connection to a single relay * Tests connection to a single relay
*/ */
export async function testRelay(url: string): Promise<RelayDiagnostic> { export function testRelay(url: string): Promise<RelayDiagnostic> {
const startTime = Date.now(); const startTime = Date.now();
return new Promise((resolve) => { return new Promise((resolve) => {

34
src/lib/utils/relay_management.ts

@ -1,7 +1,7 @@
import NDK, { NDKRelay, NDKUser } from "@nostr-dev-kit/ndk"; import NDK, { NDKKind, NDKRelay, NDKUser } from "@nostr-dev-kit/ndk";
import { communityRelays, searchRelays, secondaryRelays, anonymousRelays, lowbandwidthRelays, localRelays } from "../consts"; import { searchRelays, secondaryRelays, anonymousRelays, lowbandwidthRelays, localRelays } from "../consts.ts";
import { getRelaySetForNetworkCondition, NetworkCondition } from "./network_detection"; import { getRelaySetForNetworkCondition } from "./network_detection.ts";
import { networkCondition } from "../stores/networkStore"; import { networkCondition } from "../stores/networkStore.ts";
import { get } from "svelte/store"; import { get } from "svelte/store";
/** /**
@ -48,7 +48,7 @@ export function deduplicateRelayUrls(urls: string[]): string[] {
* @param ndk The NDK instance * @param ndk The NDK instance
* @returns Promise that resolves to connection status * @returns Promise that resolves to connection status
*/ */
export async function testRelayConnection( export function testRelayConnection(
relayUrl: string, relayUrl: string,
ndk: NDK, ndk: NDK,
): Promise<{ ): Promise<{
@ -163,7 +163,7 @@ async function testLocalRelays(localRelayUrls: string[], ndk: NDK): Promise<stri
} else { } else {
console.debug(`[relay_management.ts] Local relay failed: ${url} - ${result.error}`); console.debug(`[relay_management.ts] Local relay failed: ${url} - ${result.error}`);
} }
} catch (error) { } catch {
// Silently ignore local relay failures - they're optional // Silently ignore local relay failures - they're optional
console.debug(`[relay_management.ts] Local relay error (ignored): ${url}`); console.debug(`[relay_management.ts] Local relay error (ignored): ${url}`);
} }
@ -188,7 +188,7 @@ export async function discoverLocalRelays(ndk: NDK): Promise<string[]> {
} }
// Convert wss:// URLs from consts to ws:// for local testing // Convert wss:// URLs from consts to ws:// for local testing
const localRelayUrls = localRelays.map(url => const localRelayUrls = localRelays.map((url: string) =>
url.replace(/^wss:\/\//, 'ws://') url.replace(/^wss:\/\//, 'ws://')
); );
@ -197,7 +197,7 @@ export async function discoverLocalRelays(ndk: NDK): Promise<string[]> {
// If no local relays are working, return empty array // If no local relays are working, return empty array
// The network detection logic will provide fallback relays // The network detection logic will provide fallback relays
return workingRelays; return workingRelays;
} catch (error) { } catch {
// Silently fail and return empty array // Silently fail and return empty array
return []; return [];
} }
@ -213,7 +213,7 @@ export async function getUserLocalRelays(ndk: NDK, user: NDKUser): Promise<strin
try { try {
const localRelayEvent = await ndk.fetchEvent( const localRelayEvent = await ndk.fetchEvent(
{ {
kinds: [10432 as any], kinds: [10432 as NDKKind],
authors: [user.pubkey], authors: [user.pubkey],
}, },
{ {
@ -338,8 +338,8 @@ export async function getUserOutboxRelays(ndk: NDK, user: NDKUser): Promise<stri
export async function getExtensionRelays(): Promise<string[]> { export async function getExtensionRelays(): Promise<string[]> {
try { try {
// Check if we're in a browser environment with extension support // Check if we're in a browser environment with extension support
if (typeof window === 'undefined' || !window.nostr) { if (typeof window === 'undefined' || !globalThis.nostr) {
console.debug('[relay_management.ts] No window.nostr available'); console.debug('[relay_management.ts] No globalThis.nostr available');
return []; return [];
} }
@ -348,10 +348,10 @@ export async function getExtensionRelays(): Promise<string[]> {
// Try to get relays from the extension's API // Try to get relays from the extension's API
// Different extensions may expose their relay config differently // Different extensions may expose their relay config differently
if (window.nostr.getRelays) { if (globalThis.nostr.getRelays) {
console.debug('[relay_management.ts] getRelays() method found, calling it...'); console.debug('[relay_management.ts] getRelays() method found, calling it...');
try { try {
const relays = await window.nostr.getRelays(); const relays = await globalThis.nostr.getRelays();
console.debug('[relay_management.ts] getRelays() returned:', relays); console.debug('[relay_management.ts] getRelays() returned:', relays);
if (relays && typeof relays === 'object') { if (relays && typeof relays === 'object') {
// Convert relay object to array of URLs // Convert relay object to array of URLs
@ -363,7 +363,7 @@ export async function getExtensionRelays(): Promise<string[]> {
console.debug('[relay_management.ts] Extension getRelays() failed:', error); console.debug('[relay_management.ts] Extension getRelays() failed:', error);
} }
} else { } else {
console.debug('[relay_management.ts] getRelays() method not found on window.nostr'); console.debug('[relay_management.ts] getRelays() method not found on globalThis.nostr');
} }
// If getRelays() didn't work, try alternative methods // If getRelays() didn't work, try alternative methods
@ -457,7 +457,7 @@ export async function buildCompleteRelaySet(
try { try {
blockedRelays = await getUserBlockedRelays(ndk, user); blockedRelays = await getUserBlockedRelays(ndk, user);
console.debug('[relay_management.ts] buildCompleteRelaySet: User blocked relays:', blockedRelays); console.debug('[relay_management.ts] buildCompleteRelaySet: User blocked relays:', blockedRelays);
} catch (error) { } catch {
// Silently ignore blocked relay fetch errors // Silently ignore blocked relay fetch errors
} }
@ -511,8 +511,8 @@ export async function buildCompleteRelaySet(
// Filter out blocked relays and deduplicate final sets // Filter out blocked relays and deduplicate final sets
const finalRelaySet = { const finalRelaySet = {
inboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.inboxRelays.filter(r => !blockedRelays.includes(r))), inboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.inboxRelays.filter((r: string) => !blockedRelays.includes(r))),
outboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.outboxRelays.filter(r => !blockedRelays.includes(r))) outboxRelays: deduplicateRelayUrls(networkOptimizedRelaySet.outboxRelays.filter((r: string) => !blockedRelays.includes(r)))
}; };
// If no relays are working, use anonymous relays as fallback // If no relays are working, use anonymous relays as fallback

5
src/lib/utils/searchCache.ts

@ -1,5 +1,5 @@
import type { NDKEvent } from "./nostrUtils"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants"; import { CACHE_DURATIONS, TIMEOUTS } from "./search_constants.ts";
export interface SearchResult { export interface SearchResult {
events: NDKEvent[]; events: NDKEvent[];
@ -78,7 +78,6 @@ class SearchCache {
* Clear expired entries from cache * Clear expired entries from cache
*/ */
cleanup(): void { cleanup(): void {
const now = Date.now();
for (const [key, result] of this.cache.entries()) { for (const [key, result] of this.cache.entries()) {
if (this.isExpired(result)) { if (this.isExpired(result)) {
this.cache.delete(key); this.cache.delete(key);

6
src/lib/utils/search_types.ts

@ -1,4 +1,4 @@
import { NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKEvent, NDKFilter, NDKSubscription } from "@nostr-dev-kit/ndk";
/** /**
* Extended NostrProfile interface for search results * Extended NostrProfile interface for search results
@ -45,7 +45,7 @@ export type SearchSubscriptionType = "d" | "t" | "n";
* Search filter configuration * Search filter configuration
*/ */
export interface SearchFilter { export interface SearchFilter {
filter: any; filter: NDKFilter;
subscriptionType: string; subscriptionType: string;
} }
@ -65,5 +65,5 @@ export interface SecondOrderSearchParams {
*/ */
export interface SearchCallbacks { export interface SearchCallbacks {
onSecondOrderUpdate?: (result: SearchResult) => void; onSecondOrderUpdate?: (result: SearchResult) => void;
onSubscriptionCreated?: (sub: any) => void; onSubscriptionCreated?: (sub: NDKSubscription) => void;
} }

7
src/lib/utils/search_utils.ts

@ -1,3 +1,5 @@
import { NDKEvent } from "@nostr-dev-kit/ndk";
/** /**
* Generate well-known NIP-05 URL * Generate well-known NIP-05 URL
*/ */
@ -85,14 +87,15 @@ export const COMMON_DOMAINS = [
/** /**
* Check if an event is an emoji reaction (kind 7) * Check if an event is an emoji reaction (kind 7)
*/ */
export function isEmojiReaction(event: any): boolean { export function isEmojiReaction(event: NDKEvent): boolean {
return event.kind === 7; return event.kind === 7;
} }
/** /**
* Create a profile object from event data * Create a profile object from event data
*/ */
export function createProfileFromEvent(event: any, profileData: any): any { // deno-lint-ignore no-explicit-any
export function createProfileFromEvent(event: NDKEvent, profileData: any): any {
return { return {
name: profileData.name, name: profileData.name,
displayName: profileData.displayName || profileData.display_name, displayName: profileData.displayName || profileData.display_name,

46
src/lib/utils/subscription_search.ts

@ -1,26 +1,25 @@
import { ndkInstance } from "$lib/ndk"; // deno-lint-ignore-file no-explicit-any
import { getMatchingTags, getNpubFromNip05 } from "$lib/utils/nostrUtils"; import { ndkInstance } from "../ndk.ts";
import { nip19 } from "$lib/utils/nostrUtils"; import { getMatchingTags, getNpubFromNip05 } from "./nostrUtils.ts";
import { nip19 } from "./nostrUtils.ts";
import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk"; import { NDKRelaySet, NDKEvent } from "@nostr-dev-kit/ndk";
import { searchCache } from "$lib/utils/searchCache"; import { searchCache } from "./searchCache.ts";
import { communityRelays, searchRelays } from "$lib/consts"; import { communityRelays, searchRelays } from "../consts.ts";
import { get } from "svelte/store"; import { get } from "svelte/store";
import type { import type {
SearchResult, SearchResult,
SearchSubscriptionType, SearchSubscriptionType,
SearchFilter, SearchFilter,
SearchCallbacks, SearchCallbacks,
SecondOrderSearchParams, } from "./search_types.ts";
} from "./search_types";
import { import {
fieldMatches, fieldMatches,
nip05Matches, nip05Matches,
normalizeSearchTerm,
COMMON_DOMAINS, COMMON_DOMAINS,
isEmojiReaction, isEmojiReaction,
} from "./search_utils"; } from "./search_utils.ts";
import { TIMEOUTS, SEARCH_LIMITS } from "./search_constants"; import { TIMEOUTS, SEARCH_LIMITS } from "./search_constants.ts";
import { activeInboxRelays, activeOutboxRelays } from "$lib/ndk"; import { activeInboxRelays, activeOutboxRelays } from "../ndk.ts";
// Helper function to normalize URLs for comparison // Helper function to normalize URLs for comparison
const normalizeUrl = (url: string): string => { const normalizeUrl = (url: string): string => {
@ -132,7 +131,6 @@ export async function searchBySubscription(
searchFilter, searchFilter,
searchState, searchState,
callbacks, callbacks,
abortSignal,
cleanup, cleanup,
); );
@ -160,7 +158,6 @@ export async function searchBySubscription(
searchFilter, searchFilter,
searchState, searchState,
callbacks, callbacks,
abortSignal,
cleanup, cleanup,
); );
} }
@ -215,26 +212,30 @@ async function createSearchFilter(
}); });
switch (searchType) { switch (searchType) {
case "d": case "d": {
const dFilter = { const dFilter = {
filter: { "#d": [normalizedSearchTerm] }, filter: { "#d": [normalizedSearchTerm] },
subscriptionType: "d-tag", subscriptionType: "d-tag",
}; };
console.log("subscription_search: Created d-tag filter:", dFilter); console.log("subscription_search: Created d-tag filter:", dFilter);
return dFilter; return dFilter;
case "t": }
case "t": {
const tFilter = { const tFilter = {
filter: { "#t": [normalizedSearchTerm] }, filter: { "#t": [normalizedSearchTerm] },
subscriptionType: "t-tag", subscriptionType: "t-tag",
}; };
console.log("subscription_search: Created t-tag filter:", tFilter); console.log("subscription_search: Created t-tag filter:", tFilter);
return tFilter; return tFilter;
case "n": }
case "n": {
const nFilter = await createProfileSearchFilter(normalizedSearchTerm); const nFilter = await createProfileSearchFilter(normalizedSearchTerm);
console.log("subscription_search: Created profile filter:", nFilter); console.log("subscription_search: Created profile filter:", nFilter);
return nFilter; return nFilter;
default: }
default: {
throw new Error(`Unknown search type: ${searchType}`); throw new Error(`Unknown search type: ${searchType}`);
}
} }
} }
@ -257,7 +258,7 @@ async function createProfileSearchFilter(
subscriptionType: "npub-specific", subscriptionType: "npub-specific",
}; };
} }
} catch (e) { } catch {
// Not a valid npub, continue with other strategies // Not a valid npub, continue with other strategies
} }
@ -277,11 +278,11 @@ async function createProfileSearchFilter(
subscriptionType: "nip05-found", subscriptionType: "nip05-found",
}; };
} }
} catch (e) { } catch {
// Continue to next domain // Continue to next domain
} }
} }
} catch (e) { } catch {
// Fallback to reasonable profile search // Fallback to reasonable profile search
} }
@ -520,12 +521,11 @@ function createSearchResult(
/** /**
* Search other relays in background * Search other relays in background
*/ */
async function searchOtherRelaysInBackground( function searchOtherRelaysInBackground(
searchType: SearchSubscriptionType, searchType: SearchSubscriptionType,
searchFilter: SearchFilter, searchFilter: SearchFilter,
searchState: any, searchState: any,
callbacks?: SearchCallbacks, callbacks?: SearchCallbacks,
abortSignal?: AbortSignal,
cleanup?: () => void, cleanup?: () => void,
): Promise<SearchResult> { ): Promise<SearchResult> {
const ndk = get(ndkInstance); const ndk = get(ndkInstance);
@ -578,7 +578,7 @@ async function searchOtherRelaysInBackground(
} else { } else {
processContentEvent(event, searchType, searchState); processContentEvent(event, searchType, searchState);
} }
} catch (e) { } catch {
// Invalid JSON or other error, skip // Invalid JSON or other error, skip
} }
}); });

15
src/routes/+layout.ts

@ -1,11 +1,11 @@
import { getPersistedLogin, initNdk, ndkInstance } from "$lib/ndk"; import { getPersistedLogin, initNdk, ndkInstance } from "../lib/ndk.ts";
import { import {
loginWithExtension, loginWithExtension,
loginWithAmber, loginWithAmber,
loginWithNpub, loginWithNpub,
} from "$lib/stores/userStore"; } from "../lib/stores/userStore.ts";
import { loginMethodStorageKey } from "$lib/stores/userStore"; import { loginMethodStorageKey } from "../lib/stores/userStore.ts";
import Pharos, { pharosInstance } from "$lib/parser"; import Pharos, { pharosInstance } from "../lib/parser.ts";
import type { LayoutLoad } from "./$types"; import type { LayoutLoad } from "./$types";
import { get } from "svelte/store"; import { get } from "svelte/store";
@ -35,10 +35,11 @@ export const load: LayoutLoad = () => {
const localNsec = localStorage.getItem("amber/nsec"); const localNsec = localStorage.getItem("amber/nsec");
if (localNsec) { if (localNsec) {
import("@nostr-dev-kit/ndk").then( import("@nostr-dev-kit/ndk").then(
async ({ NDKNip46Signer, default: NDK }) => { async ({ NDKNip46Signer }) => {
const ndk = get(ndkInstance); const ndk = get(ndkInstance);
try { try {
const amberSigner = NDKNip46Signer.nostrconnect( // deno-lint-ignore no-explicit-any
const amberSigner = (NDKNip46Signer as any).nostrconnect(
ndk, ndk,
relay, relay,
localNsec, localNsec,
@ -52,7 +53,7 @@ export const load: LayoutLoad = () => {
const user = await amberSigner.user(); const user = await amberSigner.user();
await loginWithAmber(amberSigner, user); await loginWithAmber(amberSigner, user);
console.log("Amber session restored."); console.log("Amber session restored.");
} catch (err) { } catch {
// If reconnection fails, automatically fallback to npub-only mode // If reconnection fails, automatically fallback to npub-only mode
console.warn( console.warn(
"Amber session could not be restored. Falling back to npub-only mode.", "Amber session could not be restored. Falling back to npub-only mode.",

6
src/routes/+page.svelte

@ -1,12 +1,8 @@
<script lang="ts"> <script lang="ts">
import { Alert, Input } from "flowbite-svelte"; import { Input } from "flowbite-svelte";
import { HammerSolid } from "flowbite-svelte-icons";
import { userStore } from "$lib/stores/userStore";
import { activeInboxRelays, ndkSignedIn } from "$lib/ndk";
import PublicationFeed from "$lib/components/publications/PublicationFeed.svelte"; import PublicationFeed from "$lib/components/publications/PublicationFeed.svelte";
let searchQuery = $state(""); let searchQuery = $state("");
let user = $derived($userStore);
let eventCount = $state({ displayed: 0, total: 0 }); let eventCount = $state({ displayed: 0, total: 0 });
function handleEventCountUpdate(counts: { displayed: number; total: number }) { function handleEventCountUpdate(counts: { displayed: number; total: number }) {

15
src/routes/publication/+page.ts

@ -2,8 +2,9 @@ import { error } from "@sveltejs/kit";
import type { Load } from "@sveltejs/kit"; import type { Load } from "@sveltejs/kit";
import type { NDKEvent } from "@nostr-dev-kit/ndk"; import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools"; import { nip19 } from "nostr-tools";
import { getActiveRelaySetAsNDKRelaySet } from "$lib/ndk"; import { getActiveRelaySetAsNDKRelaySet } from "../../lib/ndk.ts";
import { getMatchingTags } from "$lib/utils/nostrUtils"; import { getMatchingTags } from "../../lib/utils/nostrUtils.ts";
import type NDK from "@nostr-dev-kit/ndk";
/** /**
* Decodes an naddr identifier and returns a filter object * Decodes an naddr identifier and returns a filter object
@ -30,7 +31,7 @@ function decodeNaddr(id: string) {
/** /**
* Fetches an event by ID or filter * Fetches an event by ID or filter
*/ */
async function fetchEventById(ndk: any, id: string): Promise<NDKEvent> { async function fetchEventById(ndk: NDK, id: string): Promise<NDKEvent> {
const filter = decodeNaddr(id); const filter = decodeNaddr(id);
// Handle the case where filter is null (decoding error) // Handle the case where filter is null (decoding error)
@ -66,7 +67,7 @@ async function fetchEventById(ndk: any, id: string): Promise<NDKEvent> {
/** /**
* Fetches an event by d tag * Fetches an event by d tag
*/ */
async function fetchEventByDTag(ndk: any, dTag: string): Promise<NDKEvent> { async function fetchEventByDTag(ndk: NDK, dTag: string): Promise<NDKEvent> {
try { try {
const relaySet = await getActiveRelaySetAsNDKRelaySet(ndk, true); // true for inbox relays const relaySet = await getActiveRelaySetAsNDKRelaySet(ndk, true); // true for inbox relays
const event = await ndk.fetchEvent( const event = await ndk.fetchEvent(
@ -90,7 +91,7 @@ export const load: Load = async ({
parent, parent,
}: { }: {
url: URL; url: URL;
parent: () => Promise<any>; parent: () => Promise<Partial<Record<string, NDK>>>;
}) => { }) => {
const id = url.searchParams.get("id"); const id = url.searchParams.get("id");
const dTag = url.searchParams.get("d"); const dTag = url.searchParams.get("d");
@ -102,8 +103,8 @@ export const load: Load = async ({
// Fetch the event based on available parameters // Fetch the event based on available parameters
const indexEvent = id const indexEvent = id
? await fetchEventById(ndk, id) ? await fetchEventById(ndk!, id)
: await fetchEventByDTag(ndk, dTag!); : await fetchEventByDTag(ndk!, dTag!);
const publicationType = getMatchingTags(indexEvent, "type")[0]?.[1]; const publicationType = getMatchingTags(indexEvent, "type")[0]?.[1];

3
vite.config.ts

@ -1,6 +1,7 @@
import { sveltekit } from "@sveltejs/kit/vite"; import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite"; import { defineConfig } from "vite";
import { execSync } from "child_process"; import { execSync } from "child_process";
import process from "node:process";
// Function to get the latest git tag // Function to get the latest git tag
function getAppVersionString() { function getAppVersionString() {
@ -17,7 +18,7 @@ function getAppVersionString() {
// Get the latest git tag, assuming git is installed and tagged branch is available // Get the latest git tag, assuming git is installed and tagged branch is available
const tag = execSync("git describe --tags --abbrev=0").toString().trim(); const tag = execSync("git describe --tags --abbrev=0").toString().trim();
return tag; return tag;
} catch (error) { } catch {
return "development"; return "development";
} }
} }

Loading…
Cancel
Save