@dispatchcms/next 0.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/.turbo/turbo-build.log +23 -0
- package/README.md +104 -0
- package/dist/index.d.mts +24 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +84 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +54 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +35 -0
- package/src/client.ts +69 -0
- package/src/index.ts +2 -0
- package/test/getPage.test.ts +14 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +9 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
> @dispatchcms/next@0.0.1 build /Users/jamescalmus/Documents/dispatch/packages/next
|
|
4
|
+
> tsup
|
|
5
|
+
|
|
6
|
+
[34mCLI[39m Building entry: src/index.ts
|
|
7
|
+
[34mCLI[39m Using tsconfig: tsconfig.json
|
|
8
|
+
[34mCLI[39m tsup v8.5.1
|
|
9
|
+
[34mCLI[39m Using tsup config: /Users/jamescalmus/Documents/dispatch/packages/next/tsup.config.ts
|
|
10
|
+
[34mCLI[39m Target: es2020
|
|
11
|
+
[34mCLI[39m Cleaning output folder
|
|
12
|
+
[34mCJS[39m Build start
|
|
13
|
+
[34mESM[39m Build start
|
|
14
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m1.63 KB[39m
|
|
15
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m3.30 KB[39m
|
|
16
|
+
[32mESM[39m ⚡️ Build success in 11ms
|
|
17
|
+
[32mCJS[39m [1mdist/index.js [22m[32m2.72 KB[39m
|
|
18
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m3.50 KB[39m
|
|
19
|
+
[32mCJS[39m ⚡️ Build success in 11ms
|
|
20
|
+
DTS Build start
|
|
21
|
+
DTS ⚡️ Build success in 424ms
|
|
22
|
+
DTS dist/index.d.ts 670.00 B
|
|
23
|
+
DTS dist/index.d.mts 670.00 B
|
package/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# @dispatchcms/next
|
|
2
|
+
|
|
3
|
+
Fetch published posts from a [Dispatch](https://github.com/dispatch-cms/dispatch) CMS in your Next.js app.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @dispatchcms/next
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @dispatchcms/next
|
|
11
|
+
# or
|
|
12
|
+
yarn add @dispatchcms/next
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Environment variables
|
|
16
|
+
|
|
17
|
+
Set this in your Next.js project (e.g. `.env.local`) if you don't call `initDispatch`:
|
|
18
|
+
|
|
19
|
+
| Variable | Description |
|
|
20
|
+
|----------|-------------|
|
|
21
|
+
| `NEXT_PUBLIC_DISPATCH_SITE_KEY` | Your site key (e.g. `pk_xxxx`). Required if you don't call `initDispatch`. |
|
|
22
|
+
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
Call `initDispatch` once so the client knows your site key. For example in your root layout or before any fetch:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { initDispatch } from "@dispatchcms/next";
|
|
29
|
+
|
|
30
|
+
initDispatch({
|
|
31
|
+
siteKey: process.env.NEXT_PUBLIC_DISPATCH_SITE_KEY!,
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You can omit `initDispatch` entirely if `NEXT_PUBLIC_DISPATCH_SITE_KEY` is set; the package will use it automatically.
|
|
36
|
+
|
|
37
|
+
## API
|
|
38
|
+
|
|
39
|
+
### `getPosts(siteKey?)`
|
|
40
|
+
|
|
41
|
+
Returns all published posts for the site.
|
|
42
|
+
|
|
43
|
+
- **Returns:** `Promise<Post[]>`
|
|
44
|
+
- **Optional:** pass `siteKey` to override the configured site for this call.
|
|
45
|
+
|
|
46
|
+
### `getPost(slug, siteKey?)`
|
|
47
|
+
|
|
48
|
+
Returns a single published post by slug, or `null` if not found.
|
|
49
|
+
|
|
50
|
+
- **Returns:** `Promise<Post | null>`
|
|
51
|
+
- **Optional:** pass `siteKey` as the second argument to override the configured site.
|
|
52
|
+
|
|
53
|
+
## Types
|
|
54
|
+
|
|
55
|
+
Exportable types:
|
|
56
|
+
|
|
57
|
+
- **`Post`** – A post from the CMS. Main fields: `id`, `title`, `slug`, `content` (TipTap JSON), `excerpt`, `featured_image`, `published`, `published_at`, `created_at`, `updated_at`, `site_id`.
|
|
58
|
+
- **`DispatchConfig`** – Options for `initDispatch`: `{ siteKey: string }`.
|
|
59
|
+
|
|
60
|
+
Use your editor’s type hints or the generated `.d.ts` for the full shape.
|
|
61
|
+
|
|
62
|
+
## Example (Next.js App Router)
|
|
63
|
+
|
|
64
|
+
**List posts (Server Component):**
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
// app/blog/page.tsx
|
|
68
|
+
import { getPosts } from "@dispatchcms/next";
|
|
69
|
+
|
|
70
|
+
export default async function BlogPage() {
|
|
71
|
+
const posts = await getPosts();
|
|
72
|
+
return (
|
|
73
|
+
<ul>
|
|
74
|
+
{posts.map((post) => (
|
|
75
|
+
<li key={post.id}>
|
|
76
|
+
<a href={`/blog/${post.slug}`}>{post.title}</a>
|
|
77
|
+
</li>
|
|
78
|
+
))}
|
|
79
|
+
</ul>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Single post (Server Component):**
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
// app/blog/[slug]/page.tsx
|
|
88
|
+
import { getPost } from "@dispatchcms/next";
|
|
89
|
+
import { notFound } from "next/navigation";
|
|
90
|
+
|
|
91
|
+
export default async function PostPage({ params }: { params: { slug: string } }) {
|
|
92
|
+
const post = await getPost(params.slug);
|
|
93
|
+
if (!post) notFound();
|
|
94
|
+
return (
|
|
95
|
+
<article>
|
|
96
|
+
<h1>{post.title}</h1>
|
|
97
|
+
{post.excerpt && <p>{post.excerpt}</p>}
|
|
98
|
+
{/* Render post.content (TipTap JSON) with your editor/renderer */}
|
|
99
|
+
</article>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The CMS API only returns **published** posts; drafts are not included.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type Post = {
|
|
2
|
+
id: string;
|
|
3
|
+
created_at: string;
|
|
4
|
+
published_at: string;
|
|
5
|
+
updated_at: string;
|
|
6
|
+
site_id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
content: unknown;
|
|
10
|
+
excerpt: string | null;
|
|
11
|
+
featured_image: string | null;
|
|
12
|
+
published: boolean;
|
|
13
|
+
};
|
|
14
|
+
type DispatchConfig = {
|
|
15
|
+
siteKey: string;
|
|
16
|
+
};
|
|
17
|
+
declare function initDispatch(options: DispatchConfig): void;
|
|
18
|
+
declare function getConfig(): {
|
|
19
|
+
siteKey: string;
|
|
20
|
+
};
|
|
21
|
+
declare function getPosts(siteKey?: string): Promise<Post[]>;
|
|
22
|
+
declare function getPost(slug: string, siteKey?: string): Promise<Post | null>;
|
|
23
|
+
|
|
24
|
+
export { type DispatchConfig, type Post, getConfig, getPost, getPosts, initDispatch };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
type Post = {
|
|
2
|
+
id: string;
|
|
3
|
+
created_at: string;
|
|
4
|
+
published_at: string;
|
|
5
|
+
updated_at: string;
|
|
6
|
+
site_id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
content: unknown;
|
|
10
|
+
excerpt: string | null;
|
|
11
|
+
featured_image: string | null;
|
|
12
|
+
published: boolean;
|
|
13
|
+
};
|
|
14
|
+
type DispatchConfig = {
|
|
15
|
+
siteKey: string;
|
|
16
|
+
};
|
|
17
|
+
declare function initDispatch(options: DispatchConfig): void;
|
|
18
|
+
declare function getConfig(): {
|
|
19
|
+
siteKey: string;
|
|
20
|
+
};
|
|
21
|
+
declare function getPosts(siteKey?: string): Promise<Post[]>;
|
|
22
|
+
declare function getPost(slug: string, siteKey?: string): Promise<Post | null>;
|
|
23
|
+
|
|
24
|
+
export { type DispatchConfig, type Post, getConfig, getPost, getPosts, initDispatch };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
getConfig: () => getConfig,
|
|
24
|
+
getPost: () => getPost,
|
|
25
|
+
getPosts: () => getPosts,
|
|
26
|
+
initDispatch: () => initDispatch
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/client.ts
|
|
31
|
+
var DISPATCH_API_BASE = "https://dispatch-cms.vercel.app";
|
|
32
|
+
var config = null;
|
|
33
|
+
function initDispatch(options) {
|
|
34
|
+
config = { siteKey: options.siteKey };
|
|
35
|
+
}
|
|
36
|
+
function getConfig() {
|
|
37
|
+
const envKey = typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_DISPATCH_SITE_KEY : void 0;
|
|
38
|
+
const siteKey = config?.siteKey ?? (typeof envKey === "string" ? envKey : void 0);
|
|
39
|
+
if (!siteKey || typeof siteKey !== "string") {
|
|
40
|
+
throw new Error("Dispatch site key is required. Call initDispatch({ siteKey }) or set NEXT_PUBLIC_DISPATCH_SITE_KEY.");
|
|
41
|
+
}
|
|
42
|
+
return { siteKey };
|
|
43
|
+
}
|
|
44
|
+
async function getPosts(siteKey) {
|
|
45
|
+
const { siteKey: key } = getConfig();
|
|
46
|
+
const resolvedKey = siteKey ?? key;
|
|
47
|
+
const url = `${DISPATCH_API_BASE}/api/posts`;
|
|
48
|
+
const res = await fetch(url, {
|
|
49
|
+
headers: { "X-Site-Key": resolvedKey }
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
if (res.status === 401) {
|
|
53
|
+
throw new Error("Invalid or missing site key");
|
|
54
|
+
}
|
|
55
|
+
throw new Error(`Failed to fetch posts: ${res.status} ${res.statusText}`);
|
|
56
|
+
}
|
|
57
|
+
return res.json();
|
|
58
|
+
}
|
|
59
|
+
async function getPost(slug, siteKey) {
|
|
60
|
+
const { siteKey: key } = getConfig();
|
|
61
|
+
const resolvedKey = siteKey ?? key;
|
|
62
|
+
const url = `${DISPATCH_API_BASE}/api/posts/${encodeURIComponent(slug)}`;
|
|
63
|
+
const res = await fetch(url, {
|
|
64
|
+
headers: { "X-Site-Key": resolvedKey }
|
|
65
|
+
});
|
|
66
|
+
if (res.status === 404) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
if (res.status === 401) {
|
|
71
|
+
throw new Error("Invalid or missing site key");
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Failed to fetch post: ${res.status} ${res.statusText}`);
|
|
74
|
+
}
|
|
75
|
+
return res.json();
|
|
76
|
+
}
|
|
77
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
78
|
+
0 && (module.exports = {
|
|
79
|
+
getConfig,
|
|
80
|
+
getPost,
|
|
81
|
+
getPosts,
|
|
82
|
+
initDispatch
|
|
83
|
+
});
|
|
84
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/client.ts"],"sourcesContent":["export type { Post, DispatchConfig } from \"./client\";\nexport { initDispatch, getConfig, getPosts, getPost } from \"./client\";\n","export type Post = {\n id: string;\n created_at: string;\n published_at: string;\n updated_at: string;\n site_id: string;\n title: string;\n slug: string;\n content: unknown;\n excerpt: string | null;\n featured_image: string | null;\n published: boolean;\n};\n\nconst DISPATCH_API_BASE = \"https://dispatch-cms.vercel.app\";\n\nexport type DispatchConfig = {\n siteKey: string;\n};\n\nlet config: DispatchConfig | null = null;\n\nexport function initDispatch(options: DispatchConfig): void {\n config = { siteKey: options.siteKey };\n}\n\nexport function getConfig(): { siteKey: string } {\n const envKey = typeof process !== \"undefined\" ? process.env?.NEXT_PUBLIC_DISPATCH_SITE_KEY : undefined;\n const siteKey = config?.siteKey ?? (typeof envKey === \"string\" ? envKey : undefined);\n if (!siteKey || typeof siteKey !== \"string\") {\n throw new Error(\"Dispatch site key is required. Call initDispatch({ siteKey }) or set NEXT_PUBLIC_DISPATCH_SITE_KEY.\");\n }\n return { siteKey };\n}\n\nexport async function getPosts(siteKey?: string): Promise<Post[]> {\n const { siteKey: key } = getConfig();\n const resolvedKey = siteKey ?? key;\n const url = `${DISPATCH_API_BASE}/api/posts`;\n const res = await fetch(url, {\n headers: { \"X-Site-Key\": resolvedKey },\n });\n if (!res.ok) {\n if (res.status === 401) {\n throw new Error(\"Invalid or missing site key\");\n }\n throw new Error(`Failed to fetch posts: ${res.status} ${res.statusText}`);\n }\n return res.json() as Promise<Post[]>;\n}\n\nexport async function getPost(slug: string, siteKey?: string): Promise<Post | null> {\n const { siteKey: key } = getConfig();\n const resolvedKey = siteKey ?? key;\n const url = `${DISPATCH_API_BASE}/api/posts/${encodeURIComponent(slug)}`;\n const res = await fetch(url, {\n headers: { \"X-Site-Key\": resolvedKey },\n });\n if (res.status === 404) {\n return null;\n }\n if (!res.ok) {\n if (res.status === 401) {\n throw new Error(\"Invalid or missing site key\");\n }\n throw new Error(`Failed to fetch post: ${res.status} ${res.statusText}`);\n }\n return res.json() as Promise<Post>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACcA,IAAM,oBAAoB;AAM1B,IAAI,SAAgC;AAE7B,SAAS,aAAa,SAA+B;AAC1D,WAAS,EAAE,SAAS,QAAQ,QAAQ;AACtC;AAEO,SAAS,YAAiC;AAC/C,QAAM,SAAS,OAAO,YAAY,cAAc,QAAQ,KAAK,gCAAgC;AAC7F,QAAM,UAAU,QAAQ,YAAY,OAAO,WAAW,WAAW,SAAS;AAC1E,MAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,UAAM,IAAI,MAAM,qGAAqG;AAAA,EACvH;AACA,SAAO,EAAE,QAAQ;AACnB;AAEA,eAAsB,SAAS,SAAmC;AAChE,QAAM,EAAE,SAAS,IAAI,IAAI,UAAU;AACnC,QAAM,cAAc,WAAW;AAC/B,QAAM,MAAM,GAAG,iBAAiB;AAChC,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,SAAS,EAAE,cAAc,YAAY;AAAA,EACvC,CAAC;AACD,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,IAAI,WAAW,KAAK;AACtB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,UAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,EAC1E;AACA,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,QAAQ,MAAc,SAAwC;AAClF,QAAM,EAAE,SAAS,IAAI,IAAI,UAAU;AACnC,QAAM,cAAc,WAAW;AAC/B,QAAM,MAAM,GAAG,iBAAiB,cAAc,mBAAmB,IAAI,CAAC;AACtE,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,SAAS,EAAE,cAAc,YAAY;AAAA,EACvC,CAAC;AACD,MAAI,IAAI,WAAW,KAAK;AACtB,WAAO;AAAA,EACT;AACA,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,IAAI,WAAW,KAAK;AACtB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,UAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,EACzE;AACA,SAAO,IAAI,KAAK;AAClB;","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
var DISPATCH_API_BASE = "https://dispatch-cms.vercel.app";
|
|
3
|
+
var config = null;
|
|
4
|
+
function initDispatch(options) {
|
|
5
|
+
config = { siteKey: options.siteKey };
|
|
6
|
+
}
|
|
7
|
+
function getConfig() {
|
|
8
|
+
const envKey = typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_DISPATCH_SITE_KEY : void 0;
|
|
9
|
+
const siteKey = config?.siteKey ?? (typeof envKey === "string" ? envKey : void 0);
|
|
10
|
+
if (!siteKey || typeof siteKey !== "string") {
|
|
11
|
+
throw new Error("Dispatch site key is required. Call initDispatch({ siteKey }) or set NEXT_PUBLIC_DISPATCH_SITE_KEY.");
|
|
12
|
+
}
|
|
13
|
+
return { siteKey };
|
|
14
|
+
}
|
|
15
|
+
async function getPosts(siteKey) {
|
|
16
|
+
const { siteKey: key } = getConfig();
|
|
17
|
+
const resolvedKey = siteKey ?? key;
|
|
18
|
+
const url = `${DISPATCH_API_BASE}/api/posts`;
|
|
19
|
+
const res = await fetch(url, {
|
|
20
|
+
headers: { "X-Site-Key": resolvedKey }
|
|
21
|
+
});
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
if (res.status === 401) {
|
|
24
|
+
throw new Error("Invalid or missing site key");
|
|
25
|
+
}
|
|
26
|
+
throw new Error(`Failed to fetch posts: ${res.status} ${res.statusText}`);
|
|
27
|
+
}
|
|
28
|
+
return res.json();
|
|
29
|
+
}
|
|
30
|
+
async function getPost(slug, siteKey) {
|
|
31
|
+
const { siteKey: key } = getConfig();
|
|
32
|
+
const resolvedKey = siteKey ?? key;
|
|
33
|
+
const url = `${DISPATCH_API_BASE}/api/posts/${encodeURIComponent(slug)}`;
|
|
34
|
+
const res = await fetch(url, {
|
|
35
|
+
headers: { "X-Site-Key": resolvedKey }
|
|
36
|
+
});
|
|
37
|
+
if (res.status === 404) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
if (!res.ok) {
|
|
41
|
+
if (res.status === 401) {
|
|
42
|
+
throw new Error("Invalid or missing site key");
|
|
43
|
+
}
|
|
44
|
+
throw new Error(`Failed to fetch post: ${res.status} ${res.statusText}`);
|
|
45
|
+
}
|
|
46
|
+
return res.json();
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
getConfig,
|
|
50
|
+
getPost,
|
|
51
|
+
getPosts,
|
|
52
|
+
initDispatch
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["export type Post = {\n id: string;\n created_at: string;\n published_at: string;\n updated_at: string;\n site_id: string;\n title: string;\n slug: string;\n content: unknown;\n excerpt: string | null;\n featured_image: string | null;\n published: boolean;\n};\n\nconst DISPATCH_API_BASE = \"https://dispatch-cms.vercel.app\";\n\nexport type DispatchConfig = {\n siteKey: string;\n};\n\nlet config: DispatchConfig | null = null;\n\nexport function initDispatch(options: DispatchConfig): void {\n config = { siteKey: options.siteKey };\n}\n\nexport function getConfig(): { siteKey: string } {\n const envKey = typeof process !== \"undefined\" ? process.env?.NEXT_PUBLIC_DISPATCH_SITE_KEY : undefined;\n const siteKey = config?.siteKey ?? (typeof envKey === \"string\" ? envKey : undefined);\n if (!siteKey || typeof siteKey !== \"string\") {\n throw new Error(\"Dispatch site key is required. Call initDispatch({ siteKey }) or set NEXT_PUBLIC_DISPATCH_SITE_KEY.\");\n }\n return { siteKey };\n}\n\nexport async function getPosts(siteKey?: string): Promise<Post[]> {\n const { siteKey: key } = getConfig();\n const resolvedKey = siteKey ?? key;\n const url = `${DISPATCH_API_BASE}/api/posts`;\n const res = await fetch(url, {\n headers: { \"X-Site-Key\": resolvedKey },\n });\n if (!res.ok) {\n if (res.status === 401) {\n throw new Error(\"Invalid or missing site key\");\n }\n throw new Error(`Failed to fetch posts: ${res.status} ${res.statusText}`);\n }\n return res.json() as Promise<Post[]>;\n}\n\nexport async function getPost(slug: string, siteKey?: string): Promise<Post | null> {\n const { siteKey: key } = getConfig();\n const resolvedKey = siteKey ?? key;\n const url = `${DISPATCH_API_BASE}/api/posts/${encodeURIComponent(slug)}`;\n const res = await fetch(url, {\n headers: { \"X-Site-Key\": resolvedKey },\n });\n if (res.status === 404) {\n return null;\n }\n if (!res.ok) {\n if (res.status === 401) {\n throw new Error(\"Invalid or missing site key\");\n }\n throw new Error(`Failed to fetch post: ${res.status} ${res.statusText}`);\n }\n return res.json() as Promise<Post>;\n}\n"],"mappings":";AAcA,IAAM,oBAAoB;AAM1B,IAAI,SAAgC;AAE7B,SAAS,aAAa,SAA+B;AAC1D,WAAS,EAAE,SAAS,QAAQ,QAAQ;AACtC;AAEO,SAAS,YAAiC;AAC/C,QAAM,SAAS,OAAO,YAAY,cAAc,QAAQ,KAAK,gCAAgC;AAC7F,QAAM,UAAU,QAAQ,YAAY,OAAO,WAAW,WAAW,SAAS;AAC1E,MAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,UAAM,IAAI,MAAM,qGAAqG;AAAA,EACvH;AACA,SAAO,EAAE,QAAQ;AACnB;AAEA,eAAsB,SAAS,SAAmC;AAChE,QAAM,EAAE,SAAS,IAAI,IAAI,UAAU;AACnC,QAAM,cAAc,WAAW;AAC/B,QAAM,MAAM,GAAG,iBAAiB;AAChC,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,SAAS,EAAE,cAAc,YAAY;AAAA,EACvC,CAAC;AACD,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,IAAI,WAAW,KAAK;AACtB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,UAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,EAC1E;AACA,SAAO,IAAI,KAAK;AAClB;AAEA,eAAsB,QAAQ,MAAc,SAAwC;AAClF,QAAM,EAAE,SAAS,IAAI,IAAI,UAAU;AACnC,QAAM,cAAc,WAAW;AAC/B,QAAM,MAAM,GAAG,iBAAiB,cAAc,mBAAmB,IAAI,CAAC;AACtE,QAAM,MAAM,MAAM,MAAM,KAAK;AAAA,IAC3B,SAAS,EAAE,cAAc,YAAY;AAAA,EACvC,CAAC;AACD,MAAI,IAAI,WAAW,KAAK;AACtB,WAAO;AAAA,EACT;AACA,MAAI,CAAC,IAAI,IAAI;AACX,QAAI,IAAI,WAAW,KAAK;AACtB,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AACA,UAAM,IAAI,MAAM,yBAAyB,IAAI,MAAM,IAAI,IAAI,UAAU,EAAE;AAAA,EACzE;AACA,SAAO,IAAI,KAAK;AAClB;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dispatchcms/next",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Fetch published posts from a Dispatch CMS in Next.js",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"test": "tsx test/getPage.test.ts"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "^22.10.1",
|
|
21
|
+
"tsup": "^8.3.5",
|
|
22
|
+
"tsx": "^4.19.2",
|
|
23
|
+
"typescript": "^5.7.2"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"dispatch",
|
|
30
|
+
"cms",
|
|
31
|
+
"nextjs",
|
|
32
|
+
"content"
|
|
33
|
+
],
|
|
34
|
+
"license": "MIT"
|
|
35
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type Post = {
|
|
2
|
+
id: string;
|
|
3
|
+
created_at: string;
|
|
4
|
+
published_at: string;
|
|
5
|
+
updated_at: string;
|
|
6
|
+
site_id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
content: unknown;
|
|
10
|
+
excerpt: string | null;
|
|
11
|
+
featured_image: string | null;
|
|
12
|
+
published: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const DISPATCH_API_BASE = "https://dispatch-cms.vercel.app";
|
|
16
|
+
|
|
17
|
+
export type DispatchConfig = {
|
|
18
|
+
siteKey: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
let config: DispatchConfig | null = null;
|
|
22
|
+
|
|
23
|
+
export function initDispatch(options: DispatchConfig): void {
|
|
24
|
+
config = { siteKey: options.siteKey };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getConfig(): { siteKey: string } {
|
|
28
|
+
const envKey = typeof process !== "undefined" ? process.env?.NEXT_PUBLIC_DISPATCH_SITE_KEY : undefined;
|
|
29
|
+
const siteKey = config?.siteKey ?? (typeof envKey === "string" ? envKey : undefined);
|
|
30
|
+
if (!siteKey || typeof siteKey !== "string") {
|
|
31
|
+
throw new Error("Dispatch site key is required. Call initDispatch({ siteKey }) or set NEXT_PUBLIC_DISPATCH_SITE_KEY.");
|
|
32
|
+
}
|
|
33
|
+
return { siteKey };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function getPosts(siteKey?: string): Promise<Post[]> {
|
|
37
|
+
const { siteKey: key } = getConfig();
|
|
38
|
+
const resolvedKey = siteKey ?? key;
|
|
39
|
+
const url = `${DISPATCH_API_BASE}/api/posts`;
|
|
40
|
+
const res = await fetch(url, {
|
|
41
|
+
headers: { "X-Site-Key": resolvedKey },
|
|
42
|
+
});
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
if (res.status === 401) {
|
|
45
|
+
throw new Error("Invalid or missing site key");
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Failed to fetch posts: ${res.status} ${res.statusText}`);
|
|
48
|
+
}
|
|
49
|
+
return res.json() as Promise<Post[]>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function getPost(slug: string, siteKey?: string): Promise<Post | null> {
|
|
53
|
+
const { siteKey: key } = getConfig();
|
|
54
|
+
const resolvedKey = siteKey ?? key;
|
|
55
|
+
const url = `${DISPATCH_API_BASE}/api/posts/${encodeURIComponent(slug)}`;
|
|
56
|
+
const res = await fetch(url, {
|
|
57
|
+
headers: { "X-Site-Key": resolvedKey },
|
|
58
|
+
});
|
|
59
|
+
if (res.status === 404) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
if (!res.ok) {
|
|
63
|
+
if (res.status === 401) {
|
|
64
|
+
throw new Error("Invalid or missing site key");
|
|
65
|
+
}
|
|
66
|
+
throw new Error(`Failed to fetch post: ${res.status} ${res.statusText}`);
|
|
67
|
+
}
|
|
68
|
+
return res.json() as Promise<Post>;
|
|
69
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { initDispatch, getPosts } from "../src/index";
|
|
2
|
+
|
|
3
|
+
async function main() {
|
|
4
|
+
initDispatch({
|
|
5
|
+
siteKey: process.env.NEXT_PUBLIC_DISPATCH_SITE_KEY ?? "pk_test",
|
|
6
|
+
});
|
|
7
|
+
const result = await getPosts();
|
|
8
|
+
console.log(result);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
main().catch((err) => {
|
|
12
|
+
console.error(err);
|
|
13
|
+
process.exit(1);
|
|
14
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"declarationMap": true,
|
|
10
|
+
"outDir": "dist",
|
|
11
|
+
"rootDir": "src"
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"],
|
|
14
|
+
"exclude": ["node_modules", "dist"]
|
|
15
|
+
}
|