diff --git a/scripts/deploy.mjs b/scripts/deploy.mjs index 8a5bb2d..3e9692f 100644 --- a/scripts/deploy.mjs +++ b/scripts/deploy.mjs @@ -328,20 +328,17 @@ async function getLatestManifestFromAo() { } } -function timestampMs(value) { - if (typeof value !== "string" || !value) return 0; - const parsed = Date.parse(value); - return Number.isNaN(parsed) ? 0 : parsed; -} +async function fetchPostSlugs(gateway, blogManifestTxId) { + if (!blogManifestTxId) return null; -function manifestFreshness(payload) { - const posts = Array.isArray(payload?.posts) ? payload.posts : []; - return Math.max( - timestampMs(payload?.updated), - timestampMs(payload?.date), - timestampMs(payload?.generatedAt), - ...posts.map((post) => Math.max(timestampMs(post?.updated), timestampMs(post?.publishedAt))) - ); + const response = await fetch(`${gateway.replace(/\/+$/, "")}/${blogManifestTxId}`); + if (!response.ok) return null; + const payload = await response.json(); + if (!Array.isArray(payload?.posts)) return null; + + return payload.posts + .map((post) => (typeof post?.slug === "string" ? post.slug.trim() : "")) + .filter((slug) => slug.length > 0); } async function resolvePostSlugs(gateway) { @@ -351,28 +348,16 @@ async function resolvePostSlugs(gateway) { await resolveBlogManifestTxId() ].filter(Boolean); - const manifests = []; for (const blogManifestTxId of candidates) { try { - const response = await fetch(`${gateway.replace(/\/+$/, "")}/${blogManifestTxId}`); - if (!response.ok) continue; - const payload = await response.json(); - if (!Array.isArray(payload?.posts)) continue; - manifests.push({ - txId: blogManifestTxId, - freshness: manifestFreshness(payload), - posts: payload.posts - }); + const slugs = await fetchPostSlugs(gateway, blogManifestTxId); + if (slugs) return slugs; } catch { // Try the next manifest source. } } - if (!manifests.length) return []; - manifests.sort((a, b) => b.freshness - a.freshness); - return manifests[0].posts - .map((post) => (typeof post?.slug === "string" ? post.slug.trim() : "")) - .filter((slug) => slug.length > 0); + return []; } async function main() { diff --git a/scripts/prerender-meta.mjs b/scripts/prerender-meta.mjs index 2b4d345..eae7361 100644 --- a/scripts/prerender-meta.mjs +++ b/scripts/prerender-meta.mjs @@ -121,20 +121,6 @@ const parseManifest = (input) => { }); }; -const timestampMs = (value) => { - if (typeof value !== "string" || !value) return 0; - const parsed = Date.parse(value); - return Number.isNaN(parsed) ? 0 : parsed; -}; - -const manifestFreshness = (payload, posts) => - Math.max( - timestampMs(payload?.updated), - timestampMs(payload?.date), - timestampMs(payload?.generatedAt), - ...posts.map((post) => Math.max(timestampMs(post.updated), timestampMs(post.publishedAt))) - ); - const fetchManifestPosts = async (manifestTxId) => { if (!manifestTxId) return []; const url = `https://arweave.net/${manifestTxId}`; @@ -142,43 +128,7 @@ const fetchManifestPosts = async (manifestTxId) => { if (!response.ok) throw new Error(`Manifest fetch failed (${response.status})`); const payload = await response.json(); const posts = parseManifest(payload); - return { txId: manifestTxId, posts, freshness: manifestFreshness(payload, posts) }; -}; - -const resolveManifestTxIds = async (config) => { - const candidates = []; - if (config.MANIFEST_REFERENCE_NAME) { - try { - const names = new ReferenceClient({ gateway: config.ARWEAVE_GATEWAY || DEFAULTS.ARWEAVE_GATEWAY }); - const value = await names.resolveName(config.MANIFEST_REFERENCE_NAME); - if (typeof value === "string" && value.length > 0) candidates.push(value); - else throw new Error(`Reference ${config.MANIFEST_REFERENCE_NAME} did not resolve to a manifest id`); - } catch (error) { - console.warn( - `[prerender-meta] Trying configured manifest; reference ${config.MANIFEST_REFERENCE_NAME} failed: ${error.message}` - ); - } - } - - if (config.MANIFEST_TX_ID) candidates.push(config.MANIFEST_TX_ID); - return [...new Set(candidates)]; -}; - -const fetchBestManifestPosts = async (config) => { - const candidates = await resolveManifestTxIds(config); - const loaded = []; - - for (const manifestTxId of candidates) { - try { - loaded.push(await fetchManifestPosts(manifestTxId)); - } catch (error) { - console.warn(`[prerender-meta] Manifest ${manifestTxId} failed: ${error.message}`); - } - } - - if (!loaded.length) return []; - loaded.sort((a, b) => b.freshness - a.freshness); - return loaded[0].posts; + return { txId: manifestTxId, posts }; }; const resolveManifestTxId = async (config) => { @@ -198,6 +148,22 @@ const resolveManifestTxId = async (config) => { return config.MANIFEST_TX_ID; }; +const fetchCurrentManifestPosts = async (config) => { + const manifestTxId = await resolveManifestTxId(config); + if (!manifestTxId) return []; + + try { + return (await fetchManifestPosts(manifestTxId)).posts; + } catch (error) { + if (!config.MANIFEST_REFERENCE_NAME || manifestTxId === config.MANIFEST_TX_ID) throw error; + console.warn( + `[prerender-meta] Falling back to configured manifest; reference manifest ${manifestTxId} failed: ${error.message}` + ); + } + + return config.MANIFEST_TX_ID ? (await fetchManifestPosts(config.MANIFEST_TX_ID)).posts : []; +}; + const buildMetaTags = ({ title, description, @@ -270,7 +236,7 @@ const main = async () => { let posts = []; try { - posts = await fetchBestManifestPosts(config); + posts = await fetchCurrentManifestPosts(config); } catch (error) { console.warn( `[prerender-meta] Could not fetch manifest; generating root metadata only: ${error.message}` diff --git a/src/lib.ts b/src/lib.ts index 656d250..adba96f 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -73,29 +73,12 @@ export const getReadableDate = (date?: string | null): string | null => { }; export const loadManifest = async (): Promise => { - return (await loadBestManifest()).posts; -}; - -const timestampMs = (value: unknown): number => { - if (typeof value !== "string" || !value) return 0; - const parsed = Date.parse(value); - return Number.isNaN(parsed) ? 0 : parsed; -}; - -const manifestFreshness = (payload: unknown, posts: ManifestPost[]): number => { - const root = isObject(payload) ? payload : {}; - return Math.max( - timestampMs(root.updated), - timestampMs(root.date), - timestampMs(root.generatedAt), - ...posts.map((post) => Math.max(timestampMs(post.updated), timestampMs(post.publishedAt))) - ); + return (await loadCurrentManifest()).posts; }; const fetchManifest = async (manifestTxId: string): Promise<{ txId: string; posts: ManifestPost[]; - freshness: number; }> => { const response = await fetch(arweaveUrl(manifestTxId)); if (!response.ok) { @@ -104,49 +87,46 @@ const fetchManifest = async (manifestTxId: string): Promise<{ const payload: unknown = await response.json(); const posts = parseManifest(payload); - return { txId: manifestTxId, posts, freshness: manifestFreshness(payload, posts) }; + return { txId: manifestTxId, posts }; }; -const resolveManifestCandidates = async (): Promise => { - const candidates: string[] = []; - if (MANIFEST_REFERENCE_NAME) { - try { - const names = new ReferenceClient({ gateway: ARWEAVE_GATEWAY }); - const value = await names.resolveName(MANIFEST_REFERENCE_NAME); - if (typeof value === "string" && value.length > 0) candidates.push(value); - else throw new Error(`Reference ${MANIFEST_REFERENCE_NAME} did not resolve to a manifest id`); - } catch (error) { - console.warn( - `Could not resolve manifest reference ${MANIFEST_REFERENCE_NAME}; trying configured manifest`, - error - ); - } +const resolveReferenceManifestTxId = async (): Promise => { + if (!MANIFEST_REFERENCE_NAME) return ""; + + const names = new ReferenceClient({ gateway: ARWEAVE_GATEWAY }); + const value = await names.resolveName(MANIFEST_REFERENCE_NAME); + if (typeof value !== "string" || value.length === 0) { + throw new Error(`Reference ${MANIFEST_REFERENCE_NAME} did not resolve to a manifest id`); } - if (MANIFEST_TX_ID) candidates.push(MANIFEST_TX_ID); - return [...new Set(candidates)]; + return value; }; -const loadBestManifest = async () => { - const candidates = await resolveManifestCandidates(); - if (!candidates.length) throw new Error("No manifest reference or fallback manifest configured"); +const loadReferenceManifest = async () => { + if (!MANIFEST_REFERENCE_NAME) return null; - const loaded = []; - for (const candidate of candidates) { - try { - loaded.push(await fetchManifest(candidate)); - } catch (error) { - console.warn(`Could not load manifest ${candidate}; trying other configured candidates`, error); - } + try { + return await fetchManifest(await resolveReferenceManifestTxId()); + } catch (error) { + console.warn( + `Could not load manifest reference ${MANIFEST_REFERENCE_NAME}; trying configured manifest`, + error + ); + return null; } +}; - if (!loaded.length) throw new Error("No configured manifest could be loaded"); - loaded.sort((a, b) => b.freshness - a.freshness); - return loaded[0]; +const loadConfiguredManifest = async () => { + if (!MANIFEST_TX_ID) throw new Error("No manifest reference or fallback manifest configured"); + return fetchManifest(MANIFEST_TX_ID); +}; + +const loadCurrentManifest = async () => { + return (await loadReferenceManifest()) ?? (await loadConfiguredManifest()); }; export const resolveManifestTxId = async (): Promise => { - return (await loadBestManifest()).txId; + return (await loadCurrentManifest()).txId; }; const isObject = (value: unknown): value is Record =>