Add an opt-in SSR mode with a Node adapter behind PUBLIC_SSR

This commit is contained in:
dtonon 2026-08-14 19:25:55 +01:00
parent 9cc82dc1fe
commit 54c0682dce
18 changed files with 4257 additions and 3552 deletions

View file

@ -1,5 +1,5 @@
import type { Event } from "@nostr/tools";
import { loadNostrUser, type NostrUser } from "@nostr/gadgets/metadata";
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import { RELAY_URL } from "$lib/config";
import { auth } from "$lib/auth.svelte";
import { queryForum, publishForum, subscribeForum } from "$lib/relay";

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { loadNostrUser, type NostrUser } from "@nostr/gadgets/metadata";
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import { tokenizeChat } from "$lib/linkify";
import {
resolveThreadRef,

View file

@ -1,7 +1,7 @@
<script lang="ts">
import { tick } from "svelte";
import * as nip19 from "@nostr/tools/nip19";
import { loadRelayList } from "@nostr/gadgets/lists";
import { loadRelayList } from "$lib/gadgets";
import {
profileStore,
searchLocalProfiles,

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { loadNostrUser, type NostrUser } from "@nostr/gadgets/metadata";
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import * as nip19 from "@nostr/tools/nip19";
import {
resolveThreadRef,

View file

@ -18,6 +18,9 @@ export const GROUP_ID = env.PUBLIC_GROUP_ID ?? "";
if (MODE === "simple" && !GROUP_ID) {
throw new Error("PUBLIC_GROUP_ID is required in simple mode");
}
// Server-side rendering: opt-in, and only meaningful when the build targets the
// Node adapter (svelte.config.js reads the same variable).
export const SSR_ENABLED = env.PUBLIC_SSR === "yes";
// Requires a relay with NIP-50 support.
export const SEARCH_ENABLED = env.PUBLIC_SEARCH === "yes";
export const LABELS = (env.PUBLIC_LABELS ?? "")

17
src/lib/gadgets.ts Normal file
View file

@ -0,0 +1,17 @@
import type { NostrUser } from "@nostr/gadgets/metadata";
import type { ListFetcher, RelayItem } from "@nostr/gadgets/lists";
export type { NostrUser, RelayItem };
// @nostr/gadgets reads localStorage when imported, so it can't be loaded on
// the server. Every consumer goes through these lazy wrappers; the library is
// pulled in on first use, in the browser only.
export async function loadNostrUser(pubkey: string): Promise<NostrUser> {
const m = await import("@nostr/gadgets/metadata");
return m.loadNostrUser(pubkey);
}
export const loadRelayList: ListFetcher<RelayItem> = async (...args) => {
const m = await import("@nostr/gadgets/lists");
return m.loadRelayList(...args);
};

View file

@ -1,5 +1,5 @@
import * as nip19 from "@nostr/tools/nip19";
import { loadRelayList } from "@nostr/gadgets/lists";
import { loadRelayList } from "$lib/gadgets";
const RELAY_HINT_TIMEOUT_MS = 1500;

View file

@ -1,7 +1,7 @@
import type { AbstractRelay } from "@nostr/tools/abstract-relay";
import type { Event } from "@nostr/tools/core";
import type { Filter } from "@nostr/tools/filter";
import { loadNostrUser, type NostrUser } from "@nostr/gadgets/metadata";
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import { ensureForumRelay } from "$lib/relay";
import { ingestNostrUser } from "$lib/profiles.svelte";

View file

@ -1,4 +1,4 @@
import { loadNostrUser, type NostrUser } from "@nostr/gadgets/metadata";
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import { RELAY_URL, GROUP_ID } from "$lib/config";
import { queryForum, publishForum } from "$lib/relay";
import { threads as mockThreads } from "$lib/mock";

View file

@ -1,7 +1,7 @@
import type { AbstractRelay } from "@nostr/tools/abstract-relay";
import type { Event } from "@nostr/tools/core";
import type { Filter } from "@nostr/tools/filter";
import { loadNostrUser, type NostrUser } from "@nostr/gadgets/metadata";
import { loadNostrUser, type NostrUser } from "$lib/gadgets";
import { ensureForumRelay } from "$lib/relay";
import { ingestNostrUser } from "$lib/profiles.svelte";