diff --git a/public/assets/images/kevin-brown.webp b/public/assets/images/kevin-brown.webp new file mode 100644 index 00000000..cf918db2 Binary files /dev/null and b/public/assets/images/kevin-brown.webp differ diff --git a/src/pages/api/social-card/__tests__/index.spec.ts b/src/pages/api/social-card/__tests__/index.spec.ts index 2c975c42..824e6d44 100644 --- a/src/pages/api/social-card/__tests__/index.spec.ts +++ b/src/pages/api/social-card/__tests__/index.spec.ts @@ -1,12 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { GET } from '@pages/api/social-card' - -vi.mock('@assets/images/avatars/kevin-brown.webp', () => ({ - default: { - src: '/_astro/kevin-brown.test.webp', - fsPath: '/virtual/assets/kevin-brown.webp', - }, -})) +import { fileURLToPath } from 'node:url' type CollectionFixture = Array<{ id: string @@ -73,6 +67,10 @@ const seedCollections = () => { } describe('Social Card API - GET /api/social-card', () => { + const expectedAvatarPath = fileURLToPath( + new URL('../../../../assets/images/avatars/kevin-brown.webp', import.meta.url) + ) + beforeEach(() => { generateOpenGraphImageMock.mockReset() generateOpenGraphImageMock.mockResolvedValue(Buffer.from('mock-image')) @@ -133,7 +131,7 @@ describe('Social Card API - GET /api/social-card', () => { expect(generateOpenGraphImageMock).toHaveBeenCalledWith( expect.objectContaining({ logo: expect.objectContaining({ - path: '/virtual/assets/kevin-brown.webp', + path: expectedAvatarPath, }), }) ) diff --git a/src/pages/api/social-card/index.ts b/src/pages/api/social-card/index.ts index 11c22dd1..cc63069b 100644 --- a/src/pages/api/social-card/index.ts +++ b/src/pages/api/social-card/index.ts @@ -1,21 +1,20 @@ import type { APIRoute } from 'astro' import { getCollection } from 'astro:content' import { generateOpenGraphImage } from 'astro-og-canvas' -import kevinBrownAvatar from '@assets/images/avatars/kevin-brown.webp' +import { fileURLToPath } from 'node:url' import { buildApiErrorResponse, handleApiFunctionError } from '@pages/api/_utils/errors' import { createApiFunctionContext } from '@pages/api/_utils/requestContext' export const prerender = false const ROUTE = '/api/social-card' +const AVATAR_FILE_PATH = fileURLToPath( + new URL('../../../assets/images/avatars/kevin-brown.webp', import.meta.url) +) const DEFAULT_TITLE = 'Platform Engineering by Kevin Brown' const DEFAULT_DESCRIPTION = 'Platform engineer helping teams harden delivery, modernize cloud platforms, and improve developer experience.' -type ImageMetadataWithFsPath = typeof kevinBrownAvatar & { - fsPath?: string -} - type CollectionKey = 'articles' | 'caseStudies' | 'services' | 'downloads' type PaletteKey = 'articles' | 'case-studies' | 'services' | 'downloads' | 'default' @@ -60,16 +59,6 @@ const gradientPalette: Record = { ], } -const getAvatarFilePath = (): string => { - const avatarFilePath = (kevinBrownAvatar as ImageMetadataWithFsPath).fsPath - - if (!avatarFilePath) { - throw new Error('Kevin Brown avatar asset is missing a local file path') - } - - return avatarFilePath -} - /** Normalize slug parameters to a consistent format */ const normalizeSlug = (value: string | null): string => { if (!value) return 'home' @@ -133,7 +122,6 @@ export const GET: APIRoute = async ({ request, clientAddress, cookies }) => { const slug = normalizeSlug(url.searchParams.get('slug')) const titleOverride = url.searchParams.get('title') const descriptionOverride = url.searchParams.get('description') - const avatarPath = getAvatarFilePath() const contentIndex = await buildContentIndex() const matchedEntry = contentIndex[slug] @@ -153,7 +141,7 @@ export const GET: APIRoute = async ({ request, clientAddress, cookies }) => { bgGradient: gradientPalette[palette], padding: 80, logo: { - path: avatarPath, + path: AVATAR_FILE_PATH, size: [140, 140], }, font: {