@dispatchcms/react 0.0.4

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/react@0.0.4 build /Users/jamescalmus/Documents/dispatch/packages/react
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/react/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 3.63 KB
15
+ ESM dist/index.mjs.map 7.27 KB
16
+ ESM ⚡️ Build success in 6ms
17
+ CJS dist/index.js 4.94 KB
18
+ CJS dist/index.js.map 7.58 KB
19
+ CJS ⚡️ Build success in 6ms
20
+ DTS Build start
21
+ DTS ⚡️ Build success in 296ms
22
+ DTS dist/index.d.ts 1.10 KB
23
+ DTS dist/index.d.mts 1.10 KB
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type Post = {
4
+ id: string;
5
+ created_at: string;
6
+ published_at: string;
7
+ updated_at: string;
8
+ site_id: string;
9
+ title: string;
10
+ slug: string;
11
+ content: unknown;
12
+ excerpt: string | null;
13
+ featured_image: string | null;
14
+ published: boolean;
15
+ };
16
+
17
+ type DispatchContextValue = {
18
+ siteKey: string | null;
19
+ apiBase: string;
20
+ };
21
+ declare function useDispatchContext(): DispatchContextValue | null;
22
+ type DispatchProviderProps = {
23
+ siteKey?: string | null;
24
+ apiBase?: string;
25
+ children?: unknown;
26
+ };
27
+ declare function DispatchProvider({ siteKey, apiBase, children, }: DispatchProviderProps): react_jsx_runtime.JSX.Element;
28
+
29
+ type UsePostResult = {
30
+ post: Post | null;
31
+ isLoading: boolean;
32
+ error?: string;
33
+ };
34
+ declare function usePost(slug: string | undefined): UsePostResult;
35
+ type UsePostsResult = {
36
+ posts: Post[];
37
+ isLoading: boolean;
38
+ error?: string;
39
+ };
40
+ declare function usePosts(): UsePostsResult;
41
+
42
+ export { DispatchProvider, type Post, type UsePostResult, type UsePostsResult, useDispatchContext, usePost, usePosts };
@@ -0,0 +1,42 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+
3
+ type Post = {
4
+ id: string;
5
+ created_at: string;
6
+ published_at: string;
7
+ updated_at: string;
8
+ site_id: string;
9
+ title: string;
10
+ slug: string;
11
+ content: unknown;
12
+ excerpt: string | null;
13
+ featured_image: string | null;
14
+ published: boolean;
15
+ };
16
+
17
+ type DispatchContextValue = {
18
+ siteKey: string | null;
19
+ apiBase: string;
20
+ };
21
+ declare function useDispatchContext(): DispatchContextValue | null;
22
+ type DispatchProviderProps = {
23
+ siteKey?: string | null;
24
+ apiBase?: string;
25
+ children?: unknown;
26
+ };
27
+ declare function DispatchProvider({ siteKey, apiBase, children, }: DispatchProviderProps): react_jsx_runtime.JSX.Element;
28
+
29
+ type UsePostResult = {
30
+ post: Post | null;
31
+ isLoading: boolean;
32
+ error?: string;
33
+ };
34
+ declare function usePost(slug: string | undefined): UsePostResult;
35
+ type UsePostsResult = {
36
+ posts: Post[];
37
+ isLoading: boolean;
38
+ error?: string;
39
+ };
40
+ declare function usePosts(): UsePostsResult;
41
+
42
+ export { DispatchProvider, type Post, type UsePostResult, type UsePostsResult, useDispatchContext, usePost, usePosts };
package/dist/index.js ADDED
@@ -0,0 +1,173 @@
1
+ 'use client';
2
+ "use strict";
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
20
+
21
+ // src/index.ts
22
+ var index_exports = {};
23
+ __export(index_exports, {
24
+ DispatchProvider: () => DispatchProvider,
25
+ useDispatchContext: () => useDispatchContext,
26
+ usePost: () => usePost,
27
+ usePosts: () => usePosts
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/context.tsx
32
+ var import_react = require("react");
33
+
34
+ // src/config.ts
35
+ var API_BASE = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DISPATCH_API_URL ? process.env.NEXT_PUBLIC_DISPATCH_API_URL : "https://dispatch-cms.vercel.app";
36
+ function getApiBase() {
37
+ return API_BASE;
38
+ }
39
+
40
+ // src/context.tsx
41
+ var import_jsx_runtime = require("react/jsx-runtime");
42
+ var DispatchContext = (0, import_react.createContext)(null);
43
+ function useDispatchContext() {
44
+ return (0, import_react.useContext)(DispatchContext);
45
+ }
46
+ function DispatchProvider({
47
+ siteKey = null,
48
+ apiBase = getApiBase(),
49
+ children
50
+ }) {
51
+ const value = {
52
+ siteKey: siteKey?.trim() || null,
53
+ apiBase
54
+ };
55
+ if (!value.siteKey) {
56
+ if (typeof console !== "undefined" && console.warn) {
57
+ console.warn(
58
+ "[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider or set NEXT_PUBLIC_DISPATCH_SITE_KEY. Hooks will return empty/error state."
59
+ );
60
+ }
61
+ }
62
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DispatchContext.Provider, { value, children });
63
+ }
64
+
65
+ // src/hooks.ts
66
+ var import_react2 = require("react");
67
+ function usePost(slug) {
68
+ const ctx = useDispatchContext();
69
+ const [post, setPost] = (0, import_react2.useState)(null);
70
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
71
+ const [error, setError] = (0, import_react2.useState)(void 0);
72
+ (0, import_react2.useEffect)(() => {
73
+ if (!slug?.trim()) {
74
+ setPost(null);
75
+ setIsLoading(false);
76
+ setError(void 0);
77
+ return;
78
+ }
79
+ if (!ctx?.siteKey) {
80
+ setPost(null);
81
+ setIsLoading(false);
82
+ setError("Missing site key");
83
+ return;
84
+ }
85
+ let cancelled = false;
86
+ setPost(null);
87
+ setError(void 0);
88
+ setIsLoading(true);
89
+ const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;
90
+ fetch(url, {
91
+ headers: { "X-Site-Key": ctx.siteKey }
92
+ }).then((res) => {
93
+ if (cancelled) return;
94
+ if (res.status === 404) {
95
+ setPost(null);
96
+ setIsLoading(false);
97
+ return;
98
+ }
99
+ if (!res.ok) {
100
+ setPost(null);
101
+ setIsLoading(false);
102
+ setError("Failed to load");
103
+ return;
104
+ }
105
+ return res.json();
106
+ }).then((data) => {
107
+ if (cancelled) return;
108
+ setPost(data);
109
+ setIsLoading(false);
110
+ }).catch(() => {
111
+ if (cancelled) return;
112
+ setPost(null);
113
+ setIsLoading(false);
114
+ setError("Failed to load");
115
+ });
116
+ return () => {
117
+ cancelled = true;
118
+ };
119
+ }, [slug, ctx?.siteKey, ctx?.apiBase]);
120
+ return { post, isLoading, error };
121
+ }
122
+ function usePosts() {
123
+ const ctx = useDispatchContext();
124
+ const [posts, setPosts] = (0, import_react2.useState)([]);
125
+ const [isLoading, setIsLoading] = (0, import_react2.useState)(true);
126
+ const [error, setError] = (0, import_react2.useState)(void 0);
127
+ (0, import_react2.useEffect)(() => {
128
+ if (!ctx?.siteKey) {
129
+ setPosts([]);
130
+ setIsLoading(false);
131
+ setError("Missing site key");
132
+ return;
133
+ }
134
+ let cancelled = false;
135
+ setPosts([]);
136
+ setError(void 0);
137
+ setIsLoading(true);
138
+ const url = `${ctx.apiBase}/api/posts`;
139
+ fetch(url, {
140
+ headers: { "X-Site-Key": ctx.siteKey }
141
+ }).then((res) => {
142
+ if (cancelled) return;
143
+ if (!res.ok) {
144
+ setPosts([]);
145
+ setIsLoading(false);
146
+ setError("Failed to load");
147
+ return;
148
+ }
149
+ return res.json();
150
+ }).then((data) => {
151
+ if (cancelled) return;
152
+ setPosts(Array.isArray(data) ? data : []);
153
+ setIsLoading(false);
154
+ }).catch(() => {
155
+ if (cancelled) return;
156
+ setPosts([]);
157
+ setIsLoading(false);
158
+ setError("Failed to load");
159
+ });
160
+ return () => {
161
+ cancelled = true;
162
+ };
163
+ }, [ctx?.siteKey, ctx?.apiBase]);
164
+ return { posts, isLoading, error };
165
+ }
166
+ // Annotate the CommonJS export names for ESM import in node:
167
+ 0 && (module.exports = {
168
+ DispatchProvider,
169
+ useDispatchContext,
170
+ usePost,
171
+ usePosts
172
+ });
173
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["export type { Post } from \"./types\";\nexport { DispatchProvider, useDispatchContext } from \"./context\";\nexport { usePost, usePosts } from \"./hooks\";\nexport type { UsePostResult, UsePostsResult } from \"./hooks\";\n","\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\nimport { getApiBase } from \"./config\";\n\ntype DispatchContextValue = {\n siteKey: string | null;\n apiBase: string;\n};\n\nconst DispatchContext = createContext<DispatchContextValue | null>(null);\n\nexport function useDispatchContext(): DispatchContextValue | null {\n return useContext(DispatchContext);\n}\n\ntype DispatchProviderProps = {\n siteKey?: string | null;\n apiBase?: string;\n children?: unknown;\n};\n\nexport function DispatchProvider({\n siteKey = null,\n apiBase = getApiBase(),\n children,\n}: DispatchProviderProps) {\n const value: DispatchContextValue = {\n siteKey: siteKey?.trim() || null,\n apiBase,\n };\n\n if (!value.siteKey) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n \"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider or set NEXT_PUBLIC_DISPATCH_SITE_KEY. Hooks will return empty/error state.\"\n );\n }\n }\n\n return (\n <DispatchContext.Provider value={value}>\n {children as React.ReactNode}\n </DispatchContext.Provider>\n );\n}\n","const API_BASE =\n typeof process !== \"undefined\" && process.env?.NEXT_PUBLIC_DISPATCH_API_URL\n ? process.env.NEXT_PUBLIC_DISPATCH_API_URL\n : \"https://dispatch-cms.vercel.app\";\n\nexport function getApiBase(): string {\n return API_BASE;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { Post } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UsePostResult = {\n post: Post | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePost(slug: string | undefined): UsePostResult {\n const ctx = useDispatchContext();\n const [post, setPost] = useState<Post | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!slug?.trim()) {\n setPost(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setPost(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPost(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (res.status === 404) {\n setPost(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPost(data as Post);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { post, isLoading, error };\n}\n\nexport type UsePostsResult = {\n posts: Post[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePosts(): UsePostsResult {\n const ctx = useDispatchContext();\n const [posts, setPosts] = useState<Post[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!ctx?.siteKey) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPosts([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPosts(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [ctx?.siteKey, ctx?.apiBase]);\n\n return { posts, isLoading, error };\n}\n"],"mappings":"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","names":["import_react"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,144 @@
1
+ 'use client';
2
+
3
+ // src/context.tsx
4
+ import { createContext, useContext } from "react";
5
+
6
+ // src/config.ts
7
+ var API_BASE = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DISPATCH_API_URL ? process.env.NEXT_PUBLIC_DISPATCH_API_URL : "https://dispatch-cms.vercel.app";
8
+ function getApiBase() {
9
+ return API_BASE;
10
+ }
11
+
12
+ // src/context.tsx
13
+ import { jsx } from "react/jsx-runtime";
14
+ var DispatchContext = createContext(null);
15
+ function useDispatchContext() {
16
+ return useContext(DispatchContext);
17
+ }
18
+ function DispatchProvider({
19
+ siteKey = null,
20
+ apiBase = getApiBase(),
21
+ children
22
+ }) {
23
+ const value = {
24
+ siteKey: siteKey?.trim() || null,
25
+ apiBase
26
+ };
27
+ if (!value.siteKey) {
28
+ if (typeof console !== "undefined" && console.warn) {
29
+ console.warn(
30
+ "[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider or set NEXT_PUBLIC_DISPATCH_SITE_KEY. Hooks will return empty/error state."
31
+ );
32
+ }
33
+ }
34
+ return /* @__PURE__ */ jsx(DispatchContext.Provider, { value, children });
35
+ }
36
+
37
+ // src/hooks.ts
38
+ import { useEffect, useState } from "react";
39
+ function usePost(slug) {
40
+ const ctx = useDispatchContext();
41
+ const [post, setPost] = useState(null);
42
+ const [isLoading, setIsLoading] = useState(true);
43
+ const [error, setError] = useState(void 0);
44
+ useEffect(() => {
45
+ if (!slug?.trim()) {
46
+ setPost(null);
47
+ setIsLoading(false);
48
+ setError(void 0);
49
+ return;
50
+ }
51
+ if (!ctx?.siteKey) {
52
+ setPost(null);
53
+ setIsLoading(false);
54
+ setError("Missing site key");
55
+ return;
56
+ }
57
+ let cancelled = false;
58
+ setPost(null);
59
+ setError(void 0);
60
+ setIsLoading(true);
61
+ const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;
62
+ fetch(url, {
63
+ headers: { "X-Site-Key": ctx.siteKey }
64
+ }).then((res) => {
65
+ if (cancelled) return;
66
+ if (res.status === 404) {
67
+ setPost(null);
68
+ setIsLoading(false);
69
+ return;
70
+ }
71
+ if (!res.ok) {
72
+ setPost(null);
73
+ setIsLoading(false);
74
+ setError("Failed to load");
75
+ return;
76
+ }
77
+ return res.json();
78
+ }).then((data) => {
79
+ if (cancelled) return;
80
+ setPost(data);
81
+ setIsLoading(false);
82
+ }).catch(() => {
83
+ if (cancelled) return;
84
+ setPost(null);
85
+ setIsLoading(false);
86
+ setError("Failed to load");
87
+ });
88
+ return () => {
89
+ cancelled = true;
90
+ };
91
+ }, [slug, ctx?.siteKey, ctx?.apiBase]);
92
+ return { post, isLoading, error };
93
+ }
94
+ function usePosts() {
95
+ const ctx = useDispatchContext();
96
+ const [posts, setPosts] = useState([]);
97
+ const [isLoading, setIsLoading] = useState(true);
98
+ const [error, setError] = useState(void 0);
99
+ useEffect(() => {
100
+ if (!ctx?.siteKey) {
101
+ setPosts([]);
102
+ setIsLoading(false);
103
+ setError("Missing site key");
104
+ return;
105
+ }
106
+ let cancelled = false;
107
+ setPosts([]);
108
+ setError(void 0);
109
+ setIsLoading(true);
110
+ const url = `${ctx.apiBase}/api/posts`;
111
+ fetch(url, {
112
+ headers: { "X-Site-Key": ctx.siteKey }
113
+ }).then((res) => {
114
+ if (cancelled) return;
115
+ if (!res.ok) {
116
+ setPosts([]);
117
+ setIsLoading(false);
118
+ setError("Failed to load");
119
+ return;
120
+ }
121
+ return res.json();
122
+ }).then((data) => {
123
+ if (cancelled) return;
124
+ setPosts(Array.isArray(data) ? data : []);
125
+ setIsLoading(false);
126
+ }).catch(() => {
127
+ if (cancelled) return;
128
+ setPosts([]);
129
+ setIsLoading(false);
130
+ setError("Failed to load");
131
+ });
132
+ return () => {
133
+ cancelled = true;
134
+ };
135
+ }, [ctx?.siteKey, ctx?.apiBase]);
136
+ return { posts, isLoading, error };
137
+ }
138
+ export {
139
+ DispatchProvider,
140
+ useDispatchContext,
141
+ usePost,
142
+ usePosts
143
+ };
144
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/context.tsx","../src/config.ts","../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport React, { createContext, useContext } from \"react\";\nimport { getApiBase } from \"./config\";\n\ntype DispatchContextValue = {\n siteKey: string | null;\n apiBase: string;\n};\n\nconst DispatchContext = createContext<DispatchContextValue | null>(null);\n\nexport function useDispatchContext(): DispatchContextValue | null {\n return useContext(DispatchContext);\n}\n\ntype DispatchProviderProps = {\n siteKey?: string | null;\n apiBase?: string;\n children?: unknown;\n};\n\nexport function DispatchProvider({\n siteKey = null,\n apiBase = getApiBase(),\n children,\n}: DispatchProviderProps) {\n const value: DispatchContextValue = {\n siteKey: siteKey?.trim() || null,\n apiBase,\n };\n\n if (!value.siteKey) {\n if (typeof console !== \"undefined\" && console.warn) {\n console.warn(\n \"[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider or set NEXT_PUBLIC_DISPATCH_SITE_KEY. Hooks will return empty/error state.\"\n );\n }\n }\n\n return (\n <DispatchContext.Provider value={value}>\n {children as React.ReactNode}\n </DispatchContext.Provider>\n );\n}\n","const API_BASE =\n typeof process !== \"undefined\" && process.env?.NEXT_PUBLIC_DISPATCH_API_URL\n ? process.env.NEXT_PUBLIC_DISPATCH_API_URL\n : \"https://dispatch-cms.vercel.app\";\n\nexport function getApiBase(): string {\n return API_BASE;\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport type { Post } from \"./types\";\nimport { useDispatchContext } from \"./context\";\n\nexport type UsePostResult = {\n post: Post | null;\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePost(slug: string | undefined): UsePostResult {\n const ctx = useDispatchContext();\n const [post, setPost] = useState<Post | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!slug?.trim()) {\n setPost(null);\n setIsLoading(false);\n setError(undefined);\n return;\n }\n\n if (!ctx?.siteKey) {\n setPost(null);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPost(null);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (res.status === 404) {\n setPost(null);\n setIsLoading(false);\n return;\n }\n if (!res.ok) {\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPost(data as Post);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPost(null);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [slug, ctx?.siteKey, ctx?.apiBase]);\n\n return { post, isLoading, error };\n}\n\nexport type UsePostsResult = {\n posts: Post[];\n isLoading: boolean;\n error?: string;\n};\n\nexport function usePosts(): UsePostsResult {\n const ctx = useDispatchContext();\n const [posts, setPosts] = useState<Post[]>([]);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<string | undefined>(undefined);\n\n useEffect(() => {\n if (!ctx?.siteKey) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Missing site key\");\n return;\n }\n\n let cancelled = false;\n setPosts([]);\n setError(undefined);\n setIsLoading(true);\n\n const url = `${ctx.apiBase}/api/posts`;\n fetch(url, {\n headers: { \"X-Site-Key\": ctx.siteKey },\n })\n .then((res) => {\n if (cancelled) return;\n if (!res.ok) {\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n return;\n }\n return res.json();\n })\n .then((data) => {\n if (cancelled) return;\n setPosts(Array.isArray(data) ? data : []);\n setIsLoading(false);\n })\n .catch(() => {\n if (cancelled) return;\n setPosts([]);\n setIsLoading(false);\n setError(\"Failed to load\");\n });\n\n return () => {\n cancelled = true;\n };\n }, [ctx?.siteKey, ctx?.apiBase]);\n\n return { posts, isLoading, error };\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@dispatchcms/react",
3
+ "version": "0.0.4",
4
+ "description": "React hooks and provider for Dispatch CMS",
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
+ },
18
+ "peerDependencies": {
19
+ "react": ">=18.0.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/react": "^18.3.12",
23
+ "react": "^18.3.1",
24
+ "tsup": "^8.3.5",
25
+ "typescript": "^5.7.2"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "keywords": ["dispatch", "cms", "react", "nextjs", "content"],
31
+ "license": "MIT"
32
+ }
package/src/config.ts ADDED
@@ -0,0 +1,8 @@
1
+ const API_BASE =
2
+ typeof process !== "undefined" && process.env?.NEXT_PUBLIC_DISPATCH_API_URL
3
+ ? process.env.NEXT_PUBLIC_DISPATCH_API_URL
4
+ : "https://dispatch-cms.vercel.app";
5
+
6
+ export function getApiBase(): string {
7
+ return API_BASE;
8
+ }
@@ -0,0 +1,46 @@
1
+ "use client";
2
+
3
+ import React, { createContext, useContext } from "react";
4
+ import { getApiBase } from "./config";
5
+
6
+ type DispatchContextValue = {
7
+ siteKey: string | null;
8
+ apiBase: string;
9
+ };
10
+
11
+ const DispatchContext = createContext<DispatchContextValue | null>(null);
12
+
13
+ export function useDispatchContext(): DispatchContextValue | null {
14
+ return useContext(DispatchContext);
15
+ }
16
+
17
+ type DispatchProviderProps = {
18
+ siteKey?: string | null;
19
+ apiBase?: string;
20
+ children?: unknown;
21
+ };
22
+
23
+ export function DispatchProvider({
24
+ siteKey = null,
25
+ apiBase = getApiBase(),
26
+ children,
27
+ }: DispatchProviderProps) {
28
+ const value: DispatchContextValue = {
29
+ siteKey: siteKey?.trim() || null,
30
+ apiBase,
31
+ };
32
+
33
+ if (!value.siteKey) {
34
+ if (typeof console !== "undefined" && console.warn) {
35
+ console.warn(
36
+ "[Dispatch] No siteKey provided. Pass siteKey to DispatchProvider or set NEXT_PUBLIC_DISPATCH_SITE_KEY. Hooks will return empty/error state."
37
+ );
38
+ }
39
+ }
40
+
41
+ return (
42
+ <DispatchContext.Provider value={value}>
43
+ {children as React.ReactNode}
44
+ </DispatchContext.Provider>
45
+ );
46
+ }
package/src/hooks.ts ADDED
@@ -0,0 +1,135 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+ import type { Post } from "./types";
5
+ import { useDispatchContext } from "./context";
6
+
7
+ export type UsePostResult = {
8
+ post: Post | null;
9
+ isLoading: boolean;
10
+ error?: string;
11
+ };
12
+
13
+ export function usePost(slug: string | undefined): UsePostResult {
14
+ const ctx = useDispatchContext();
15
+ const [post, setPost] = useState<Post | null>(null);
16
+ const [isLoading, setIsLoading] = useState(true);
17
+ const [error, setError] = useState<string | undefined>(undefined);
18
+
19
+ useEffect(() => {
20
+ if (!slug?.trim()) {
21
+ setPost(null);
22
+ setIsLoading(false);
23
+ setError(undefined);
24
+ return;
25
+ }
26
+
27
+ if (!ctx?.siteKey) {
28
+ setPost(null);
29
+ setIsLoading(false);
30
+ setError("Missing site key");
31
+ return;
32
+ }
33
+
34
+ let cancelled = false;
35
+ setPost(null);
36
+ setError(undefined);
37
+ setIsLoading(true);
38
+
39
+ const url = `${ctx.apiBase}/api/posts/${encodeURIComponent(slug.trim())}`;
40
+ fetch(url, {
41
+ headers: { "X-Site-Key": ctx.siteKey },
42
+ })
43
+ .then((res) => {
44
+ if (cancelled) return;
45
+ if (res.status === 404) {
46
+ setPost(null);
47
+ setIsLoading(false);
48
+ return;
49
+ }
50
+ if (!res.ok) {
51
+ setPost(null);
52
+ setIsLoading(false);
53
+ setError("Failed to load");
54
+ return;
55
+ }
56
+ return res.json();
57
+ })
58
+ .then((data) => {
59
+ if (cancelled) return;
60
+ setPost(data as Post);
61
+ setIsLoading(false);
62
+ })
63
+ .catch(() => {
64
+ if (cancelled) return;
65
+ setPost(null);
66
+ setIsLoading(false);
67
+ setError("Failed to load");
68
+ });
69
+
70
+ return () => {
71
+ cancelled = true;
72
+ };
73
+ }, [slug, ctx?.siteKey, ctx?.apiBase]);
74
+
75
+ return { post, isLoading, error };
76
+ }
77
+
78
+ export type UsePostsResult = {
79
+ posts: Post[];
80
+ isLoading: boolean;
81
+ error?: string;
82
+ };
83
+
84
+ export function usePosts(): UsePostsResult {
85
+ const ctx = useDispatchContext();
86
+ const [posts, setPosts] = useState<Post[]>([]);
87
+ const [isLoading, setIsLoading] = useState(true);
88
+ const [error, setError] = useState<string | undefined>(undefined);
89
+
90
+ useEffect(() => {
91
+ if (!ctx?.siteKey) {
92
+ setPosts([]);
93
+ setIsLoading(false);
94
+ setError("Missing site key");
95
+ return;
96
+ }
97
+
98
+ let cancelled = false;
99
+ setPosts([]);
100
+ setError(undefined);
101
+ setIsLoading(true);
102
+
103
+ const url = `${ctx.apiBase}/api/posts`;
104
+ fetch(url, {
105
+ headers: { "X-Site-Key": ctx.siteKey },
106
+ })
107
+ .then((res) => {
108
+ if (cancelled) return;
109
+ if (!res.ok) {
110
+ setPosts([]);
111
+ setIsLoading(false);
112
+ setError("Failed to load");
113
+ return;
114
+ }
115
+ return res.json();
116
+ })
117
+ .then((data) => {
118
+ if (cancelled) return;
119
+ setPosts(Array.isArray(data) ? data : []);
120
+ setIsLoading(false);
121
+ })
122
+ .catch(() => {
123
+ if (cancelled) return;
124
+ setPosts([]);
125
+ setIsLoading(false);
126
+ setError("Failed to load");
127
+ });
128
+
129
+ return () => {
130
+ cancelled = true;
131
+ };
132
+ }, [ctx?.siteKey, ctx?.apiBase]);
133
+
134
+ return { posts, isLoading, error };
135
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export type { Post } from "./types";
2
+ export { DispatchProvider, useDispatchContext } from "./context";
3
+ export { usePost, usePosts } from "./hooks";
4
+ export type { UsePostResult, UsePostsResult } from "./hooks";
package/src/types.ts ADDED
@@ -0,0 +1,13 @@
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
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "moduleResolution": "bundler",
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "jsx": "react-jsx",
10
+ "declaration": true,
11
+ "declarationMap": true,
12
+ "outDir": "dist"
13
+ },
14
+ "include": ["src"]
15
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,13 @@
1
+ import { defineConfig } from "tsup";
2
+
3
+ const useClientBanner = { js: "'use client';", css: "" };
4
+
5
+ export default defineConfig({
6
+ entry: ["src/index.ts"],
7
+ format: ["cjs", "esm"],
8
+ dts: true,
9
+ clean: true,
10
+ sourcemap: true,
11
+ external: ["react"],
12
+ banner: useClientBanner,
13
+ });