Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .oxfmtrc.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"ignorePatterns": ["**/dist/**", "**/.next/**", "**/.source/**"]
"ignorePatterns": ["**/dist/**", "**/.next/**", "**/.source/**", "**/public/**", "**/*.mdx"]
}
2 changes: 1 addition & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,5 @@
"builtin": true
},
"globals": {},
"ignorePatterns": ["**/dist/**", "**/.next/**", "**/.source/**", "**/node_modules/**"]
"ignorePatterns": ["**/dist/**", "**/.next/**", "**/.source/**", "**/node_modules/**", "**/public/**"]
}
4 changes: 1 addition & 3 deletions apps/blog/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,7 @@ const securityHeaders = [
},
];

const allowedDevOrigins = (
process.env.ALLOWED_DEV_ORIGINS ?? "localhost,127.0.0.1,192.168.1.48"
)
const allowedDevOrigins = (process.env.ALLOWED_DEV_ORIGINS ?? "localhost,127.0.0.1,192.168.1.48")
.split(",")
.map((origin) => origin.trim())
.filter(Boolean);
Expand Down
12 changes: 6 additions & 6 deletions apps/blog/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,23 @@
},
"dependencies": {
"@base-ui/react": "catalog:",
"@mixedbread/sdk": "catalog:",
"@fumadocs/base-ui": "catalog:",
"@fumadocs/cli": "catalog:",
"@prisma/eclipse": "workspace:^",
"@mixedbread/sdk": "catalog:",
"@prisma-docs/ui": "workspace:*",
"@prisma/eclipse": "workspace:^",
"cors": "^2.8.6",
"fumadocs-core": "catalog:",
"fumadocs-mdx": "catalog:",
"fumadocs-openapi": "catalog:",
"fumadocs-ui": "catalog:",
"@fumadocs/base-ui": "catalog:",
"lucide-react": "catalog:",
"next": "catalog:",
"npm-to-yarn": "catalog:",
"posthog-js": "catalog:",
"react": "catalog:",
"react-dom": "catalog:",
"react-tweet": "catalog:",
"posthog-js": "catalog:",
"remark-directive": "catalog:",
"zod": "catalog:"
},
Expand All @@ -40,11 +40,11 @@
"@types/node": "catalog:",
"@types/react": "catalog:",
"@types/react-dom": "catalog:",
"babel-plugin-react-compiler": "catalog:",
"next-validate-link": "catalog:",
"postcss": "catalog:",
"tailwindcss": "catalog:",
"tsx": "catalog:",
"typescript": "catalog:",
"babel-plugin-react-compiler": "catalog:"
"typescript": "catalog:"
}
}
32 changes: 13 additions & 19 deletions apps/blog/scripts/lint.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,22 @@
import {
type FileObject,
printErrors,
scanURLs,
validateFiles,
} from 'next-validate-link';
import type { InferPageType } from 'fumadocs-core/source';
import { type FileObject, printErrors, scanURLs, validateFiles } from "next-validate-link";
import type { InferPageType } from "fumadocs-core/source";

import { register } from 'node:module';
register('fumadocs-mdx/node/loader', import.meta.url);
import { register } from "node:module";
register("fumadocs-mdx/node/loader", import.meta.url);

const { blog } = await import('@/lib/source');
const { blog } = await import("@/lib/source");
const blogPages = blog.getPages().map((page) => {
return {
value: { slug: page.slugs },
hashes: getHeadings(page),
};
});


async function checkLinks() {
const scanned = await scanURLs({
preset: 'next',
preset: "next",
populate: {
'(blog)/[slug]': blogPages,
"(blog)/[slug]": blogPages,
},
});

Expand All @@ -31,11 +25,11 @@ async function checkLinks() {
scanned,
markdown: {
components: {
Card: { attributes: ['href'] },
Cards: { attributes: ['href'] },
Card: { attributes: ["href"] },
Cards: { attributes: ["href"] },
},
},
checkRelativePaths: 'as-url',
checkRelativePaths: "as-url",
}),
true,
);
Expand All @@ -46,12 +40,12 @@ function getHeadings({ data }: InferPageType<typeof blog>): string[] {
}

