@xexr/blog-platform 1.1.4 → 1.1.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/CHANGELOG.md +8 -0
- package/dist/app/blog/[slug]/page.tsx +10 -3
- package/dist/app/blog/page.tsx +12 -11
- package/dist/app/blog/series/[slug]/page.d.ts +28 -0
- package/dist/app/blog/series/[slug]/page.tsx +39 -0
- package/dist/app/blog/series/page.d.ts +24 -0
- package/dist/app/blog/series/page.tsx +28 -0
- package/dist/components/ArchiveStructuredData.tsx +61 -0
- package/dist/components/SeriesArchivePages.tsx +222 -0
- package/dist/components/SeriesNavigation.tsx +117 -0
- package/dist/components/TopicArchivePages.test.ts +52 -4
- package/dist/components/TopicArchivePages.tsx +14 -4
- package/dist/{index-Dr8HaKGm.d.mts → index-DsXjuPn4.d.mts} +45 -1
- package/dist/{index-Dr8HaKGm.d.ts → index-DsXjuPn4.d.ts} +45 -1
- package/dist/index.d.mts +86 -5
- package/dist/index.d.ts +86 -5
- package/dist/index.js +14 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -14
- package/dist/index.mjs.map +1 -1
- package/dist/lib/related-articles.d.mts +3 -2
- package/dist/lib/related-articles.d.ts +3 -2
- package/dist/lib/series.ts +55 -0
- package/dist/lib/sitemap.ts +78 -46
- package/dist/lib/storage/drizzle.ts +9 -0
- package/dist/lib/structured-data.ts +10 -11
- package/dist/lib/urls.ts +7 -0
- package/dist/{sitemap-BmCh8BpN.d.ts → sitemap-B64QGT4l.d.ts} +11 -4
- package/dist/{sitemap-Dbl4CUGI.d.mts → sitemap-Dy7Q4ATM.d.mts} +11 -4
- package/dist/sitemap.d.mts +2 -2
- package/dist/sitemap.d.ts +2 -2
- package/dist/sitemap.js +5 -5
- package/dist/sitemap.js.map +1 -1
- package/dist/sitemap.mjs +5 -5
- package/dist/sitemap.mjs.map +1 -1
- package/dist/types/contracts.ts +61 -0
- package/dist/types/index.d.mts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +12 -13
|
@@ -2,10 +2,8 @@ import React from "react";
|
|
|
2
2
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
BlogTopicsIndexPage,
|
|
8
|
-
} from "./TopicArchivePages";
|
|
5
|
+
import { BlogTopicArchivePage, BlogTopicsIndexPage } from "./TopicArchivePages";
|
|
6
|
+
import { BlogSeriesArchivePage } from "./SeriesArchivePages";
|
|
9
7
|
import type { PublishedArticle, PublishedSite } from "../types/contracts";
|
|
10
8
|
|
|
11
9
|
const site: PublishedSite = {
|
|
@@ -99,3 +97,53 @@ describe("Blog topic archive pages", () => {
|
|
|
99
97
|
expect(html).not.toContain("h-full w-full object-contain");
|
|
100
98
|
});
|
|
101
99
|
});
|
|
100
|
+
|
|
101
|
+
function schemas(html: string): unknown[] {
|
|
102
|
+
return [
|
|
103
|
+
...html.matchAll(/<script type="application\/ld\+json">(.*?)<\/script>/g),
|
|
104
|
+
].flatMap((match): unknown[] => JSON.parse(match[1]!) as unknown[]);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
it("renders topic archive collection and breadcrumbs for the listed articles", () => {
|
|
108
|
+
const data = schemas(
|
|
109
|
+
renderToStaticMarkup(
|
|
110
|
+
React.createElement(BlogTopicArchivePage, {
|
|
111
|
+
articles: [article],
|
|
112
|
+
topicSlug: "recurring-work-and-routines",
|
|
113
|
+
basePath: "/new-blog",
|
|
114
|
+
}),
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
expect(JSON.stringify(data)).toContain(
|
|
118
|
+
"https://example.com/new-blog/useful-routines",
|
|
119
|
+
);
|
|
120
|
+
expect(JSON.stringify(data)).toContain("CollectionPage");
|
|
121
|
+
expect(JSON.stringify(data)).toContain("BreadcrumbList");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("renders series archive collection and breadcrumbs for the listed articles", () => {
|
|
125
|
+
const seriesArticle = {
|
|
126
|
+
...article,
|
|
127
|
+
series: {
|
|
128
|
+
id: "s",
|
|
129
|
+
title: "Routines",
|
|
130
|
+
slug: "routines",
|
|
131
|
+
position: 1,
|
|
132
|
+
total: 1,
|
|
133
|
+
articles: [],
|
|
134
|
+
},
|
|
135
|
+
};
|
|
136
|
+
const data = schemas(
|
|
137
|
+
renderToStaticMarkup(
|
|
138
|
+
React.createElement(BlogSeriesArchivePage, {
|
|
139
|
+
articles: [seriesArticle],
|
|
140
|
+
seriesSlug: "routines",
|
|
141
|
+
}),
|
|
142
|
+
),
|
|
143
|
+
);
|
|
144
|
+
expect(JSON.stringify(data)).toContain(
|
|
145
|
+
"https://example.com/blog/useful-routines",
|
|
146
|
+
);
|
|
147
|
+
expect(JSON.stringify(data)).toContain("CollectionPage");
|
|
148
|
+
expect(JSON.stringify(data)).toContain("BreadcrumbList");
|
|
149
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import { ArchiveStructuredData } from "./ArchiveStructuredData";
|
|
2
3
|
import Link from "next/link.js";
|
|
3
4
|
import Image from "next/image.js";
|
|
4
5
|
import { formatDistanceToNow } from "date-fns";
|
|
@@ -52,7 +53,7 @@ export function BlogTopicsIndexPage({
|
|
|
52
53
|
<header className="mb-10 space-y-3 text-center">
|
|
53
54
|
<Link
|
|
54
55
|
href={normalizedBasePath}
|
|
55
|
-
className="text-muted-foreground hover:text-[var(--blog-accent)]
|
|
56
|
+
className="text-muted-foreground text-sm font-medium transition-colors hover:text-[var(--blog-accent)]"
|
|
56
57
|
>
|
|
57
58
|
Back to all articles
|
|
58
59
|
</Link>
|
|
@@ -88,7 +89,7 @@ export function BlogTopicsIndexPage({
|
|
|
88
89
|
href={buildBlogPath(normalizedBasePath, `topics/${topic.slug}`)}
|
|
89
90
|
className="group rounded-2xl border border-[var(--blog-accent-border)] bg-[var(--blog-card-bg)] p-5 transition hover:border-[var(--blog-accent)] hover:no-underline"
|
|
90
91
|
>
|
|
91
|
-
<h2 className="group-hover:text-[var(--blog-accent)]
|
|
92
|
+
<h2 className="text-xl font-semibold transition-colors group-hover:text-[var(--blog-accent)]">
|
|
92
93
|
{topic.name}
|
|
93
94
|
</h2>
|
|
94
95
|
{topic.description && (
|
|
@@ -126,10 +127,19 @@ export function BlogTopicArchivePage({
|
|
|
126
127
|
className,
|
|
127
128
|
)}
|
|
128
129
|
>
|
|
130
|
+
{archive && (
|
|
131
|
+
<ArchiveStructuredData
|
|
132
|
+
articles={archive.articles}
|
|
133
|
+
title={archive.topic.name}
|
|
134
|
+
kind="topics"
|
|
135
|
+
slug={topicSlug}
|
|
136
|
+
basePath={normalizedBasePath}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
129
139
|
<header className="mb-10 space-y-3 text-center">
|
|
130
140
|
<Link
|
|
131
141
|
href={buildBlogPath(normalizedBasePath, "topics")}
|
|
132
|
-
className="text-muted-foreground hover:text-[var(--blog-accent)]
|
|
142
|
+
className="text-muted-foreground text-sm font-medium transition-colors hover:text-[var(--blog-accent)]"
|
|
133
143
|
>
|
|
134
144
|
Back to all topics
|
|
135
145
|
</Link>
|
|
@@ -202,7 +212,7 @@ function TopicArticleCard({
|
|
|
202
212
|
<span className="inline-flex rounded-full border border-[var(--blog-accent-border)] px-2.5 py-1 text-xs font-medium text-[var(--blog-text-accent)]">
|
|
203
213
|
{topic.name}
|
|
204
214
|
</span>
|
|
205
|
-
<h2 className="group-hover:text-[var(--blog-accent)]
|
|
215
|
+
<h2 className="text-xl font-semibold text-balance transition-colors group-hover:text-[var(--blog-accent)]">
|
|
206
216
|
{article.title}
|
|
207
217
|
</h2>
|
|
208
218
|
{article.excerpt && (
|
|
@@ -44,6 +44,8 @@ interface PublishedAuthor {
|
|
|
44
44
|
readonly pronouns?: string;
|
|
45
45
|
/** Whether this is a guest author */
|
|
46
46
|
readonly isGuest: boolean;
|
|
47
|
+
/** Areas of subject expertise. */
|
|
48
|
+
readonly expertise?: readonly string[];
|
|
47
49
|
/** Tone adjectives that describe this author's writing style */
|
|
48
50
|
readonly toneAdjectives: readonly string[];
|
|
49
51
|
}
|
|
@@ -122,6 +124,46 @@ interface PublishedTopic {
|
|
|
122
124
|
/** Whether this is the article's primary topic */
|
|
123
125
|
readonly isPrimary: boolean;
|
|
124
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Compact link metadata for an article within a published series.
|
|
129
|
+
*/
|
|
130
|
+
interface PublishedSeriesArticleLink {
|
|
131
|
+
/** Unique article identifier */
|
|
132
|
+
readonly id: string;
|
|
133
|
+
/** URL-friendly article slug */
|
|
134
|
+
readonly slug: string;
|
|
135
|
+
/** Display title */
|
|
136
|
+
readonly title: string;
|
|
137
|
+
/** Ordered position within the series */
|
|
138
|
+
readonly position: number;
|
|
139
|
+
/** Whether this entry is the current article */
|
|
140
|
+
readonly isCurrent: boolean;
|
|
141
|
+
/** Optional excerpt for archive/list rendering */
|
|
142
|
+
readonly excerpt?: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Reader-facing series context for a published article.
|
|
146
|
+
*/
|
|
147
|
+
interface PublishedSeriesContext {
|
|
148
|
+
/** Unique series identifier */
|
|
149
|
+
readonly id: string;
|
|
150
|
+
/** Display title */
|
|
151
|
+
readonly title: string;
|
|
152
|
+
/** URL-friendly series slug */
|
|
153
|
+
readonly slug: string;
|
|
154
|
+
/** Optional public description */
|
|
155
|
+
readonly description?: string;
|
|
156
|
+
/** Current article position in the series */
|
|
157
|
+
readonly position: number;
|
|
158
|
+
/** Number of visible articles in the series context */
|
|
159
|
+
readonly total: number;
|
|
160
|
+
/** Previous published article in the series, when available */
|
|
161
|
+
readonly previous?: PublishedSeriesArticleLink;
|
|
162
|
+
/** Next published article in the series, when available */
|
|
163
|
+
readonly next?: PublishedSeriesArticleLink;
|
|
164
|
+
/** Ordered article list for compact navigation and archive pages */
|
|
165
|
+
readonly articles: readonly PublishedSeriesArticleLink[];
|
|
166
|
+
}
|
|
125
167
|
/**
|
|
126
168
|
* Represents a published article with all necessary metadata for rendering
|
|
127
169
|
* on external blog platforms.
|
|
@@ -153,6 +195,8 @@ interface PublishedArticle {
|
|
|
153
195
|
readonly cta?: PublishedArticleCta;
|
|
154
196
|
/** Public topic taxonomy assigned to the article */
|
|
155
197
|
readonly topics?: readonly PublishedTopic[];
|
|
198
|
+
/** Optional ordered series context for article navigation */
|
|
199
|
+
readonly series?: PublishedSeriesContext;
|
|
156
200
|
/** Featured image URL (optional) */
|
|
157
201
|
readonly featuredImage?: string;
|
|
158
202
|
/** Alt text for featured image */
|
|
@@ -226,4 +270,4 @@ interface PublishResult {
|
|
|
226
270
|
readonly idempotencyKey: string;
|
|
227
271
|
}
|
|
228
272
|
|
|
229
|
-
export type { PublishedTopic as P, PublishedArticle as a, PublishedSite as b, PublishedAuthor as c, PublishedNewsletterSettings as d, PublishedArticleCta as e, PublishResult as f,
|
|
273
|
+
export type { PublishedTopic as P, PublishedArticle as a, PublishedSite as b, PublishedAuthor as c, PublishedNewsletterSettings as d, PublishedArticleCta as e, PublishResult as f, PublishedSeriesContext as g, PublishPayload as h, PublishedAuthorSocialLinks as i };
|
|
@@ -44,6 +44,8 @@ interface PublishedAuthor {
|
|
|
44
44
|
readonly pronouns?: string;
|
|
45
45
|
/** Whether this is a guest author */
|
|
46
46
|
readonly isGuest: boolean;
|
|
47
|
+
/** Areas of subject expertise. */
|
|
48
|
+
readonly expertise?: readonly string[];
|
|
47
49
|
/** Tone adjectives that describe this author's writing style */
|
|
48
50
|
readonly toneAdjectives: readonly string[];
|
|
49
51
|
}
|
|
@@ -122,6 +124,46 @@ interface PublishedTopic {
|
|
|
122
124
|
/** Whether this is the article's primary topic */
|
|
123
125
|
readonly isPrimary: boolean;
|
|
124
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Compact link metadata for an article within a published series.
|
|
129
|
+
*/
|
|
130
|
+
interface PublishedSeriesArticleLink {
|
|
131
|
+
/** Unique article identifier */
|
|
132
|
+
readonly id: string;
|
|
133
|
+
/** URL-friendly article slug */
|
|
134
|
+
readonly slug: string;
|
|
135
|
+
/** Display title */
|
|
136
|
+
readonly title: string;
|
|
137
|
+
/** Ordered position within the series */
|
|
138
|
+
readonly position: number;
|
|
139
|
+
/** Whether this entry is the current article */
|
|
140
|
+
readonly isCurrent: boolean;
|
|
141
|
+
/** Optional excerpt for archive/list rendering */
|
|
142
|
+
readonly excerpt?: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Reader-facing series context for a published article.
|
|
146
|
+
*/
|
|
147
|
+
interface PublishedSeriesContext {
|
|
148
|
+
/** Unique series identifier */
|
|
149
|
+
readonly id: string;
|
|
150
|
+
/** Display title */
|
|
151
|
+
readonly title: string;
|
|
152
|
+
/** URL-friendly series slug */
|
|
153
|
+
readonly slug: string;
|
|
154
|
+
/** Optional public description */
|
|
155
|
+
readonly description?: string;
|
|
156
|
+
/** Current article position in the series */
|
|
157
|
+
readonly position: number;
|
|
158
|
+
/** Number of visible articles in the series context */
|
|
159
|
+
readonly total: number;
|
|
160
|
+
/** Previous published article in the series, when available */
|
|
161
|
+
readonly previous?: PublishedSeriesArticleLink;
|
|
162
|
+
/** Next published article in the series, when available */
|
|
163
|
+
readonly next?: PublishedSeriesArticleLink;
|
|
164
|
+
/** Ordered article list for compact navigation and archive pages */
|
|
165
|
+
readonly articles: readonly PublishedSeriesArticleLink[];
|
|
166
|
+
}
|
|
125
167
|
/**
|
|
126
168
|
* Represents a published article with all necessary metadata for rendering
|
|
127
169
|
* on external blog platforms.
|
|
@@ -153,6 +195,8 @@ interface PublishedArticle {
|
|
|
153
195
|
readonly cta?: PublishedArticleCta;
|
|
154
196
|
/** Public topic taxonomy assigned to the article */
|
|
155
197
|
readonly topics?: readonly PublishedTopic[];
|
|
198
|
+
/** Optional ordered series context for article navigation */
|
|
199
|
+
readonly series?: PublishedSeriesContext;
|
|
156
200
|
/** Featured image URL (optional) */
|
|
157
201
|
readonly featuredImage?: string;
|
|
158
202
|
/** Alt text for featured image */
|
|
@@ -226,4 +270,4 @@ interface PublishResult {
|
|
|
226
270
|
readonly idempotencyKey: string;
|
|
227
271
|
}
|
|
228
272
|
|
|
229
|
-
export type { PublishedTopic as P, PublishedArticle as a, PublishedSite as b, PublishedAuthor as c, PublishedNewsletterSettings as d, PublishedArticleCta as e, PublishResult as f,
|
|
273
|
+
export type { PublishedTopic as P, PublishedArticle as a, PublishedSite as b, PublishedAuthor as c, PublishedNewsletterSettings as d, PublishedArticleCta as e, PublishResult as f, PublishedSeriesContext as g, PublishPayload as h, PublishedAuthorSocialLinks as i };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as PublishedArticle, b as PublishedSite, d as PublishedNewsletterSettings, e as PublishedArticleCta, c as PublishedAuthor, f as PublishResult, P as PublishedTopic } from './index-
|
|
2
|
-
export {
|
|
1
|
+
import { a as PublishedArticle, b as PublishedSite, d as PublishedNewsletterSettings, e as PublishedArticleCta, c as PublishedAuthor, f as PublishResult, P as PublishedTopic, g as PublishedSeriesContext } from './index-DsXjuPn4.mjs';
|
|
2
|
+
export { h as PublishPayload, i as PublishedAuthorSocialLinks } from './index-DsXjuPn4.mjs';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { CSSProperties, ReactElement } from 'react';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
@@ -10,8 +10,8 @@ export { RelatedArticleCandidate, RelatedFeaturedArticlesOptions, getRelatedFeat
|
|
|
10
10
|
import { NextRequest, NextResponse } from 'next/server.js';
|
|
11
11
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
12
12
|
import { LibSQLDatabase } from 'drizzle-orm/libsql';
|
|
13
|
-
import { C as CanonicalUrlOptions } from './sitemap-
|
|
14
|
-
export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, f as generateCanonicalUrl, h as generateCanonicalUrlFromSlug, i as generateSitemap, j as generateSitemapIndex, k as getBaseUrl, l as isValidCanonicalUrl, n as normalizeDomain, m as normalizeSlug, s as sitemapToXml, u as updateArticleCanonicalUrl, v as validateSitemap } from './sitemap-
|
|
13
|
+
import { C as CanonicalUrlOptions } from './sitemap-Dy7Q4ATM.mjs';
|
|
14
|
+
export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, f as generateCanonicalUrl, h as generateCanonicalUrlFromSlug, i as generateSitemap, j as generateSitemapIndex, k as getBaseUrl, l as isValidCanonicalUrl, n as normalizeDomain, m as normalizeSlug, s as sitemapToXml, u as updateArticleCanonicalUrl, v as validateSitemap } from './sitemap-Dy7Q4ATM.mjs';
|
|
15
15
|
|
|
16
16
|
interface BlogTheme {
|
|
17
17
|
accentColor?: string;
|
|
@@ -159,6 +159,52 @@ declare function generateArticleMetadata(
|
|
|
159
159
|
};
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
+
interface BlogSeriesPageProps {
|
|
163
|
+
articles: PublishedArticle[];
|
|
164
|
+
basePath?: string;
|
|
165
|
+
title?: string;
|
|
166
|
+
description?: string;
|
|
167
|
+
className?: string;
|
|
168
|
+
theme?: BlogTheme;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
declare function BlogSeriesPage(
|
|
172
|
+
props: BlogSeriesPageProps,
|
|
173
|
+
): ReactElement;
|
|
174
|
+
|
|
175
|
+
declare function generateSeriesIndexMetadata(basePath?: string): {
|
|
176
|
+
title: string;
|
|
177
|
+
description: string;
|
|
178
|
+
alternates: {
|
|
179
|
+
canonical: string;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
interface BlogSeriesArchiveRoutePageProps {
|
|
184
|
+
articles: PublishedArticle[];
|
|
185
|
+
seriesSlug: string;
|
|
186
|
+
basePath?: string;
|
|
187
|
+
className?: string;
|
|
188
|
+
theme?: BlogTheme;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
declare function BlogSeriesArchiveRoutePage(
|
|
192
|
+
props: BlogSeriesArchiveRoutePageProps,
|
|
193
|
+
): ReactElement;
|
|
194
|
+
|
|
195
|
+
declare function generateSeriesArchiveMetadata(options: {
|
|
196
|
+
title: string;
|
|
197
|
+
description?: string;
|
|
198
|
+
slug: string;
|
|
199
|
+
basePath?: string;
|
|
200
|
+
}): {
|
|
201
|
+
title: string;
|
|
202
|
+
description: string;
|
|
203
|
+
alternates: {
|
|
204
|
+
canonical: string;
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
162
208
|
interface AuthorPageProps {
|
|
163
209
|
author: PublishedAuthor;
|
|
164
210
|
articles: PublishedArticle[];
|
|
@@ -297,6 +343,7 @@ declare function cn(...inputs: ClassValue[]): string;
|
|
|
297
343
|
declare function normalizeBlogBasePath(basePath?: string): string;
|
|
298
344
|
declare function buildBlogPath(basePath: string | undefined, slug?: string): string;
|
|
299
345
|
declare function buildAuthorPath(basePath: string | undefined, authorSlug: string): string;
|
|
346
|
+
declare function buildSeriesPath(basePath: string | undefined, seriesSlug: string): string;
|
|
300
347
|
declare function getPathPrefixFromBlogUrl(blogUrl: string): string;
|
|
301
348
|
|
|
302
349
|
/**
|
|
@@ -397,6 +444,14 @@ declare function getArticlePrimaryTopic(article: PublishedArticle): PublishedTop
|
|
|
397
444
|
declare function getAllTopics(articles: PublishedArticle[]): PublishedTopic[];
|
|
398
445
|
declare function getTopicArchive(articles: PublishedArticle[], topicSlug: string): TopicArchive | null;
|
|
399
446
|
|
|
447
|
+
interface SeriesArchive {
|
|
448
|
+
series: PublishedSeriesContext;
|
|
449
|
+
articles: PublishedArticle[];
|
|
450
|
+
}
|
|
451
|
+
declare function getAllSeries(articles: PublishedArticle[]): PublishedSeriesContext[];
|
|
452
|
+
declare function getSeriesArchive(articles: PublishedArticle[], seriesSlug: string): SeriesArchive | null;
|
|
453
|
+
declare function getArticleSeriesNavigation(article: PublishedArticle): PublishedSeriesContext | null;
|
|
454
|
+
|
|
400
455
|
interface BlogTopicsIndexPageProps {
|
|
401
456
|
articles: PublishedArticle[];
|
|
402
457
|
basePath?: string;
|
|
@@ -415,6 +470,31 @@ interface BlogTopicArchivePageProps {
|
|
|
415
470
|
declare function BlogTopicsIndexPage({ articles, basePath, title, description, className, theme, }: BlogTopicsIndexPageProps): react_jsx_runtime.JSX.Element;
|
|
416
471
|
declare function BlogTopicArchivePage({ articles, topicSlug, basePath, className, theme, }: BlogTopicArchivePageProps): react_jsx_runtime.JSX.Element;
|
|
417
472
|
|
|
473
|
+
interface BlogSeriesIndexPageProps {
|
|
474
|
+
articles: PublishedArticle[];
|
|
475
|
+
basePath?: string;
|
|
476
|
+
title?: string;
|
|
477
|
+
description?: string;
|
|
478
|
+
className?: string;
|
|
479
|
+
theme?: BlogTheme;
|
|
480
|
+
}
|
|
481
|
+
interface BlogSeriesArchivePageProps {
|
|
482
|
+
articles: PublishedArticle[];
|
|
483
|
+
seriesSlug: string;
|
|
484
|
+
basePath?: string;
|
|
485
|
+
className?: string;
|
|
486
|
+
theme?: BlogTheme;
|
|
487
|
+
}
|
|
488
|
+
declare function BlogSeriesIndexPage({ articles, basePath, title, description, className, theme, }: BlogSeriesIndexPageProps): react_jsx_runtime.JSX.Element;
|
|
489
|
+
declare function BlogSeriesArchivePage({ articles, seriesSlug, basePath, className, theme, }: BlogSeriesArchivePageProps): react_jsx_runtime.JSX.Element;
|
|
490
|
+
|
|
491
|
+
interface SeriesNavigationProps {
|
|
492
|
+
article: PublishedArticle;
|
|
493
|
+
basePath?: string;
|
|
494
|
+
className?: string;
|
|
495
|
+
}
|
|
496
|
+
declare function SeriesNavigation({ article, basePath, className, }: SeriesNavigationProps): react_jsx_runtime.JSX.Element | null;
|
|
497
|
+
|
|
418
498
|
interface BlogAuthorsIndexPageProps {
|
|
419
499
|
articles: PublishedArticle[];
|
|
420
500
|
basePath?: string;
|
|
@@ -2203,4 +2283,5 @@ declare function OPTIONS(request: NextRequest): Promise<NextResponse>;
|
|
|
2203
2283
|
|
|
2204
2284
|
declare const PACKAGE_VERSION: string;
|
|
2205
2285
|
|
|
2206
|
-
export { ApiKeyAuth,
|
|
2286
|
+
export { ApiKeyAuth, BLOG_PLATFORM_SCHEMA_VERSION, BLOG_PLATFORM_TABLE_NAMES, ArticlePage as BlogArticlePage, AuthorPage as BlogAuthorPage, BlogAuthorsIndexPage, BlogHomePage, BlogPlatformSchemaError, BlogSeriesArchivePage, BlogSeriesArchiveRoutePage, BlogSeriesIndexPage, BlogSeriesPage, BlogTopicArchivePage, BlogTopicsIndexPage, Button, CanonicalUrlOptions, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, DrizzleStorage, EnvAuth, InMemoryStorage, NEWSLETTER_SUCCESS_MESSAGE, NewsletterSignup, NoAuth, PACKAGE_VERSION, Pagination$1 as Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PublishResult, PublishedArticle, PublishedAuthor, PublishedNewsletterSettings, PublishedSite, PublishedTopic, SeriesNavigation, Pagination as ShadcnPagination, StructuredDataError, UninitializedAuth, autoConfigureRateLimit, blogPlatformDrizzleSchema, bpArticles, bpMetadata, bpOperations, buildAuthorPath, buildBlogPath, buildSeriesPath, buttonVariants, checkDrizzleAdapterSchema, checkRateLimit, cn, POST as configHandler, OPTIONS$1 as configOptionsHandler, configureRateLimit, createRateLimitErrorResponse, createStructuredDataScript, createTokenFingerprint, enforceRateLimit, ensureDrizzleAdapterSchema, extractKeywordsFromArticle, extractTableOfContents, extractTokenFromHeader, formatArticleDateMeta, generateArticleMetadata, generateArticleStructuredData, generateAuthorPageMetadata, generateAuthorStructuredData, generateBlogHomeMetadata, generateBlogHomeStructuredData, generateBreadcrumbStructuredData, generateCompleteArticleStructuredData, generateOrganizationStructuredData, generatePaginationMetadata, generateSeriesArchiveMetadata, generateSeriesIndexMetadata, generateSiteMetadata, generateWebSiteStructuredData, getAllSeries, getAllTopics, getArticlePrimaryTopic, getArticleSeriesNavigation, getAuthConfig, getAuthorArchive, getAuthorsFromArticles, getBlogThemeStyle, getDrizzleAdapterSql, getPathPrefixFromBlogUrl, getRateLimitHeaders, getSeriesArchive, getStorage, getTopicArchive, GET$1 as indexNowKeyRoute, initBlogPlatform, initBlogPlatformDev, initBlogPlatformOnce, initBlogPlatformProd, initEnvAuth, loadAuthorArchive, metadataToHtml, normalizeBlogBasePath, POST$2 as publishHandler, safeGenerateArticleStructuredData, setAuthConfig, setStorage, shouldSkipAuth, GET as slugExistsHandler, OPTIONS as slugExistsOptionsHandler, structuredDataToJsonLd, POST$1 as unpublishHandler, usePagination, validateMetadata, validateStructuredData, GET$2 as versionHandler };
|
|
2287
|
+
export type { AuthConfig, AuthResult, AuthorArchive, AuthorArchiveOptions, BlogPlatformConfig, BlogPlatformSchemaCheckResult, BlogPlatformStorage, BlogPlatformTableName, BlogPostingSchema, BlogTheme, BreadcrumbListSchema, GeneratedMetadata, LinkTag, MetaTag, MetadataOptions, NewsletterSignupProps, OrganizationSchema, PersonSchema, RateLimitConfig, RateLimitResult, SeriesArchive, StructuredDataOptions, TopicArchive, WebSiteSchema };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as PublishedArticle, b as PublishedSite, d as PublishedNewsletterSettings, e as PublishedArticleCta, c as PublishedAuthor, f as PublishResult, P as PublishedTopic } from './index-
|
|
2
|
-
export {
|
|
1
|
+
import { a as PublishedArticle, b as PublishedSite, d as PublishedNewsletterSettings, e as PublishedArticleCta, c as PublishedAuthor, f as PublishResult, P as PublishedTopic, g as PublishedSeriesContext } from './index-DsXjuPn4.js';
|
|
2
|
+
export { h as PublishPayload, i as PublishedAuthorSocialLinks } from './index-DsXjuPn4.js';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { CSSProperties, ReactElement } from 'react';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
@@ -10,8 +10,8 @@ export { RelatedArticleCandidate, RelatedFeaturedArticlesOptions, getRelatedFeat
|
|
|
10
10
|
import { NextRequest, NextResponse } from 'next/server.js';
|
|
11
11
|
import * as drizzle_orm_sqlite_core from 'drizzle-orm/sqlite-core';
|
|
12
12
|
import { LibSQLDatabase } from 'drizzle-orm/libsql';
|
|
13
|
-
import { C as CanonicalUrlOptions } from './sitemap-
|
|
14
|
-
export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, f as generateCanonicalUrl, h as generateCanonicalUrlFromSlug, i as generateSitemap, j as generateSitemapIndex, k as getBaseUrl, l as isValidCanonicalUrl, n as normalizeDomain, m as normalizeSlug, s as sitemapToXml, u as updateArticleCanonicalUrl, v as validateSitemap } from './sitemap-
|
|
13
|
+
import { C as CanonicalUrlOptions } from './sitemap-B64QGT4l.js';
|
|
14
|
+
export { B as BlogSitemapConfig, N as NextjsSitemapEntry, S as SitemapChangeFreq, a as SitemapData, b as SitemapEntry, c as SitemapOptions, d as createBlogSitemapRoute, e as createDynamicBlogSitemap, g as generateBlogSitemapEntries, f as generateCanonicalUrl, h as generateCanonicalUrlFromSlug, i as generateSitemap, j as generateSitemapIndex, k as getBaseUrl, l as isValidCanonicalUrl, n as normalizeDomain, m as normalizeSlug, s as sitemapToXml, u as updateArticleCanonicalUrl, v as validateSitemap } from './sitemap-B64QGT4l.js';
|
|
15
15
|
|
|
16
16
|
interface BlogTheme {
|
|
17
17
|
accentColor?: string;
|
|
@@ -159,6 +159,52 @@ declare function generateArticleMetadata(
|
|
|
159
159
|
};
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
+
interface BlogSeriesPageProps {
|
|
163
|
+
articles: PublishedArticle[];
|
|
164
|
+
basePath?: string;
|
|
165
|
+
title?: string;
|
|
166
|
+
description?: string;
|
|
167
|
+
className?: string;
|
|
168
|
+
theme?: BlogTheme;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
declare function BlogSeriesPage(
|
|
172
|
+
props: BlogSeriesPageProps,
|
|
173
|
+
): ReactElement;
|
|
174
|
+
|
|
175
|
+
declare function generateSeriesIndexMetadata(basePath?: string): {
|
|
176
|
+
title: string;
|
|
177
|
+
description: string;
|
|
178
|
+
alternates: {
|
|
179
|
+
canonical: string;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
interface BlogSeriesArchiveRoutePageProps {
|
|
184
|
+
articles: PublishedArticle[];
|
|
185
|
+
seriesSlug: string;
|
|
186
|
+
basePath?: string;
|
|
187
|
+
className?: string;
|
|
188
|
+
theme?: BlogTheme;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
declare function BlogSeriesArchiveRoutePage(
|
|
192
|
+
props: BlogSeriesArchiveRoutePageProps,
|
|
193
|
+
): ReactElement;
|
|
194
|
+
|
|
195
|
+
declare function generateSeriesArchiveMetadata(options: {
|
|
196
|
+
title: string;
|
|
197
|
+
description?: string;
|
|
198
|
+
slug: string;
|
|
199
|
+
basePath?: string;
|
|
200
|
+
}): {
|
|
201
|
+
title: string;
|
|
202
|
+
description: string;
|
|
203
|
+
alternates: {
|
|
204
|
+
canonical: string;
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
|
|
162
208
|
interface AuthorPageProps {
|
|
163
209
|
author: PublishedAuthor;
|
|
164
210
|
articles: PublishedArticle[];
|
|
@@ -297,6 +343,7 @@ declare function cn(...inputs: ClassValue[]): string;
|
|
|
297
343
|
declare function normalizeBlogBasePath(basePath?: string): string;
|
|
298
344
|
declare function buildBlogPath(basePath: string | undefined, slug?: string): string;
|
|
299
345
|
declare function buildAuthorPath(basePath: string | undefined, authorSlug: string): string;
|
|
346
|
+
declare function buildSeriesPath(basePath: string | undefined, seriesSlug: string): string;
|
|
300
347
|
declare function getPathPrefixFromBlogUrl(blogUrl: string): string;
|
|
301
348
|
|
|
302
349
|
/**
|
|
@@ -397,6 +444,14 @@ declare function getArticlePrimaryTopic(article: PublishedArticle): PublishedTop
|
|
|
397
444
|
declare function getAllTopics(articles: PublishedArticle[]): PublishedTopic[];
|
|
398
445
|
declare function getTopicArchive(articles: PublishedArticle[], topicSlug: string): TopicArchive | null;
|
|
399
446
|
|
|
447
|
+
interface SeriesArchive {
|
|
448
|
+
series: PublishedSeriesContext;
|
|
449
|
+
articles: PublishedArticle[];
|
|
450
|
+
}
|
|
451
|
+
declare function getAllSeries(articles: PublishedArticle[]): PublishedSeriesContext[];
|
|
452
|
+
declare function getSeriesArchive(articles: PublishedArticle[], seriesSlug: string): SeriesArchive | null;
|
|
453
|
+
declare function getArticleSeriesNavigation(article: PublishedArticle): PublishedSeriesContext | null;
|
|
454
|
+
|
|
400
455
|
interface BlogTopicsIndexPageProps {
|
|
401
456
|
articles: PublishedArticle[];
|
|
402
457
|
basePath?: string;
|
|
@@ -415,6 +470,31 @@ interface BlogTopicArchivePageProps {
|
|
|
415
470
|
declare function BlogTopicsIndexPage({ articles, basePath, title, description, className, theme, }: BlogTopicsIndexPageProps): react_jsx_runtime.JSX.Element;
|
|
416
471
|
declare function BlogTopicArchivePage({ articles, topicSlug, basePath, className, theme, }: BlogTopicArchivePageProps): react_jsx_runtime.JSX.Element;
|
|
417
472
|
|
|
473
|
+
interface BlogSeriesIndexPageProps {
|
|
474
|
+
articles: PublishedArticle[];
|
|
475
|
+
basePath?: string;
|
|
476
|
+
title?: string;
|
|
477
|
+
description?: string;
|
|
478
|
+
className?: string;
|
|
479
|
+
theme?: BlogTheme;
|
|
480
|
+
}
|
|
481
|
+
interface BlogSeriesArchivePageProps {
|
|
482
|
+
articles: PublishedArticle[];
|
|
483
|
+
seriesSlug: string;
|
|
484
|
+
basePath?: string;
|
|
485
|
+
className?: string;
|
|
486
|
+
theme?: BlogTheme;
|
|
487
|
+
}
|
|
488
|
+
declare function BlogSeriesIndexPage({ articles, basePath, title, description, className, theme, }: BlogSeriesIndexPageProps): react_jsx_runtime.JSX.Element;
|
|
489
|
+
declare function BlogSeriesArchivePage({ articles, seriesSlug, basePath, className, theme, }: BlogSeriesArchivePageProps): react_jsx_runtime.JSX.Element;
|
|
490
|
+
|
|
491
|
+
interface SeriesNavigationProps {
|
|
492
|
+
article: PublishedArticle;
|
|
493
|
+
basePath?: string;
|
|
494
|
+
className?: string;
|
|
495
|
+
}
|
|
496
|
+
declare function SeriesNavigation({ article, basePath, className, }: SeriesNavigationProps): react_jsx_runtime.JSX.Element | null;
|
|
497
|
+
|
|
418
498
|
interface BlogAuthorsIndexPageProps {
|
|
419
499
|
articles: PublishedArticle[];
|
|
420
500
|
basePath?: string;
|
|
@@ -2203,4 +2283,5 @@ declare function OPTIONS(request: NextRequest): Promise<NextResponse>;
|
|
|
2203
2283
|
|
|
2204
2284
|
declare const PACKAGE_VERSION: string;
|
|
2205
2285
|
|
|
2206
|
-
export { ApiKeyAuth,
|
|
2286
|
+
export { ApiKeyAuth, BLOG_PLATFORM_SCHEMA_VERSION, BLOG_PLATFORM_TABLE_NAMES, ArticlePage as BlogArticlePage, AuthorPage as BlogAuthorPage, BlogAuthorsIndexPage, BlogHomePage, BlogPlatformSchemaError, BlogSeriesArchivePage, BlogSeriesArchiveRoutePage, BlogSeriesIndexPage, BlogSeriesPage, BlogTopicArchivePage, BlogTopicsIndexPage, Button, CanonicalUrlOptions, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, DrizzleStorage, EnvAuth, InMemoryStorage, NEWSLETTER_SUCCESS_MESSAGE, NewsletterSignup, NoAuth, PACKAGE_VERSION, Pagination$1 as Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PublishResult, PublishedArticle, PublishedAuthor, PublishedNewsletterSettings, PublishedSite, PublishedTopic, SeriesNavigation, Pagination as ShadcnPagination, StructuredDataError, UninitializedAuth, autoConfigureRateLimit, blogPlatformDrizzleSchema, bpArticles, bpMetadata, bpOperations, buildAuthorPath, buildBlogPath, buildSeriesPath, buttonVariants, checkDrizzleAdapterSchema, checkRateLimit, cn, POST as configHandler, OPTIONS$1 as configOptionsHandler, configureRateLimit, createRateLimitErrorResponse, createStructuredDataScript, createTokenFingerprint, enforceRateLimit, ensureDrizzleAdapterSchema, extractKeywordsFromArticle, extractTableOfContents, extractTokenFromHeader, formatArticleDateMeta, generateArticleMetadata, generateArticleStructuredData, generateAuthorPageMetadata, generateAuthorStructuredData, generateBlogHomeMetadata, generateBlogHomeStructuredData, generateBreadcrumbStructuredData, generateCompleteArticleStructuredData, generateOrganizationStructuredData, generatePaginationMetadata, generateSeriesArchiveMetadata, generateSeriesIndexMetadata, generateSiteMetadata, generateWebSiteStructuredData, getAllSeries, getAllTopics, getArticlePrimaryTopic, getArticleSeriesNavigation, getAuthConfig, getAuthorArchive, getAuthorsFromArticles, getBlogThemeStyle, getDrizzleAdapterSql, getPathPrefixFromBlogUrl, getRateLimitHeaders, getSeriesArchive, getStorage, getTopicArchive, GET$1 as indexNowKeyRoute, initBlogPlatform, initBlogPlatformDev, initBlogPlatformOnce, initBlogPlatformProd, initEnvAuth, loadAuthorArchive, metadataToHtml, normalizeBlogBasePath, POST$2 as publishHandler, safeGenerateArticleStructuredData, setAuthConfig, setStorage, shouldSkipAuth, GET as slugExistsHandler, OPTIONS as slugExistsOptionsHandler, structuredDataToJsonLd, POST$1 as unpublishHandler, usePagination, validateMetadata, validateStructuredData, GET$2 as versionHandler };
|
|
2287
|
+
export type { AuthConfig, AuthResult, AuthorArchive, AuthorArchiveOptions, BlogPlatformConfig, BlogPlatformSchemaCheckResult, BlogPlatformStorage, BlogPlatformTableName, BlogPostingSchema, BlogTheme, BreadcrumbListSchema, GeneratedMetadata, LinkTag, MetaTag, MetadataOptions, NewsletterSignupProps, OrganizationSchema, PersonSchema, RateLimitConfig, RateLimitResult, SeriesArchive, StructuredDataOptions, TopicArchive, WebSiteSchema };
|