@autoblogwriter/sdk 2.1.1 → 3.0.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,11 +12,40 @@ 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
+ ## v3 Migration (Breaking Changes)
16
+
17
+ Version `3.0.0` removes legacy `BlogAuto*` symbols and legacy webhook/env identifiers. There are no compatibility aliases in v3.
18
+
19
+ ### API Rename Map
20
+
21
+ | Old (removed) | New |
22
+ | --- | --- |
23
+ | `createBlogAutoClient` | `createAutoBlogWriterClient` |
24
+ | `BlogAutoClient` | `AutoBlogWriterClient` |
25
+ | `BlogAutoError` | `AutoBlogWriterError` |
26
+ | `createBlogAutoFromEnv` | `createAutoBlogWriterFromEnv` |
27
+ | `BlogAutoEnvConfig` | `AutoBlogWriterEnvConfig` |
28
+ | `BlogAutoClientConfig` | `AutoBlogWriterClientConfig` |
29
+ | `BlogAutoRevalidatePayload` | `AutoBlogWriterRevalidatePayload` |
30
+
31
+ ### Wire/Config Identifier Changes
32
+
33
+ | Old (removed) | New |
34
+ | --- | --- |
35
+ | `BLOGAUTO_API_KEY` | `AUTOBLOGWRITER_API_KEY` |
36
+ | `BLOGAUTO_WORKSPACE_SLUG` | `AUTOBLOGWRITER_WORKSPACE_SLUG` |
37
+ | `BLOGAUTO_API_URL` | `AUTOBLOGWRITER_API_URL` |
38
+ | `BLOGAUTO_WORKSPACE_ID` | `AUTOBLOGWRITER_WORKSPACE_ID` |
39
+ | `BLOGAUTO_REVALIDATE_SECRET` | `AUTOBLOGWRITER_REVALIDATE_SECRET` |
40
+ | `BLOGAUTO_DEBUG` | `AUTOBLOGWRITER_DEBUG` |
41
+ | `x-blogauto-signature` | `x-autoblogwriter-signature` |
42
+ | `blogauto:{workspaceSlug}:...` | `autoblogwriter:{workspaceSlug}:...` |
43
+
15
44
  ## Entry Points
16
45
 
17
46
  ```ts
18
47
  // Core client, types, and utilities
19
- import { createBlogAutoClient } from "@autoblogwriter/sdk";
48
+ import { createAutoBlogWriterClient } from "@autoblogwriter/sdk";
20
49
 
21
50
  // Next.js App Router helpers (server-side)
22
51
  import { fetchBlogPosts, fetchBlogPost } from "@autoblogwriter/sdk/next";
@@ -39,6 +68,34 @@ import "@autoblogwriter/sdk/styles.css";
39
68
  | `@autoblogwriter/sdk/revalidate` | Server | `createRevalidateRouteHandler`, `verifyWebhookSignature` |
40
69
  | `@autoblogwriter/sdk/styles.css` | Client | Default dark-theme styles for all components |
41
70
 
71
+ ## Quick Start (Next.js App Router)
72
+
73
+ 1. Install the package:
74
+
75
+ ```bash
76
+ npm install @autoblogwriter/sdk
77
+ ```
78
+
79
+ 2. Configure environment variables:
80
+
81
+ ```bash
82
+ AUTOBLOGWRITER_API_KEY=ba_pk_your_api_key
83
+ AUTOBLOGWRITER_WORKSPACE_SLUG=your-workspace
84
+ AUTOBLOGWRITER_REVALIDATE_SECRET=your_webhook_secret
85
+ ```
86
+
87
+ 3. Fetch and render posts:
88
+
89
+ ```tsx
90
+ import { fetchBlogPosts } from "@autoblogwriter/sdk/next";
91
+ import { BlogPostList } from "@autoblogwriter/sdk/react";
92
+
93
+ export default async function BlogPage() {
94
+ const { posts } = await fetchBlogPosts({ limit: 20 });
95
+ return <BlogPostList posts={posts} />;
96
+ }
97
+ ```
98
+
42
99
  ## Security Notes (Read First)
43
100
  - Never ship AutoBlogWriter API keys in public, client-side code.
44
101
  - Run the SDK inside Next.js server components, route handlers, or your own backend proxy.
@@ -47,13 +104,13 @@ import "@autoblogwriter/sdk/styles.css";
47
104
  ## Client Configuration
48
105
 
49
106
  ```ts
50
- import { createBlogAutoClient } from "@autoblogwriter/sdk";
107
+ import { createAutoBlogWriterClient } from "@autoblogwriter/sdk";
51
108
 