function getFiles() {
console.log("Validating Files")
console.log("Validating Files");

const blogPromises = blog.getPages().map(
async (page): Promise<FileObject> => ({
path: page.absolutePath ?? '',
content: await page.data.getText('raw'),
path: page.absolutePath ?? "",
content: await page.data.getText("raw"),
url: page.url,
data: page.data,
}),
Expand Down
26 changes: 14 additions & 12 deletions apps/blog/source.config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
import remarkDirective from "remark-directive";
import {
remarkDirectiveAdmonition,
remarkMdxFiles,
} from "fumadocs-core/mdx-plugins";
import { remarkDirectiveAdmonition, remarkMdxFiles } from "fumadocs-core/mdx-plugins";
import { remarkImage } from "fumadocs-core/mdx-plugins";
import {
defineCollections,
defineConfig,
frontmatterSchema,
} from "fumadocs-mdx/config";
import { defineCollections, defineConfig, frontmatterSchema } from "fumadocs-mdx/config";
import lastModified from "fumadocs-mdx/plugins/last-modified";
import { z } from "zod";
import convert from "npm-to-yarn";
Expand Down Expand Up @@ -67,9 +60,18 @@ export default defineConfig({
persist: { id: "package-manager" },
// Custom package managers to add --bun flag for bunx commands
packageManagers: [
{ command: (cmd: string) => convert(cmd.replace(/^npm init -y$/, "npm init"), "npm"), name: "npm" },
{ command: (cmd: string) => convert(cmd.replace(/^npm init -y$/, "npm init"), "pnpm"), name: "pnpm" },
{ command: (cmd: string) => convert(cmd.replace(/^npm init -y$/, "npm init"), "yarn"), name: "yarn" },
{
command: (cmd: string) => convert(cmd.replace(/^npm init -y$/, "npm init"), "npm"),
name: "npm",
},
{
command: (cmd: string) => convert(cmd.replace(/^npm init -y$/, "npm init"), "pnpm"),
name: "pnpm",
},
{
command: (cmd: string) => convert(cmd.replace(/^npm init -y$/, "npm init"), "yarn"),
name: "yarn",
},
{
command: (cmd: string) => {
const converted = convert(cmd.replace(/^npm init -y$/, "npm init"), "bun");
Expand Down
37 changes: 10 additions & 27 deletions apps/blog/src/app/(blog)/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,13 @@ import { notFound } from "next/navigation";
import { getMDXComponents } from "@/mdx-components";
import { createRelativeLink } from "fumadocs-ui/mdx";
import { blog } from "@/lib/source";
import {
Badge,
InlineTOC,
Separator,
} from "@prisma/eclipse";
import { Badge, InlineTOC, Separator } from "@prisma/eclipse";

import { JsonLd } from "@prisma-docs/ui/components/json-ld";
import { FooterNewsletterForm } from "@prisma-docs/ui/components/newsletter";
import { BlogShare } from "@/components/BlogShare";
import { AuthorAvatarGroup } from "@/components/AuthorAvatarGroup";
import {
getBaseUrl,
withBlogBasePath,
withBlogBasePathForImageSrc,
} from "@/lib/url";
import { getBaseUrl, withBlogBasePath, withBlogBasePathForImageSrc } from "@/lib/url";
import Link from "next/link";
import type { Metadata } from "next";

Expand Down Expand Up @@ -83,19 +75,18 @@ function getBlogPostingJsonLd(page: ReturnType<typeof blog.getPage>): BlogPostin
const canonicalPath = withBlogBasePath(page.url);
const canonicalUrl = toAbsoluteUrl(canonicalPath);
const imagePath = page.data.metaImagePath ?? page.data.heroImagePath;
const imageUrl = imagePath
? toAbsoluteUrl(withBlogBasePathForImageSrc(imagePath))
: undefined;
const imageUrl = imagePath ? toAbsoluteUrl(withBlogBasePathForImageSrc(imagePath)) : undefined;

const authorNames = Array.isArray(page.data.authors)
? page.data.authors
.filter((author): author is string => typeof author === "string")
.map((author) => author.trim())
.filter(Boolean)
.filter((author): author is string => typeof author === "string")
.map((author) => author.trim())
.filter(Boolean)
: [];

const datePublished = toIsoDate(page.data.date);
const dateModified = toIsoDate((page.data as { lastModified?: unknown }).lastModified) ?? datePublished;
const dateModified =
toIsoDate((page.data as { lastModified?: unknown }).lastModified) ?? datePublished;

const jsonLd: BlogPostingSchema = {
"@context": "https://schema.org",
Expand Down Expand Up @@ -140,9 +131,7 @@ function getBlogPostingJsonLd(page: ReturnType<typeof blog.getPage>): BlogPostin
return jsonLd;
}

export default async function Page(props: {
params: Promise<{ slug: string }>;
}) {
export default async function Page(props: { params: Promise<{ slug: string }> }) {
const params = await props.params;
const page = blog.getPage([params.slug]);

Expand All @@ -159,10 +148,7 @@ export default async function Page(props: {
<div className="post-contents w-full">
{/* Title + meta */}
<header className="w-full relative">
<Link
href="/"
className="text-fd-primary hover:underline text-sm absolute -top-8"
>
<Link href="/" className="text-fd-primary hover:underline text-sm absolute -top-8">
← Back to Blog
</Link>
<h1 className="mt-3 mb-8 font-bold max-md:text-3xl md:text-5xl stretch-display font-sans-display text-foreground-neutral">
Expand Down Expand Up @@ -195,10 +181,8 @@ export default async function Page(props: {
hover:bg-background-ppg/50
hover:border-stroke-ppg/50
hover:text-foreground-ppg"

/>
</Link>

))}
</div>
)}
Expand All @@ -207,7 +191,6 @@ export default async function Page(props: {
{/* Body */}
<article className="w-full flex flex-col pb-8 mt-12">
<div className="prose min-w-0 [&_figure]:w-full [&_figure]:md:max-w-140 [&_figure]:lg:max-w-200">

<p className="font-semibold text-lg">{page.data.excerpt}</p>

<MDX
Expand Down
5 changes: 1 addition & 4 deletions apps/blog/src/app/(blog)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider defaultTheme="system" storageKey="theme">
<UtmPersistence />
<NavigationWrapper
links={baseOptions().links}
utm={{ source: "website", medium: "blog" }}
/>
<NavigationWrapper links={baseOptions().links} utm={{ source: "website", medium: "blog" }} />
{children}
<Footer />
</ThemeProvider>
Expand Down
13 changes: 3 additions & 10 deletions apps/blog/src/app/(blog)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ export default async function BlogHome({
return authors.length > 0 ? authors[0] : null;
};


const items: BlogCardItem[] = posts.map((post) => {
const data = post.data as any;

Expand Down Expand Up @@ -157,15 +156,12 @@ export default async function BlogHome({

const uniqueTags = [
...new Set(
items
.flatMap((item) => item.tags ?? [])
.filter((tag): tag is string => Boolean(tag)),
items.flatMap((item) => item.tags ?? []).filter((tag): tag is string => Boolean(tag)),
),
];
const validTags = new Set(uniqueTags);
const tagFromQuery = getFirstQueryValue(resolvedSearchParams.tag);
const currentCategory =
tagFromQuery && validTags.has(tagFromQuery) ? tagFromQuery : SHOW_ALL;
const currentCategory = tagFromQuery && validTags.has(tagFromQuery) ? tagFromQuery : SHOW_ALL;
const filteredItems =
currentCategory === SHOW_ALL
? items
Expand Down Expand Up @@ -235,10 +231,7 @@ export default async function BlogHome({
))}
<PaginationItem>
<PaginationNext
href={buildBlogHref(
currentCategory,
Math.min(totalPages, currentPage + 1),
)}
href={buildBlogHref(currentCategory, Math.min(totalPages, currentPage + 1))}
aria-disabled={currentPage === totalPages}
/>
</PaginationItem>
Expand Down
19 changes: 5 additions & 14 deletions apps/blog/src/app/api/newsletter/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ export const dynamic = "force-dynamic";

// CORS headers configuration
const corsHeaders = {
"Access-Control-Allow-Origin":
"https://prisma.io, https://www.prisma.io, https://prisma.io/docs",
"Access-Control-Allow-Origin": "https://prisma.io, https://www.prisma.io, https://prisma.io/docs",
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
Expand Down Expand Up @@ -110,10 +109,7 @@ export async function POST(request: Request) {
});

// Handle specific Brevo errors
if (
data?.code === "duplicate_parameter" ||
data?.message?.includes("already exists")
) {
if (data?.code === "duplicate_parameter" || data?.message?.includes("already exists")) {
return NextResponse.json(
{ message: "Already subscribed", alreadySubscribed: true },
{ status: 200, headers: corsHeaders },
Expand All @@ -122,8 +118,7 @@ export async function POST(request: Request) {

return NextResponse.json(
{
error:
data?.message || "Failed to subscribe. Please try again later.",
error: data?.message || "Failed to subscribe. Please try again later.",
debug:
process.env.NODE_ENV === "development"
? {
Expand All @@ -145,19 +140,15 @@ export async function POST(request: Request) {
);
} catch (error) {
console.error("Newsletter subscription error:", error);
const errorMessage =
error instanceof Error ? error.message : "An unexpected error occurred";
const errorMessage = error instanceof Error ? error.message : "An unexpected error occurred";

return NextResponse.json(
{
error: errorMessage,
debug:
process.env.NODE_ENV === "development"
? {
errorType:
error instanceof Error
? error.constructor.name
: typeof error,
errorType: error instanceof Error ? error.constructor.name : typeof error,
stack: error instanceof Error ? error.stack : undefined,
}
: undefined,
Expand Down
2 changes: 1 addition & 1 deletion apps/blog/src/app/api/search/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export type GeneratedMetadata = {
heroImageAlt: string;
tags: string[];
excerpt: string;
}
};
export const dynamic = "force-dynamic";
const mixedbreadApiKey = process.env.MIXEDBREAD_API_KEY;
if (!mixedbreadApiKey) {
Expand Down
Loading
Loading