@autoblogwriter/sdk 2.0.5 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,6 +12,33 @@ npm install @autoblogwriter/sdk
12
12
 
13
13
  > Requires Node.js 18+ and native `fetch`. Bundles ship as ESM, CJS, and types via `tsup`.
14
14
 
15
+ ## Entry Points
16
+
17
+ ```ts
18
+ // Core client, types, and utilities
19
+ import { createBlogAutoClient } from "@autoblogwriter/sdk";
20
+
21
+ // Next.js App Router helpers (server-side)
22
+ import { fetchBlogPosts, fetchBlogPost } from "@autoblogwriter/sdk/next";
23
+
24
+ // React components
25
+ import { BlogPost, BlogPostList, Markdown } from "@autoblogwriter/sdk/react";
26
+
27
+ // Webhook signature verification (server-side)
28
+ import { verifyWebhookSignature } from "@autoblogwriter/sdk/revalidate";
29
+
30
+ // Default styles
31
+ import "@autoblogwriter/sdk/styles.css";
32
+ ```
33
+
34
+ | Entry Point | Environment | Description |
35
+ | --- | --- | --- |
36
+ | `@autoblogwriter/sdk` | Server | Core client, markdown renderer, sitemap/robots builders |
37
+ | `@autoblogwriter/sdk/next` | Server (Next.js) | `fetchBlogPosts`, `fetchBlogPost`, `generatePostMetadata`, `generateBlogSitemap`, `generateBlogRobots`, `createEnvRevalidateHandler` |
38
+ | `@autoblogwriter/sdk/react` | Client or Server | `<BlogPost>`, `<BlogPostList>`, `<Markdown>` components |
39
+ | `@autoblogwriter/sdk/revalidate` | Server | `createRevalidateRouteHandler`, `verifyWebhookSignature` |
40
+ | `@autoblogwriter/sdk/styles.css` | Client | Default dark-theme styles for all components |
41
+
15
42
  ## Security Notes (Read First)
16
43
  - Never ship AutoBlogWriter API keys in public, client-side code.
17
44
  - Run the SDK inside Next.js server components, route handlers, or your own backend proxy.