52
- const client = createBlogAutoClient({
109
+ const client = createAutoBlogWriterClient({
53
110
  apiUrl: "https://api.autoblogwriter.app",
54
- apiKey: process.env.BLOGAUTO_API_KEY!,
55
- workspaceId: process.env.BLOGAUTO_WORKSPACE_ID,
56
- workspaceSlug: process.env.BLOGAUTO_WORKSPACE_SLUG,
111
+ apiKey: process.env.AUTOBLOGWRITER_API_KEY!,
112
+ workspaceId: process.env.AUTOBLOGWRITER_WORKSPACE_ID,
113
+ workspaceSlug: process.env.AUTOBLOGWRITER_WORKSPACE_SLUG,
57
114
  authMode: "bearer", // or "x-api-key"
58
115
  headers: { "x-trace-id": "..." },
59
116
  timeoutMs: 10_000,
@@ -74,16 +131,16 @@ const client = createBlogAutoClient({
74
131
 
75
132
  ## Next.js Helper Functions (`@autoblogwriter/sdk/next`)
76
133
 
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:
134
+ The `next` entry point provides high-level helpers that read configuration from environment variables automatically (via `createAutoBlogWriterFromEnv`). Set these env vars and the helpers handle client creation, cache tagging, and metadata for you:
78
135
 
79
136
  | Env Variable | Required | Description |
80
137
  | --- | --- | --- |
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 |
138
+ | `AUTOBLOGWRITER_API_KEY` | yes | Workspace API key |
139
+ | `AUTOBLOGWRITER_WORKSPACE_SLUG` | yes | Workspace slug for content APIs |
140
+ | `AUTOBLOGWRITER_API_URL` | no | Defaults to `https://api.autoblogwriter.app` |
141
+ | `AUTOBLOGWRITER_WORKSPACE_ID` | no | Optional workspace ID |
85
142
  | `SITE_URL` or `NEXT_PUBLIC_SITE_URL` | no | Defaults to `http://localhost:3000` |
86
- | `BLOGAUTO_REVALIDATE_SECRET` | no | Required for the revalidation handler |
143
+ | `AUTOBLOGWRITER_REVALIDATE_SECRET` | no | Required for the revalidation handler |
87
144
 
88
145
  ### `fetchBlogPosts(options?)`
89
146
 
@@ -143,10 +200,10 @@ export default function robots() {
143
200
 
144
201
  ### `createEnvRevalidateHandler()`
145
202
 
146
- Creates a POST route handler for webhook-based revalidation. Reads `BLOGAUTO_REVALIDATE_SECRET` from env, verifies the HMAC signature, and calls `revalidatePath`/`revalidateTag`.
203
+ Creates a POST route handler for webhook-based revalidation. Reads `AUTOBLOGWRITER_REVALIDATE_SECRET` from env, verifies the HMAC signature, and calls `revalidatePath`/`revalidateTag`.
147
204
 
148
205
  ```ts
149
- // app/api/blogauto/revalidate/route.ts
206
+ // app/api/autoblogwriter/revalidate/route.ts
150
207
  import { createEnvRevalidateHandler } from "@autoblogwriter/sdk/next";
151
208
 
152
209
  export const POST = createEnvRevalidateHandler();
@@ -329,36 +386,6 @@ For a light theme, override the color variables:
329
386
  | `.ba-post-meta` | `<BlogPost>` | Date and reading time |
330
387
  | `.ba-markdown` | `<Markdown>` | Markdown content wrapper |
331
388
 
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:
335
-
336
- ```ts
337
- import { createBlogAutoClient } from "@autoblogwriter/sdk";
338
-
339
- const client = createBlogAutoClient({
340
- apiUrl: "https://api.autoblogwriter.app",
341
- apiKey: process.env.BLOGAUTO_API_KEY!,
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
348
- });
349
- ```
350
-
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. |
361
-
362
389
  ## Revalidation
363
390
 
364
391
  When AutoBlogWriter publishes a post it can ping your Next.js site so cached pages refresh immediately.
@@ -366,32 +393,32 @@ When AutoBlogWriter publishes a post it can ping your Next.js site so cached pag
366
393
  **Quick setup** (env-based, one line):
367
394
 
368
395
  ```ts
369
- // app/api/blogauto/revalidate/route.ts
396
+ // app/api/autoblogwriter/revalidate/route.ts
370
397
  import { createEnvRevalidateHandler } from "@autoblogwriter/sdk/next";
371
398
 
372
399
  export const POST = createEnvRevalidateHandler();
373
400
  ```
374
401
 
375
- Set `BLOGAUTO_REVALIDATE_SECRET` in your environment and configure the webhook URL in the AutoBlogWriter dashboard under **Workspace Settings → Revalidation URL**.
402
+ Set `AUTOBLOGWRITER_REVALIDATE_SECRET` in your environment and configure the webhook URL in the AutoBlogWriter dashboard under **Workspace Settings → Revalidation URL**.
376
403
 
377
404
  **Advanced setup** (manual control via `@autoblogwriter/sdk/revalidate`):
378
405
 
379
406
  ```ts
380
- // app/api/blogauto/revalidate/route.ts
407
+ // app/api/autoblogwriter/revalidate/route.ts
381
408
  import { revalidatePath, revalidateTag } from "next/cache";
382
409
  import { createRevalidateRouteHandler } from "@autoblogwriter/sdk/revalidate";
383
410
 
384
411
  export const POST = createRevalidateRouteHandler({
385
- secret: process.env.BLOGAUTO_REVALIDATE_SECRET!,
412
+ secret: process.env.AUTOBLOGWRITER_REVALIDATE_SECRET!,
386
413
  revalidatePath,
387
414
  revalidateTag,
388
415
  });
389
416
  ```
390
417
 
391
- The handler verifies the `X-BlogAuto-Signature` HMAC header, enforces timestamp skew (default 5 minutes), and revalidates:
418
+ The handler verifies the `X-AutoBlogWriter-Signature` HMAC header, enforces timestamp skew (default 5 minutes), and revalidates:
392
419
 
393
420
  - Paths: `/sitemap.xml`, `/robots.txt`, `/blog`, `/blog/:slug`
394
- - Tags: `blogauto:<workspaceSlug>:sitemap`, `blogauto:<workspaceSlug>:posts`, and `blogauto:<workspaceSlug>:post:<slug>`
421
+ - Tags: `autoblogwriter:<workspaceSlug>:sitemap`, `autoblogwriter:<workspaceSlug>:posts`, and `autoblogwriter:<workspaceSlug>:post:<slug>`
395
422
 
396
423
  For manual signature verification:
397
424
 
@@ -400,8 +427,8 @@ import { verifyWebhookSignature } from "@autoblogwriter/sdk/revalidate";
400
427
 
401
428
  const isValid = verifyWebhookSignature({
402
429
  rawBody,
403
- signature: req.headers.get("x-blogauto-signature"),
404
- secret: process.env.BLOGAUTO_REVALIDATE_SECRET!,
430
+ signature: req.headers.get("x-autoblogwriter-signature"),
431
+ secret: process.env.AUTOBLOGWRITER_REVALIDATE_SECRET!,
405
432
  });
406
433
  ```
407
434
 
package/dist/index.cjs CHANGED
@@ -31,7 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var src_exports = {};
32
32
  __export(src_exports, {
33
33
  ApiError: () => ApiError,
34
- BlogAutoError: () => BlogAutoError,
34
+ AutoBlogWriterError: () => AutoBlogWriterError,
35
35
  ConfigError: () => ConfigError,
36
36
  DEFAULT_TIMEOUT_MS: () => DEFAULT_TIMEOUT_MS,
37
37
  NotFoundError: () => NotFoundError,
@@ -39,8 +39,8 @@ __export(src_exports, {
39
39
  buildNextMetadata: () => buildNextMetadata,
40
40
  buildRobots: () => buildRobots,
41
41
  buildSitemap: () => buildSitemap,
42
- createBlogAutoClient: () => createBlogAutoClient,
43
- createBlogAutoFromEnv: () => createBlogAutoFromEnv,
42
+ createAutoBlogWriterClient: () => createAutoBlogWriterClient,
43
+ createAutoBlogWriterFromEnv: () => createAutoBlogWriterFromEnv,
44
44
  createRevalidateRouteHandler: () => createRevalidateRouteHandler,
45
45
  renderMarkdownToHtml: () => renderMarkdownToHtml,
46
46
  resolveClientConfig: () => resolveClientConfig,
@@ -57,16 +57,16 @@ function buildAuthHeaders(apiKey, authMode = "bearer") {
57
57
  }
58
58
 
59
59
  // src/errors.ts
60
- var BlogAutoError = class extends Error {
60
+ var AutoBlogWriterError = class extends Error {
61
61
  constructor(message, options) {
62
62
  super(message);
63
63
  this.name = new.target.name;
64
64
  this.causeError = options?.cause;
65
65
  }
66
66
  };
67
- var ConfigError = class extends BlogAutoError {
67
+ var ConfigError = class extends AutoBlogWriterError {
68
68
  };
69
- var ApiError = class extends BlogAutoError {
69
+ var ApiError = class extends AutoBlogWriterError {
70
70
  constructor(message, info, options) {
71
71
  super(message, options);
72
72
  this.status = info.status;
@@ -94,7 +94,7 @@ function resolveClientConfig(config) {
94
94
  }
95
95
  const apiKey = config.apiKey?.trim();
96
96
  if (!apiKey) {
97
- throw new ConfigError("apiKey is required to authenticate with BlogAuto");
97
+ throw new ConfigError("apiKey is required to authenticate with AutoBlogWriter");
98
98
  }
99
99
  if (!config.workspaceId && !config.workspaceSlug) {
100
100
  throw new ConfigError("Provide either workspaceId or workspaceSlug");
@@ -158,18 +158,18 @@ function mergeHeaders(...headerObjects) {
158
158
  }
159
159
 
160
160
  // src/client.ts
161
- function createBlogAutoClient(config) {
161
+ function createAutoBlogWriterClient(config) {
162
162
  const resolved = resolveClientConfig(config);
163
163
  const fetchImpl = resolved.fetch;
164
- const debug = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.BLOGAUTO_DEBUG === "true";
164
+ const debug = typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.AUTOBLOGWRITER_DEBUG === "true";
165
165
  const debugLog = (...args) => {
166
166
  if (debug) {
167
- console.log("[blogauto]", ...args);
167
+ console.log("[autoblogwriter]", ...args);
168
168
  }
169
169
  };
170
170
  function ensureWorkspaceSlug() {
171
171
  if (!resolved.workspaceSlug) {
172
- throw new ConfigError("workspaceSlug is required to call the BlogAuto public API");
172
+ throw new ConfigError("workspaceSlug is required to call the AutoBlogWriter public API");
173
173
  }
174
174
  return resolved.workspaceSlug;
175
175
  }
@@ -183,7 +183,7 @@ function createBlogAutoClient(config) {
183
183
  if ("success" in maybePayload) {
184
184
  if (maybePayload.success === false) {
185
185
  throw new ApiError(
186
- maybePayload.error?.message ?? "BlogAuto request failed",
186
+ maybePayload.error?.message ?? "AutoBlogWriter request failed",
187
187
  { status: 500, details: maybePayload }
188
188
  );
189
189
  }
@@ -254,11 +254,11 @@ function createBlogAutoClient(config) {
254
254
  durationMs: Date.now() - startedAt,
255
255
  error: error instanceof Error ? error.message : error
256
256
  });
257
- if (error instanceof BlogAutoError) {
257
+ if (error instanceof AutoBlogWriterError) {
258
258
  throw error;
259
259
  }
260
260
  const causeMessage = error instanceof Error ? error.message : typeof error === "string" ? error : void 0;
261
- const message = causeMessage ? `Network request to BlogAuto failed: ${causeMessage}` : "Network request to BlogAuto failed";
261
+ const message = causeMessage ? `Network request to AutoBlogWriter failed: ${causeMessage}` : "Network request to AutoBlogWriter failed";
262
262
  throw new ApiError(
263
263
  message,
264
264
  {
@@ -379,7 +379,7 @@ function buildRobots(opts) {
379
379
  }
380
380
 
381
381
  // src/render.ts
382
- var CODE_BLOCK_TOKEN = "__BLOGAUTO_CODE_BLOCK_";
382
+ var CODE_BLOCK_TOKEN = "__AUTOBLOGWRITER_CODE_BLOCK_";
383
383
  function escapeHtml(value) {
384
384
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
385
385
  }
@@ -407,7 +407,7 @@ function replaceCodeBlocks(markdown, blocks) {
407
407
  });
408
408
  }
409
409
  function restoreCodeBlocks(html, blocks) {
410
- return html.replace(/__BLOGAUTO_CODE_BLOCK_(\d+)__/g, (_, rawIndex) => blocks[Number(rawIndex)] ?? "");
410
+ return html.replace(/__AUTOBLOGWRITER_CODE_BLOCK_(\d+)__/g, (_, rawIndex) => blocks[Number(rawIndex)] ?? "");
411
411
  }
412
412
  function renderMarkdownToHtml(markdown) {
413
413
  if (!markdown) {
@@ -491,10 +491,10 @@ function defaultPaths(payload) {
491
491
  function defaultTags(payload) {
492
492
  const tags = /* @__PURE__ */ new Set();
493
493
  if (payload.workspaceSlug) {
494
- tags.add(`blogauto:${payload.workspaceSlug}:sitemap`);
495
- tags.add(`blogauto:${payload.workspaceSlug}:posts`);
494
+ tags.add(`autoblogwriter:${payload.workspaceSlug}:sitemap`);
495
+ tags.add(`autoblogwriter:${payload.workspaceSlug}:posts`);
496
496
  if (payload.postSlug) {
497
- tags.add(`blogauto:${payload.workspaceSlug}:post:${payload.postSlug}`);
497
+ tags.add(`autoblogwriter:${payload.workspaceSlug}:post:${payload.postSlug}`);
498
498
  }
499
499
  }
500
500
  return Array.from(tags);
@@ -523,8 +523,8 @@ function createRevalidateRouteHandler(options) {
523
523
  const allowedSkewMs = Math.max(1, options.allowedSkewSeconds ?? 300) * 1e3;
524
524
  const pathBuilder = options.revalidatePaths ?? defaultPaths;
525
525
  const tagBuilder = options.revalidateTags ?? defaultTags;
526
- return async function blogAutoRevalidateHandler(request) {
527
- const signature = request.headers.get("x-blogauto-signature");
526
+ return async function autoBlogWriterRevalidateHandler(request) {
527
+ const signature = request.headers.get("x-autoblogwriter-signature");
528
528
  const receivedAt = Date.now();
529
529
  const rawBody = await request.text();
530
530
  const isValid = verifyWebhookSignature({
@@ -629,17 +629,17 @@ function requireEnv(name) {
629
629
  }
630
630
  return value;
631
631
  }
632
- function createBlogAutoFromEnv() {
632
+ function createAutoBlogWriterFromEnv() {
633
633
  if (_instance) {
634
634
  return _instance;
635
635
  }
636
- const apiUrl = process.env.BLOGAUTO_API_URL ?? "https://api.autoblogwriter.app";
637
- const apiKey = requireEnv("BLOGAUTO_API_KEY");
638
- const workspaceSlug = requireEnv("BLOGAUTO_WORKSPACE_SLUG");
639
- const workspaceId = process.env.BLOGAUTO_WORKSPACE_ID;
636
+ const apiUrl = process.env.AUTOBLOGWRITER_API_URL ?? "https://api.autoblogwriter.app";
637
+ const apiKey = requireEnv("AUTOBLOGWRITER_API_KEY");
638
+ const workspaceSlug = requireEnv("AUTOBLOGWRITER_WORKSPACE_SLUG");
639
+ const workspaceId = process.env.AUTOBLOGWRITER_WORKSPACE_ID;
640
640
  const siteUrl = process.env.SITE_URL ?? process.env.NEXT_PUBLIC_SITE_URL ?? "http://localhost:3000";
641
- const revalidateSecret = process.env.BLOGAUTO_REVALIDATE_SECRET;
642
- const client = createBlogAutoClient({
641
+ const revalidateSecret = process.env.AUTOBLOGWRITER_REVALIDATE_SECRET;
642
+ const client = createAutoBlogWriterClient({
643
643
  apiUrl,
644
644
  apiKey,
645
645
  workspaceSlug,
@@ -654,9 +654,9 @@ function createBlogAutoFromEnv() {
654
654
  apiUrl,
655
655
  apiKey,
656
656
  tags: {
657
- posts: `blogauto:${workspaceSlug}:posts`,
658
- post: (slug) => `blogauto:${workspaceSlug}:post:${slug}`,
659
- sitemap: `blogauto:${workspaceSlug}:sitemap`
657
+ posts: `autoblogwriter:${workspaceSlug}:posts`,
658
+ post: (slug) => `autoblogwriter:${workspaceSlug}:post:${slug}`,
659
+ sitemap: `autoblogwriter:${workspaceSlug}:sitemap`
660
660
  }
661
661
  };
662
662
  return _instance;
@@ -664,7 +664,7 @@ function createBlogAutoFromEnv() {
664
664
  // Annotate the CommonJS export names for ESM import in node:
665
665
  0 && (module.exports = {
666
666
  ApiError,
667
- BlogAutoError,
667
+ AutoBlogWriterError,
668
668
  ConfigError,
669
669
  DEFAULT_TIMEOUT_MS,
670
670
  NotFoundError,
@@ -672,8 +672,8 @@ function createBlogAutoFromEnv() {
672
672
  buildNextMetadata,
673
673
  buildRobots,
674
674
  buildSitemap,
675
- createBlogAutoClient,
676
- createBlogAutoFromEnv,
675
+ createAutoBlogWriterClient,
676
+ createAutoBlogWriterFromEnv,
677
677
  createRevalidateRouteHandler,
678
678
  renderMarkdownToHtml,
679
679
  resolveClientConfig,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/auth.ts","../src/errors.ts","../src/utils.ts","../src/client.ts","../src/sitemap.ts","../src/robots.ts","../src/render.ts","../src/revalidate.ts","../src/metadata.ts","../src/env.ts"],"sourcesContent":["export { createBlogAutoClient } from \"./client\";\nexport type { BlogAutoClient } from \"./client\";\n\nexport { buildSitemap } from \"./sitemap\";\nexport { buildRobots } from \"./robots\";\nexport { renderMarkdownToHtml } from \"./render\";\nexport { verifyWebhookSignature, createRevalidateRouteHandler } from \"./revalidate\";\nexport { buildNextMetadata, type NextMetadata } from \"./metadata\";\n\nexport { buildAuthHeaders } from \"./auth\";\nexport { DEFAULT_TIMEOUT_MS, resolveClientConfig } from \"./utils\";\nexport { BlogAutoError, ConfigError, ApiError, NotFoundError } from \"./errors\";\nexport { createBlogAutoFromEnv, type BlogAutoEnvConfig } from \"./env\";\n\nexport type {\n BlogAutoClientConfig,\n BlogPost,\n BuildRobotsOptions,\n BuildSitemapOptions,\n MetadataRouteRobots,\n MetadataRouteSitemap,\n PaginatedList,\n PostsResponse,\n SitemapEntry,\n BlogAutoRevalidatePayload,\n RevalidatePathFn,\n RevalidateTagFn,\n FetchRequestOptions,\n FetchNextConfig,\n} from \"./types\";\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 { 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","const CODE_BLOCK_TOKEN = \"__BLOGAUTO_CODE_BLOCK_\";\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction renderInline(input: string): string {\n let output = escapeHtml(input);\n output = output.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\");\n output = output.replace(/\\*(.+?)\\*/g, \"<em>$1</em>\");\n output = output.replace(/`([^`]+)`/g, (_, code) => `<code>${code}</code>`);\n output = output.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_, alt, src) => {\n const safeSrc = escapeHtml(src);\n const safeAlt = escapeHtml(alt);\n return `<img src=\"${safeSrc}\" alt=\"${safeAlt}\" />`;\n });\n output = output.replace(/\\[(.+?)\\]\\((.+?)\\)/g, (_, label, href) => {\n const safeHref = escapeHtml(href);\n return `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noreferrer\">${label}</a>`;\n });\n output = output.replace(/\\n/g, \"<br />\");\n return output;\n}\n\nfunction replaceCodeBlocks(markdown: string, blocks: string[]): string {\n return markdown.replace(/```([\\s\\S]*?)```/g, (_, code) => {\n const index = blocks.push(`<pre><code>${escapeHtml(code.trim())}</code></pre>`) - 1;\n return `${CODE_BLOCK_TOKEN}${index}__`;\n });\n}\n\nfunction restoreCodeBlocks(html: string, blocks: string[]): string {\n return html.replace(/__BLOGAUTO_CODE_BLOCK_(\\d+)__/g, (_, rawIndex) => blocks[Number(rawIndex)] ?? \"\");\n}\n\nexport function renderMarkdownToHtml(markdown: string): string {\n if (!markdown) {\n return \"\";\n }\n\n const codeBlocks: string[] = [];\n const withoutCode = replaceCodeBlocks(markdown, codeBlocks);\n const normalized = withoutCode.replace(/\\r\\n/g, \"\\n\");\n // Insert blank lines around heading lines so they become separate blocks\n const withHeadingBreaks = normalized\n .replace(/\\n(#{1,6}\\s)/g, \"\\n\\n$1\")\n .replace(/(#{1,6}\\s[^\\n]+)\\n(?!#|\\n)/g, \"$1\\n\\n\");\n const blocks = withHeadingBreaks\n .split(/\\n{2,}/)\n .map((block) => block.trim())\n .filter(Boolean);\n\n const htmlBlocks = blocks.map((block) => {\n const headingMatch = block.match(/^(#{1,6})\\s+(.*)$/);\n if (headingMatch) {\n const level = headingMatch[1].length;\n const content = renderInline(headingMatch[2]);\n return `<h${level}>${content}</h${level}>`;\n }\n\n // Check if block is a standalone image\n const imageMatch = block.match(/^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/);\n if (imageMatch) {\n const safeSrc = escapeHtml(imageMatch[2]);\n const safeAlt = escapeHtml(imageMatch[1]);\n return `<img src=\"${safeSrc}\" alt=\"${safeAlt}\" />`;\n }\n\n return `<p>${renderInline(block)}</p>`;\n });\n\n const html = htmlBlocks.join(\"\\n\");\n return restoreCodeBlocks(html, codeBlocks);\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 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 { 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"],"mappings":"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","names":["normalizeSiteUrl","crypto"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/auth.ts","../src/errors.ts","../src/utils.ts","../src/client.ts","../src/sitemap.ts","../src/robots.ts","../src/render.ts","../src/revalidate.ts","../src/metadata.ts","../src/env.ts"],"sourcesContent":["export { createAutoBlogWriterClient } from \"./client\";\nexport type { AutoBlogWriterClient } from \"./client\";\n\nexport { buildSitemap } from \"./sitemap\";\nexport { buildRobots } from \"./robots\";\nexport { renderMarkdownToHtml } from \"./render\";\nexport { verifyWebhookSignature, createRevalidateRouteHandler } from \"./revalidate\";\nexport { buildNextMetadata, type NextMetadata } from \"./metadata\";\n\nexport { buildAuthHeaders } from \"./auth\";\nexport { DEFAULT_TIMEOUT_MS, resolveClientConfig } from \"./utils\";\nexport { AutoBlogWriterError, ConfigError, ApiError, NotFoundError } from \"./errors\";\nexport { createAutoBlogWriterFromEnv, type AutoBlogWriterEnvConfig } from \"./env\";\n\nexport type {\n AutoBlogWriterClientConfig,\n BlogPost,\n BuildRobotsOptions,\n BuildSitemapOptions,\n MetadataRouteRobots,\n MetadataRouteSitemap,\n PaginatedList,\n PostsResponse,\n SitemapEntry,\n AutoBlogWriterRevalidatePayload,\n RevalidatePathFn,\n RevalidateTagFn,\n FetchRequestOptions,\n FetchNextConfig,\n} from \"./types\";\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 AutoBlogWriterError 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 AutoBlogWriterError {}\n\nexport interface ApiErrorDetails {\n status: number;\n code?: string;\n details?: unknown;\n}\n\nexport class ApiError extends AutoBlogWriterError {\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, AutoBlogWriterClientConfig, 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: AutoBlogWriterClientConfig): 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 AutoBlogWriter\");\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, AutoBlogWriterError, ConfigError } from \"./errors\";\nimport { buildQuery, mergeHeaders, resolveClientConfig, withTimeout } from \"./utils\";\nimport type {\n AutoBlogWriterClientConfig,\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 AutoBlogWriterClient {\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 createAutoBlogWriterClient(config: AutoBlogWriterClientConfig): AutoBlogWriterClient {\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.AUTOBLOGWRITER_DEBUG === \"true\";\n const debugLog = (...args: unknown[]) => {\n if (debug) {\n // eslint-disable-next-line no-console\n console.log(\"[autoblogwriter]\", ...args);\n }\n };\n\n function ensureWorkspaceSlug(): string {\n if (!resolved.workspaceSlug) {\n throw new ConfigError(\"workspaceSlug is required to call the AutoBlogWriter 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 ?? \"AutoBlogWriter 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 AutoBlogWriterError) {\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 AutoBlogWriter failed: ${causeMessage}`\n : \"Network request to AutoBlogWriter 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 { 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","const CODE_BLOCK_TOKEN = \"__AUTOBLOGWRITER_CODE_BLOCK_\";\n\nfunction escapeHtml(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nfunction renderInline(input: string): string {\n let output = escapeHtml(input);\n output = output.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\");\n output = output.replace(/\\*(.+?)\\*/g, \"<em>$1</em>\");\n output = output.replace(/`([^`]+)`/g, (_, code) => `<code>${code}</code>`);\n output = output.replace(/!\\[([^\\]]*)\\]\\(([^)]+)\\)/g, (_, alt, src) => {\n const safeSrc = escapeHtml(src);\n const safeAlt = escapeHtml(alt);\n return `<img src=\"${safeSrc}\" alt=\"${safeAlt}\" />`;\n });\n output = output.replace(/\\[(.+?)\\]\\((.+?)\\)/g, (_, label, href) => {\n const safeHref = escapeHtml(href);\n return `<a href=\"${safeHref}\" target=\"_blank\" rel=\"noreferrer\">${label}</a>`;\n });\n output = output.replace(/\\n/g, \"<br />\");\n return output;\n}\n\nfunction replaceCodeBlocks(markdown: string, blocks: string[]): string {\n return markdown.replace(/```([\\s\\S]*?)```/g, (_, code) => {\n const index = blocks.push(`<pre><code>${escapeHtml(code.trim())}</code></pre>`) - 1;\n return `${CODE_BLOCK_TOKEN}${index}__`;\n });\n}\n\nfunction restoreCodeBlocks(html: string, blocks: string[]): string {\n return html.replace(/__AUTOBLOGWRITER_CODE_BLOCK_(\\d+)__/g, (_, rawIndex) => blocks[Number(rawIndex)] ?? \"\");\n}\n\nexport function renderMarkdownToHtml(markdown: string): string {\n if (!markdown) {\n return \"\";\n }\n\n const codeBlocks: string[] = [];\n const withoutCode = replaceCodeBlocks(markdown, codeBlocks);\n const normalized = withoutCode.replace(/\\r\\n/g, \"\\n\");\n // Insert blank lines around heading lines so they become separate blocks\n const withHeadingBreaks = normalized\n .replace(/\\n(#{1,6}\\s)/g, \"\\n\\n$1\")\n .replace(/(#{1,6}\\s[^\\n]+)\\n(?!#|\\n)/g, \"$1\\n\\n\");\n const blocks = withHeadingBreaks\n .split(/\\n{2,}/)\n .map((block) => block.trim())\n .filter(Boolean);\n\n const htmlBlocks = blocks.map((block) => {\n const headingMatch = block.match(/^(#{1,6})\\s+(.*)$/);\n if (headingMatch) {\n const level = headingMatch[1].length;\n const content = renderInline(headingMatch[2]);\n return `<h${level}>${content}</h${level}>`;\n }\n\n // Check if block is a standalone image\n const imageMatch = block.match(/^!\\[([^\\]]*)\\]\\(([^)]+)\\)$/);\n if (imageMatch) {\n const safeSrc = escapeHtml(imageMatch[2]);\n const safeAlt = escapeHtml(imageMatch[1]);\n return `<img src=\"${safeSrc}\" alt=\"${safeAlt}\" />`;\n }\n\n return `<p>${renderInline(block)}</p>`;\n });\n\n const html = htmlBlocks.join(\"\\n\");\n return restoreCodeBlocks(html, codeBlocks);\n}\n","import crypto from \"crypto\";\nimport type { AutoBlogWriterRevalidatePayload, 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: AutoBlogWriterRevalidatePayload) => string[];\n revalidateTags?: (payload: AutoBlogWriterRevalidatePayload) => 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: AutoBlogWriterRevalidatePayload): 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: AutoBlogWriterRevalidatePayload): string[] {\n const tags = new Set<string>();\n if (payload.workspaceSlug) {\n tags.add(`autoblogwriter:${payload.workspaceSlug}:sitemap`);\n tags.add(`autoblogwriter:${payload.workspaceSlug}:posts`);\n if (payload.postSlug) {\n tags.add(`autoblogwriter:${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 autoBlogWriterRevalidateHandler(request: Request): Promise<Response> {\n const signature = request.headers.get(\"x-autoblogwriter-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: AutoBlogWriterRevalidatePayload;\n try {\n payload = JSON.parse(rawBody) as AutoBlogWriterRevalidatePayload;\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 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 { createAutoBlogWriterClient, type AutoBlogWriterClient } from \"./client\";\n\nexport interface AutoBlogWriterEnvConfig {\n client: AutoBlogWriterClient;\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: AutoBlogWriterEnvConfig | 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 createAutoBlogWriterFromEnv(): AutoBlogWriterEnvConfig {\n if (_instance) {\n return _instance;\n }\n\n const apiUrl = process.env.AUTOBLOGWRITER_API_URL ?? \"https://api.autoblogwriter.app\";\n const apiKey = requireEnv(\"AUTOBLOGWRITER_API_KEY\");\n const workspaceSlug = requireEnv(\"AUTOBLOGWRITER_WORKSPACE_SLUG\");\n const workspaceId = process.env.AUTOBLOGWRITER_WORKSPACE_ID;\n const siteUrl =\n process.env.SITE_URL ?? process.env.NEXT_PUBLIC_SITE_URL ?? \"http://localhost:3000\";\n const revalidateSecret = process.env.AUTOBLOGWRITER_REVALIDATE_SECRET;\n\n const client = createAutoBlogWriterClient({\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: `autoblogwriter:${workspaceSlug}:posts`,\n post: (slug: string) => `autoblogwriter:${workspaceSlug}:post:${slug}`,\n sitemap: `autoblogwriter:${workspaceSlug}:sitemap`,\n },\n };\n\n return _instance;\n}\n"],"mappings":"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","names":["normalizeSiteUrl","crypto"]}