-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontentful.ts
More file actions
76 lines (71 loc) · 2.4 KB
/
Copy pathcontentful.ts
File metadata and controls
76 lines (71 loc) · 2.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/**
* Contentful-shaped adapter STUB (stretch goal).
*
* This is intentionally non-functional: it demonstrates the *shape* of the seam
* a real CMS slots into. It shows two things a production adapter must do:
*
* 1. Map the CMS's response shape onto this repo's `Post`/`Product` types.
* 2. Validate the mapped record against the contract before returning it, so
* a CMS schema change surfaces as a loud error at the boundary instead of
* a silent SEO regression downstream.
*
* To use it for real: install the Contentful client, replace `fetchEntry` with
* a live query, and point `lib/cms/index.ts` at these functions.
*/
import type { Post } from '../types';
import { assertValidRecord } from '../../contract/validate';
/** A trimmed view of a Contentful entry envelope (`{ sys, fields }`). */
interface ContentfulEntry<TFields> {
sys: {
id: string;
createdAt: string;
updatedAt: string;
};
fields: TFields;
}
interface ContentfulPostFields {
slug: string;
title: string;
excerpt: string;
body: string;
publishedState: 'published' | 'draft' | 'archived';
contentUpdatedAt: string;
metaTitle?: string;
metaDescription?: string;
canonicalOverride?: string;
noindex?: boolean;
ogImage?: string;
}
/** Map a Contentful entry onto this repo's `Post` contract. */
export function mapContentfulPost(entry: ContentfulEntry<ContentfulPostFields>): Post {
const { sys, fields } = entry;
const post: Post = {
type: 'post',
id: sys.id,
slug: fields.slug,
status: fields.publishedState,
title: fields.title,
excerpt: fields.excerpt,
body: fields.body,
createdAt: sys.createdAt,
updatedAt: sys.updatedAt,
contentUpdatedAt: fields.contentUpdatedAt,
seo: {
metaTitle: fields.metaTitle ?? null,
metaDescription: fields.metaDescription ?? null,
canonicalOverride: fields.canonicalOverride ?? null,
noindex: fields.noindex ?? false,
ogImage: fields.ogImage ?? null,
},
};
// Catch schema drift at the boundary — never let an invalid record through.
assertValidRecord(post);
return post;
}
/* eslint-disable @typescript-eslint/no-unused-vars */
export async function getPost(_slug: string): Promise<Post | null> {
throw new Error(
'Contentful adapter is a stub. Wire up the Contentful client, then point ' +
'lib/cms/index.ts at mapContentfulPost(). See lib/cms/adapters/contentful.ts.',
);
}