From 39266540ffdd005daea677f2ca02def8c55c13e6 Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Sun, 6 Oct 2024 23:02:26 +0100 Subject: [PATCH 1/7] Cache DIDs atomically --- .../frontpage/lib/data/atproto/identity.ts | 117 +++++++++--------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/packages/frontpage/lib/data/atproto/identity.ts b/packages/frontpage/lib/data/atproto/identity.ts index 36256936..4b0020ec 100644 --- a/packages/frontpage/lib/data/atproto/identity.ts +++ b/packages/frontpage/lib/data/atproto/identity.ts @@ -2,35 +2,45 @@ import { cache } from "react"; import { DID, getDidDoc, isDid, parseDid } from "./did"; import { unstable_cache } from "next/cache"; import { z } from "zod"; - -export const getVerifiedDid = cache(async (handle: string) => { - const [dnsDid, httpDid] = await Promise.all([ - getAtprotoDidFromDns(handle).catch((_) => { - return null; - }), - getAtprotoFromHttps(handle).catch((_) => { - return null; - }), - ]); - - if (dnsDid && httpDid && dnsDid !== httpDid) { - return null; - } - - const did = dnsDid ?? (httpDid ? parseDid(httpDid) : null); - if (!did) { - return null; - } - - const plcDoc = await getDidDoc(did); - const plcHandle = plcDoc.alsoKnownAs - .find((handle) => handle.startsWith("at://")) - ?.replace("at://", ""); - - if (!plcHandle) return null; - - return plcHandle.toLowerCase() === handle.toLowerCase() ? did : null; -}); +import { startSpan } from "@sentry/nextjs"; + +export const getVerifiedDid = cache( + unstable_cache( + (handle: string) => + startSpan({ name: "getVerifiedDid" }, async () => { + const [dnsDid, httpDid] = await Promise.all([ + getAtprotoDidFromDns(handle).catch((_) => { + return null; + }), + getAtprotoFromHttps(handle).catch((_) => { + return null; + }), + ]); + + if (dnsDid && httpDid && dnsDid !== httpDid) { + return null; + } + + const did = dnsDid ?? (httpDid ? parseDid(httpDid) : null); + if (!did) { + return null; + } + + const plcDoc = await getDidDoc(did); + const plcHandle = plcDoc.alsoKnownAs + .find((handle) => handle.startsWith("at://")) + ?.replace("at://", ""); + + if (!plcHandle) return null; + + return plcHandle.toLowerCase() === handle.toLowerCase() ? did : null; + }), + ["getVerifiedDid"], + { + revalidate: 60 * 60 * 24, // 24 hours + }, + ), +); const DnsQueryResponse = z.object({ Answer: z.array( @@ -44,7 +54,7 @@ const DnsQueryResponse = z.object({ }); // See https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/make-api-requests/dns-json/ -async function getAtprotoDidFromDns(handle: string) { +const getAtprotoDidFromDns = cache(async (handle: string) => { const url = new URL("https://cloudflare-dns.com/dns-query"); url.searchParams.set("type", "TXT"); url.searchParams.set("name", `_atproto.${handle}`); @@ -53,9 +63,6 @@ async function getAtprotoDidFromDns(handle: string) { headers: { Accept: "application/dns-json", }, - next: { - revalidate: 60 * 60 * 24, // 24 hours - }, }); const { Answer } = DnsQueryResponse.parse(await response.json()); @@ -65,31 +72,25 @@ async function getAtprotoDidFromDns(handle: string) { : null; return val ? parseDid(val) : null; -} - -const getAtprotoFromHttps = unstable_cache( - async (handle: string) => { - let res; - const timeoutSignal = AbortSignal.timeout(1500); - try { - res = await fetch(`https://${handle}/.well-known/atproto-did`, { - signal: timeoutSignal, - }); - } catch (_e) { - // We're caching failures here, we should at some point invalidate the cache by listening to handle changes on the network - return null; - } - - if (!res.ok) { - return null; - } - return parseDid((await res.text()).trim()); - }, - ["did", "https"], - { - revalidate: 60 * 60 * 24, // 24 hours - }, -); +}); + +const getAtprotoFromHttps = cache(async (handle: string) => { + let res; + const timeoutSignal = AbortSignal.timeout(1500); + try { + res = await fetch(`https://${handle}/.well-known/atproto-did`, { + signal: timeoutSignal, + }); + } catch (_e) { + // We're caching failures here, we should at some point invalidate the cache by listening to handle changes on the network + return null; + } + + if (!res.ok) { + return null; + } + return parseDid((await res.text()).trim()); +}); /** * Returns the DID of the the handle or the DID itself if it's a DID. Or null if the handle doesn't resolve to a DID. From d05121f0a6ca29aa314203865dfb6b6022ed96fd Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Sun, 6 Oct 2024 23:28:46 +0100 Subject: [PATCH 2/7] Move hover card avatar to the client --- .../[postAuthor]/[postRkey]/_lib/comment.tsx | 3 +- .../app/api/hover-card-content/route.ts | 6 +- .../lib/components/user-avatar-shared.tsx | 51 +++++++++++++++ .../frontpage/lib/components/user-avatar.tsx | 53 +++------------- .../lib/components/user-hover-card-client.tsx | 63 ++++++++++--------- .../lib/components/user-hover-card.tsx | 2 - 6 files changed, 99 insertions(+), 79 deletions(-) create mode 100644 packages/frontpage/lib/components/user-avatar-shared.tsx diff --git a/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment.tsx b/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment.tsx index f025fa77..0fb8e696 100644 --- a/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment.tsx +++ b/packages/frontpage/app/(app)/post/[postAuthor]/[postRkey]/_lib/comment.tsx @@ -2,7 +2,7 @@ import { getUser } from "@/lib/data/user"; import { CommentClientWrapperWithToolbar } from "./comment-client"; import { CommentModel } from "@/lib/data/db/comment"; import { TimeAgo } from "@/lib/components/time-ago"; -import { AvatarFallback, UserAvatar } from "@/lib/components/user-avatar"; +import { UserAvatar } from "@/lib/components/user-avatar"; import Link from "next/link"; import { getDidFromHandleOrDid, @@ -11,6 +11,7 @@ import { import { UserHoverCard } from "@/lib/components/user-hover-card"; import { VariantProps, cva } from "class-variance-authority"; import { cn } from "@/lib/utils"; +import { AvatarFallback } from "@/lib/components/user-avatar-shared"; const commentVariants = cva(undefined, { variants: { diff --git a/packages/frontpage/app/api/hover-card-content/route.ts b/packages/frontpage/app/api/hover-card-content/route.ts index 558f631e..ffe8f1cd 100644 --- a/packages/frontpage/app/api/hover-card-content/route.ts +++ b/packages/frontpage/app/api/hover-card-content/route.ts @@ -1,7 +1,7 @@ import { badRequest, createApiRoute } from "@/lib/api-route"; import { parseDid } from "@/lib/data/atproto/did"; import { getVerifiedHandle } from "@/lib/data/atproto/identity"; -import { getTotalSubmissions } from "@/lib/data/user"; +import { getBlueskyProfile, getTotalSubmissions } from "@/lib/data/user"; export const GET = createApiRoute(async (request) => { const url = new URL(request.url); @@ -13,13 +13,15 @@ export const GET = createApiRoute(async (request) => { badRequest("Missing did parameter"); } - const [submissions, handle] = await Promise.all([ + const [submissions, handle, profile] = await Promise.all([ getTotalSubmissions(did), getVerifiedHandle(did), + getBlueskyProfile(did), ]); return { ...submissions, handle, + avatar: profile.avatar, }; }); diff --git a/packages/frontpage/lib/components/user-avatar-shared.tsx b/packages/frontpage/lib/components/user-avatar-shared.tsx new file mode 100644 index 00000000..957818be --- /dev/null +++ b/packages/frontpage/lib/components/user-avatar-shared.tsx @@ -0,0 +1,51 @@ +import { DID } from "../data/atproto/did"; + +const userAvatarSizes = { + small: 22, + smedium: 50, + medium: 100, + large: 150, +}; + +type Size = keyof typeof userAvatarSizes; + +export type UserAvatarProps = { + did: DID; + size?: Size; +}; + +export function AvatarImage({ + size: sizeVariant = "small", + avatar, +}: { + avatar: string; + size?: UserAvatarProps["size"]; +}) { + const size = userAvatarSizes[sizeVariant]; + return ( + // eslint-disable-next-line @next/next/no-img-element + + ); +} + +export function AvatarFallback({ size }: { size: UserAvatarProps["size"] }) { + const sizePx = userAvatarSizes[size ?? "small"]; + return ( + + + + ); +} diff --git a/packages/frontpage/lib/components/user-avatar.tsx b/packages/frontpage/lib/components/user-avatar.tsx index 4adf7fa7..1d949f6d 100644 --- a/packages/frontpage/lib/components/user-avatar.tsx +++ b/packages/frontpage/lib/components/user-avatar.tsx @@ -1,61 +1,24 @@ import "server-only"; import { getBlueskyProfile } from "@/lib/data/user"; import { Suspense } from "react"; -import { DID } from "../data/atproto/did"; - -const userAvatarSizes = { - small: 22, - smedium: 50, - medium: 100, - large: 150, -}; - -type Size = keyof typeof userAvatarSizes; - -type UserAvatarProps = { - did: DID; - size?: Size; -}; +import { + AvatarFallback, + AvatarImage, + UserAvatarProps, +} from "./user-avatar-shared"; export async function UserAvatar(props: UserAvatarProps) { return ( }> - + ); } -export function AvatarFallback({ size }: { size: UserAvatarProps["size"] }) { - const sizePx = userAvatarSizes[size ?? "small"]; - return ( - - - - ); -} - -async function AvatarImage({ +async function UserAvatarImpl({ did, size: sizeVariant = "small", }: UserAvatarProps) { const { avatar } = await getBlueskyProfile(did); - const size = userAvatarSizes[sizeVariant]; - return ( - // eslint-disable-next-line @next/next/no-img-element - - ); + return ; } diff --git a/packages/frontpage/lib/components/user-hover-card-client.tsx b/packages/frontpage/lib/components/user-hover-card-client.tsx index 64df63cd..858e5414 100644 --- a/packages/frontpage/lib/components/user-hover-card-client.tsx +++ b/packages/frontpage/lib/components/user-hover-card-client.tsx @@ -11,12 +11,12 @@ import type { GET as GetHoverCardContent } from "@/app/api/hover-card-content/ro import Link from "next/link"; import { ReportDialogIcon } from "@/app/(app)/_components/report-dialog"; import { Separator } from "./ui/separator"; +import { AvatarFallback, AvatarImage } from "./user-avatar-shared"; type Props = { did: DID; children: ReactNode; asChild?: boolean; - avatar: ReactNode; initialHandle: string; reportAction: (formData: FormData) => Promise; }; @@ -25,7 +25,6 @@ export function UserHoverCardClient({ did, children, asChild, - avatar, initialHandle, reportAction, }: Props) { @@ -41,14 +40,9 @@ export function UserHoverCardClient({
- - {avatar} - -
- }> - - -
+ }> + +
@@ -67,21 +61,29 @@ function Content({ did }: { did: DID }) { return ( <> - - @{data.handle} + + -

- {data.commentCount} -

-

- {data.postCount} -

+
+ + @{data.handle} + +

+ {data.commentCount} +

+

+ {data.postCount} +

+
); } @@ -89,11 +91,14 @@ function Content({ did }: { did: DID }) { function Fallback({ handle }: { handle: string }) { return ( <> - - @{handle} - - - + +
+ + @{handle} + + + +
); } diff --git a/packages/frontpage/lib/components/user-hover-card.tsx b/packages/frontpage/lib/components/user-hover-card.tsx index b6403cad..96599294 100644 --- a/packages/frontpage/lib/components/user-hover-card.tsx +++ b/packages/frontpage/lib/components/user-hover-card.tsx @@ -1,4 +1,3 @@ -import { UserAvatar } from "./user-avatar"; import { HoverCard } from "@/lib/components/ui/hover-card"; import { DID } from "../data/atproto/did"; import { getVerifiedHandle } from "../data/atproto/identity"; @@ -19,7 +18,6 @@ export async function UserHoverCard({ did, children, asChild }: Props) { return ( } did={did} asChild={asChild} initialHandle={handle ?? ""} From 2d3eb91f4c92fa749431eb79f49b6d98042a20cf Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Sun, 6 Oct 2024 23:42:39 +0100 Subject: [PATCH 3/7] Trace cache also --- .../frontpage/lib/data/atproto/identity.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/frontpage/lib/data/atproto/identity.ts b/packages/frontpage/lib/data/atproto/identity.ts index 4b0020ec..dabeaed0 100644 --- a/packages/frontpage/lib/data/atproto/identity.ts +++ b/packages/frontpage/lib/data/atproto/identity.ts @@ -4,10 +4,10 @@ import { unstable_cache } from "next/cache"; import { z } from "zod"; import { startSpan } from "@sentry/nextjs"; -export const getVerifiedDid = cache( - unstable_cache( - (handle: string) => - startSpan({ name: "getVerifiedDid" }, async () => { +export const getVerifiedDid = cache((handle: string) => + startSpan({ name: "getVerifiedDid" }, () => + unstable_cache( + async () => { const [dnsDid, httpDid] = await Promise.all([ getAtprotoDidFromDns(handle).catch((_) => { return null; @@ -34,11 +34,12 @@ export const getVerifiedDid = cache( if (!plcHandle) return null; return plcHandle.toLowerCase() === handle.toLowerCase() ? did : null; - }), - ["getVerifiedDid"], - { - revalidate: 60 * 60 * 24, // 24 hours - }, + }, + ["getVerifiedDid", handle], + { + revalidate: 60 * 60 * 24, // 24 hours + }, + )(), ), ); From 9c02183ea6fe6efd61f16ce93af336f8c15d0eab Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Sun, 6 Oct 2024 23:43:53 +0100 Subject: [PATCH 4/7] Remove unused try/catch --- packages/frontpage/lib/data/atproto/identity.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/frontpage/lib/data/atproto/identity.ts b/packages/frontpage/lib/data/atproto/identity.ts index dabeaed0..d8ecc11b 100644 --- a/packages/frontpage/lib/data/atproto/identity.ts +++ b/packages/frontpage/lib/data/atproto/identity.ts @@ -76,16 +76,9 @@ const getAtprotoDidFromDns = cache(async (handle: string) => { }); const getAtprotoFromHttps = cache(async (handle: string) => { - let res; - const timeoutSignal = AbortSignal.timeout(1500); - try { - res = await fetch(`https://${handle}/.well-known/atproto-did`, { - signal: timeoutSignal, - }); - } catch (_e) { - // We're caching failures here, we should at some point invalidate the cache by listening to handle changes on the network - return null; - } + const res = await fetch(`https://${handle}/.well-known/atproto-did`, { + signal: AbortSignal.timeout(1500), + }); if (!res.ok) { return null; From d6038296838a243a27864b482d34c6a89cc66961 Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Mon, 7 Oct 2024 16:37:01 +0100 Subject: [PATCH 5/7] Profile samples --- packages/frontpage/sentry.server.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/frontpage/sentry.server.config.ts b/packages/frontpage/sentry.server.config.ts index b3f5bd1c..0c194b79 100644 --- a/packages/frontpage/sentry.server.config.ts +++ b/packages/frontpage/sentry.server.config.ts @@ -13,4 +13,5 @@ Sentry.init({ // Setting this option to true will print useful information to the console while you're setting up Sentry. debug: false, enabled: process.env.NODE_ENV === "production", + profilesSampleRate: 1, }); From e3e6935697d3f5582ab705534139a6face7b7810 Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Mon, 7 Oct 2024 16:48:58 +0100 Subject: [PATCH 6/7] Enable profiling for real --- packages/frontpage/package.json | 1 + packages/frontpage/sentry.server.config.ts | 2 + pnpm-lock.yaml | 46 ++++++++++++++-------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/packages/frontpage/package.json b/packages/frontpage/package.json index 9a054f91..9d955508 100644 --- a/packages/frontpage/package.json +++ b/packages/frontpage/package.json @@ -33,6 +33,7 @@ "@radix-ui/react-toast": "^1.2.1", "@radix-ui/react-tooltip": "^1.1.1", "@sentry/nextjs": "^8", + "@sentry/profiling-node": "^8.33.1", "@vercel/analytics": "^1.3.1", "@vercel/speed-insights": "^1.0.12", "class-variance-authority": "^0.7.0", diff --git a/packages/frontpage/sentry.server.config.ts b/packages/frontpage/sentry.server.config.ts index 0c194b79..c2512206 100644 --- a/packages/frontpage/sentry.server.config.ts +++ b/packages/frontpage/sentry.server.config.ts @@ -3,9 +3,11 @@ // https://docs.sentry.io/platforms/javascript/guides/nextjs/ import * as Sentry from "@sentry/nextjs"; +import { nodeProfilingIntegration } from "@sentry/profiling-node"; Sentry.init({ dsn: "https://09bfc307f1fd12228eadd7477e1656c8@o4508064544391168.ingest.de.sentry.io/4508064550551632", + integrations: [nodeProfilingIntegration()], // Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control. tracesSampleRate: 1, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 71d7e582..243e0b10 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,6 +168,9 @@ importers: '@sentry/nextjs': specifier: ^8 version: 8.33.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@1.26.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@1.26.0(@opentelemetry/api@1.9.0))(next@15.0.0-canary.178(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522)(webpack@5.95.0(esbuild@0.19.12)) + '@sentry/profiling-node': + specifier: ^8.33.1 + version: 8.33.1 '@vercel/analytics': specifier: ^1.3.1 version: 1.3.1(next@15.0.0-canary.178(@babel/core@7.24.7)(@opentelemetry/api@1.9.0)(babel-plugin-react-compiler@0.0.0-experimental-334f00b-20240725)(react-dom@19.0.0-rc-f994737d14-20240522(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522))(react@19.0.0-rc-f994737d14-20240522) @@ -2614,6 +2617,11 @@ packages: '@opentelemetry/sdk-trace-base': ^1.26.0 '@opentelemetry/semantic-conventions': ^1.27.0 + '@sentry/profiling-node@8.33.1': + resolution: {integrity: sha512-mpgcqT/yUyWiRKjHFJ6UMjNmMgAYK4aeaMQDL7P61y5mrVxfK9vRQbKuXdP9XiyiZe06j1PSskiBEA2S1cDVJQ==} + engines: {node: '>=14.18'} + hasBin: true + '@sentry/react@8.33.1': resolution: {integrity: sha512-SsEX05xfcfOvo7/pK1UyeyTAYWH8iSIsXXlsjvnSRsbuJkjb0c+q6yiZpj3A2PRdbcx43nTVE1n0lSpgaqj2HA==} engines: {node: '>=14.18'} @@ -5809,11 +5817,6 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.6.2: - resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} - engines: {node: '>=10'} - hasBin: true - semver@7.6.3: resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} engines: {node: '>=10'} @@ -9363,6 +9366,17 @@ snapshots: '@sentry/types': 8.33.1 '@sentry/utils': 8.33.1 + '@sentry/profiling-node@8.33.1': + dependencies: + '@sentry/core': 8.33.1 + '@sentry/node': 8.33.1 + '@sentry/types': 8.33.1 + '@sentry/utils': 8.33.1 + detect-libc: 2.0.3 + node-abi: 3.63.0 + transitivePeerDependencies: + - supports-color + '@sentry/react@8.33.1(react@19.0.0-rc-f994737d14-20240522)': dependencies: '@sentry/browser': 8.33.1 @@ -9958,7 +9972,7 @@ snapshots: debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.6.2 + semver: 7.6.3 tsutils: 3.21.0(typescript@5.5.2) optionalDependencies: typescript: 5.5.2 @@ -9973,7 +9987,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 - semver: 7.6.2 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: typescript: 5.5.2 @@ -9988,7 +10002,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.6.2 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: typescript: 5.4.5 @@ -10003,7 +10017,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.6.2 + semver: 7.6.3 ts-api-utils: 1.3.0(typescript@5.5.2) optionalDependencies: typescript: 5.5.2 @@ -10020,7 +10034,7 @@ snapshots: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.5.2) eslint: 8.57.0 eslint-scope: 5.1.1 - semver: 7.6.2 + semver: 7.6.3 transitivePeerDependencies: - supports-color - typescript @@ -11333,7 +11347,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.2.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@7.14.1(eslint@8.57.0)(typescript@5.5.2))(eslint-plugin-import@2.29.1)(eslint@8.57.0))(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.13.1 is-glob: 4.0.3 @@ -11460,7 +11474,7 @@ snapshots: read-pkg-up: 7.0.1 regexp-tree: 0.1.27 regjsparser: 0.10.0 - semver: 7.6.2 + semver: 7.6.3 strip-indent: 3.0.0 transitivePeerDependencies: - supports-color @@ -13213,8 +13227,6 @@ snapshots: semver@6.3.1: {} - semver@7.6.2: {} - semver@7.6.3: {} send@0.18.0: @@ -13274,7 +13286,7 @@ snapshots: detect-libc: 2.0.3 node-addon-api: 6.1.0 prebuild-install: 7.1.2 - semver: 7.6.2 + semver: 7.6.3 simple-get: 4.0.1 tar-fs: 3.0.6 tunnel-agent: 0.6.0 @@ -13283,7 +13295,7 @@ snapshots: dependencies: color: 4.2.3 detect-libc: 2.0.3 - semver: 7.6.2 + semver: 7.6.3 optionalDependencies: '@img/sharp-darwin-arm64': 0.33.4 '@img/sharp-darwin-x64': 0.33.4 @@ -13384,7 +13396,7 @@ snapshots: git-hooks-list: 3.1.0 globby: 13.2.2 is-plain-obj: 4.1.0 - semver: 7.6.2 + semver: 7.6.3 sort-object-keys: 1.1.3 source-map-js@1.2.0: {} From 8b528f50b27a21ddbcafd132df5db1ed4c032c4f Mon Sep 17 00:00:00 2001 From: Tom Sherman Date: Mon, 7 Oct 2024 17:31:54 +0100 Subject: [PATCH 7/7] Trace getDidDoc --- packages/frontpage/lib/data/atproto/did.ts | 25 ++++++++++++---------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/frontpage/lib/data/atproto/did.ts b/packages/frontpage/lib/data/atproto/did.ts index 1459d401..e3acc60e 100644 --- a/packages/frontpage/lib/data/atproto/did.ts +++ b/packages/frontpage/lib/data/atproto/did.ts @@ -1,3 +1,4 @@ +import { startSpan } from "@sentry/nextjs"; import { cache } from "react"; import { z } from "zod"; @@ -15,17 +16,19 @@ export function parseDid(s: string): DID | null { return s; } -export const getDidDoc = cache(async (did: DID) => { - const response = await fetch(`https://plc.directory/${did}`, { - next: { - // TODO: Also revalidate this when we receive an identity change event - // That would allow us to extend the revalidation time to 1 day - revalidate: 60 * 60, // 1 hour - }, - }); - - return PlcDocument.parse(await response.json()); -}); +export const getDidDoc = cache(async (did: DID) => + startSpan({ name: "getDidDoc" }, async () => { + const response = await fetch(`https://plc.directory/${did}`, { + next: { + // TODO: Also revalidate this when we receive an identity change event + // That would allow us to extend the revalidation time to 1 day + revalidate: 60 * 60, // 1 hour + }, + }); + + return PlcDocument.parse(await response.json()); + }), +); export const getPdsUrl = cache(async (did: DID) => { const plc = await getDidDoc(did);