Browse Source

fixed the publication loading

master
silberengel 7 months ago
parent
commit
12cf16b36d
  1. 21
      src/lib/utils.ts
  2. 36
      src/lib/utils/websocket_utils.ts
  3. 39
      src/routes/publication/[type]/[identifier]/+layout.server.ts
  4. 2
      src/routes/publication/[type]/[identifier]/+layout.svelte
  5. 10
      src/routes/publication/[type]/[identifier]/+page.svelte
  6. 82
      src/routes/publication/[type]/[identifier]/+page.ts

21
src/lib/utils.ts

@ -2,6 +2,7 @@ import type { NDKEvent } from "@nostr-dev-kit/ndk"; @@ -2,6 +2,7 @@ import type { NDKEvent } from "@nostr-dev-kit/ndk";
import { nip19 } from "nostr-tools";
import { getMatchingTags } from "./utils/nostrUtils.ts";
import type { AddressPointer, EventPointer } from "nostr-tools/nip19";
import type { NostrEvent } from "./utils/websocket_utils.ts";
export class DecodeError extends Error {
constructor(message: string) {
@ -40,6 +41,26 @@ export function naddrEncode(event: NDKEvent, relays: string[]) { @@ -40,6 +41,26 @@ export function naddrEncode(event: NDKEvent, relays: string[]) {
});
}
/**
* Creates a tag address from a raw Nostr event (for compatibility with NDK events)
* @param event The raw Nostr event
* @param relays Optional relay list for the address
* @returns A tag address string
*/
export function createTagAddress(event: NostrEvent, relays: string[] = []): string {
const dTag = event.tags.find((tag: string[]) => tag[0] === "d")?.[1];
if (!dTag) {
throw new Error("Event does not have a d tag");
}
return nip19.naddrEncode({
identifier: dTag,
pubkey: event.pubkey,
kind: event.kind,
relays,
});
}
export function nprofileEncode(pubkey: string, relays: string[]) {
return nip19.nprofileEncode({ pubkey, relays });
}

36
src/lib/utils/websocket_utils.ts

@ -152,26 +152,25 @@ export async function fetchNostrEvent(filter: NostrFilter): Promise<NostrEvent | @@ -152,26 +152,25 @@ export async function fetchNostrEvent(filter: NostrFilter): Promise<NostrEvent |
}
});
// Wait for the first successful result with timeout
const timeoutPromise = new Promise<null>((resolve) => {
setTimeout(() => {
console.warn("[WebSocket Utils]: Fetch timeout reached");
resolve(null);
}, 5000); // 5 second timeout for the entire fetch operation
});
// Race between individual relay results and the timeout
const result = await Promise.race([
// Wait for the first successful result from any relay
Promise.race(relayPromises.filter(p => p !== null)),
timeoutPromise
]);
// Wait for all relay results and find the first successful one
const results = await Promise.allSettled(relayPromises);
if (result) {
return result;
// Find the first successful result
for (const result of results) {
if (result.status === 'fulfilled' && result.value) {
console.debug(`[WebSocket Utils]: Returning successful result from relay`);
return result.value;
}
}
console.warn("[WebSocket Utils]: Failed to fetch event from all relays (timeout or no results)");
// Debug: log all results to see what happened
console.debug(`[WebSocket Utils]: All relay results:`, results.map((r, i) => ({
relay: availableRelays[i],
status: r.status,
value: r.status === 'fulfilled' ? r.value : r.reason
})));
console.warn("[WebSocket Utils]: Failed to fetch event from all relays (no successful results)");
return null;
}
@ -222,12 +221,15 @@ export async function fetchEventByNaddr(naddr: string): Promise<NostrEvent> { @@ -222,12 +221,15 @@ export async function fetchEventByNaddr(naddr: string): Promise<NostrEvent> {
authors: [decoded.pubkey],
"#d": [decoded.identifier],
};
console.debug(`[fetchEventByNaddr] Calling fetchNostrEvent with filter:`, filter);
const event = await fetchNostrEvent(filter);
console.debug(`[fetchEventByNaddr] fetchNostrEvent returned:`, event ? 'success' : 'null');
if (!event) {
error(404, `Event not found for naddr: ${naddr}. href="/events?id=${naddr}"`);
}
return event;
} catch (err) {
console.error(`[fetchEventByNaddr] Error:`, err);
if (err && typeof err === "object" && "status" in err) {
throw err;
}

39
src/routes/publication/[type]/[identifier]/+layout.server.ts

@ -1,40 +1,29 @@ @@ -1,40 +1,29 @@
import { error } from "@sveltejs/kit";
import type { LayoutServerLoad } from "./$types";
import { fetchEventByDTag, fetchEventById, fetchEventByNaddr, fetchEventByNevent } from "../../../../lib/utils/websocket_utils.ts";
import type { NostrEvent } from "../../../../lib/utils/websocket_utils.ts";
// AI-NOTE: Server-side event fetching for SEO metadata
async function fetchEventServerSide(type: string, identifier: string): Promise<NostrEvent | null> {
// For now, return null to indicate server-side fetch not implemented
// This will fall back to client-side fetching
return null;
}
export const load: LayoutServerLoad = async ({ params, url }) => {
const { type, identifier } = params;
let indexEvent: NostrEvent;
// Handle different identifier types
switch (type) {
case 'id':
indexEvent = await fetchEventById(identifier);
break;
case 'd':
indexEvent = await fetchEventByDTag(identifier);
break;
case 'naddr':
indexEvent = await fetchEventByNaddr(identifier);
break;
case 'nevent':
indexEvent = await fetchEventByNevent(identifier);
break;
default:
error(400, `Unsupported identifier type: ${type}`);
}
// Try to fetch event server-side for metadata
const indexEvent = await fetchEventServerSide(type, identifier);
// Extract metadata for meta tags
const title = indexEvent.tags.find((tag) => tag[0] === "title")?.[1] || "Alexandria Publication";
const summary = indexEvent.tags.find((tag) => tag[0] === "summary")?.[1] ||
// Extract metadata for meta tags (use fallbacks if no event found)
const title = indexEvent?.tags.find((tag) => tag[0] === "title")?.[1] || "Alexandria Publication";
const summary = indexEvent?.tags.find((tag) => tag[0] === "summary")?.[1] ||
"Alexandria is a digital library, utilizing Nostr events for curated publications and wiki pages.";
const image = indexEvent.tags.find((tag) => tag[0] === "image")?.[1] || "/screenshots/old_books.jpg";
const image = indexEvent?.tags.find((tag) => tag[0] === "image")?.[1] || "/screenshots/old_books.jpg";
const currentUrl = `${url.origin}${url.pathname}`;
return {
indexEvent,
indexEvent, // Will be null, triggering client-side fetch
metadata: {
title,
summary,

2
src/routes/publication/[type]/[identifier]/+layout.svelte

@ -3,6 +3,8 @@ @@ -3,6 +3,8 @@
import type { LayoutProps } from "./$types";
let { data, children }: LayoutProps = $props();
// AI-NOTE: Use metadata from server-side load for SEO and social sharing
const { metadata } = data;
</script>

10
src/routes/publication/[type]/[identifier]/+page.svelte

@ -9,12 +9,20 @@ @@ -9,12 +9,20 @@
import { page } from "$app/state";
import { goto } from "$app/navigation";
import { createNDKEvent } from "$lib/utils/nostrUtils";
import { createTagAddress } from "$lib/utils";
import { get } from "svelte/store";
import { activeInboxRelays } from "$lib/ndk";
let { data }: PageProps = $props();
// data.indexEvent can be null from server-side rendering
// We need to handle this case properly
const indexEvent = data.indexEvent ? createNDKEvent(data.ndk, data.indexEvent) : null;
// AI-NOTE: Always create NDK event since we now ensure NDK is available
const indexEvent = data.indexEvent && data.ndk
? createNDKEvent(data.ndk, data.indexEvent)
: null; // No event if no NDK or no event data
// Only create publication tree if we have a valid index event
const publicationTree = indexEvent ? new SveltePublicationTree(indexEvent, data.ndk) : null;

82
src/routes/publication/[type]/[identifier]/+page.ts

@ -3,29 +3,46 @@ import type { PageLoad } from "./$types"; @@ -3,29 +3,46 @@ import type { PageLoad } from "./$types";
import { fetchEventByDTag, fetchEventById, fetchEventByNaddr, fetchEventByNevent } from "../../../../lib/utils/websocket_utils.ts";
import type { NostrEvent } from "../../../../lib/utils/websocket_utils.ts";
export const load: PageLoad = async ({ params }: { params: { type: string; identifier: string } }) => {
export const load: PageLoad = async ({ params, parent }: { params: { type: string; identifier: string }; parent: any }) => {
console.debug(`[Publication Load] Page load function called with params:`, params);
const { type, identifier } = params;
console.debug(`[Publication Load] About to call parent()...`);
// Get layout data (no server-side data since SSR is disabled)
const layoutData = await parent();
console.debug(`[Publication Load] Layout data received:`, layoutData ? 'success' : 'null');
let indexEvent: NostrEvent | null;
// AI-NOTE: Always fetch client-side since server-side fetch returns null for now
let indexEvent: NostrEvent | null = null;
console.debug(`[Publication Load] Fetching client-side for: ${identifier}`);
try {
// Handle different identifier types
switch (type) {
case 'id':
indexEvent = await fetchEventById(identifier);
break;
case 'd':
indexEvent = await fetchEventByDTag(identifier);
break;
case 'naddr':
console.debug(`[Publication Load] Calling fetchEventByNaddr for: ${identifier}`);
indexEvent = await fetchEventByNaddr(identifier);
console.debug(`[Publication Load] fetchEventByNaddr returned:`, indexEvent ? 'success' : 'null');
break;
case 'nevent':
indexEvent = await fetchEventByNevent(identifier);
break;
default:
error(400, `Unsupported identifier type: ${type}`);
}
// Handle different identifier types
switch (type) {
case 'id':
indexEvent = await fetchEventById(identifier);
break;
case 'd':
indexEvent = await fetchEventByDTag(identifier);
break;
case 'naddr':
indexEvent = await fetchEventByNaddr(identifier);
break;
case 'nevent':
indexEvent = await fetchEventByNevent(identifier);
break;
default:
error(400, `Unsupported identifier type: ${type}`);
console.debug(`[Publication Load] Client-side indexEvent after fetch:`, indexEvent ? 'success' : 'null');
} catch (err) {
console.error(`[Publication Load] Error fetching event client-side:`, err);
throw err;
}
if (!indexEvent) {
// AI-NOTE: Handle case where no relays are available during preloading
// This prevents 404 errors when relay stores haven't been populated yet
@ -51,10 +68,35 @@ export const load: PageLoad = async ({ params }: { params: { type: string; ident @@ -51,10 +68,35 @@ export const load: PageLoad = async ({ params }: { params: { type: string; ident
error(404, `Event not found for ${type}: ${identifier}. href="/events?${searchParam}"`);
}
console.debug(`[Publication Load] indexEvent details:`, {
id: indexEvent.id,
kind: indexEvent.kind,
pubkey: indexEvent.pubkey,
tags: indexEvent.tags.length,
contentLength: indexEvent.content.length
});
const publicationType = indexEvent.tags.find((tag) => tag[0] === "type")?.[1] ?? "";
console.debug(`[Publication Load] publicationType:`, publicationType);
// AI-NOTE: Use proper NDK instance from layout or create one with relays
let ndk = layoutData?.ndk;
if (!ndk) {
console.debug(`[Publication Load] Layout NDK not available, creating NDK instance with relays`);
// Import NDK dynamically to avoid SSR issues
const NDK = (await import("@nostr-dev-kit/ndk")).default;
// Import initNdk to get properly configured NDK with relays
const { initNdk } = await import("$lib/ndk");
ndk = initNdk();
}
return {
const result = {
publicationType,
indexEvent,
ndk, // Use minimal NDK instance
};
console.debug(`[Publication Load] Returning result:`, result);
return result;
};

Loading…
Cancel
Save