@@ -45,198 +72,319 @@ const client = createBlogAutoClient({
45
72
  | `fetch` | `typeof fetch` | no | Provide a custom fetch implementation (e.g., for SSR polyfills). |
46
73
  | `timeoutMs` | `number` | no | Optional request timeout enforced client-side. |
47
74
 
48
- ## Next.js App Router Usage
75
+ ## Next.js Helper Functions (`@autoblogwriter/sdk/next`)
76
+
77
+ The `next` entry point provides high-level helpers that read configuration from environment variables automatically (via `createBlogAutoFromEnv`). Set these env vars and the helpers handle client creation, cache tagging, and metadata for you:
78
+
79
+ | Env Variable | Required | Description |
80
+ | --- | --- | --- |
81
+ | `BLOGAUTO_API_KEY` | yes | Workspace API key |
82
+ | `BLOGAUTO_WORKSPACE_SLUG` | yes | Workspace slug for content APIs |
83
+ | `BLOGAUTO_API_URL` | no | Defaults to `https://api.autoblogwriter.app` |
84
+ | `BLOGAUTO_WORKSPACE_ID` | no | Optional workspace ID |
85
+ | `SITE_URL` or `NEXT_PUBLIC_SITE_URL` | no | Defaults to `http://localhost:3000` |
86
+ | `BLOGAUTO_REVALIDATE_SECRET` | no | Required for the revalidation handler |
49
87
 
50
- All examples assume you run in server files where environment variables are available. **Do not** move these snippets to client components without a secure proxy.
88
+ ### `fetchBlogPosts(options?)`
51
89
 
52
- ### `app/blog/page.tsx`
90
+ Fetches a paginated list of posts with automatic cache tagging.
53
91
 
54
92
  ```ts
55
- // app/blog/page.tsx
56
- import { createBlogAutoClient, renderMarkdownToHtml } from "@autoblogwriter/sdk";
93
+ import { fetchBlogPosts } from "@autoblogwriter/sdk/next";
57
94
 
58
- const workspaceSlug = process.env.BLOGAUTO_WORKSPACE!;
59
- const blogClient = createBlogAutoClient({
60
- apiUrl: process.env.BLOGAUTO_API_URL!,
61
- apiKey: process.env.BLOGAUTO_API_KEY!,
62
- workspaceSlug,
63
- });
95
+ const { posts, nextCursor } = await fetchBlogPosts({ limit: 20 });
96
+ ```
64
97
 
65
- export default async function BlogIndexPage() {
66
- const { posts } = await blogClient.getPosts({
67
- limit: 20,
68
- next: { tags: [`blogauto:${workspaceSlug}:posts`] },
69
- });
70
-
71
- return (
72
- <div>
73
- {posts.map((post) => (
74
- <article key={post.id}>
75
- <h2>{post.title}</h2>
76
- <div dangerouslySetInnerHTML={{ __html: renderMarkdownToHtml(post.excerpt ?? "") }} />
77
- </article>
78
- ))}
79
- </div>
80
- );
98
+ ### `fetchBlogPost(slug)`
99
+
100
+ Fetches a single post by slug. Automatically calls `notFound()` if the post doesn't exist.
101
+
102
+ ```ts
103
+ import { fetchBlogPost } from "@autoblogwriter/sdk/next";
104
+
105
+ const post = await fetchBlogPost(params.slug);
106
+ ```
107
+
108
+ ### `generatePostMetadata(slug)`
109
+
110
+ Returns a Next.js `Metadata` object (title, description, Open Graph, Twitter cards) for a blog post. Use it in your `generateMetadata` export.
111
+
112
+ ```ts
113
+ import { generatePostMetadata } from "@autoblogwriter/sdk/next";
114
+
115
+ export async function generateMetadata({ params }: Props) {
116
+ return generatePostMetadata(params.slug);
81
117
  }
82
118
  ```
83
119
 
84
- ### `app/blog/[slug]/page.tsx`
120
+ ### `generateBlogSitemap()`
121
+
122
+ Returns a `MetadataRoute.Sitemap` array for `app/sitemap.ts`.
85
123
 
86
124
  ```ts
87
- // app/blog/[slug]/page.tsx
88
- import { notFound } from "next/navigation";
89
- import { createBlogAutoClient, renderMarkdownToHtml } from "@autoblogwriter/sdk";
125
+ import { generateBlogSitemap } from "@autoblogwriter/sdk/next";
90
126
 
91
- const workspaceSlug = process.env.BLOGAUTO_WORKSPACE!;
92
- const blogClient = createBlogAutoClient({
93
- apiUrl: process.env.BLOGAUTO_API_URL!,
94
- apiKey: process.env.BLOGAUTO_API_KEY!,
95
- workspaceSlug,
96
- });
127
+ export default async function sitemap() {
128
+ return generateBlogSitemap();
129
+ }
130
+ ```
131
+
132
+ ### `generateBlogRobots()`
133
+
134
+ Returns a `MetadataRoute.Robots` object for `app/robots.ts`.
135
+
136
+ ```ts
137
+ import { generateBlogRobots } from "@autoblogwriter/sdk/next";
138
+
139
+ export default function robots() {
140
+ return generateBlogRobots();
141
+ }
142
+ ```
143
+
144
+ ### `createEnvRevalidateHandler()`
145
+
146
+ Creates a POST route handler for webhook-based revalidation. Reads `BLOGAUTO_REVALIDATE_SECRET` from env, verifies the HMAC signature, and calls `revalidatePath`/`revalidateTag`.
147
+
148
+ ```ts
149
+ // app/api/blogauto/revalidate/route.ts
150
+ import { createEnvRevalidateHandler } from "@autoblogwriter/sdk/next";
151
+
152
+ export const POST = createEnvRevalidateHandler();
153
+ ```
154
+
155
+ ### Full Next.js Example
156
+
157
+ ```ts
158
+ // app/blog/page.tsx
159
+ import { fetchBlogPosts } from "@autoblogwriter/sdk/next";
160
+ import { BlogPostList } from "@autoblogwriter/sdk/react";
161
+
162
+ export default async function BlogIndexPage() {
163
+ const { posts } = await fetchBlogPosts({ limit: 20 });
164
+ return <BlogPostList posts={posts} />;
165
+ }
166
+ ```
167
+
168
+ ```ts
169
+ // app/blog/[slug]/page.tsx
170
+ import { fetchBlogPost, generatePostMetadata } from "@autoblogwriter/sdk/next";
171
+ import { BlogPost } from "@autoblogwriter/sdk/react";
97
172
 
98
173
  interface Props {
99
174
  params: { slug: string };
100
175
  }
101
176
 
177
+ export async function generateMetadata({ params }: Props) {
178
+ return generatePostMetadata(params.slug);
179
+ }
180
+
102
181
  export default async function BlogPostPage({ params }: Props) {
103
- const post = await blogClient.getPostBySlug(params.slug, {
104
- next: { tags: [`blogauto:${workspaceSlug}:post:${params.slug}`] },
105
- });
106
- if (!post) {
107
- notFound();
108
- }
109
-
110
- return (
111
- <article>
112
- <h1>{post.title}</h1>
113
- <time dateTime={post.publishedAt ?? post.updatedAt}>{post.publishedAt}</time>
114
- <div dangerouslySetInnerHTML={{ __html: renderMarkdownToHtml(post.content) }} />
115
- </article>
116
- );
182
+ const post = await fetchBlogPost(params.slug);
183
+ return <BlogPost post={post} />;
117
184
  }
118
185
  ```
119
186
 
120
- ### `app/sitemap.ts`
187
+ ## React Components (`@autoblogwriter/sdk/react`)
121
188
 
122
- ```ts
123
- // app/sitemap.ts
124
- import { buildSitemap, createBlogAutoClient } from "@autoblogwriter/sdk";
189
+ Pre-built components for rendering blog content. Works in Next.js, Vite, or any React 18+ app.
125
190
 
126
- const blogClient = createBlogAutoClient({
127
- apiUrl: process.env.BLOGAUTO_API_URL!,
128
- apiKey: process.env.BLOGAUTO_API_KEY!,
129
- workspaceSlug: process.env.BLOGAUTO_WORKSPACE!,
130
- });
191
+ ### `<Markdown>`
131
192
 
132
- export default async function sitemap() {
133
- const entries = await blogClient.getSitemapEntries();
134
- return buildSitemap({
135
- siteUrl: process.env.SITE_URL!,
136
- entries,
137
- routePrefix: "/blog",
138
- });
139
- }
193
+ Renders a markdown string to HTML using the built-in renderer.
194
+
195
+ ```tsx
196
+ import { Markdown } from "@autoblogwriter/sdk/react";
197
+
198
+ <Markdown source={post.content} />
199
+ <Markdown source={post.content} className="custom-markdown" />
140
200
  ```
141
201
 
142
- ### `app/robots.ts`
202
+ | Prop | Type | Default | Description |
203
+ | --- | --- | --- | --- |
204
+ | `source` | `string \| null` | — | Markdown string to render. Returns `null` if empty. |
205
+ | `className` | `string` | `"ba-markdown"` | CSS class on the wrapper `<div>`. |
206
+
207
+ ### `<BlogPost>`
208
+
209
+ Renders a full blog post with title, date, reading time, and markdown content.
210
+
211
+ ```tsx
212
+ import { BlogPost } from "@autoblogwriter/sdk/react";
213
+
214
+ <BlogPost post={post} />
215
+ <BlogPost post={post} showDate={false} />
216
+ <BlogPost post={post} renderContent={(md) => <MyCustomRenderer source={md} />} />
217
+ ```
218
+
219
+ | Prop | Type | Default | Description |
220
+ | --- | --- | --- | --- |
221
+ | `post` | `BlogPost` | — | The post object from the SDK. |
222
+ | `showTitle` | `boolean` | `true` | Show the post title as an `<h1>`. |
223
+ | `showDate` | `boolean` | `true` | Show the published/updated date. |
224
+ | `className` | `string` | `"ba-post"` | CSS class on the `<article>`. |
225
+ | `renderContent` | `(content: string) => ReactNode` | — | Override the default `<Markdown>` renderer. |
226
+
227
+ ### `<BlogPostList>`
228
+
229
+ Renders a list of post cards with titles, dates, and excerpts.
230
+
231
+ ```tsx
232
+ import { BlogPostList } from "@autoblogwriter/sdk/react";
233
+
234
+ <BlogPostList posts={posts} />
235
+ <BlogPostList posts={posts} title="Blog" routePrefix="/articles" />
236
+ ```
237
+
238
+ With Next.js `<Link>`:
239
+
240
+ ```tsx
241
+ import Link from "next/link";
242
+
243
+ <BlogPostList posts={posts} linkComponent={Link} />
244
+ ```
245
+
246
+ With a custom card:
247
+
248
+ ```tsx
249
+ <BlogPostList
250
+ posts={posts}
251
+ renderCard={(post, href) => (
252
+ <a href={href}>{post.title} — {post.excerpt}</a>
253
+ )}
254
+ />
255
+ ```
256
+
257
+ | Prop | Type | Default | Description |
258
+ | --- | --- | --- | --- |
259
+ | `posts` | `BlogPost[]` | — | Array of post objects. |
260
+ | `title` | `string` | `"Latest posts"` | Section heading. Pass empty string to hide. |
261
+ | `routePrefix` | `string` | `"/blog"` | URL prefix for post links (`{routePrefix}/{slug}`). |
262
+ | `linkComponent` | `React.ComponentType` | `<a>` | Custom link component (e.g. Next.js `Link`). |
263
+ | `className` | `string` | `"ba-listing"` | CSS class on the `<section>`. |
264
+ | `renderCard` | `(post, href) => ReactNode` | — | Override the default card rendering. |
265
+
266
+ ## Styles (`@autoblogwriter/sdk/styles.css`)
267
+
268
+ The SDK ships a default dark-theme stylesheet that styles all the React components out of the box. Import it in your app entry point:
143
269
 
144
270
  ```ts
145
- // app/robots.ts
146
- import { buildRobots } from "@autoblogwriter/sdk";
271
+ // app/layout.tsx or src/main.tsx
272
+ import "@autoblogwriter/sdk/styles.css";
273
+ ```
147
274
 
148
- export default function robots() {
149
- return buildRobots({
150
- siteUrl: process.env.SITE_URL!,
151
- sitemapPath: "/sitemap.xml",
152
- });
275
+ All values are driven by CSS custom properties on `:root`, so you can override them to match your theme:
276
+
277
+ ```css
278
+ :root {
279
+ --ba-color-bg: #0c0d10;
280
+ --ba-color-text: #f2f4f8;
281
+ --ba-color-text-muted: rgba(242, 244, 248, 0.6);
282
+ --ba-color-link: #6cf;
283
+ --ba-color-link-hover: #8df;
284
+ --ba-color-border: rgba(255, 255, 255, 0.08);
285
+ --ba-color-card-bg: rgba(255, 255, 255, 0.02);
286
+ --ba-color-card-bg-hover: rgba(255, 255, 255, 0.04);
287
+ --ba-color-code-bg: rgba(255, 255, 255, 0.1);
288
+ --ba-color-pre-bg: rgba(255, 255, 255, 0.05);
289
+ --ba-radius: 8px;
290
+ --ba-max-width: 720px;
291
+ --ba-font-sans: system-ui, -apple-system, sans-serif;
292
+ --ba-font-mono: ui-monospace, SFMono-Regular, monospace;
153
293
  }
154
294
  ```
155
295
 
156
- ## Vite/React Usage with Server Proxy
296
+ For a light theme, override the color variables:
297
+
298
+ ```css
299
+ :root {
300
+ --ba-color-bg: #ffffff;
301
+ --ba-color-text: #1a1a1a;
302
+ --ba-color-text-muted: rgba(0, 0, 0, 0.5);
303
+ --ba-color-text-secondary: rgba(0, 0, 0, 0.7);
304
+ --ba-color-text-content: rgba(0, 0, 0, 0.85);
305
+ --ba-color-link: #0066cc;
306
+ --ba-color-link-hover: #0052a3;
307
+ --ba-color-border: rgba(0, 0, 0, 0.1);
308
+ --ba-color-card-bg: rgba(0, 0, 0, 0.02);
309
+ --ba-color-card-bg-hover: rgba(0, 0, 0, 0.04);
310
+ --ba-color-code-bg: rgba(0, 0, 0, 0.06);
311
+ --ba-color-pre-bg: rgba(0, 0, 0, 0.03);
312
+ }
313
+ ```
314
+
315
+ ### CSS Class Reference
316
+
317
+ | Class | Used by | Description |
318
+ | --- | --- | --- |
319
+ | `.ba-listing` | `<BlogPostList>` | Outer section wrapper |
320
+ | `.ba-listing-title` | `<BlogPostList>` | Section heading |
321
+ | `.ba-posts` | `<BlogPostList>` | Flex column container for cards |
322
+ | `.ba-post-card` | `<BlogPostList>` | Individual post card |
323
+ | `.ba-post-card-title` | `<BlogPostList>` | Card title |
324
+ | `.ba-post-card-link` | `<BlogPostList>` | Title link |
325
+ | `.ba-post-card-meta` | `<BlogPostList>` | Card date |
326
+ | `.ba-post-card-excerpt` | `<BlogPostList>` | Card excerpt |
327
+ | `.ba-post` | `<BlogPost>` | Article wrapper |
328
+ | `.ba-post-title` | `<BlogPost>` | Post title |
329
+ | `.ba-post-meta` | `<BlogPost>` | Date and reading time |
330
+ | `.ba-markdown` | `<Markdown>` | Markdown content wrapper |
157
331
 
158
- Never pipe the API key directly to the browser. Instead, add a tiny proxy route inside your server (Express, Fastify, Next API route, etc.) that calls the SDK.
332
+ ## Low-Level Client Configuration
333
+
334
+ For advanced use cases where you need more control than the env-based helpers provide, you can create a client directly:
159
335
 
160
336
  ```ts
161
- // server/routes/blogauto.ts (Express example)
162
- import express from "express";
163
337
  import { createBlogAutoClient } from "@autoblogwriter/sdk";
164
338
 
165
- const router = express.Router();
166
- const blogClient = createBlogAutoClient({
167
- apiUrl: process.env.BLOGAUTO_API_URL!,
339
+ const client = createBlogAutoClient({
340
+ apiUrl: "https://api.autoblogwriter.app",
168
341
  apiKey: process.env.BLOGAUTO_API_KEY!,
169
- workspaceId: process.env.BLOGAUTO_WORKSPACE_ID!,
342
+ workspaceId: process.env.BLOGAUTO_WORKSPACE_ID,
343
+ workspaceSlug: process.env.BLOGAUTO_WORKSPACE_SLUG,
344
+ authMode: "bearer", // or "x-api-key"
345
+ headers: { "x-trace-id": "..." },
346
+ timeoutMs: 10_000,
347
+ fetch: globalThis.fetch, // optional custom fetch
170
348
  });
349
+ ```
171
350
 
172
- router.get("/posts", async (req, res) => {
173
- const { posts, nextCursor } = await blogClient.getPosts({
174
- limit: Number(req.query.limit) || 10,
175
- cursor: req.query.cursor?.toString(),
176
- });
177
- res.json({ posts, nextCursor });
178
- });
351
+ | Option | Type | Required | Description |
352
+ | --- | --- | --- | --- |
353
+ | `apiUrl` | `string` | yes | Root API URL, e.g. `https://api.autoblogwriter.app`. Trailing slash removed automatically. |
354
+ | `apiKey` | `string` | yes | Workspace-scoped API key created in the AutoBlogWriter dashboard. |
355
+ | `workspaceId` | `string` | one of `workspaceId` or `workspaceSlug` | Optional; used for account scoping. |
356
+ | `workspaceSlug` | `string` | one of `workspaceId` or `workspaceSlug` | Required for public content APIs (`/v1/public/:workspaceSlug/...`). |
357
+ | `authMode` | `"bearer" \| "x-api-key"` | no (default `"bearer"`) | Sends the API key via `Authorization: Bearer` or `x-api-key`. |
358
+ | `headers` | `Record<string, string>` | no | Additional static headers (merged on each request). |
359
+ | `fetch` | `typeof fetch` | no | Provide a custom fetch implementation (e.g., for SSR polyfills). |
360
+ | `timeoutMs` | `number` | no | Optional request timeout enforced client-side. |
179
361
 
180
- router.get("/posts/:slug", async (req, res) => {
181
- const post = await blogClient.getPostBySlug(req.params.slug);
182
- if (!post) {
183
- return res.status(404).json({ error: "Not Found" });
184
- }
185
- res.json(post);
186
- });
362
+ ## Revalidation
187
363
 
188
- export default router;
189
- ```
364
+ When AutoBlogWriter publishes a post it can ping your Next.js site so cached pages refresh immediately.
190
365
 
191
- React (client) calls your proxy:
366
+ **Quick setup** (env-based, one line):
192
367
 
193
368
  ```ts
194
- // src/pages/Blog.tsx
195
- import useSWR from "swr";
196
-
197
- const fetcher = (url: string) => fetch(url).then((res) => res.json());
198
-
199
- export function BlogList() {
200
- const { data } = useSWR("/api/blogauto/posts", fetcher);
201
- if (!data) return <p>Loading…</p>;
202
-
203
- return (
204
- <ul>
205
- {data.posts.map((post: any) => (
206
- <li key={post.id}>{post.title}</li>
207
- ))}
208
- </ul>
209
- );
210
- }
211
- ```
369
+ // app/api/blogauto/revalidate/route.ts
370
+ import { createEnvRevalidateHandler } from "@autoblogwriter/sdk/next";
212
371
 
213
- ## Automatic Revalidation Setup
372
+ export const POST = createEnvRevalidateHandler();
373
+ ```
214
374
 
215
- When AutoBlogWriter publishes a post it can ping your Next.js App Router site so sitemap, robots, and cached blog pages refresh immediately.
375
+ Set `BLOGAUTO_REVALIDATE_SECRET` in your environment and configure the webhook URL in the AutoBlogWriter dashboard under **Workspace Settings Revalidation URL**.
216
376
 
217
- 1. **Configure your workspace**
218
- - In the AutoBlogWriter dashboard open **Workspace Settings → Revalidation URL** and set your endpoint (e.g., `https://yoursite.com/api/blogauto/revalidate`).
219
- - Generate a **Revalidation Webhook secret**, copy the plain secret once, and store it as `BLOGAUTO_REVALIDATE_SECRET`.
220
- 2. **Create the route handler**
377
+ **Advanced setup** (manual control via `@autoblogwriter/sdk/revalidate`):
221
378
 
222
379
  ```ts
223
380
  // app/api/blogauto/revalidate/route.ts
224
381
  import { revalidatePath, revalidateTag } from "next/cache";
225
382
  import { createRevalidateRouteHandler } from "@autoblogwriter/sdk/revalidate";
226
383
 
227
- const secret = process.env.BLOGAUTO_REVALIDATE_SECRET;
228
- if (!secret) {
229
- throw new Error("Set BLOGAUTO_REVALIDATE_SECRET on the server");
230
- }
231
-
232
384
  export const POST = createRevalidateRouteHandler({
233
- secret,
385
+ secret: process.env.BLOGAUTO_REVALIDATE_SECRET!,
234
386
  revalidatePath,
235
387
  revalidateTag,
236
- // Optional overrides:
237
- // allowedSkewSeconds: 600,
238
- // revalidatePaths: (payload) => [...custom paths...],
239
- // revalidateTags: (payload) => [...custom tags...],
240
388
  });
241
389
  ```
242
390
 
@@ -245,50 +393,18 @@ The handler verifies the `X-BlogAuto-Signature` HMAC header, enforces timestamp
245
393
  - Paths: `/sitemap.xml`, `/robots.txt`, `/blog`, `/blog/:slug`
246
394
  - Tags: `blogauto:<workspaceSlug>:sitemap`, `blogauto:<workspaceSlug>:posts`, and `blogauto:<workspaceSlug>:post:<slug>`
247
395
 
248
- 3. **Tag your data fetches**
249
-
250
- Use the `next` option when calling SDK methods so `revalidateTag` knows which caches to expire:
251
-
252
- ```ts
253
- await blogClient.getPosts({
254
- limit: 20,
255
- next: { tags: [`blogauto:${workspaceSlug}:posts`] },
256
- });
257
-
258
- await blogClient.getPostBySlug(slug, {
259
- next: { tags: [`blogauto:${workspaceSlug}:post:${slug}`] },
260
- });
261
- ```
262
-
263
- ### Cache Invalidation Notes
264
-
265
- - In production, rely on tag-based revalidation via the webhook handler above. This prevents users from needing hard refreshes after publishing.
266
- - For very dynamic pages, you can opt out of caching per request with `cache: "no-store"` in the fetch options.
267
- - For client-side lists (SWR/React Query), call `mutate`/`invalidateQueries` after your proxy endpoint updates, or on a webhook-driven event from your backend.
268
-
269
- 4. **Need manual verification?**
396
+ For manual signature verification:
270
397
 
271
398
  ```ts
272
399
  import { verifyWebhookSignature } from "@autoblogwriter/sdk/revalidate";
273
400
 
274
401
  const isValid = verifyWebhookSignature({
275
- rawBody, // string or Buffer
402
+ rawBody,
276
403
  signature: req.headers.get("x-blogauto-signature"),
277
404
  secret: process.env.BLOGAUTO_REVALIDATE_SECRET!,
278
405
  });
279
406
  ```
280
407
 
281
- Reject missing/invalid signatures or stale timestamps to prevent replay attacks, and avoid logging the secret or signature hash.
282
-
283
- ## Markdown Rendering Helper
284
-
285
- `renderMarkdownToHtml(markdown: string)` ships a dependency-free renderer that covers headings, links, emphasis, inline/code fences, and paragraphs. For richer formatting you can bring your own renderer—this helper simply provides a safe default.
286
-
287
- ## Dynamic Sitemaps & Robots
288
-
289
- - `buildSitemap({ siteUrl, entries, routePrefix })` returns a `MetadataRoute.Sitemap` array ready for `app/sitemap.ts`.
290
- - `buildRobots({ siteUrl, sitemapPath })` outputs a `MetadataRoute.Robots` structure. Defaults: route prefix `/blog`, sitemap path `/sitemap.xml`.
291
-
292
408
  ## Testing
293
409
 
294
410
  ```bash
package/dist/next.cjs CHANGED
@@ -461,7 +461,7 @@ async function fetchBlogPost(slug) {
461
461
  if (!post) {
462
462
  const nav = await import(
463
463
  /* webpackIgnore: true */
464
- "next/navigation"
464
+ "next/navigation.js"
465
465
  );
466
466
  nav.notFound();
467
467
  throw new Error("notFound");
@@ -645,7 +645,7 @@ function createEnvRevalidateHandler() {
645
645
  }
646
646
  const nextCache = await import(
647
647
  /* webpackIgnore: true */
648
- "next/cache"
648
+ "next/cache.js"
649
649
  );
650
650
  const { revalidatePath, revalidateTag } = nextCache;
651
651
  const handler = createRevalidateRouteHandler({
package/dist/next.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/next/index.ts","../src/auth.ts","../src/errors.ts","../src/utils.ts","../src/client.ts","../src/env.ts","../src/metadata.ts","../src/sitemap.ts","../src/robots.ts","../src/next/helpers.ts","../src/revalidate.ts","../src/next/route-handlers.ts"],"sourcesContent":["export {\n fetchBlogPost,\n fetchBlogPosts,\n generatePostMetadata,\n generateBlogSitemap,\n generateBlogRobots,\n type FetchBlogPostsOptions,\n} from \"./helpers\";\n\nexport {\n createEnvRevalidateHandler,\n} from \"./route-handlers\";\n","import { AuthMode } from \"./types\";\n\nexport function buildAuthHeaders(apiKey: string, authMode: AuthMode = \"bearer\"): Record<string, string> {\n if (authMode === \"x-api-key\") {\n return { \"x-api-key\": apiKey };\n }\n return { Authorization: `Bearer ${apiKey}` };\n}\n","export class BlogAutoError extends Error {\n public readonly causeError?: unknown;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = new.target.name;\n this.causeError = options?.cause;\n }\n}\n\nexport class ConfigError extends BlogAutoError {}\n\nexport interface ApiErrorDetails {\n status: number;\n code?: string;\n details?: unknown;\n}\n\nexport class ApiError extends BlogAutoError {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: unknown;\n\n constructor(message: string, info: ApiErrorDetails, options?: { cause?: unknown }) {\n super(message, options);\n this.status = info.status;\n this.code = info.code;\n this.details = info.details;\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor(message: string, info?: Partial<ApiErrorDetails>) {\n super(message, { status: info?.status ?? 404, code: info?.code, details: info?.details });\n }\n}\n","import { ApiError, ConfigError } from \"./errors\";\nimport { AuthMode, BlogAutoClientConfig, InternalClientConfig } from \"./types\";\n\nexport const DEFAULT_TIMEOUT_MS = 10_000;\n\nexport function normalizeApiUrl(apiUrl: string): string {\n if (!apiUrl) {\n throw new ConfigError(\"apiUrl is required\");\n }\n\n return apiUrl.replace(/\\/$/, \"\");\n}\n\nexport function resolveClientConfig(config: BlogAutoClientConfig): InternalClientConfig {\n if (!config) {\n throw new ConfigError(\"Client configuration is required\");\n }\n\n const apiKey = config.apiKey?.trim();\n if (!apiKey) {\n throw new ConfigError(\"apiKey is required to authenticate with BlogAuto\");\n }\n\n if (!config.workspaceId && !config.workspaceSlug) {\n throw new ConfigError(\"Provide either workspaceId or workspaceSlug\");\n }\n\n const authMode: AuthMode = config.authMode ?? \"bearer\";\n\n return {\n apiKey,\n apiUrl: normalizeApiUrl(config.apiUrl),\n workspaceId: config.workspaceId,\n workspaceSlug: config.workspaceSlug,\n authMode,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n headers: { ...(config.headers ?? {}) },\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n };\n}\n\nexport function buildQuery(params: Record<string, string | number | undefined | null>): string {\n const query = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null || value === \"\") {\n return;\n }\n query.set(key, String(value));\n });\n const qs = query.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nexport async function withTimeout<T>(promise: Promise<T>, timeoutMs?: number): Promise<T> {\n if (!timeoutMs) {\n return promise;\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n new ApiError(`Request timed out after ${timeoutMs}ms`, {\n status: 408,\n }),\n );\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n clearTimeout(timeoutId!);\n }\n}\n\nexport function mergeHeaders(\n ...headerObjects: Array<Record<string, string> | undefined>\n): Record<string, string> {\n return headerObjects.reduce<Record<string, string>>((acc, headers) => {\n if (!headers) {\n return acc;\n }\n Object.entries(headers).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n acc[key.toLowerCase()] = value;\n });\n return acc;\n }, {});\n}\n","import { buildAuthHeaders } from \"./auth\";\nimport { ApiError, BlogAutoError, ConfigError } from \"./errors\";\nimport { buildQuery, mergeHeaders, resolveClientConfig, withTimeout } from \"./utils\";\nimport type {\n BlogAutoClientConfig,\n BlogPost,\n FetchRequestOptions,\n PaginatedList,\n PostsResponse,\n} from \"./types\";\n\ninterface RequestOptions {\n path: string;\n method?: string;\n query?: Record<string, string | number | undefined | null>;\n body?: unknown;\n allowNotFound?: boolean;\n headers?: Record<string, string>;\n cache?: RequestCache;\n next?: FetchRequestOptions[\"next\"];\n}\n\nexport interface BlogAutoClient {\n getPosts(params?: { limit?: number; cursor?: string } & FetchRequestOptions): Promise<PostsResponse>;\n getPostBySlug(slug: string, options?: FetchRequestOptions): Promise<BlogPost | null>;\n getSitemapEntries(): Promise<Array<{ slug: string; updatedAt: string }>>;\n}\n\nexport function createBlogAutoClient(config: BlogAutoClientConfig): BlogAutoClient {\n const resolved = resolveClientConfig(config);\n const fetchImpl = resolved.fetch;\n const debug =\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.BLOGAUTO_DEBUG === \"true\";\n const debugLog = (...args: unknown[]) => {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(\"[blogauto]\", ...args);\n }\n };\n\n function ensureWorkspaceSlug(): string {\n if (!resolved.workspaceSlug) {\n throw new ConfigError(\"workspaceSlug is required to call the BlogAuto public API\");\n }\n return resolved.workspaceSlug;\n }\n\n function buildUrl(path: string, query?: Record<string, string | number | undefined | null>): string {\n const qs = buildQuery(query ?? {});\n return `${resolved.apiUrl}${path}${qs}`;\n }\n\n function unwrapSuccessPayload<T>(payload: unknown): T {\n if (payload && typeof payload === \"object\") {\n const maybePayload = payload as { success?: boolean; data?: T; error?: { message?: string } };\n if (\"success\" in maybePayload) {\n if (maybePayload.success === false) {\n throw new ApiError(\n maybePayload.error?.message ?? \"BlogAuto request failed\",\n { status: 500, details: maybePayload },\n );\n }\n if (maybePayload.success && \"data\" in maybePayload) {\n return maybePayload.data as T;\n }\n }\n }\n return payload as T;\n }\n\n async function request<T>(opts: RequestOptions): Promise<T> {\n const method = opts.method ?? \"GET\";\n const url = buildUrl(opts.path, opts.query);\n\n const authHeaders = buildAuthHeaders(resolved.apiKey, resolved.authMode);\n const baseHeaders = mergeHeaders(resolved.headers, authHeaders, opts.headers);\n\n const init: RequestInit = {\n method,\n headers: baseHeaders,\n };\n\n if (opts.body) {\n init.body = typeof opts.body === \"string\" ? opts.body : JSON.stringify(opts.body);\n init.headers = {\n ...baseHeaders,\n \"content-type\": baseHeaders[\"content-type\"] ?? \"application/json\",\n };\n }\n\n if (opts.cache !== undefined) {\n init.cache = opts.cache;\n }\n\n if (opts.next) {\n (init as RequestInit & { next?: FetchRequestOptions[\"next\"] }).next = opts.next;\n }\n\n const startedAt = Date.now();\n try {\n const response = await withTimeout(fetchImpl(url, init), resolved.timeoutMs);\n debugLog(\"response\", {\n method,\n url,\n status: response.status,\n durationMs: Date.now() - startedAt,\n });\n if (opts.allowNotFound && response.status === 404) {\n return null as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const isJson = contentType.includes(\"application/json\");\n const payload = isJson ? await response.json().catch(() => undefined) : await response.text();\n\n if (!response.ok) {\n if (response.status === 404 && opts.allowNotFound) {\n return null as T;\n }\n\n const errorBody = payload as any;\n const message =\n errorBody?.error?.message ?? errorBody?.message ?? `Request failed with status ${response.status}`;\n throw new ApiError(message, {\n status: response.status,\n code: errorBody?.error?.code ?? errorBody?.code,\n details: errorBody?.error?.details ?? errorBody,\n });\n }\n\n if (isJson) {\n return unwrapSuccessPayload<T>(payload);\n }\n\n return (payload as T) ?? (undefined as T);\n } catch (error) {\n debugLog(\"request failed\", {\n method,\n url,\n durationMs: Date.now() - startedAt,\n error: error instanceof Error ? error.message : error,\n });\n if (error instanceof BlogAutoError) {\n throw error;\n }\n const causeMessage =\n error instanceof Error ? error.message : typeof error === \"string\" ? error : undefined;\n const message = causeMessage\n ? `Network request to BlogAuto failed: ${causeMessage}`\n : \"Network request to BlogAuto failed\";\n throw new ApiError(\n message,\n {\n status: 0,\n details: { url, method },\n },\n { cause: error },\n );\n }\n }\n\n async function fetchBlogPage(\n limit: number,\n page: number,\n cacheOptions?: FetchRequestOptions,\n ): Promise<PaginatedList<BlogPost>> {\n const workspaceSlug = ensureWorkspaceSlug();\n debugLog(\"fetch posts page\", { workspaceSlug, limit, page });\n return request<PaginatedList<BlogPost>>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs`,\n query: { limit, page },\n cache: cacheOptions?.cache,\n next: cacheOptions?.next,\n });\n }\n\n return {\n async getPosts(params) {\n const limit = params?.limit ?? 20;\n const cursorPage = params?.cursor ? Number(params.cursor) : undefined;\n const page = Number.isFinite(cursorPage) && cursorPage! >= 1 ? cursorPage! : 1;\n const data = await fetchBlogPage(limit, page, params);\n return {\n posts: data.items,\n nextCursor: data.pagination.hasMore ? String(data.pagination.page + 1) : undefined,\n };\n },\n async getPostBySlug(slug: string, options?: FetchRequestOptions) {\n if (!slug) {\n throw new ApiError(\"slug is required\", { status: 400 });\n }\n const workspaceSlug = ensureWorkspaceSlug();\n const post = await request<{ post: BlogPost } | null>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs/${encodeURIComponent(slug)}`,\n allowNotFound: true,\n cache: options?.cache,\n next: options?.next,\n });\n if (post === null) {\n return null;\n }\n return post.post;\n },\n async getSitemapEntries() {\n const entries: Array<{ slug: string; updatedAt: string }> = [];\n const limit = 100;\n let page = 1;\n\n while (true) {\n const pageData = await fetchBlogPage(limit, page);\n pageData.items.forEach((post) => {\n entries.push({ slug: post.slug, updatedAt: post.updatedAt });\n });\n\n if (!pageData.pagination.hasMore) {\n break;\n }\n\n page = pageData.pagination.page + 1;\n }\n\n return entries;\n },\n };\n}\n","import { createBlogAutoClient, type BlogAutoClient } from \"./client\";\n\nexport interface BlogAutoEnvConfig {\n client: BlogAutoClient;\n workspaceSlug: string;\n workspaceId?: string;\n siteUrl: string;\n revalidateSecret?: string;\n apiUrl: string;\n apiKey: string;\n tags: {\n posts: string;\n post: (slug: string) => string;\n sitemap: string;\n };\n}\n\nlet _instance: BlogAutoEnvConfig | null = null;\n\nfunction requireEnv(name: string): string {\n const value = process.env[name];\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nexport function createBlogAutoFromEnv(): BlogAutoEnvConfig {\n if (_instance) {\n return _instance;\n }\n\n const apiUrl = process.env.BLOGAUTO_API_URL ?? \"https://api.autoblogwriter.app\";\n const apiKey = requireEnv(\"BLOGAUTO_API_KEY\");\n const workspaceSlug = requireEnv(\"BLOGAUTO_WORKSPACE_SLUG\");\n const workspaceId = process.env.BLOGAUTO_WORKSPACE_ID;\n const siteUrl =\n process.env.SITE_URL ?? process.env.NEXT_PUBLIC_SITE_URL ?? \"http://localhost:3000\";\n const revalidateSecret = process.env.BLOGAUTO_REVALIDATE_SECRET;\n\n const client = createBlogAutoClient({\n apiUrl,\n apiKey,\n workspaceSlug,\n workspaceId,\n });\n\n _instance = {\n client,\n workspaceSlug,\n workspaceId,\n siteUrl,\n revalidateSecret,\n apiUrl,\n apiKey,\n tags: {\n posts: `blogauto:${workspaceSlug}:posts`,\n post: (slug: string) => `blogauto:${workspaceSlug}:post:${slug}`,\n sitemap: `blogauto:${workspaceSlug}:sitemap`,\n },\n };\n\n return _instance;\n}\n","import type { BlogPost } from \"./types\";\n\nexport interface NextMetadata {\n title?: string;\n description?: string;\n keywords?: string[];\n alternates?: {\n canonical?: string;\n };\n openGraph?: {\n type?: string;\n title?: string;\n description?: string;\n images?: Array<{ url: string }>;\n publishedTime?: string;\n modifiedTime?: string;\n };\n twitter?: {\n card?: string;\n title?: string;\n description?: string;\n images?: string[];\n };\n}\n\nexport function buildNextMetadata(post: BlogPost): NextMetadata {\n const title = post.seo?.title ?? post.title;\n const description = post.seo?.description ?? post.excerpt;\n const keywords = post.seo?.keywords;\n const canonical = post.metadata?.canonicalUrl;\n const ogImageUrl = post.metadata?.ogImageUrl;\n\n const metadata: NextMetadata = {\n title,\n description,\n };\n\n if (keywords && keywords.length > 0) {\n metadata.keywords = keywords;\n }\n\n if (canonical) {\n metadata.alternates = { canonical };\n }\n\n metadata.openGraph = {\n type: \"article\",\n title,\n description,\n publishedTime: post.publishedAt,\n modifiedTime: post.updatedAt,\n };\n\n if (ogImageUrl) {\n metadata.openGraph.images = [{ url: ogImageUrl }];\n }\n\n metadata.twitter = {\n card: ogImageUrl ? \"summary_large_image\" : \"summary\",\n title,\n description,\n };\n\n if (ogImageUrl) {\n metadata.twitter.images = [ogImageUrl];\n }\n\n return metadata;\n}\n","import { BuildSitemapOptions, MetadataRouteSitemap, MetadataRouteSitemapEntry } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeRoutePrefix(routePrefix?: string): string {\n if (!routePrefix || routePrefix === \"/\") {\n return \"\";\n }\n const withSlash = routePrefix.startsWith(\"/\") ? routePrefix : `/${routePrefix}`;\n return withSlash.endsWith(\"/\") ? withSlash.slice(0, -1) : withSlash;\n}\n\nfunction normalizeSlug(slug: string): string {\n return slug.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function buildSitemap(opts: BuildSitemapOptions): MetadataRouteSitemap {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const prefix = normalizeRoutePrefix(opts.routePrefix ?? \"/blog\");\n\n const entries: MetadataRouteSitemapEntry[] = opts.entries.map((entry) => {\n const slug = normalizeSlug(entry.slug);\n const hasSlug = slug.length > 0;\n const slugFragment = hasSlug ? `/${slug}` : \"\";\n const path = prefix ? `${prefix}${slugFragment}` : hasSlug ? `/${slug}` : \"/\";\n return {\n url: `${siteUrl}${path}`,\n lastModified: entry.updatedAt,\n };\n });\n\n return entries;\n}\n","import { BuildRobotsOptions, MetadataRouteRobots } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizePath(path: string): string {\n if (!path) {\n return \"/sitemap.xml\";\n }\n if (!path.startsWith(\"/\")) {\n return `/${path}`;\n }\n return path;\n}\n\nexport function buildRobots(opts: BuildRobotsOptions): MetadataRouteRobots {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const sitemapPath = normalizePath(opts.sitemapPath ?? \"/sitemap.xml\");\n const sitemapUrl = `${siteUrl}${sitemapPath}`;\n\n return {\n rules: [{ userAgent: \"*\", allow: \"/\" }],\n sitemap: sitemapUrl,\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { buildNextMetadata, type NextMetadata } from \"../metadata\";\nimport { buildSitemap } from \"../sitemap\";\nimport { buildRobots } from \"../robots\";\nimport type { BlogPost, PostsResponse, MetadataRouteSitemap, MetadataRouteRobots } from \"../types\";\n\nexport interface FetchBlogPostsOptions {\n limit?: number;\n cursor?: string;\n}\n\nexport async function fetchBlogPosts(options?: FetchBlogPostsOptions): Promise<PostsResponse> {\n const { client, tags } = createBlogAutoFromEnv();\n return client.getPosts({\n limit: options?.limit,\n cursor: options?.cursor,\n next: { tags: [tags.posts] },\n });\n}\n\nexport async function fetchBlogPost(slug: string): Promise<BlogPost> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n // Dynamic import to avoid pulling next/navigation into non-Next environments\n const nav = await import(/* webpackIgnore: true */ \"next/navigation\" as string) as {\n notFound: () => never;\n };\n nav.notFound();\n // notFound() throws, but TS can't infer `never` through dynamic import\n throw new Error(\"notFound\");\n }\n\n return post;\n}\n\nexport async function generatePostMetadata(slug: string): Promise<NextMetadata> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n return {};\n }\n\n return buildNextMetadata(post);\n}\n\nexport async function generateBlogSitemap(): Promise<MetadataRouteSitemap> {\n const { client, siteUrl } = createBlogAutoFromEnv();\n const entries = await client.getSitemapEntries();\n return buildSitemap({ siteUrl, routePrefix: \"/blog\", entries });\n}\n\nexport function generateBlogRobots(): MetadataRouteRobots {\n const { siteUrl } = createBlogAutoFromEnv();\n return buildRobots({ siteUrl, sitemapPath: \"/sitemap.xml\" });\n}\n","import crypto from \"crypto\";\nimport type { BlogAutoRevalidatePayload, RevalidatePathFn, RevalidateTagFn } from \"./types\";\n\nexport interface VerifyWebhookSignatureOptions {\n rawBody: string | Buffer;\n signature: string | null;\n secret: string;\n}\n\nexport interface CreateRevalidateRouteHandlerOptions {\n secret: string;\n allowedSkewSeconds?: number;\n revalidatePath?: RevalidatePathFn;\n revalidateTag?: RevalidateTagFn;\n revalidatePaths?: (payload: BlogAutoRevalidatePayload) => string[];\n revalidateTags?: (payload: BlogAutoRevalidatePayload) => string[];\n}\n\ninterface JsonResponseInit extends ResponseInit {\n status?: number;\n}\n\nfunction jsonResponse(body: unknown, init?: JsonResponseInit): Response {\n const headers = new Headers(init?.headers);\n headers.set(\"content-type\", \"application/json\");\n return new Response(JSON.stringify(body), {\n ...init,\n headers,\n });\n}\n\nfunction normalizeSignature(signature: string | null): Buffer | null {\n if (!signature) {\n return null;\n }\n const trimmed = signature.trim();\n if (!trimmed) {\n return null;\n }\n\n const withoutPrefix = trimmed.startsWith(\"sha256=\") ? trimmed.slice(7) : trimmed;\n if (!withoutPrefix) {\n return null;\n }\n\n try {\n return Buffer.from(withoutPrefix, \"hex\");\n } catch {\n return null;\n }\n}\n\nexport function verifyWebhookSignature(opts: VerifyWebhookSignatureOptions): boolean {\n const { rawBody, signature, secret } = opts;\n if (!secret) {\n throw new Error(\"Secret is required to verify webhook signatures\");\n }\n const providedSignature = normalizeSignature(signature);\n if (!providedSignature) {\n return false;\n }\n\n const bodyBuffer = typeof rawBody === \"string\" ? Buffer.from(rawBody) : rawBody;\n const expected = crypto.createHmac(\"sha256\", secret).update(bodyBuffer).digest();\n\n if (providedSignature.length !== expected.length) {\n return false;\n }\n\n return crypto.timingSafeEqual(providedSignature, expected);\n}\n\nfunction defaultPaths(payload: BlogAutoRevalidatePayload): string[] {\n const paths = new Set<string>([\"/sitemap.xml\", \"/robots.txt\", \"/blog\"]);\n if (payload.postSlug) {\n paths.add(`/blog/${payload.postSlug}`);\n }\n return Array.from(paths);\n}\n\nfunction defaultTags(payload: BlogAutoRevalidatePayload): string[] {\n const tags = new Set<string>();\n if (payload.workspaceSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:sitemap`);\n tags.add(`blogauto:${payload.workspaceSlug}:posts`);\n if (payload.postSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:post:${payload.postSlug}`);\n }\n }\n return Array.from(tags);\n}\n\nfunction dedupe(values: string[] | undefined): string[] {\n if (!values || values.length === 0) {\n return [];\n }\n return Array.from(\n new Set(\n values\n .filter((value) => typeof value === \"string\" && value.trim().length > 0)\n .map((value) => value.trim()),\n ),\n );\n}\n\nfunction determineRouteType(path: string): \"route\" | \"page\" {\n const lower = path.toLowerCase();\n if (lower.endsWith(\".xml\") || lower.endsWith(\".txt\")) {\n return \"route\";\n }\n return \"page\";\n}\n\nexport function createRevalidateRouteHandler(\n options: CreateRevalidateRouteHandlerOptions,\n): (request: Request) => Promise<Response> {\n if (!options.secret) {\n throw new Error(\"secret is required for createRevalidateRouteHandler\");\n }\n\n const allowedSkewMs = Math.max(1, options.allowedSkewSeconds ?? 300) * 1000;\n const pathBuilder = options.revalidatePaths ?? defaultPaths;\n const tagBuilder = options.revalidateTags ?? defaultTags;\n\n return async function blogAutoRevalidateHandler(request: Request): Promise<Response> {\n const signature = request.headers.get(\"x-blogauto-signature\");\n const receivedAt = Date.now();\n\n const rawBody = await request.text();\n const isValid = verifyWebhookSignature({\n rawBody,\n signature,\n secret: options.secret,\n });\n\n if (!isValid) {\n return jsonResponse({ error: \"Invalid webhook signature\" }, { status: 401 });\n }\n\n let payload: BlogAutoRevalidatePayload;\n try {\n payload = JSON.parse(rawBody) as BlogAutoRevalidatePayload;\n } catch {\n return jsonResponse({ error: \"Invalid JSON payload\" }, { status: 400 });\n }\n\n if (!payload.workspaceSlug || typeof payload.workspaceSlug !== \"string\") {\n return jsonResponse({ error: \"workspaceSlug is required\" }, { status: 400 });\n }\n\n if (!payload.ts || typeof payload.ts !== \"string\") {\n return jsonResponse({ error: \"Timestamp is required\" }, { status: 400 });\n }\n\n const payloadTs = Date.parse(payload.ts);\n if (Number.isNaN(payloadTs)) {\n return jsonResponse({ error: \"Invalid timestamp\" }, { status: 400 });\n }\n\n if (Math.abs(receivedAt - payloadTs) > allowedSkewMs) {\n return jsonResponse({ error: \"Webhook timestamp is outside allowed skew\" }, { status: 409 });\n }\n\n const paths = dedupe(pathBuilder(payload));\n const tags = dedupe(tagBuilder(payload));\n\n try {\n if (options.revalidatePath && paths.length > 0) {\n await Promise.all(\n paths.map((path) => options.revalidatePath!(path, determineRouteType(path))),\n );\n }\n\n if (options.revalidateTag && tags.length > 0) {\n await Promise.all(tags.map((tag) => options.revalidateTag!(tag)));\n }\n } catch (error) {\n return jsonResponse(\n { error: \"Failed to revalidate cache\", details: (error as Error).message },\n { status: 500 },\n );\n }\n\n return jsonResponse({\n ok: true,\n event: payload.event ?? \"post.published\",\n revalidated: {\n paths,\n tags,\n },\n });\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { createRevalidateRouteHandler } from \"../revalidate\";\n\nexport function createEnvRevalidateHandler(): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n // Lazy init so env vars are read at request time, not module load time\n const { revalidateSecret } = createBlogAutoFromEnv();\n\n if (!revalidateSecret) {\n return new Response(\n JSON.stringify({ error: \"Missing BLOGAUTO_REVALIDATE_SECRET\" }),\n { status: 500, headers: { \"content-type\": \"application/json\" } },\n );\n }\n\n // Dynamic import to avoid pulling next/cache into non-Next environments\n const nextCache = await import(/* webpackIgnore: true */ \"next/cache\" as string) as {\n revalidatePath: (path: string, type?: \"page\" | \"layout\" | \"route\") => void;\n revalidateTag: (tag: string) => void;\n };\n const { revalidatePath, revalidateTag } = nextCache;\n\n const handler = createRevalidateRouteHandler({\n secret: revalidateSecret,\n revalidatePath,\n revalidateTag,\n });\n\n return handler(request);\n };\n}\n"],"mappings":"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","names":["normalizeSiteUrl","crypto"]}
1
+ {"version":3,"sources":["../src/next/index.ts","../src/auth.ts","../src/errors.ts","../src/utils.ts","../src/client.ts","../src/env.ts","../src/metadata.ts","../src/sitemap.ts","../src/robots.ts","../src/next/helpers.ts","../src/revalidate.ts","../src/next/route-handlers.ts"],"sourcesContent":["export {\n fetchBlogPost,\n fetchBlogPosts,\n generatePostMetadata,\n generateBlogSitemap,\n generateBlogRobots,\n type FetchBlogPostsOptions,\n} from \"./helpers\";\n\nexport {\n createEnvRevalidateHandler,\n} from \"./route-handlers\";\n","import { AuthMode } from \"./types\";\n\nexport function buildAuthHeaders(apiKey: string, authMode: AuthMode = \"bearer\"): Record<string, string> {\n if (authMode === \"x-api-key\") {\n return { \"x-api-key\": apiKey };\n }\n return { Authorization: `Bearer ${apiKey}` };\n}\n","export class BlogAutoError extends Error {\n public readonly causeError?: unknown;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = new.target.name;\n this.causeError = options?.cause;\n }\n}\n\nexport class ConfigError extends BlogAutoError {}\n\nexport interface ApiErrorDetails {\n status: number;\n code?: string;\n details?: unknown;\n}\n\nexport class ApiError extends BlogAutoError {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: unknown;\n\n constructor(message: string, info: ApiErrorDetails, options?: { cause?: unknown }) {\n super(message, options);\n this.status = info.status;\n this.code = info.code;\n this.details = info.details;\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor(message: string, info?: Partial<ApiErrorDetails>) {\n super(message, { status: info?.status ?? 404, code: info?.code, details: info?.details });\n }\n}\n","import { ApiError, ConfigError } from \"./errors\";\nimport { AuthMode, BlogAutoClientConfig, InternalClientConfig } from \"./types\";\n\nexport const DEFAULT_TIMEOUT_MS = 10_000;\n\nexport function normalizeApiUrl(apiUrl: string): string {\n if (!apiUrl) {\n throw new ConfigError(\"apiUrl is required\");\n }\n\n return apiUrl.replace(/\\/$/, \"\");\n}\n\nexport function resolveClientConfig(config: BlogAutoClientConfig): InternalClientConfig {\n if (!config) {\n throw new ConfigError(\"Client configuration is required\");\n }\n\n const apiKey = config.apiKey?.trim();\n if (!apiKey) {\n throw new ConfigError(\"apiKey is required to authenticate with BlogAuto\");\n }\n\n if (!config.workspaceId && !config.workspaceSlug) {\n throw new ConfigError(\"Provide either workspaceId or workspaceSlug\");\n }\n\n const authMode: AuthMode = config.authMode ?? \"bearer\";\n\n return {\n apiKey,\n apiUrl: normalizeApiUrl(config.apiUrl),\n workspaceId: config.workspaceId,\n workspaceSlug: config.workspaceSlug,\n authMode,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n headers: { ...(config.headers ?? {}) },\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n };\n}\n\nexport function buildQuery(params: Record<string, string | number | undefined | null>): string {\n const query = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null || value === \"\") {\n return;\n }\n query.set(key, String(value));\n });\n const qs = query.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nexport async function withTimeout<T>(promise: Promise<T>, timeoutMs?: number): Promise<T> {\n if (!timeoutMs) {\n return promise;\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n new ApiError(`Request timed out after ${timeoutMs}ms`, {\n status: 408,\n }),\n );\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n clearTimeout(timeoutId!);\n }\n}\n\nexport function mergeHeaders(\n ...headerObjects: Array<Record<string, string> | undefined>\n): Record<string, string> {\n return headerObjects.reduce<Record<string, string>>((acc, headers) => {\n if (!headers) {\n return acc;\n }\n Object.entries(headers).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n acc[key.toLowerCase()] = value;\n });\n return acc;\n }, {});\n}\n","import { buildAuthHeaders } from \"./auth\";\nimport { ApiError, BlogAutoError, ConfigError } from \"./errors\";\nimport { buildQuery, mergeHeaders, resolveClientConfig, withTimeout } from \"./utils\";\nimport type {\n BlogAutoClientConfig,\n BlogPost,\n FetchRequestOptions,\n PaginatedList,\n PostsResponse,\n} from \"./types\";\n\ninterface RequestOptions {\n path: string;\n method?: string;\n query?: Record<string, string | number | undefined | null>;\n body?: unknown;\n allowNotFound?: boolean;\n headers?: Record<string, string>;\n cache?: RequestCache;\n next?: FetchRequestOptions[\"next\"];\n}\n\nexport interface BlogAutoClient {\n getPosts(params?: { limit?: number; cursor?: string } & FetchRequestOptions): Promise<PostsResponse>;\n getPostBySlug(slug: string, options?: FetchRequestOptions): Promise<BlogPost | null>;\n getSitemapEntries(): Promise<Array<{ slug: string; updatedAt: string }>>;\n}\n\nexport function createBlogAutoClient(config: BlogAutoClientConfig): BlogAutoClient {\n const resolved = resolveClientConfig(config);\n const fetchImpl = resolved.fetch;\n const debug =\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.BLOGAUTO_DEBUG === \"true\";\n const debugLog = (...args: unknown[]) => {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(\"[blogauto]\", ...args);\n }\n };\n\n function ensureWorkspaceSlug(): string {\n if (!resolved.workspaceSlug) {\n throw new ConfigError(\"workspaceSlug is required to call the BlogAuto public API\");\n }\n return resolved.workspaceSlug;\n }\n\n function buildUrl(path: string, query?: Record<string, string | number | undefined | null>): string {\n const qs = buildQuery(query ?? {});\n return `${resolved.apiUrl}${path}${qs}`;\n }\n\n function unwrapSuccessPayload<T>(payload: unknown): T {\n if (payload && typeof payload === \"object\") {\n const maybePayload = payload as { success?: boolean; data?: T; error?: { message?: string } };\n if (\"success\" in maybePayload) {\n if (maybePayload.success === false) {\n throw new ApiError(\n maybePayload.error?.message ?? \"BlogAuto request failed\",\n { status: 500, details: maybePayload },\n );\n }\n if (maybePayload.success && \"data\" in maybePayload) {\n return maybePayload.data as T;\n }\n }\n }\n return payload as T;\n }\n\n async function request<T>(opts: RequestOptions): Promise<T> {\n const method = opts.method ?? \"GET\";\n const url = buildUrl(opts.path, opts.query);\n\n const authHeaders = buildAuthHeaders(resolved.apiKey, resolved.authMode);\n const baseHeaders = mergeHeaders(resolved.headers, authHeaders, opts.headers);\n\n const init: RequestInit = {\n method,\n headers: baseHeaders,\n };\n\n if (opts.body) {\n init.body = typeof opts.body === \"string\" ? opts.body : JSON.stringify(opts.body);\n init.headers = {\n ...baseHeaders,\n \"content-type\": baseHeaders[\"content-type\"] ?? \"application/json\",\n };\n }\n\n if (opts.cache !== undefined) {\n init.cache = opts.cache;\n }\n\n if (opts.next) {\n (init as RequestInit & { next?: FetchRequestOptions[\"next\"] }).next = opts.next;\n }\n\n const startedAt = Date.now();\n try {\n const response = await withTimeout(fetchImpl(url, init), resolved.timeoutMs);\n debugLog(\"response\", {\n method,\n url,\n status: response.status,\n durationMs: Date.now() - startedAt,\n });\n if (opts.allowNotFound && response.status === 404) {\n return null as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const isJson = contentType.includes(\"application/json\");\n const payload = isJson ? await response.json().catch(() => undefined) : await response.text();\n\n if (!response.ok) {\n if (response.status === 404 && opts.allowNotFound) {\n return null as T;\n }\n\n const errorBody = payload as any;\n const message =\n errorBody?.error?.message ?? errorBody?.message ?? `Request failed with status ${response.status}`;\n throw new ApiError(message, {\n status: response.status,\n code: errorBody?.error?.code ?? errorBody?.code,\n details: errorBody?.error?.details ?? errorBody,\n });\n }\n\n if (isJson) {\n return unwrapSuccessPayload<T>(payload);\n }\n\n return (payload as T) ?? (undefined as T);\n } catch (error) {\n debugLog(\"request failed\", {\n method,\n url,\n durationMs: Date.now() - startedAt,\n error: error instanceof Error ? error.message : error,\n });\n if (error instanceof BlogAutoError) {\n throw error;\n }\n const causeMessage =\n error instanceof Error ? error.message : typeof error === \"string\" ? error : undefined;\n const message = causeMessage\n ? `Network request to BlogAuto failed: ${causeMessage}`\n : \"Network request to BlogAuto failed\";\n throw new ApiError(\n message,\n {\n status: 0,\n details: { url, method },\n },\n { cause: error },\n );\n }\n }\n\n async function fetchBlogPage(\n limit: number,\n page: number,\n cacheOptions?: FetchRequestOptions,\n ): Promise<PaginatedList<BlogPost>> {\n const workspaceSlug = ensureWorkspaceSlug();\n debugLog(\"fetch posts page\", { workspaceSlug, limit, page });\n return request<PaginatedList<BlogPost>>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs`,\n query: { limit, page },\n cache: cacheOptions?.cache,\n next: cacheOptions?.next,\n });\n }\n\n return {\n async getPosts(params) {\n const limit = params?.limit ?? 20;\n const cursorPage = params?.cursor ? Number(params.cursor) : undefined;\n const page = Number.isFinite(cursorPage) && cursorPage! >= 1 ? cursorPage! : 1;\n const data = await fetchBlogPage(limit, page, params);\n return {\n posts: data.items,\n nextCursor: data.pagination.hasMore ? String(data.pagination.page + 1) : undefined,\n };\n },\n async getPostBySlug(slug: string, options?: FetchRequestOptions) {\n if (!slug) {\n throw new ApiError(\"slug is required\", { status: 400 });\n }\n const workspaceSlug = ensureWorkspaceSlug();\n const post = await request<{ post: BlogPost } | null>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs/${encodeURIComponent(slug)}`,\n allowNotFound: true,\n cache: options?.cache,\n next: options?.next,\n });\n if (post === null) {\n return null;\n }\n return post.post;\n },\n async getSitemapEntries() {\n const entries: Array<{ slug: string; updatedAt: string }> = [];\n const limit = 100;\n let page = 1;\n\n while (true) {\n const pageData = await fetchBlogPage(limit, page);\n pageData.items.forEach((post) => {\n entries.push({ slug: post.slug, updatedAt: post.updatedAt });\n });\n\n if (!pageData.pagination.hasMore) {\n break;\n }\n\n page = pageData.pagination.page + 1;\n }\n\n return entries;\n },\n };\n}\n","import { createBlogAutoClient, type BlogAutoClient } from \"./client\";\n\nexport interface BlogAutoEnvConfig {\n client: BlogAutoClient;\n workspaceSlug: string;\n workspaceId?: string;\n siteUrl: string;\n revalidateSecret?: string;\n apiUrl: string;\n apiKey: string;\n tags: {\n posts: string;\n post: (slug: string) => string;\n sitemap: string;\n };\n}\n\nlet _instance: BlogAutoEnvConfig | null = null;\n\nfunction requireEnv(name: string): string {\n const value = process.env[name];\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nexport function createBlogAutoFromEnv(): BlogAutoEnvConfig {\n if (_instance) {\n return _instance;\n }\n\n const apiUrl = process.env.BLOGAUTO_API_URL ?? \"https://api.autoblogwriter.app\";\n const apiKey = requireEnv(\"BLOGAUTO_API_KEY\");\n const workspaceSlug = requireEnv(\"BLOGAUTO_WORKSPACE_SLUG\");\n const workspaceId = process.env.BLOGAUTO_WORKSPACE_ID;\n const siteUrl =\n process.env.SITE_URL ?? process.env.NEXT_PUBLIC_SITE_URL ?? \"http://localhost:3000\";\n const revalidateSecret = process.env.BLOGAUTO_REVALIDATE_SECRET;\n\n const client = createBlogAutoClient({\n apiUrl,\n apiKey,\n workspaceSlug,\n workspaceId,\n });\n\n _instance = {\n client,\n workspaceSlug,\n workspaceId,\n siteUrl,\n revalidateSecret,\n apiUrl,\n apiKey,\n tags: {\n posts: `blogauto:${workspaceSlug}:posts`,\n post: (slug: string) => `blogauto:${workspaceSlug}:post:${slug}`,\n sitemap: `blogauto:${workspaceSlug}:sitemap`,\n },\n };\n\n return _instance;\n}\n","import type { BlogPost } from \"./types\";\n\nexport interface NextMetadata {\n title?: string;\n description?: string;\n keywords?: string[];\n alternates?: {\n canonical?: string;\n };\n openGraph?: {\n type?: string;\n title?: string;\n description?: string;\n images?: Array<{ url: string }>;\n publishedTime?: string;\n modifiedTime?: string;\n };\n twitter?: {\n card?: string;\n title?: string;\n description?: string;\n images?: string[];\n };\n}\n\nexport function buildNextMetadata(post: BlogPost): NextMetadata {\n const title = post.seo?.title ?? post.title;\n const description = post.seo?.description ?? post.excerpt;\n const keywords = post.seo?.keywords;\n const canonical = post.metadata?.canonicalUrl;\n const ogImageUrl = post.metadata?.ogImageUrl;\n\n const metadata: NextMetadata = {\n title,\n description,\n };\n\n if (keywords && keywords.length > 0) {\n metadata.keywords = keywords;\n }\n\n if (canonical) {\n metadata.alternates = { canonical };\n }\n\n metadata.openGraph = {\n type: \"article\",\n title,\n description,\n publishedTime: post.publishedAt,\n modifiedTime: post.updatedAt,\n };\n\n if (ogImageUrl) {\n metadata.openGraph.images = [{ url: ogImageUrl }];\n }\n\n metadata.twitter = {\n card: ogImageUrl ? \"summary_large_image\" : \"summary\",\n title,\n description,\n };\n\n if (ogImageUrl) {\n metadata.twitter.images = [ogImageUrl];\n }\n\n return metadata;\n}\n","import { BuildSitemapOptions, MetadataRouteSitemap, MetadataRouteSitemapEntry } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeRoutePrefix(routePrefix?: string): string {\n if (!routePrefix || routePrefix === \"/\") {\n return \"\";\n }\n const withSlash = routePrefix.startsWith(\"/\") ? routePrefix : `/${routePrefix}`;\n return withSlash.endsWith(\"/\") ? withSlash.slice(0, -1) : withSlash;\n}\n\nfunction normalizeSlug(slug: string): string {\n return slug.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function buildSitemap(opts: BuildSitemapOptions): MetadataRouteSitemap {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const prefix = normalizeRoutePrefix(opts.routePrefix ?? \"/blog\");\n\n const entries: MetadataRouteSitemapEntry[] = opts.entries.map((entry) => {\n const slug = normalizeSlug(entry.slug);\n const hasSlug = slug.length > 0;\n const slugFragment = hasSlug ? `/${slug}` : \"\";\n const path = prefix ? `${prefix}${slugFragment}` : hasSlug ? `/${slug}` : \"/\";\n return {\n url: `${siteUrl}${path}`,\n lastModified: entry.updatedAt,\n };\n });\n\n return entries;\n}\n","import { BuildRobotsOptions, MetadataRouteRobots } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizePath(path: string): string {\n if (!path) {\n return \"/sitemap.xml\";\n }\n if (!path.startsWith(\"/\")) {\n return `/${path}`;\n }\n return path;\n}\n\nexport function buildRobots(opts: BuildRobotsOptions): MetadataRouteRobots {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const sitemapPath = normalizePath(opts.sitemapPath ?? \"/sitemap.xml\");\n const sitemapUrl = `${siteUrl}${sitemapPath}`;\n\n return {\n rules: [{ userAgent: \"*\", allow: \"/\" }],\n sitemap: sitemapUrl,\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { buildNextMetadata, type NextMetadata } from \"../metadata\";\nimport { buildSitemap } from \"../sitemap\";\nimport { buildRobots } from \"../robots\";\nimport type { BlogPost, PostsResponse, MetadataRouteSitemap, MetadataRouteRobots } from \"../types\";\n\nexport interface FetchBlogPostsOptions {\n limit?: number;\n cursor?: string;\n}\n\nexport async function fetchBlogPosts(options?: FetchBlogPostsOptions): Promise<PostsResponse> {\n const { client, tags } = createBlogAutoFromEnv();\n return client.getPosts({\n limit: options?.limit,\n cursor: options?.cursor,\n next: { tags: [tags.posts] },\n });\n}\n\nexport async function fetchBlogPost(slug: string): Promise<BlogPost> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n // Dynamic import to avoid pulling next/navigation into non-Next environments\n const nav = await import(/* webpackIgnore: true */ \"next/navigation.js\" as string) as {\n notFound: () => never;\n };\n nav.notFound();\n // notFound() throws, but TS can't infer `never` through dynamic import\n throw new Error(\"notFound\");\n }\n\n return post;\n}\n\nexport async function generatePostMetadata(slug: string): Promise<NextMetadata> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n return {};\n }\n\n return buildNextMetadata(post);\n}\n\nexport async function generateBlogSitemap(): Promise<MetadataRouteSitemap> {\n const { client, siteUrl } = createBlogAutoFromEnv();\n const entries = await client.getSitemapEntries();\n return buildSitemap({ siteUrl, routePrefix: \"/blog\", entries });\n}\n\nexport function generateBlogRobots(): MetadataRouteRobots {\n const { siteUrl } = createBlogAutoFromEnv();\n return buildRobots({ siteUrl, sitemapPath: \"/sitemap.xml\" });\n}\n","import crypto from \"crypto\";\nimport type { BlogAutoRevalidatePayload, RevalidatePathFn, RevalidateTagFn } from \"./types\";\n\nexport interface VerifyWebhookSignatureOptions {\n rawBody: string | Buffer;\n signature: string | null;\n secret: string;\n}\n\nexport interface CreateRevalidateRouteHandlerOptions {\n secret: string;\n allowedSkewSeconds?: number;\n revalidatePath?: RevalidatePathFn;\n revalidateTag?: RevalidateTagFn;\n revalidatePaths?: (payload: BlogAutoRevalidatePayload) => string[];\n revalidateTags?: (payload: BlogAutoRevalidatePayload) => string[];\n}\n\ninterface JsonResponseInit extends ResponseInit {\n status?: number;\n}\n\nfunction jsonResponse(body: unknown, init?: JsonResponseInit): Response {\n const headers = new Headers(init?.headers);\n headers.set(\"content-type\", \"application/json\");\n return new Response(JSON.stringify(body), {\n ...init,\n headers,\n });\n}\n\nfunction normalizeSignature(signature: string | null): Buffer | null {\n if (!signature) {\n return null;\n }\n const trimmed = signature.trim();\n if (!trimmed) {\n return null;\n }\n\n const withoutPrefix = trimmed.startsWith(\"sha256=\") ? trimmed.slice(7) : trimmed;\n if (!withoutPrefix) {\n return null;\n }\n\n try {\n return Buffer.from(withoutPrefix, \"hex\");\n } catch {\n return null;\n }\n}\n\nexport function verifyWebhookSignature(opts: VerifyWebhookSignatureOptions): boolean {\n const { rawBody, signature, secret } = opts;\n if (!secret) {\n throw new Error(\"Secret is required to verify webhook signatures\");\n }\n const providedSignature = normalizeSignature(signature);\n if (!providedSignature) {\n return false;\n }\n\n const bodyBuffer = typeof rawBody === \"string\" ? Buffer.from(rawBody) : rawBody;\n const expected = crypto.createHmac(\"sha256\", secret).update(bodyBuffer).digest();\n\n if (providedSignature.length !== expected.length) {\n return false;\n }\n\n return crypto.timingSafeEqual(providedSignature, expected);\n}\n\nfunction defaultPaths(payload: BlogAutoRevalidatePayload): string[] {\n const paths = new Set<string>([\"/sitemap.xml\", \"/robots.txt\", \"/blog\"]);\n if (payload.postSlug) {\n paths.add(`/blog/${payload.postSlug}`);\n }\n return Array.from(paths);\n}\n\nfunction defaultTags(payload: BlogAutoRevalidatePayload): string[] {\n const tags = new Set<string>();\n if (payload.workspaceSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:sitemap`);\n tags.add(`blogauto:${payload.workspaceSlug}:posts`);\n if (payload.postSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:post:${payload.postSlug}`);\n }\n }\n return Array.from(tags);\n}\n\nfunction dedupe(values: string[] | undefined): string[] {\n if (!values || values.length === 0) {\n return [];\n }\n return Array.from(\n new Set(\n values\n .filter((value) => typeof value === \"string\" && value.trim().length > 0)\n .map((value) => value.trim()),\n ),\n );\n}\n\nfunction determineRouteType(path: string): \"route\" | \"page\" {\n const lower = path.toLowerCase();\n if (lower.endsWith(\".xml\") || lower.endsWith(\".txt\")) {\n return \"route\";\n }\n return \"page\";\n}\n\nexport function createRevalidateRouteHandler(\n options: CreateRevalidateRouteHandlerOptions,\n): (request: Request) => Promise<Response> {\n if (!options.secret) {\n throw new Error(\"secret is required for createRevalidateRouteHandler\");\n }\n\n const allowedSkewMs = Math.max(1, options.allowedSkewSeconds ?? 300) * 1000;\n const pathBuilder = options.revalidatePaths ?? defaultPaths;\n const tagBuilder = options.revalidateTags ?? defaultTags;\n\n return async function blogAutoRevalidateHandler(request: Request): Promise<Response> {\n const signature = request.headers.get(\"x-blogauto-signature\");\n const receivedAt = Date.now();\n\n const rawBody = await request.text();\n const isValid = verifyWebhookSignature({\n rawBody,\n signature,\n secret: options.secret,\n });\n\n if (!isValid) {\n return jsonResponse({ error: \"Invalid webhook signature\" }, { status: 401 });\n }\n\n let payload: BlogAutoRevalidatePayload;\n try {\n payload = JSON.parse(rawBody) as BlogAutoRevalidatePayload;\n } catch {\n return jsonResponse({ error: \"Invalid JSON payload\" }, { status: 400 });\n }\n\n if (!payload.workspaceSlug || typeof payload.workspaceSlug !== \"string\") {\n return jsonResponse({ error: \"workspaceSlug is required\" }, { status: 400 });\n }\n\n if (!payload.ts || typeof payload.ts !== \"string\") {\n return jsonResponse({ error: \"Timestamp is required\" }, { status: 400 });\n }\n\n const payloadTs = Date.parse(payload.ts);\n if (Number.isNaN(payloadTs)) {\n return jsonResponse({ error: \"Invalid timestamp\" }, { status: 400 });\n }\n\n if (Math.abs(receivedAt - payloadTs) > allowedSkewMs) {\n return jsonResponse({ error: \"Webhook timestamp is outside allowed skew\" }, { status: 409 });\n }\n\n const paths = dedupe(pathBuilder(payload));\n const tags = dedupe(tagBuilder(payload));\n\n try {\n if (options.revalidatePath && paths.length > 0) {\n await Promise.all(\n paths.map((path) => options.revalidatePath!(path, determineRouteType(path))),\n );\n }\n\n if (options.revalidateTag && tags.length > 0) {\n await Promise.all(tags.map((tag) => options.revalidateTag!(tag)));\n }\n } catch (error) {\n return jsonResponse(\n { error: \"Failed to revalidate cache\", details: (error as Error).message },\n { status: 500 },\n );\n }\n\n return jsonResponse({\n ok: true,\n event: payload.event ?? \"post.published\",\n revalidated: {\n paths,\n tags,\n },\n });\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { createRevalidateRouteHandler } from \"../revalidate\";\n\nexport function createEnvRevalidateHandler(): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n // Lazy init so env vars are read at request time, not module load time\n const { revalidateSecret } = createBlogAutoFromEnv();\n\n if (!revalidateSecret) {\n return new Response(\n JSON.stringify({ error: \"Missing BLOGAUTO_REVALIDATE_SECRET\" }),\n { status: 500, headers: { \"content-type\": \"application/json\" } },\n );\n }\n\n // Dynamic import to avoid pulling next/cache into non-Next environments\n const nextCache = await import(/* webpackIgnore: true */ \"next/cache.js\" as string) as {\n revalidatePath: (path: string, type?: \"page\" | \"layout\" | \"route\") => void;\n revalidateTag: (tag: string) => void;\n };\n const { revalidatePath, revalidateTag } = nextCache;\n\n const handler = createRevalidateRouteHandler({\n secret: revalidateSecret,\n revalidatePath,\n revalidateTag,\n });\n\n return handler(request);\n };\n}\n"],"mappings":"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","names":["normalizeSiteUrl","crypto"]}
package/dist/next.js CHANGED
@@ -420,7 +420,7 @@ async function fetchBlogPost(slug) {
420
420
  if (!post) {
421
421
  const nav = await import(
422
422
  /* webpackIgnore: true */
423
- "next/navigation"
423
+ "next/navigation.js"
424
424
  );
425
425
  nav.notFound();
426
426
  throw new Error("notFound");
@@ -604,7 +604,7 @@ function createEnvRevalidateHandler() {
604
604
  }
605
605
  const nextCache = await import(
606
606
  /* webpackIgnore: true */
607
- "next/cache"
607
+ "next/cache.js"
608
608
  );
609
609
  const { revalidatePath, revalidateTag } = nextCache;
610
610
  const handler = createRevalidateRouteHandler({
package/dist/next.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/auth.ts","../src/errors.ts","../src/utils.ts","../src/client.ts","../src/env.ts","../src/metadata.ts","../src/sitemap.ts","../src/robots.ts","../src/next/helpers.ts","../src/revalidate.ts","../src/next/route-handlers.ts"],"sourcesContent":["import { AuthMode } from \"./types\";\n\nexport function buildAuthHeaders(apiKey: string, authMode: AuthMode = \"bearer\"): Record<string, string> {\n if (authMode === \"x-api-key\") {\n return { \"x-api-key\": apiKey };\n }\n return { Authorization: `Bearer ${apiKey}` };\n}\n","export class BlogAutoError extends Error {\n public readonly causeError?: unknown;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = new.target.name;\n this.causeError = options?.cause;\n }\n}\n\nexport class ConfigError extends BlogAutoError {}\n\nexport interface ApiErrorDetails {\n status: number;\n code?: string;\n details?: unknown;\n}\n\nexport class ApiError extends BlogAutoError {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: unknown;\n\n constructor(message: string, info: ApiErrorDetails, options?: { cause?: unknown }) {\n super(message, options);\n this.status = info.status;\n this.code = info.code;\n this.details = info.details;\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor(message: string, info?: Partial<ApiErrorDetails>) {\n super(message, { status: info?.status ?? 404, code: info?.code, details: info?.details });\n }\n}\n","import { ApiError, ConfigError } from \"./errors\";\nimport { AuthMode, BlogAutoClientConfig, InternalClientConfig } from \"./types\";\n\nexport const DEFAULT_TIMEOUT_MS = 10_000;\n\nexport function normalizeApiUrl(apiUrl: string): string {\n if (!apiUrl) {\n throw new ConfigError(\"apiUrl is required\");\n }\n\n return apiUrl.replace(/\\/$/, \"\");\n}\n\nexport function resolveClientConfig(config: BlogAutoClientConfig): InternalClientConfig {\n if (!config) {\n throw new ConfigError(\"Client configuration is required\");\n }\n\n const apiKey = config.apiKey?.trim();\n if (!apiKey) {\n throw new ConfigError(\"apiKey is required to authenticate with BlogAuto\");\n }\n\n if (!config.workspaceId && !config.workspaceSlug) {\n throw new ConfigError(\"Provide either workspaceId or workspaceSlug\");\n }\n\n const authMode: AuthMode = config.authMode ?? \"bearer\";\n\n return {\n apiKey,\n apiUrl: normalizeApiUrl(config.apiUrl),\n workspaceId: config.workspaceId,\n workspaceSlug: config.workspaceSlug,\n authMode,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n headers: { ...(config.headers ?? {}) },\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n };\n}\n\nexport function buildQuery(params: Record<string, string | number | undefined | null>): string {\n const query = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null || value === \"\") {\n return;\n }\n query.set(key, String(value));\n });\n const qs = query.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nexport async function withTimeout<T>(promise: Promise<T>, timeoutMs?: number): Promise<T> {\n if (!timeoutMs) {\n return promise;\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n new ApiError(`Request timed out after ${timeoutMs}ms`, {\n status: 408,\n }),\n );\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n clearTimeout(timeoutId!);\n }\n}\n\nexport function mergeHeaders(\n ...headerObjects: Array<Record<string, string> | undefined>\n): Record<string, string> {\n return headerObjects.reduce<Record<string, string>>((acc, headers) => {\n if (!headers) {\n return acc;\n }\n Object.entries(headers).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n acc[key.toLowerCase()] = value;\n });\n return acc;\n }, {});\n}\n","import { buildAuthHeaders } from \"./auth\";\nimport { ApiError, BlogAutoError, ConfigError } from \"./errors\";\nimport { buildQuery, mergeHeaders, resolveClientConfig, withTimeout } from \"./utils\";\nimport type {\n BlogAutoClientConfig,\n BlogPost,\n FetchRequestOptions,\n PaginatedList,\n PostsResponse,\n} from \"./types\";\n\ninterface RequestOptions {\n path: string;\n method?: string;\n query?: Record<string, string | number | undefined | null>;\n body?: unknown;\n allowNotFound?: boolean;\n headers?: Record<string, string>;\n cache?: RequestCache;\n next?: FetchRequestOptions[\"next\"];\n}\n\nexport interface BlogAutoClient {\n getPosts(params?: { limit?: number; cursor?: string } & FetchRequestOptions): Promise<PostsResponse>;\n getPostBySlug(slug: string, options?: FetchRequestOptions): Promise<BlogPost | null>;\n getSitemapEntries(): Promise<Array<{ slug: string; updatedAt: string }>>;\n}\n\nexport function createBlogAutoClient(config: BlogAutoClientConfig): BlogAutoClient {\n const resolved = resolveClientConfig(config);\n const fetchImpl = resolved.fetch;\n const debug =\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.BLOGAUTO_DEBUG === \"true\";\n const debugLog = (...args: unknown[]) => {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(\"[blogauto]\", ...args);\n }\n };\n\n function ensureWorkspaceSlug(): string {\n if (!resolved.workspaceSlug) {\n throw new ConfigError(\"workspaceSlug is required to call the BlogAuto public API\");\n }\n return resolved.workspaceSlug;\n }\n\n function buildUrl(path: string, query?: Record<string, string | number | undefined | null>): string {\n const qs = buildQuery(query ?? {});\n return `${resolved.apiUrl}${path}${qs}`;\n }\n\n function unwrapSuccessPayload<T>(payload: unknown): T {\n if (payload && typeof payload === \"object\") {\n const maybePayload = payload as { success?: boolean; data?: T; error?: { message?: string } };\n if (\"success\" in maybePayload) {\n if (maybePayload.success === false) {\n throw new ApiError(\n maybePayload.error?.message ?? \"BlogAuto request failed\",\n { status: 500, details: maybePayload },\n );\n }\n if (maybePayload.success && \"data\" in maybePayload) {\n return maybePayload.data as T;\n }\n }\n }\n return payload as T;\n }\n\n async function request<T>(opts: RequestOptions): Promise<T> {\n const method = opts.method ?? \"GET\";\n const url = buildUrl(opts.path, opts.query);\n\n const authHeaders = buildAuthHeaders(resolved.apiKey, resolved.authMode);\n const baseHeaders = mergeHeaders(resolved.headers, authHeaders, opts.headers);\n\n const init: RequestInit = {\n method,\n headers: baseHeaders,\n };\n\n if (opts.body) {\n init.body = typeof opts.body === \"string\" ? opts.body : JSON.stringify(opts.body);\n init.headers = {\n ...baseHeaders,\n \"content-type\": baseHeaders[\"content-type\"] ?? \"application/json\",\n };\n }\n\n if (opts.cache !== undefined) {\n init.cache = opts.cache;\n }\n\n if (opts.next) {\n (init as RequestInit & { next?: FetchRequestOptions[\"next\"] }).next = opts.next;\n }\n\n const startedAt = Date.now();\n try {\n const response = await withTimeout(fetchImpl(url, init), resolved.timeoutMs);\n debugLog(\"response\", {\n method,\n url,\n status: response.status,\n durationMs: Date.now() - startedAt,\n });\n if (opts.allowNotFound && response.status === 404) {\n return null as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const isJson = contentType.includes(\"application/json\");\n const payload = isJson ? await response.json().catch(() => undefined) : await response.text();\n\n if (!response.ok) {\n if (response.status === 404 && opts.allowNotFound) {\n return null as T;\n }\n\n const errorBody = payload as any;\n const message =\n errorBody?.error?.message ?? errorBody?.message ?? `Request failed with status ${response.status}`;\n throw new ApiError(message, {\n status: response.status,\n code: errorBody?.error?.code ?? errorBody?.code,\n details: errorBody?.error?.details ?? errorBody,\n });\n }\n\n if (isJson) {\n return unwrapSuccessPayload<T>(payload);\n }\n\n return (payload as T) ?? (undefined as T);\n } catch (error) {\n debugLog(\"request failed\", {\n method,\n url,\n durationMs: Date.now() - startedAt,\n error: error instanceof Error ? error.message : error,\n });\n if (error instanceof BlogAutoError) {\n throw error;\n }\n const causeMessage =\n error instanceof Error ? error.message : typeof error === \"string\" ? error : undefined;\n const message = causeMessage\n ? `Network request to BlogAuto failed: ${causeMessage}`\n : \"Network request to BlogAuto failed\";\n throw new ApiError(\n message,\n {\n status: 0,\n details: { url, method },\n },\n { cause: error },\n );\n }\n }\n\n async function fetchBlogPage(\n limit: number,\n page: number,\n cacheOptions?: FetchRequestOptions,\n ): Promise<PaginatedList<BlogPost>> {\n const workspaceSlug = ensureWorkspaceSlug();\n debugLog(\"fetch posts page\", { workspaceSlug, limit, page });\n return request<PaginatedList<BlogPost>>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs`,\n query: { limit, page },\n cache: cacheOptions?.cache,\n next: cacheOptions?.next,\n });\n }\n\n return {\n async getPosts(params) {\n const limit = params?.limit ?? 20;\n const cursorPage = params?.cursor ? Number(params.cursor) : undefined;\n const page = Number.isFinite(cursorPage) && cursorPage! >= 1 ? cursorPage! : 1;\n const data = await fetchBlogPage(limit, page, params);\n return {\n posts: data.items,\n nextCursor: data.pagination.hasMore ? String(data.pagination.page + 1) : undefined,\n };\n },\n async getPostBySlug(slug: string, options?: FetchRequestOptions) {\n if (!slug) {\n throw new ApiError(\"slug is required\", { status: 400 });\n }\n const workspaceSlug = ensureWorkspaceSlug();\n const post = await request<{ post: BlogPost } | null>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs/${encodeURIComponent(slug)}`,\n allowNotFound: true,\n cache: options?.cache,\n next: options?.next,\n });\n if (post === null) {\n return null;\n }\n return post.post;\n },\n async getSitemapEntries() {\n const entries: Array<{ slug: string; updatedAt: string }> = [];\n const limit = 100;\n let page = 1;\n\n while (true) {\n const pageData = await fetchBlogPage(limit, page);\n pageData.items.forEach((post) => {\n entries.push({ slug: post.slug, updatedAt: post.updatedAt });\n });\n\n if (!pageData.pagination.hasMore) {\n break;\n }\n\n page = pageData.pagination.page + 1;\n }\n\n return entries;\n },\n };\n}\n","import { createBlogAutoClient, type BlogAutoClient } from \"./client\";\n\nexport interface BlogAutoEnvConfig {\n client: BlogAutoClient;\n workspaceSlug: string;\n workspaceId?: string;\n siteUrl: string;\n revalidateSecret?: string;\n apiUrl: string;\n apiKey: string;\n tags: {\n posts: string;\n post: (slug: string) => string;\n sitemap: string;\n };\n}\n\nlet _instance: BlogAutoEnvConfig | null = null;\n\nfunction requireEnv(name: string): string {\n const value = process.env[name];\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nexport function createBlogAutoFromEnv(): BlogAutoEnvConfig {\n if (_instance) {\n return _instance;\n }\n\n const apiUrl = process.env.BLOGAUTO_API_URL ?? \"https://api.autoblogwriter.app\";\n const apiKey = requireEnv(\"BLOGAUTO_API_KEY\");\n const workspaceSlug = requireEnv(\"BLOGAUTO_WORKSPACE_SLUG\");\n const workspaceId = process.env.BLOGAUTO_WORKSPACE_ID;\n const siteUrl =\n process.env.SITE_URL ?? process.env.NEXT_PUBLIC_SITE_URL ?? \"http://localhost:3000\";\n const revalidateSecret = process.env.BLOGAUTO_REVALIDATE_SECRET;\n\n const client = createBlogAutoClient({\n apiUrl,\n apiKey,\n workspaceSlug,\n workspaceId,\n });\n\n _instance = {\n client,\n workspaceSlug,\n workspaceId,\n siteUrl,\n revalidateSecret,\n apiUrl,\n apiKey,\n tags: {\n posts: `blogauto:${workspaceSlug}:posts`,\n post: (slug: string) => `blogauto:${workspaceSlug}:post:${slug}`,\n sitemap: `blogauto:${workspaceSlug}:sitemap`,\n },\n };\n\n return _instance;\n}\n","import type { BlogPost } from \"./types\";\n\nexport interface NextMetadata {\n title?: string;\n description?: string;\n keywords?: string[];\n alternates?: {\n canonical?: string;\n };\n openGraph?: {\n type?: string;\n title?: string;\n description?: string;\n images?: Array<{ url: string }>;\n publishedTime?: string;\n modifiedTime?: string;\n };\n twitter?: {\n card?: string;\n title?: string;\n description?: string;\n images?: string[];\n };\n}\n\nexport function buildNextMetadata(post: BlogPost): NextMetadata {\n const title = post.seo?.title ?? post.title;\n const description = post.seo?.description ?? post.excerpt;\n const keywords = post.seo?.keywords;\n const canonical = post.metadata?.canonicalUrl;\n const ogImageUrl = post.metadata?.ogImageUrl;\n\n const metadata: NextMetadata = {\n title,\n description,\n };\n\n if (keywords && keywords.length > 0) {\n metadata.keywords = keywords;\n }\n\n if (canonical) {\n metadata.alternates = { canonical };\n }\n\n metadata.openGraph = {\n type: \"article\",\n title,\n description,\n publishedTime: post.publishedAt,\n modifiedTime: post.updatedAt,\n };\n\n if (ogImageUrl) {\n metadata.openGraph.images = [{ url: ogImageUrl }];\n }\n\n metadata.twitter = {\n card: ogImageUrl ? \"summary_large_image\" : \"summary\",\n title,\n description,\n };\n\n if (ogImageUrl) {\n metadata.twitter.images = [ogImageUrl];\n }\n\n return metadata;\n}\n","import { BuildSitemapOptions, MetadataRouteSitemap, MetadataRouteSitemapEntry } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeRoutePrefix(routePrefix?: string): string {\n if (!routePrefix || routePrefix === \"/\") {\n return \"\";\n }\n const withSlash = routePrefix.startsWith(\"/\") ? routePrefix : `/${routePrefix}`;\n return withSlash.endsWith(\"/\") ? withSlash.slice(0, -1) : withSlash;\n}\n\nfunction normalizeSlug(slug: string): string {\n return slug.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function buildSitemap(opts: BuildSitemapOptions): MetadataRouteSitemap {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const prefix = normalizeRoutePrefix(opts.routePrefix ?? \"/blog\");\n\n const entries: MetadataRouteSitemapEntry[] = opts.entries.map((entry) => {\n const slug = normalizeSlug(entry.slug);\n const hasSlug = slug.length > 0;\n const slugFragment = hasSlug ? `/${slug}` : \"\";\n const path = prefix ? `${prefix}${slugFragment}` : hasSlug ? `/${slug}` : \"/\";\n return {\n url: `${siteUrl}${path}`,\n lastModified: entry.updatedAt,\n };\n });\n\n return entries;\n}\n","import { BuildRobotsOptions, MetadataRouteRobots } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizePath(path: string): string {\n if (!path) {\n return \"/sitemap.xml\";\n }\n if (!path.startsWith(\"/\")) {\n return `/${path}`;\n }\n return path;\n}\n\nexport function buildRobots(opts: BuildRobotsOptions): MetadataRouteRobots {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const sitemapPath = normalizePath(opts.sitemapPath ?? \"/sitemap.xml\");\n const sitemapUrl = `${siteUrl}${sitemapPath}`;\n\n return {\n rules: [{ userAgent: \"*\", allow: \"/\" }],\n sitemap: sitemapUrl,\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { buildNextMetadata, type NextMetadata } from \"../metadata\";\nimport { buildSitemap } from \"../sitemap\";\nimport { buildRobots } from \"../robots\";\nimport type { BlogPost, PostsResponse, MetadataRouteSitemap, MetadataRouteRobots } from \"../types\";\n\nexport interface FetchBlogPostsOptions {\n limit?: number;\n cursor?: string;\n}\n\nexport async function fetchBlogPosts(options?: FetchBlogPostsOptions): Promise<PostsResponse> {\n const { client, tags } = createBlogAutoFromEnv();\n return client.getPosts({\n limit: options?.limit,\n cursor: options?.cursor,\n next: { tags: [tags.posts] },\n });\n}\n\nexport async function fetchBlogPost(slug: string): Promise<BlogPost> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n // Dynamic import to avoid pulling next/navigation into non-Next environments\n const nav = await import(/* webpackIgnore: true */ \"next/navigation\" as string) as {\n notFound: () => never;\n };\n nav.notFound();\n // notFound() throws, but TS can't infer `never` through dynamic import\n throw new Error(\"notFound\");\n }\n\n return post;\n}\n\nexport async function generatePostMetadata(slug: string): Promise<NextMetadata> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n return {};\n }\n\n return buildNextMetadata(post);\n}\n\nexport async function generateBlogSitemap(): Promise<MetadataRouteSitemap> {\n const { client, siteUrl } = createBlogAutoFromEnv();\n const entries = await client.getSitemapEntries();\n return buildSitemap({ siteUrl, routePrefix: \"/blog\", entries });\n}\n\nexport function generateBlogRobots(): MetadataRouteRobots {\n const { siteUrl } = createBlogAutoFromEnv();\n return buildRobots({ siteUrl, sitemapPath: \"/sitemap.xml\" });\n}\n","import crypto from \"crypto\";\nimport type { BlogAutoRevalidatePayload, RevalidatePathFn, RevalidateTagFn } from \"./types\";\n\nexport interface VerifyWebhookSignatureOptions {\n rawBody: string | Buffer;\n signature: string | null;\n secret: string;\n}\n\nexport interface CreateRevalidateRouteHandlerOptions {\n secret: string;\n allowedSkewSeconds?: number;\n revalidatePath?: RevalidatePathFn;\n revalidateTag?: RevalidateTagFn;\n revalidatePaths?: (payload: BlogAutoRevalidatePayload) => string[];\n revalidateTags?: (payload: BlogAutoRevalidatePayload) => string[];\n}\n\ninterface JsonResponseInit extends ResponseInit {\n status?: number;\n}\n\nfunction jsonResponse(body: unknown, init?: JsonResponseInit): Response {\n const headers = new Headers(init?.headers);\n headers.set(\"content-type\", \"application/json\");\n return new Response(JSON.stringify(body), {\n ...init,\n headers,\n });\n}\n\nfunction normalizeSignature(signature: string | null): Buffer | null {\n if (!signature) {\n return null;\n }\n const trimmed = signature.trim();\n if (!trimmed) {\n return null;\n }\n\n const withoutPrefix = trimmed.startsWith(\"sha256=\") ? trimmed.slice(7) : trimmed;\n if (!withoutPrefix) {\n return null;\n }\n\n try {\n return Buffer.from(withoutPrefix, \"hex\");\n } catch {\n return null;\n }\n}\n\nexport function verifyWebhookSignature(opts: VerifyWebhookSignatureOptions): boolean {\n const { rawBody, signature, secret } = opts;\n if (!secret) {\n throw new Error(\"Secret is required to verify webhook signatures\");\n }\n const providedSignature = normalizeSignature(signature);\n if (!providedSignature) {\n return false;\n }\n\n const bodyBuffer = typeof rawBody === \"string\" ? Buffer.from(rawBody) : rawBody;\n const expected = crypto.createHmac(\"sha256\", secret).update(bodyBuffer).digest();\n\n if (providedSignature.length !== expected.length) {\n return false;\n }\n\n return crypto.timingSafeEqual(providedSignature, expected);\n}\n\nfunction defaultPaths(payload: BlogAutoRevalidatePayload): string[] {\n const paths = new Set<string>([\"/sitemap.xml\", \"/robots.txt\", \"/blog\"]);\n if (payload.postSlug) {\n paths.add(`/blog/${payload.postSlug}`);\n }\n return Array.from(paths);\n}\n\nfunction defaultTags(payload: BlogAutoRevalidatePayload): string[] {\n const tags = new Set<string>();\n if (payload.workspaceSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:sitemap`);\n tags.add(`blogauto:${payload.workspaceSlug}:posts`);\n if (payload.postSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:post:${payload.postSlug}`);\n }\n }\n return Array.from(tags);\n}\n\nfunction dedupe(values: string[] | undefined): string[] {\n if (!values || values.length === 0) {\n return [];\n }\n return Array.from(\n new Set(\n values\n .filter((value) => typeof value === \"string\" && value.trim().length > 0)\n .map((value) => value.trim()),\n ),\n );\n}\n\nfunction determineRouteType(path: string): \"route\" | \"page\" {\n const lower = path.toLowerCase();\n if (lower.endsWith(\".xml\") || lower.endsWith(\".txt\")) {\n return \"route\";\n }\n return \"page\";\n}\n\nexport function createRevalidateRouteHandler(\n options: CreateRevalidateRouteHandlerOptions,\n): (request: Request) => Promise<Response> {\n if (!options.secret) {\n throw new Error(\"secret is required for createRevalidateRouteHandler\");\n }\n\n const allowedSkewMs = Math.max(1, options.allowedSkewSeconds ?? 300) * 1000;\n const pathBuilder = options.revalidatePaths ?? defaultPaths;\n const tagBuilder = options.revalidateTags ?? defaultTags;\n\n return async function blogAutoRevalidateHandler(request: Request): Promise<Response> {\n const signature = request.headers.get(\"x-blogauto-signature\");\n const receivedAt = Date.now();\n\n const rawBody = await request.text();\n const isValid = verifyWebhookSignature({\n rawBody,\n signature,\n secret: options.secret,\n });\n\n if (!isValid) {\n return jsonResponse({ error: \"Invalid webhook signature\" }, { status: 401 });\n }\n\n let payload: BlogAutoRevalidatePayload;\n try {\n payload = JSON.parse(rawBody) as BlogAutoRevalidatePayload;\n } catch {\n return jsonResponse({ error: \"Invalid JSON payload\" }, { status: 400 });\n }\n\n if (!payload.workspaceSlug || typeof payload.workspaceSlug !== \"string\") {\n return jsonResponse({ error: \"workspaceSlug is required\" }, { status: 400 });\n }\n\n if (!payload.ts || typeof payload.ts !== \"string\") {\n return jsonResponse({ error: \"Timestamp is required\" }, { status: 400 });\n }\n\n const payloadTs = Date.parse(payload.ts);\n if (Number.isNaN(payloadTs)) {\n return jsonResponse({ error: \"Invalid timestamp\" }, { status: 400 });\n }\n\n if (Math.abs(receivedAt - payloadTs) > allowedSkewMs) {\n return jsonResponse({ error: \"Webhook timestamp is outside allowed skew\" }, { status: 409 });\n }\n\n const paths = dedupe(pathBuilder(payload));\n const tags = dedupe(tagBuilder(payload));\n\n try {\n if (options.revalidatePath && paths.length > 0) {\n await Promise.all(\n paths.map((path) => options.revalidatePath!(path, determineRouteType(path))),\n );\n }\n\n if (options.revalidateTag && tags.length > 0) {\n await Promise.all(tags.map((tag) => options.revalidateTag!(tag)));\n }\n } catch (error) {\n return jsonResponse(\n { error: \"Failed to revalidate cache\", details: (error as Error).message },\n { status: 500 },\n );\n }\n\n return jsonResponse({\n ok: true,\n event: payload.event ?? \"post.published\",\n revalidated: {\n paths,\n tags,\n },\n });\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { createRevalidateRouteHandler } from \"../revalidate\";\n\nexport function createEnvRevalidateHandler(): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n // Lazy init so env vars are read at request time, not module load time\n const { revalidateSecret } = createBlogAutoFromEnv();\n\n if (!revalidateSecret) {\n return new Response(\n JSON.stringify({ error: \"Missing BLOGAUTO_REVALIDATE_SECRET\" }),\n { status: 500, headers: { \"content-type\": \"application/json\" } },\n );\n }\n\n // Dynamic import to avoid pulling next/cache into non-Next environments\n const nextCache = await import(/* webpackIgnore: true */ \"next/cache\" as string) as {\n revalidatePath: (path: string, type?: \"page\" | \"layout\" | \"route\") => void;\n revalidateTag: (tag: string) => void;\n };\n const { revalidatePath, revalidateTag } = nextCache;\n\n const handler = createRevalidateRouteHandler({\n secret: revalidateSecret,\n revalidatePath,\n revalidateTag,\n });\n\n return handler(request);\n };\n}\n"],"mappings":"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","names":["normalizeSiteUrl"]}
1
+ {"version":3,"sources":["../src/auth.ts","../src/errors.ts","../src/utils.ts","../src/client.ts","../src/env.ts","../src/metadata.ts","../src/sitemap.ts","../src/robots.ts","../src/next/helpers.ts","../src/revalidate.ts","../src/next/route-handlers.ts"],"sourcesContent":["import { AuthMode } from \"./types\";\n\nexport function buildAuthHeaders(apiKey: string, authMode: AuthMode = \"bearer\"): Record<string, string> {\n if (authMode === \"x-api-key\") {\n return { \"x-api-key\": apiKey };\n }\n return { Authorization: `Bearer ${apiKey}` };\n}\n","export class BlogAutoError extends Error {\n public readonly causeError?: unknown;\n\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = new.target.name;\n this.causeError = options?.cause;\n }\n}\n\nexport class ConfigError extends BlogAutoError {}\n\nexport interface ApiErrorDetails {\n status: number;\n code?: string;\n details?: unknown;\n}\n\nexport class ApiError extends BlogAutoError {\n public readonly status: number;\n public readonly code?: string;\n public readonly details?: unknown;\n\n constructor(message: string, info: ApiErrorDetails, options?: { cause?: unknown }) {\n super(message, options);\n this.status = info.status;\n this.code = info.code;\n this.details = info.details;\n }\n}\n\nexport class NotFoundError extends ApiError {\n constructor(message: string, info?: Partial<ApiErrorDetails>) {\n super(message, { status: info?.status ?? 404, code: info?.code, details: info?.details });\n }\n}\n","import { ApiError, ConfigError } from \"./errors\";\nimport { AuthMode, BlogAutoClientConfig, InternalClientConfig } from \"./types\";\n\nexport const DEFAULT_TIMEOUT_MS = 10_000;\n\nexport function normalizeApiUrl(apiUrl: string): string {\n if (!apiUrl) {\n throw new ConfigError(\"apiUrl is required\");\n }\n\n return apiUrl.replace(/\\/$/, \"\");\n}\n\nexport function resolveClientConfig(config: BlogAutoClientConfig): InternalClientConfig {\n if (!config) {\n throw new ConfigError(\"Client configuration is required\");\n }\n\n const apiKey = config.apiKey?.trim();\n if (!apiKey) {\n throw new ConfigError(\"apiKey is required to authenticate with BlogAuto\");\n }\n\n if (!config.workspaceId && !config.workspaceSlug) {\n throw new ConfigError(\"Provide either workspaceId or workspaceSlug\");\n }\n\n const authMode: AuthMode = config.authMode ?? \"bearer\";\n\n return {\n apiKey,\n apiUrl: normalizeApiUrl(config.apiUrl),\n workspaceId: config.workspaceId,\n workspaceSlug: config.workspaceSlug,\n authMode,\n fetch: config.fetch ?? globalThis.fetch.bind(globalThis),\n headers: { ...(config.headers ?? {}) },\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n };\n}\n\nexport function buildQuery(params: Record<string, string | number | undefined | null>): string {\n const query = new URLSearchParams();\n Object.entries(params).forEach(([key, value]) => {\n if (value === undefined || value === null || value === \"\") {\n return;\n }\n query.set(key, String(value));\n });\n const qs = query.toString();\n return qs ? `?${qs}` : \"\";\n}\n\nexport async function withTimeout<T>(promise: Promise<T>, timeoutMs?: number): Promise<T> {\n if (!timeoutMs) {\n return promise;\n }\n\n let timeoutId: ReturnType<typeof setTimeout>;\n\n const timeoutPromise = new Promise<never>((_, reject) => {\n timeoutId = setTimeout(() => {\n reject(\n new ApiError(`Request timed out after ${timeoutMs}ms`, {\n status: 408,\n }),\n );\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([promise, timeoutPromise]);\n } finally {\n clearTimeout(timeoutId!);\n }\n}\n\nexport function mergeHeaders(\n ...headerObjects: Array<Record<string, string> | undefined>\n): Record<string, string> {\n return headerObjects.reduce<Record<string, string>>((acc, headers) => {\n if (!headers) {\n return acc;\n }\n Object.entries(headers).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n acc[key.toLowerCase()] = value;\n });\n return acc;\n }, {});\n}\n","import { buildAuthHeaders } from \"./auth\";\nimport { ApiError, BlogAutoError, ConfigError } from \"./errors\";\nimport { buildQuery, mergeHeaders, resolveClientConfig, withTimeout } from \"./utils\";\nimport type {\n BlogAutoClientConfig,\n BlogPost,\n FetchRequestOptions,\n PaginatedList,\n PostsResponse,\n} from \"./types\";\n\ninterface RequestOptions {\n path: string;\n method?: string;\n query?: Record<string, string | number | undefined | null>;\n body?: unknown;\n allowNotFound?: boolean;\n headers?: Record<string, string>;\n cache?: RequestCache;\n next?: FetchRequestOptions[\"next\"];\n}\n\nexport interface BlogAutoClient {\n getPosts(params?: { limit?: number; cursor?: string } & FetchRequestOptions): Promise<PostsResponse>;\n getPostBySlug(slug: string, options?: FetchRequestOptions): Promise<BlogPost | null>;\n getSitemapEntries(): Promise<Array<{ slug: string; updatedAt: string }>>;\n}\n\nexport function createBlogAutoClient(config: BlogAutoClientConfig): BlogAutoClient {\n const resolved = resolveClientConfig(config);\n const fetchImpl = resolved.fetch;\n const debug =\n typeof process !== \"undefined\" &&\n typeof process.env !== \"undefined\" &&\n process.env.BLOGAUTO_DEBUG === \"true\";\n const debugLog = (...args: unknown[]) => {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(\"[blogauto]\", ...args);\n }\n };\n\n function ensureWorkspaceSlug(): string {\n if (!resolved.workspaceSlug) {\n throw new ConfigError(\"workspaceSlug is required to call the BlogAuto public API\");\n }\n return resolved.workspaceSlug;\n }\n\n function buildUrl(path: string, query?: Record<string, string | number | undefined | null>): string {\n const qs = buildQuery(query ?? {});\n return `${resolved.apiUrl}${path}${qs}`;\n }\n\n function unwrapSuccessPayload<T>(payload: unknown): T {\n if (payload && typeof payload === \"object\") {\n const maybePayload = payload as { success?: boolean; data?: T; error?: { message?: string } };\n if (\"success\" in maybePayload) {\n if (maybePayload.success === false) {\n throw new ApiError(\n maybePayload.error?.message ?? \"BlogAuto request failed\",\n { status: 500, details: maybePayload },\n );\n }\n if (maybePayload.success && \"data\" in maybePayload) {\n return maybePayload.data as T;\n }\n }\n }\n return payload as T;\n }\n\n async function request<T>(opts: RequestOptions): Promise<T> {\n const method = opts.method ?? \"GET\";\n const url = buildUrl(opts.path, opts.query);\n\n const authHeaders = buildAuthHeaders(resolved.apiKey, resolved.authMode);\n const baseHeaders = mergeHeaders(resolved.headers, authHeaders, opts.headers);\n\n const init: RequestInit = {\n method,\n headers: baseHeaders,\n };\n\n if (opts.body) {\n init.body = typeof opts.body === \"string\" ? opts.body : JSON.stringify(opts.body);\n init.headers = {\n ...baseHeaders,\n \"content-type\": baseHeaders[\"content-type\"] ?? \"application/json\",\n };\n }\n\n if (opts.cache !== undefined) {\n init.cache = opts.cache;\n }\n\n if (opts.next) {\n (init as RequestInit & { next?: FetchRequestOptions[\"next\"] }).next = opts.next;\n }\n\n const startedAt = Date.now();\n try {\n const response = await withTimeout(fetchImpl(url, init), resolved.timeoutMs);\n debugLog(\"response\", {\n method,\n url,\n status: response.status,\n durationMs: Date.now() - startedAt,\n });\n if (opts.allowNotFound && response.status === 404) {\n return null as T;\n }\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const isJson = contentType.includes(\"application/json\");\n const payload = isJson ? await response.json().catch(() => undefined) : await response.text();\n\n if (!response.ok) {\n if (response.status === 404 && opts.allowNotFound) {\n return null as T;\n }\n\n const errorBody = payload as any;\n const message =\n errorBody?.error?.message ?? errorBody?.message ?? `Request failed with status ${response.status}`;\n throw new ApiError(message, {\n status: response.status,\n code: errorBody?.error?.code ?? errorBody?.code,\n details: errorBody?.error?.details ?? errorBody,\n });\n }\n\n if (isJson) {\n return unwrapSuccessPayload<T>(payload);\n }\n\n return (payload as T) ?? (undefined as T);\n } catch (error) {\n debugLog(\"request failed\", {\n method,\n url,\n durationMs: Date.now() - startedAt,\n error: error instanceof Error ? error.message : error,\n });\n if (error instanceof BlogAutoError) {\n throw error;\n }\n const causeMessage =\n error instanceof Error ? error.message : typeof error === \"string\" ? error : undefined;\n const message = causeMessage\n ? `Network request to BlogAuto failed: ${causeMessage}`\n : \"Network request to BlogAuto failed\";\n throw new ApiError(\n message,\n {\n status: 0,\n details: { url, method },\n },\n { cause: error },\n );\n }\n }\n\n async function fetchBlogPage(\n limit: number,\n page: number,\n cacheOptions?: FetchRequestOptions,\n ): Promise<PaginatedList<BlogPost>> {\n const workspaceSlug = ensureWorkspaceSlug();\n debugLog(\"fetch posts page\", { workspaceSlug, limit, page });\n return request<PaginatedList<BlogPost>>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs`,\n query: { limit, page },\n cache: cacheOptions?.cache,\n next: cacheOptions?.next,\n });\n }\n\n return {\n async getPosts(params) {\n const limit = params?.limit ?? 20;\n const cursorPage = params?.cursor ? Number(params.cursor) : undefined;\n const page = Number.isFinite(cursorPage) && cursorPage! >= 1 ? cursorPage! : 1;\n const data = await fetchBlogPage(limit, page, params);\n return {\n posts: data.items,\n nextCursor: data.pagination.hasMore ? String(data.pagination.page + 1) : undefined,\n };\n },\n async getPostBySlug(slug: string, options?: FetchRequestOptions) {\n if (!slug) {\n throw new ApiError(\"slug is required\", { status: 400 });\n }\n const workspaceSlug = ensureWorkspaceSlug();\n const post = await request<{ post: BlogPost } | null>({\n path: `/v1/public/${encodeURIComponent(workspaceSlug)}/blogs/${encodeURIComponent(slug)}`,\n allowNotFound: true,\n cache: options?.cache,\n next: options?.next,\n });\n if (post === null) {\n return null;\n }\n return post.post;\n },\n async getSitemapEntries() {\n const entries: Array<{ slug: string; updatedAt: string }> = [];\n const limit = 100;\n let page = 1;\n\n while (true) {\n const pageData = await fetchBlogPage(limit, page);\n pageData.items.forEach((post) => {\n entries.push({ slug: post.slug, updatedAt: post.updatedAt });\n });\n\n if (!pageData.pagination.hasMore) {\n break;\n }\n\n page = pageData.pagination.page + 1;\n }\n\n return entries;\n },\n };\n}\n","import { createBlogAutoClient, type BlogAutoClient } from \"./client\";\n\nexport interface BlogAutoEnvConfig {\n client: BlogAutoClient;\n workspaceSlug: string;\n workspaceId?: string;\n siteUrl: string;\n revalidateSecret?: string;\n apiUrl: string;\n apiKey: string;\n tags: {\n posts: string;\n post: (slug: string) => string;\n sitemap: string;\n };\n}\n\nlet _instance: BlogAutoEnvConfig | null = null;\n\nfunction requireEnv(name: string): string {\n const value = process.env[name];\n if (!value) {\n throw new Error(`Missing required environment variable: ${name}`);\n }\n return value;\n}\n\nexport function createBlogAutoFromEnv(): BlogAutoEnvConfig {\n if (_instance) {\n return _instance;\n }\n\n const apiUrl = process.env.BLOGAUTO_API_URL ?? \"https://api.autoblogwriter.app\";\n const apiKey = requireEnv(\"BLOGAUTO_API_KEY\");\n const workspaceSlug = requireEnv(\"BLOGAUTO_WORKSPACE_SLUG\");\n const workspaceId = process.env.BLOGAUTO_WORKSPACE_ID;\n const siteUrl =\n process.env.SITE_URL ?? process.env.NEXT_PUBLIC_SITE_URL ?? \"http://localhost:3000\";\n const revalidateSecret = process.env.BLOGAUTO_REVALIDATE_SECRET;\n\n const client = createBlogAutoClient({\n apiUrl,\n apiKey,\n workspaceSlug,\n workspaceId,\n });\n\n _instance = {\n client,\n workspaceSlug,\n workspaceId,\n siteUrl,\n revalidateSecret,\n apiUrl,\n apiKey,\n tags: {\n posts: `blogauto:${workspaceSlug}:posts`,\n post: (slug: string) => `blogauto:${workspaceSlug}:post:${slug}`,\n sitemap: `blogauto:${workspaceSlug}:sitemap`,\n },\n };\n\n return _instance;\n}\n","import type { BlogPost } from \"./types\";\n\nexport interface NextMetadata {\n title?: string;\n description?: string;\n keywords?: string[];\n alternates?: {\n canonical?: string;\n };\n openGraph?: {\n type?: string;\n title?: string;\n description?: string;\n images?: Array<{ url: string }>;\n publishedTime?: string;\n modifiedTime?: string;\n };\n twitter?: {\n card?: string;\n title?: string;\n description?: string;\n images?: string[];\n };\n}\n\nexport function buildNextMetadata(post: BlogPost): NextMetadata {\n const title = post.seo?.title ?? post.title;\n const description = post.seo?.description ?? post.excerpt;\n const keywords = post.seo?.keywords;\n const canonical = post.metadata?.canonicalUrl;\n const ogImageUrl = post.metadata?.ogImageUrl;\n\n const metadata: NextMetadata = {\n title,\n description,\n };\n\n if (keywords && keywords.length > 0) {\n metadata.keywords = keywords;\n }\n\n if (canonical) {\n metadata.alternates = { canonical };\n }\n\n metadata.openGraph = {\n type: \"article\",\n title,\n description,\n publishedTime: post.publishedAt,\n modifiedTime: post.updatedAt,\n };\n\n if (ogImageUrl) {\n metadata.openGraph.images = [{ url: ogImageUrl }];\n }\n\n metadata.twitter = {\n card: ogImageUrl ? \"summary_large_image\" : \"summary\",\n title,\n description,\n };\n\n if (ogImageUrl) {\n metadata.twitter.images = [ogImageUrl];\n }\n\n return metadata;\n}\n","import { BuildSitemapOptions, MetadataRouteSitemap, MetadataRouteSitemapEntry } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeRoutePrefix(routePrefix?: string): string {\n if (!routePrefix || routePrefix === \"/\") {\n return \"\";\n }\n const withSlash = routePrefix.startsWith(\"/\") ? routePrefix : `/${routePrefix}`;\n return withSlash.endsWith(\"/\") ? withSlash.slice(0, -1) : withSlash;\n}\n\nfunction normalizeSlug(slug: string): string {\n return slug.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n}\n\nexport function buildSitemap(opts: BuildSitemapOptions): MetadataRouteSitemap {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const prefix = normalizeRoutePrefix(opts.routePrefix ?? \"/blog\");\n\n const entries: MetadataRouteSitemapEntry[] = opts.entries.map((entry) => {\n const slug = normalizeSlug(entry.slug);\n const hasSlug = slug.length > 0;\n const slugFragment = hasSlug ? `/${slug}` : \"\";\n const path = prefix ? `${prefix}${slugFragment}` : hasSlug ? `/${slug}` : \"/\";\n return {\n url: `${siteUrl}${path}`,\n lastModified: entry.updatedAt,\n };\n });\n\n return entries;\n}\n","import { BuildRobotsOptions, MetadataRouteRobots } from \"./types\";\n\nfunction normalizeSiteUrl(url: string): string {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizePath(path: string): string {\n if (!path) {\n return \"/sitemap.xml\";\n }\n if (!path.startsWith(\"/\")) {\n return `/${path}`;\n }\n return path;\n}\n\nexport function buildRobots(opts: BuildRobotsOptions): MetadataRouteRobots {\n const siteUrl = normalizeSiteUrl(opts.siteUrl);\n const sitemapPath = normalizePath(opts.sitemapPath ?? \"/sitemap.xml\");\n const sitemapUrl = `${siteUrl}${sitemapPath}`;\n\n return {\n rules: [{ userAgent: \"*\", allow: \"/\" }],\n sitemap: sitemapUrl,\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { buildNextMetadata, type NextMetadata } from \"../metadata\";\nimport { buildSitemap } from \"../sitemap\";\nimport { buildRobots } from \"../robots\";\nimport type { BlogPost, PostsResponse, MetadataRouteSitemap, MetadataRouteRobots } from \"../types\";\n\nexport interface FetchBlogPostsOptions {\n limit?: number;\n cursor?: string;\n}\n\nexport async function fetchBlogPosts(options?: FetchBlogPostsOptions): Promise<PostsResponse> {\n const { client, tags } = createBlogAutoFromEnv();\n return client.getPosts({\n limit: options?.limit,\n cursor: options?.cursor,\n next: { tags: [tags.posts] },\n });\n}\n\nexport async function fetchBlogPost(slug: string): Promise<BlogPost> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n // Dynamic import to avoid pulling next/navigation into non-Next environments\n const nav = await import(/* webpackIgnore: true */ \"next/navigation.js\" as string) as {\n notFound: () => never;\n };\n nav.notFound();\n // notFound() throws, but TS can't infer `never` through dynamic import\n throw new Error(\"notFound\");\n }\n\n return post;\n}\n\nexport async function generatePostMetadata(slug: string): Promise<NextMetadata> {\n const { client, tags } = createBlogAutoFromEnv();\n const post = await client.getPostBySlug(slug, {\n next: { tags: [tags.post(slug)] },\n });\n\n if (!post) {\n return {};\n }\n\n return buildNextMetadata(post);\n}\n\nexport async function generateBlogSitemap(): Promise<MetadataRouteSitemap> {\n const { client, siteUrl } = createBlogAutoFromEnv();\n const entries = await client.getSitemapEntries();\n return buildSitemap({ siteUrl, routePrefix: \"/blog\", entries });\n}\n\nexport function generateBlogRobots(): MetadataRouteRobots {\n const { siteUrl } = createBlogAutoFromEnv();\n return buildRobots({ siteUrl, sitemapPath: \"/sitemap.xml\" });\n}\n","import crypto from \"crypto\";\nimport type { BlogAutoRevalidatePayload, RevalidatePathFn, RevalidateTagFn } from \"./types\";\n\nexport interface VerifyWebhookSignatureOptions {\n rawBody: string | Buffer;\n signature: string | null;\n secret: string;\n}\n\nexport interface CreateRevalidateRouteHandlerOptions {\n secret: string;\n allowedSkewSeconds?: number;\n revalidatePath?: RevalidatePathFn;\n revalidateTag?: RevalidateTagFn;\n revalidatePaths?: (payload: BlogAutoRevalidatePayload) => string[];\n revalidateTags?: (payload: BlogAutoRevalidatePayload) => string[];\n}\n\ninterface JsonResponseInit extends ResponseInit {\n status?: number;\n}\n\nfunction jsonResponse(body: unknown, init?: JsonResponseInit): Response {\n const headers = new Headers(init?.headers);\n headers.set(\"content-type\", \"application/json\");\n return new Response(JSON.stringify(body), {\n ...init,\n headers,\n });\n}\n\nfunction normalizeSignature(signature: string | null): Buffer | null {\n if (!signature) {\n return null;\n }\n const trimmed = signature.trim();\n if (!trimmed) {\n return null;\n }\n\n const withoutPrefix = trimmed.startsWith(\"sha256=\") ? trimmed.slice(7) : trimmed;\n if (!withoutPrefix) {\n return null;\n }\n\n try {\n return Buffer.from(withoutPrefix, \"hex\");\n } catch {\n return null;\n }\n}\n\nexport function verifyWebhookSignature(opts: VerifyWebhookSignatureOptions): boolean {\n const { rawBody, signature, secret } = opts;\n if (!secret) {\n throw new Error(\"Secret is required to verify webhook signatures\");\n }\n const providedSignature = normalizeSignature(signature);\n if (!providedSignature) {\n return false;\n }\n\n const bodyBuffer = typeof rawBody === \"string\" ? Buffer.from(rawBody) : rawBody;\n const expected = crypto.createHmac(\"sha256\", secret).update(bodyBuffer).digest();\n\n if (providedSignature.length !== expected.length) {\n return false;\n }\n\n return crypto.timingSafeEqual(providedSignature, expected);\n}\n\nfunction defaultPaths(payload: BlogAutoRevalidatePayload): string[] {\n const paths = new Set<string>([\"/sitemap.xml\", \"/robots.txt\", \"/blog\"]);\n if (payload.postSlug) {\n paths.add(`/blog/${payload.postSlug}`);\n }\n return Array.from(paths);\n}\n\nfunction defaultTags(payload: BlogAutoRevalidatePayload): string[] {\n const tags = new Set<string>();\n if (payload.workspaceSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:sitemap`);\n tags.add(`blogauto:${payload.workspaceSlug}:posts`);\n if (payload.postSlug) {\n tags.add(`blogauto:${payload.workspaceSlug}:post:${payload.postSlug}`);\n }\n }\n return Array.from(tags);\n}\n\nfunction dedupe(values: string[] | undefined): string[] {\n if (!values || values.length === 0) {\n return [];\n }\n return Array.from(\n new Set(\n values\n .filter((value) => typeof value === \"string\" && value.trim().length > 0)\n .map((value) => value.trim()),\n ),\n );\n}\n\nfunction determineRouteType(path: string): \"route\" | \"page\" {\n const lower = path.toLowerCase();\n if (lower.endsWith(\".xml\") || lower.endsWith(\".txt\")) {\n return \"route\";\n }\n return \"page\";\n}\n\nexport function createRevalidateRouteHandler(\n options: CreateRevalidateRouteHandlerOptions,\n): (request: Request) => Promise<Response> {\n if (!options.secret) {\n throw new Error(\"secret is required for createRevalidateRouteHandler\");\n }\n\n const allowedSkewMs = Math.max(1, options.allowedSkewSeconds ?? 300) * 1000;\n const pathBuilder = options.revalidatePaths ?? defaultPaths;\n const tagBuilder = options.revalidateTags ?? defaultTags;\n\n return async function blogAutoRevalidateHandler(request: Request): Promise<Response> {\n const signature = request.headers.get(\"x-blogauto-signature\");\n const receivedAt = Date.now();\n\n const rawBody = await request.text();\n const isValid = verifyWebhookSignature({\n rawBody,\n signature,\n secret: options.secret,\n });\n\n if (!isValid) {\n return jsonResponse({ error: \"Invalid webhook signature\" }, { status: 401 });\n }\n\n let payload: BlogAutoRevalidatePayload;\n try {\n payload = JSON.parse(rawBody) as BlogAutoRevalidatePayload;\n } catch {\n return jsonResponse({ error: \"Invalid JSON payload\" }, { status: 400 });\n }\n\n if (!payload.workspaceSlug || typeof payload.workspaceSlug !== \"string\") {\n return jsonResponse({ error: \"workspaceSlug is required\" }, { status: 400 });\n }\n\n if (!payload.ts || typeof payload.ts !== \"string\") {\n return jsonResponse({ error: \"Timestamp is required\" }, { status: 400 });\n }\n\n const payloadTs = Date.parse(payload.ts);\n if (Number.isNaN(payloadTs)) {\n return jsonResponse({ error: \"Invalid timestamp\" }, { status: 400 });\n }\n\n if (Math.abs(receivedAt - payloadTs) > allowedSkewMs) {\n return jsonResponse({ error: \"Webhook timestamp is outside allowed skew\" }, { status: 409 });\n }\n\n const paths = dedupe(pathBuilder(payload));\n const tags = dedupe(tagBuilder(payload));\n\n try {\n if (options.revalidatePath && paths.length > 0) {\n await Promise.all(\n paths.map((path) => options.revalidatePath!(path, determineRouteType(path))),\n );\n }\n\n if (options.revalidateTag && tags.length > 0) {\n await Promise.all(tags.map((tag) => options.revalidateTag!(tag)));\n }\n } catch (error) {\n return jsonResponse(\n { error: \"Failed to revalidate cache\", details: (error as Error).message },\n { status: 500 },\n );\n }\n\n return jsonResponse({\n ok: true,\n event: payload.event ?? \"post.published\",\n revalidated: {\n paths,\n tags,\n },\n });\n };\n}\n","import { createBlogAutoFromEnv } from \"../env\";\nimport { createRevalidateRouteHandler } from \"../revalidate\";\n\nexport function createEnvRevalidateHandler(): (request: Request) => Promise<Response> {\n return async (request: Request): Promise<Response> => {\n // Lazy init so env vars are read at request time, not module load time\n const { revalidateSecret } = createBlogAutoFromEnv();\n\n if (!revalidateSecret) {\n return new Response(\n JSON.stringify({ error: \"Missing BLOGAUTO_REVALIDATE_SECRET\" }),\n { status: 500, headers: { \"content-type\": \"application/json\" } },\n );\n }\n\n // Dynamic import to avoid pulling next/cache into non-Next environments\n const nextCache = await import(/* webpackIgnore: true */ \"next/cache.js\" as string) as {\n revalidatePath: (path: string, type?: \"page\" | \"layout\" | \"route\") => void;\n revalidateTag: (tag: string) => void;\n };\n const { revalidatePath, revalidateTag } = nextCache;\n\n const handler = createRevalidateRouteHandler({\n secret: revalidateSecret,\n revalidatePath,\n revalidateTag,\n });\n\n return handler(request);\n };\n}\n"],"mappings":"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","names":["normalizeSiteUrl"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@autoblogwriter/sdk",
3
- "version": "2.0.5",
3
+ "version": "2.1.1",
4
4
  "description": "Official AutoBlogWriter SDK for fetching posts, building sitemaps, rendering helpers, and revalidation utilities.",
5
5
  "license": "MIT",
6
6
  "type": "module",