diff --git a/apps/web/content/blog/getting-started-with-deessejs-errors.mdx b/apps/web/content/blog/getting-started-with-deessejs-errors.mdx new file mode 100644 index 0000000..57b0748 --- /dev/null +++ b/apps/web/content/blog/getting-started-with-deessejs-errors.mdx @@ -0,0 +1,80 @@ +--- +title: "Getting Started with @deessejs/errors" +description: "Learn how to implement Python-inspired error handling in TypeScript with exception chaining, hierarchical inheritance, and rich error semantics." +author: "Nesalia Inc" +date: "2026-06-05" +--- + +## Introduction + +`@deessejs/errors` brings Python's powerful error handling system to TypeScript. If you've ever wished JavaScript had the same expressive error handling as Python, this library is for you. + +## Installation + +```bash +npm install @deessejs/errors +``` + +## Creating Your First Error + +Unlike traditional JavaScript errors that use classes, `@deessejs/errors` uses a function-based API: + +```ts +import { error } from '@deessejs/errors'; + +// Create an error factory +const ValidationError = error({ + name: 'ValidationError', + message: 'Validation failed for field "{field}"', +}); + +// Use it +const err = ValidationError({ field: 'email' }); +console.log(err.message); // "Validation failed for field "email"" +``` + +## Exception Chaining + +The `.from()` method lets you chain errors together, preserving the full context of what went wrong: + +```ts +import { error, raise } from '@deessejs/errors'; + +const AppError = error({ name: 'AppError' }); +const ValidationError = error({ name: 'ValidationError' }); + +try { + // Something fails + raise(ValidationError({ field: 'email' })); +} catch (e) { + // Chain the error + AppError({}).from(e); +} +``` + +## Hierarchical Inheritance + +Build error hierarchies that let you catch errors at different levels: + +```ts +import { error, is } from '@deessejs/errors'; + +const AppError = error({ name: 'AppError' }); +const ValidationError = error({ + name: 'ValidationError', + inherits: AppError, +}); + +// Now you can catch any AppError +if (is(err, AppError)) { + // Handles both ValidationError and AppError +} +``` + +## Next Steps + +- Read the [Error Factory documentation](/docs/error-factory) to learn about message templates +- Explore [Exception Chaining](/docs/from-method) for advanced error handling +- Check out [Recipes](/docs/recipes) for common patterns + +Happy error handling! diff --git a/apps/web/source.config.ts b/apps/web/source.config.ts index a35628a..2f9071b 100644 --- a/apps/web/source.config.ts +++ b/apps/web/source.config.ts @@ -1,5 +1,6 @@ -import { defineConfig, defineDocs } from 'fumadocs-mdx/config'; +import { defineConfig, defineDocs, defineCollections } from 'fumadocs-mdx/config'; import { metaSchema, pageSchema } from 'fumadocs-core/source/schema'; +import { z } from 'zod'; // You can customize Zod schemas for frontmatter and `meta.json` here // see https://fumadocs.dev/docs/mdx/collections @@ -16,6 +17,15 @@ export const docs = defineDocs({ }, }); +export const blog = defineCollections({ + type: 'doc', + dir: 'content/blog', + schema: pageSchema.extend({ + author: z.string(), + date: z.iso.date().or(z.date()), + }), +}); + export default defineConfig({ mdxOptions: { // MDX options diff --git a/apps/web/src/app/(home)/blog/[slug]/page.client.tsx b/apps/web/src/app/(home)/blog/[slug]/page.client.tsx new file mode 100644 index 0000000..f8dc82f --- /dev/null +++ b/apps/web/src/app/(home)/blog/[slug]/page.client.tsx @@ -0,0 +1,20 @@ +'use client'; +import { Check, Share } from 'lucide-react'; +import { useCopyButton } from 'fumadocs-ui/utils/use-copy-button'; + +export function ShareButton({ url }: { url: string }) { + const [isChecked, onCopy] = useCopyButton(() => { + void navigator.clipboard.writeText(`${window.location.origin}${url}`); + }); + + return ( + + ); +} diff --git a/apps/web/src/app/(home)/blog/[slug]/page.tsx b/apps/web/src/app/(home)/blog/[slug]/page.tsx new file mode 100644 index 0000000..c8c149a --- /dev/null +++ b/apps/web/src/app/(home)/blog/[slug]/page.tsx @@ -0,0 +1,129 @@ +import type { Metadata } from 'next'; +import { notFound } from 'next/navigation'; +import Link from 'next/link'; +import { InlineTOC } from 'fumadocs-ui/components/inline-toc'; +import { blogSource } from '@/lib/source'; +import { baseUrl } from '@/lib/shared'; +import { getMDXComponents } from '@/components/mdx'; +import { ShareButton } from './page.client'; + +export default async function Page(props: PageProps<'/blog/[slug]'>) { + const params = await props.params; + const page = blogSource.getPage([params.slug]); + + if (!page) notFound(); + + const MDX = page.data.body; + const toc = page.data.toc; + + return ( +
+ {/* Author& Date */} +
+
+

Written by

+

{page.data.author}

+
+
+

Published

+

+ {new Date(page.data.date).toDateString()} +

+
+
+ + {/* Title & Description */} +

{page.data.title}

+

{page.data.description}

+ + {/* Actions */} +
+ + + Back to Blog + +
+ + {/* Content */} +
+ + +
+ + {/* Article JSON-LD */} +