@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.
@@ -0,0 +1,23 @@
1
+
2
+ 
3
+ > @dispatchcms/next@0.0.1 build /Users/jamescalmus/Documents/dispatch/packages/next
4
+ > tsup
5
+
6
+ CLI Building entry: src/index.ts
7
+ CLI Using tsconfig: tsconfig.json
8
+ CLI tsup v8.5.1
9
+ CLI Using tsup config: /Users/jamescalmus/Documents/dispatch/packages/next/tsup.config.ts
10
+ CLI Target: es2020
11
+ CLI Cleaning output folder
12
+ CJS Build start
13
+ ESM Build start
14
+ ESM dist/index.mjs 1.63 KB
15
+ ESM dist/index.mjs.map 3.30 KB
16
+ ESM ⚡️ Build success in 11ms
17
+ CJS dist/index.js 2.72 KB
18
+ CJS dist/index.js.map 3.50 KB
19
+ CJS ⚡️ 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.
@@ -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 };
@@ -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,2 @@
1
+ export type { Post, DispatchConfig } from "./client";
2
+ export { initDispatch, getConfig, getPosts, getPost } from "./client";
@@ -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
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ export default defineConfig({
4
+ entry: ["src/index.ts"],
5
+ format: ["cjs", "esm"],
6
+ dts: true,
7
+ clean: true,
8
+ sourcemap: true,
9
+ });