@earlyseo/blog 1.0.5 → 1.0.7

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
@@ -20,12 +20,13 @@ Articles are authored in the EarlySEO dashboard and rendered on your site. No da
20
20
 
21
21
  ```bash
22
22
  npm install @earlyseo/blog
23
- npx earlyseo-blog
23
+ npx @earlyseo/blog init
24
24
  ```
25
25
 
26
26
  The CLI will detect your Next.js project, ask for your site ID, and generate:
27
27
  - `app/blog/page.tsx` — Paginated blog listing
28
28
  - `app/blog/[slug]/page.tsx` — Article detail with full SEO metadata
29
+ - `app/blog/sitemap.ts` — Blog sitemap at `/blog/sitemap.xml` (auto-detects base URL from Host header)
29
30
  - `.env.local` — `EARLYSEO_SITE_ID` added automatically
30
31
 
31
32
  That's it — run `npm run dev` and visit `/blog`.
@@ -43,6 +44,7 @@ npm install @earlyseo/blog
43
44
  ```env
44
45
  # .env.local
45
46
  EARLYSEO_SITE_ID=your-site-id
47
+ NEXT_PUBLIC_BASE_URL=https://example.com
46
48
  ```
47
49
 
48
50
  ### 3. Add the blog listing page
@@ -77,6 +79,40 @@ export const generateMetadata = createBlogPostMetadata({ siteId, siteName: "My S
77
79
 
78
80
  That's it! Articles published from EarlySEO automatically appear on your blog.
79
81
 
82
+ ### 5. Add blog sitemap
83
+
84
+ The recommended approach — a dedicated blog sitemap at `/blog/sitemap.xml`:
85
+
86
+ ```tsx
87
+ // app/blog/sitemap.ts
88
+ import { createBlogSitemap } from "@earlyseo/blog/next";
89
+
90
+ const siteId = process.env.EARLYSEO_SITE_ID!;
91
+
92
+ // baseUrl is auto-detected from NEXT_PUBLIC_BASE_URL or the request Host header
93
+ export default createBlogSitemap({ siteId });
94
+ ```
95
+
96
+ Or merge blog entries into your existing `app/sitemap.ts`:
97
+
98
+ ```tsx
99
+ import { getBlogSitemapEntries } from "@earlyseo/blog/next";
100
+ import type { MetadataRoute } from "next";
101
+
102
+ const siteId = process.env.EARLYSEO_SITE_ID!;
103
+
104
+ export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
105
+ const blogEntries = await getBlogSitemapEntries({ siteId });
106
+
107
+ return [
108
+ { url: "https://example.com", lastModified: new Date() },
109
+ ...blogEntries,
110
+ ];
111
+ }
112
+ ```
113
+
114
+ `baseUrl` is resolved automatically: explicit option → `NEXT_PUBLIC_BASE_URL` env var → request `Host` header.
115
+
80
116
  ---
81
117
 
82
118
  ## How It Works
@@ -280,6 +316,15 @@ interface Article {
280
316
  canonicalUrl?: string;
281
317
  version: number;
282
318
  }
319
+
320
+ interface BlogSitemapOptions {
321
+ siteId: string;
322
+ baseUrl: string;
323
+ basePath?: string;
324
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
325
+ priority?: number;
326
+ fetchInit?: RequestInit;
327
+ }
283
328
  ```
284
329
 
285
330
  ### Imports
@@ -288,7 +333,7 @@ interface Article {
288
333
  |-------------|----------|
289
334
  | `@earlyseo/blog` | `EarlySeoClient`, core types, CSS constants |
290
335
  | `@earlyseo/blog/react` | Provider, hooks, components |
291
- | `@earlyseo/blog/next` | Next.js page creators, metadata helpers |
336
+ | `@earlyseo/blog/next` | Next.js page creators, metadata helpers, sitemap helpers |
292
337
  | `@earlyseo/blog/css` | `ARTICLE_CSS`, `BLOG_CSS` |
293
338
 
294
339
  ---
@@ -1,5 +1,6 @@
1
1
  export { createBlogListPage, type BlogListPageOptions } from "./blog-list-page";
2
2
  export { createBlogPostPage, createBlogPostMetadata, createBlogListMetadata, type BlogPostPageOptions, } from "./blog-post-page";
3
3
  export { BackLink } from "./back-link";
4
+ export { createBlogSitemap, getBlogSitemapEntries, type BlogSitemapOptions, type SitemapEntry, } from "./sitemap";
4
5
  export { EarlySeoClient } from "../client";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,kBAAkB,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,EACtB,KAAK,mBAAmB,GACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
@@ -6,6 +6,8 @@ export { createBlogListPage } from "./blog-list-page";
6
6
  export { createBlogPostPage, createBlogPostMetadata, createBlogListMetadata, } from "./blog-post-page";
7
7
  // Client components
8
8
  export { BackLink } from "./back-link";
9
+ // Sitemap
10
+ export { createBlogSitemap, getBlogSitemapEntries, } from "./sitemap";
9
11
  // Re-export client for convenience
10
12
  export { EarlySeoClient } from "../client";
11
13
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mCAAmC;AACnC,gFAAgF;AAEhF,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAA4B,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,kBAAkB,CAAC;AAE1B,oBAAoB;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,mCAAmC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/next/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,mCAAmC;AACnC,gFAAgF;AAEhF,yBAAyB;AACzB,OAAO,EAAE,kBAAkB,EAA4B,MAAM,kBAAkB,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,sBAAsB,GAEvB,MAAM,kBAAkB,CAAC;AAE1B,oBAAoB;AACpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,UAAU;AACV,OAAO,EACL,iBAAiB,EACjB,qBAAqB,GAGtB,MAAM,WAAW,CAAC;AAEnB,mCAAmC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { EarlySeoConfig } from "../types";
2
+ export interface BlogSitemapOptions extends EarlySeoConfig {
3
+ /**
4
+ * Your site's public base URL (e.g. "https://example.com").
5
+ * If omitted, falls back to NEXT_PUBLIC_BASE_URL env var,
6
+ * then to the request Host header (via next/headers).
7
+ */
8
+ baseUrl?: string;
9
+ /** Blog base path (default: "/blog") */
10
+ basePath?: string;
11
+ /** Change frequency hint for sitemap (default: "weekly") */
12
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
13
+ /** Priority hint for blog articles (default: 0.7) */
14
+ priority?: number;
15
+ /** Additional fetch options (e.g. `{ next: { revalidate: 60 } }`) */
16
+ fetchInit?: RequestInit;
17
+ }
18
+ export interface SitemapEntry {
19
+ url: string;
20
+ lastModified?: Date | string;
21
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
22
+ priority?: number;
23
+ }
24
+ /**
25
+ * Fetches all published blog articles and returns an array of sitemap entries.
26
+ * Use this when you want to merge blog entries into an existing sitemap.
27
+ */
28
+ export declare function getBlogSitemapEntries(options: BlogSitemapOptions): Promise<SitemapEntry[]>;
29
+ /**
30
+ * Creates a Next.js App Router sitemap function that returns blog article entries.
31
+ * Use as the default export of `app/blog/sitemap.ts` (serves `/blog/sitemap.xml`).
32
+ */
33
+ export declare function createBlogSitemap(options: BlogSitemapOptions): () => Promise<SitemapEntry[]>;
34
+ //# sourceMappingURL=sitemap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.d.ts","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,MAAM,WAAW,kBAAmB,SAAQ,cAAc;IACxD;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,eAAe,CAAC,EACZ,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;IACZ,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,SAAS,CAAC,EAAE,WAAW,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IAC7B,eAAe,CAAC,EACZ,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,OAAO,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA2BD;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CA8CzB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,SAC1B,OAAO,CAAC,YAAY,EAAE,CAAC,CAGzD"}
@@ -0,0 +1,100 @@
1
+ // ─────────────────────────────────────────────────────────────────────────────
2
+ // @earlyseo/blog — Next.js Sitemap Helper
3
+ // ─────────────────────────────────────────────────────────────────────────────
4
+ // Generates sitemap entries for all published blog articles.
5
+ // Designed for Next.js App Router `app/blog/sitemap.ts` files.
6
+ //
7
+ // Usage:
8
+ // // app/blog/sitemap.ts → serves /blog/sitemap.xml
9
+ // import { createBlogSitemap } from "@earlyseo/blog/next";
10
+ //
11
+ // const siteId = process.env.EARLYSEO_SITE_ID!;
12
+ // export default createBlogSitemap({ siteId });
13
+ // // baseUrl is auto-detected from NEXT_PUBLIC_BASE_URL or the request host
14
+ //
15
+ // // Or merge with your own sitemap entries:
16
+ // import { getBlogSitemapEntries } from "@earlyseo/blog/next";
17
+ //
18
+ // export default async function sitemap() {
19
+ // const blogEntries = await getBlogSitemapEntries({
20
+ // siteId: process.env.EARLYSEO_SITE_ID!,
21
+ // });
22
+ // return [
23
+ // { url: "https://example.com", lastModified: new Date() },
24
+ // ...blogEntries,
25
+ // ];
26
+ // }
27
+ // ─────────────────────────────────────────────────────────────────────────────
28
+ import { EarlySeoClient } from "../client";
29
+ /**
30
+ * Resolve the base URL from: explicit option → NEXT_PUBLIC_BASE_URL → Host header.
31
+ */
32
+ async function resolveBaseUrl(explicit) {
33
+ if (explicit)
34
+ return explicit;
35
+ const envUrl = process.env.NEXT_PUBLIC_BASE_URL;
36
+ if (envUrl)
37
+ return envUrl;
38
+ // Fallback: read host from the incoming request via next/headers
39
+ try {
40
+ const { headers } = await import("next/headers");
41
+ const headerStore = await headers();
42
+ const host = headerStore.get("host");
43
+ if (host) {
44
+ const proto = headerStore.get("x-forwarded-proto") ?? "https";
45
+ return `${proto}://${host}`;
46
+ }
47
+ }
48
+ catch {
49
+ // next/headers unavailable (e.g. build time) — fall through
50
+ }
51
+ return "https://localhost:3000";
52
+ }
53
+ /**
54
+ * Fetches all published blog articles and returns an array of sitemap entries.
55
+ * Use this when you want to merge blog entries into an existing sitemap.
56
+ */
57
+ export async function getBlogSitemapEntries(options) {
58
+ const { siteId, cdnBaseUrl, baseUrl: explicitBaseUrl, basePath = "/blog", changeFrequency = "weekly", priority = 0.7, fetchInit, } = options;
59
+ const baseUrl = await resolveBaseUrl(explicitBaseUrl);
60
+ const client = new EarlySeoClient({ siteId, cdnBaseUrl }, fetchInit);
61
+ const entries = [];
62
+ const manifest = await client.getManifest();
63
+ if (!manifest)
64
+ return entries;
65
+ const normalizedBase = baseUrl.replace(/\/+$/, "");
66
+ const normalizedPath = basePath.replace(/\/+$/, "");
67
+ // Add the blog list page itself
68
+ entries.push({
69
+ url: `${normalizedBase}${normalizedPath}`,
70
+ lastModified: manifest.updatedAt,
71
+ changeFrequency,
72
+ priority: priority - 0.1,
73
+ });
74
+ // Fetch all list pages to gather every article slug
75
+ const totalPages = manifest.totalPages;
76
+ for (let page = 1; page <= totalPages; page++) {
77
+ const listPage = await client.getListPage(page);
78
+ if (!listPage)
79
+ continue;
80
+ for (const article of listPage.articles) {
81
+ entries.push({
82
+ url: `${normalizedBase}${normalizedPath}/${article.slug}`,
83
+ lastModified: article.createdAt,
84
+ changeFrequency,
85
+ priority,
86
+ });
87
+ }
88
+ }
89
+ return entries;
90
+ }
91
+ /**
92
+ * Creates a Next.js App Router sitemap function that returns blog article entries.
93
+ * Use as the default export of `app/blog/sitemap.ts` (serves `/blog/sitemap.xml`).
94
+ */
95
+ export function createBlogSitemap(options) {
96
+ return async function sitemap() {
97
+ return getBlogSitemapEntries(options);
98
+ };
99
+ }
100
+ //# sourceMappingURL=sitemap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sitemap.js","sourceRoot":"","sources":["../../src/next/sitemap.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earlyseo/blog",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Drop-in blog integration for React & Next.js — powered by EarlySEO. Articles are served from EarlySEO's CDN. Just add your site ID and render.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli/init.mjs CHANGED
@@ -100,6 +100,17 @@ export const generateMetadata = createBlogPostMetadata({
100
100
  `;
101
101
  }
102
102
 
103
+ function blogSitemapPage(siteId) {
104
+ return `import { createBlogSitemap } from "@earlyseo/blog/next";
105
+
106
+ const siteId = process.env.EARLYSEO_SITE_ID ?? "${siteId}";
107
+
108
+ // baseUrl is auto-detected from NEXT_PUBLIC_BASE_URL or the request Host header.
109
+ // You can also pass it explicitly: createBlogSitemap({ siteId, baseUrl: "https://example.com" })
110
+ export default createBlogSitemap({ siteId });
111
+ `;
112
+ }
113
+
103
114
  // ── Main ─────────────────────────────────────────────────────────────────────
104
115
 
105
116
  async function main() {
@@ -177,9 +188,14 @@ async function main() {
177
188
  await writeFileSafe(listPagePath, blogListPage(siteId));
178
189
  await writeFileSafe(postPagePath, blogPostPage(siteId));
179
190
 
180
- // 6. Add EARLYSEO_SITE_ID to .env.local
191
+ // 5b. Generate blog sitemap (scoped to /blog/sitemap.xml)
192
+ const sitemapPath = `${blogDir}/sitemap.ts`;
193
+ await writeFileSafe(sitemapPath, blogSitemapPage(siteId));
194
+
195
+ // 6. Add EARLYSEO_SITE_ID and NEXT_PUBLIC_BASE_URL to .env.local
181
196
  const envPath = path.join(cwd, ".env.local");
182
197
  const envKey = "EARLYSEO_SITE_ID";
198
+ const baseUrlKey = "NEXT_PUBLIC_BASE_URL";
183
199
  if (fs.existsSync(envPath)) {
184
200
  const envContent = fs.readFileSync(envPath, "utf-8");
185
201
  if (envContent.includes(envKey)) {
@@ -188,9 +204,13 @@ async function main() {
188
204
  fs.appendFileSync(envPath, `\n# EarlySEO Blog SDK\n${envKey}=${siteId}\n`);
189
205
  console.log(` ✅ Added ${envKey} to .env.local`);
190
206
  }
207
+ if (!envContent.includes(baseUrlKey)) {
208
+ fs.appendFileSync(envPath, `${baseUrlKey}=https://example.com\n`);
209
+ console.log(` ✅ Added ${baseUrlKey} to .env.local (update with your site URL)`);
210
+ }
191
211
  } else {
192
- fs.writeFileSync(envPath, `# EarlySEO Blog SDK\n${envKey}=${siteId}\n`, "utf-8");
193
- console.log(` ✅ Created .env.local with ${envKey}`);
212
+ fs.writeFileSync(envPath, `# EarlySEO Blog SDK\n${envKey}=${siteId}\n${baseUrlKey}=https://example.com\n`, "utf-8");
213
+ console.log(` ✅ Created .env.local with ${envKey} and ${baseUrlKey}`);
194
214
  }
195
215
 
196
216
  // 7. Done
@@ -199,9 +219,11 @@ async function main() {
199
219
  console.log(" ✓ Setup complete! Your blog is ready at /blog");
200
220
  console.log();
201
221
  console.log(" Next steps:");
202
- console.log(" 1. Start your dev server: npm run dev");
203
- console.log(" 2. Visit: http://localhost:3000/blog");
204
- console.log(" 3. Publish articles from your EarlySEO dashboard");
222
+ console.log(" 1. Optionally set NEXT_PUBLIC_BASE_URL in .env.local (auto-detected from Host if missing)");
223
+ console.log(" 2. Start your dev server: npm run dev");
224
+ console.log(" 3. Visit: http://localhost:3000/blog");
225
+ console.log(" 4. Blog sitemap at: http://localhost:3000/blog/sitemap.xml");
226
+ console.log(" 5. Publish articles from your EarlySEO dashboard");
205
227
  console.log();
206
228
  console.log(" Docs: https://www.npmjs.com/package/@earlyseo/blog");
207
229
  console.log();