@sleekcms/client 0.1.5 → 1.0.0

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/README.md CHANGED
@@ -22,7 +22,7 @@ const client = createClient({
22
22
  const content = await client.getContent();
23
23
 
24
24
  // Get specific pages
25
- const blogPosts = await client.findPages('/blog');
25
+ const blogPosts = await client.getPages('/blog');
26
26
  ```
27
27
 
28
28
  ## Client Types
@@ -96,30 +96,60 @@ const homePage = await client.getContent('pages[?_path == `/`] | [0]');
96
96
  const siteTitle = await client.getContent<string>('config.title');
97
97
  ```
98
98
 
99
- ### `findPages<T>(path, query?)`
99
+ ### `getPages(path, query?)`
100
100
 
101
- Find pages that start with the specified path.
101
+ Get pages that start with the specified path.
102
102
 
103
103
  **Parameters:**
104
104
  - `path` (required): Path prefix to filter pages (e.g., `/blog`, `/products`)
105
105
  - `query` (optional): JMESPath query to further filter results
106
106
 
107
- **Returns:** `Promise<T>` (async) or `T` (sync)
107
+ **Returns:** `Promise<SleekSiteContent["pages"]>` (async) or `SleekSiteContent["pages"]` (sync)
108
108
 
109
109
  **Examples:**
110
110
 
111
111
  ```typescript
112
112
  // Get all blog posts
113
- const blogPosts = await client.findPages('/blog');
113
+ const blogPosts = await client.getPages('/blog');
114
114
 
115
115
  // Get blog posts with custom query
116
- const publishedPosts = await client.findPages(
116
+ const publishedPosts = await client.getPages(
117
117
  '/blog',
118
118
  '[?published == `true`]'
119
119
  );
120
120
 
121
121
  // Get post titles only
122
- const titles = await client.findPages('/blog', '[].title');
122
+ const titles = await client.getPages('/blog', '[].title');
123
+ ```
124
+
125
+ ### `getPage(path)`
126
+
127
+ Get a single page by its exact path.
128
+
129
+ **Parameters:**
130
+ - `path` (required): Exact page path (e.g., `/blog/my-post`, `/about`)
131
+
132
+ **Returns:** `Promise<Page>` (async) or `Page | null` (sync)
133
+
134
+ **Note:** Async client throws an error if page is not found. Sync client returns `null`.
135
+
136
+ **Examples:**
137
+
138
+ ```typescript
139
+ // Async client - throws if not found
140
+ try {
141
+ const aboutPage = await client.getPage('/about');
142
+ console.log(aboutPage.title);
143
+ } catch (error) {
144
+ console.error('Page not found');
145
+ }
146
+
147
+ // Sync client - returns null if not found
148
+ const syncClient = await createSyncClient({ siteToken: '...' });
149
+ const aboutPage = syncClient.getPage('/about');
150
+ if (aboutPage) {
151
+ console.log(aboutPage.title);
152
+ }
123
153
  ```
124
154
 
125
155
  ### `getImages()`
@@ -167,6 +197,27 @@ const categories = await client.getList('categories');
167
197
  // [{ label: "Technology", value: "tech" }, ...]
168
198
  ```
169
199
 
200
+ ### `getSlugs(path)`
201
+
202
+ Get an array of slugs from pages that start with the specified path. Only includes pages that have a `_slug` property.
203
+
204
+ **Parameters:**
205
+ - `path` (required): Path prefix to filter pages (e.g., `/blog`, `/products`)
206
+
207
+ **Returns:** `Promise<string[]>` (async) or `string[]` (sync)
208
+
209
+ **Example:**
210
+
211
+ ```typescript
212
+ // Get all blog post slugs
213
+ const slugs = await client.getSlugs('/blog');
214
+ // ["my-first-post", "second-post", "latest-update"]
215
+
216
+ // Useful for generating static paths in Next.js
217
+ const productSlugs = await client.getSlugs('/products');
218
+ // ["laptop", "keyboard", "mouse"]
219
+ ```
220
+
170
221
  ## Content Structure
171
222
 
172
223
  The SleekCMS content has the following structure:
@@ -228,7 +279,7 @@ export default async function BlogPage() {
228
279
  env: 'published',
229
280
  });
230
281
 
231
- const posts = await client.findPages('/blog');
282
+ const posts = await client.getPages('/blog');
232
283
 
233
284
  return (
234
285
  <div>
@@ -255,12 +306,96 @@ const client = await createSyncClient({
255
306
  });
256
307
 
257
308
  // Generate static pages
258
- const pages = client.findPages('/');
309
+ const pages = client.getPages('/');
259
310
  const images = client.getImages();
260
311
 
261
312
  // All subsequent calls are synchronous and instant
262
313
  ```
263
314
 
315
+ ### Next.js Static Params (generateStaticParams)
316
+
317
+ Use `getSlugs()` to generate static paths for dynamic routes in Next.js:
318
+
319
+ ```typescript
320
+ // app/blog/[slug]/page.tsx
321
+ import { createClient } from '@sleekcms/client';
322
+
323
+ // Generate static paths at build time
324
+ export async function generateStaticParams() {
325
+ const client = createClient({
326
+ siteToken: process.env.SLEEKCMS_TOKEN!,
327
+ env: 'published',
328
+ });
329
+
330
+ const slugs = await client.getSlugs('/blog');
331
+
332
+ return slugs.map((slug) => ({
333
+ slug: slug,
334
+ }));
335
+ }
336
+
337
+ // Render the page
338
+ export default async function BlogPost({ params }: { params: { slug: string } }) {
339
+ const client = createClient({
340
+ siteToken: process.env.SLEEKCMS_TOKEN!,
341
+ env: 'published',
342
+ });
343
+
344
+ const post = await client.getPage(`/blog/${params.slug}`);
345
+
346
+ return (
347
+ <article>
348
+ <h1>{post.title}</h1>
349
+ <div>{post.content}</div>
350
+ </article>
351
+ );
352
+ }
353
+ ```
354
+
355
+ **Pages Router Example:**
356
+
357
+ ```typescript
358
+ // pages/blog/[slug].tsx
359
+ import { createClient } from '@sleekcms/client';
360
+ import type { GetStaticPaths, GetStaticProps } from 'next';
361
+
362
+ export const getStaticPaths: GetStaticPaths = async () => {
363
+ const client = createClient({
364
+ siteToken: process.env.SLEEKCMS_TOKEN!,
365
+ env: 'published',
366
+ });
367
+
368
+ const slugs = await client.getSlugs('/blog');
369
+
370
+ return {
371
+ paths: slugs.map((slug) => ({ params: { slug } })),
372
+ fallback: false,
373
+ };
374
+ };
375
+
376
+ export const getStaticProps: GetStaticProps = async ({ params }) => {
377
+ const client = createClient({
378
+ siteToken: process.env.SLEEKCMS_TOKEN!,
379
+ env: 'published',
380
+ });
381
+
382
+ const post = await client.getPage(`/blog/${params!.slug}`);
383
+
384
+ return {
385
+ props: { post },
386
+ };
387
+ };
388
+
389
+ export default function BlogPost({ post }: any) {
390
+ return (
391
+ <article>
392
+ <h1>{post.title}</h1>
393
+ <div>{post.content}</div>
394
+ </article>
395
+ );
396
+ }
397
+ ```
398
+
264
399
  ### Browser Usage
265
400
 
266
401
  ```typescript
@@ -316,7 +451,10 @@ interface BlogPost {
316
451
  _path: string;
317
452
  }
318
453
 
319
- const posts = await client.findPages<BlogPost[]>('/blog');
454
+ const posts = await client.getPages('/blog');
455
+
456
+ // Get a single page with error handling
457
+ const aboutPage = await client.getPage('/about');
320
458
  ```
321
459
 
322
460
  ## License
package/index.cjs CHANGED
@@ -33,6 +33,8 @@ __export(index_exports, {
33
33
  createSyncClient: () => createSyncClient
34
34
  });
35
35
  module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/lib.ts
36
38
  var jmespath = __toESM(require("jmespath"), 1);
37
39
  function isDevToken(token) {
38
40
  return token.startsWith("dev-");
@@ -41,149 +43,164 @@ function getBaseUrl(token) {
41
43
  let [env, siteId, ...rest] = token.split("-");
42
44
  return `https://${env}.sleekcms.com/${siteId}`;
43
45
  }
44
- async function fetchSiteContent(options, searchQuery) {
45
- const { siteToken, env = "latest", mock } = options;
46
- if (!siteToken) {
47
- throw new Error("[SleekCMS] siteToken is required");
48
- }
49
- const baseUrl = getBaseUrl(siteToken).replace(/\/$/, "");
50
- const url = new URL(`${baseUrl}/${env}`);
51
- if (searchQuery) {
52
- url.searchParams.set("search", searchQuery);
53
- }
54
- if (mock && isDevToken(siteToken)) {
55
- url.searchParams.set("mock", "true");
56
- }
57
- const res = await fetch(url.toString(), {
58
- method: "GET",
59
- headers: {
60
- "Content-Type": "application/json",
61
- Authorization: siteToken
62
- }
63
- });
64
- if (!res.ok) {
65
- let message = res.statusText;
66
- try {
67
- const data = await res.json();
68
- if (data && data.message) message = data.message;
69
- } catch {
70
- }
71
- throw new Error(`[SleekCMS] Request failed (${res.status}): ${message}`);
72
- }
73
- return res.json();
74
- }
75
46
  function applyJmes(data, query) {
76
47
  if (!query) return data;
77
48
  return jmespath.search(data, query);
78
49
  }
79
- function createClient(options) {
80
- const dev = isDevToken(options.siteToken);
81
- let cacheMode = !!options.cache || !!options.mock && dev;
50
+ function createFetchSiteContent(options) {
51
+ const { siteToken, env = "latest", mock } = options;
52
+ const dev = isDevToken(siteToken);
53
+ let cacheMode = !!options.cache || !!mock && dev;
82
54
  let cachedContent = null;
83
- async function ensureCacheLoaded() {
84
- if (cachedContent) return cachedContent;
85
- const data = await fetchSiteContent(options);
86
- cachedContent = data;
87
- return data;
88
- }
89
- async function getContent(query) {
90
- if (cacheMode) {
91
- const data2 = await ensureCacheLoaded();
92
- return applyJmes(data2, query);
55
+ return async function fetchSiteContent(searchQuery) {
56
+ if (!siteToken) {
57
+ throw new Error("[SleekCMS] siteToken is required");
58
+ }
59
+ if (cachedContent) {
60
+ return applyJmes(cachedContent, searchQuery);
93
61
  }
94
- if (!query) {
95
- const data2 = await fetchSiteContent(options);
96
- cachedContent = data2;
62
+ const baseUrl = getBaseUrl(siteToken).replace(/\/$/, "");
63
+ const url = new URL(`${baseUrl}/${env}`);
64
+ if (searchQuery && !cacheMode && !cachedContent) {
65
+ url.searchParams.set("search", searchQuery);
66
+ }
67
+ if (mock && dev) {
68
+ url.searchParams.set("mock", "true");
69
+ }
70
+ const res = await fetch(url.toString(), {
71
+ method: "GET",
72
+ headers: {
73
+ "Content-Type": "application/json",
74
+ Authorization: siteToken
75
+ }
76
+ });
77
+ if (!res.ok) {
78
+ let message = res.statusText;
79
+ try {
80
+ const data2 = await res.json();
81
+ if (data2 && data2.message) message = data2.message;
82
+ } catch {
83
+ }
84
+ throw new Error(`[SleekCMS] Request failed (${res.status}): ${message}`);
85
+ }
86
+ const data = await res.json();
87
+ if (!searchQuery) {
88
+ cachedContent = data;
97
89
  cacheMode = true;
98
- return data2;
99
90
  }
100
- const data = await fetchSiteContent(options, query);
101
91
  return data;
92
+ };
93
+ }
94
+
95
+ // src/index.ts
96
+ function extractSlugs(pages, path) {
97
+ const slugs = [];
98
+ const pagesList = pages ?? [];
99
+ for (const page of pagesList) {
100
+ const pth = typeof page._path === "string" ? page._path : "";
101
+ if (pth.startsWith(path) && "_slug" in page && typeof page._slug === "string") {
102
+ slugs.push(page._slug);
103
+ }
104
+ }
105
+ return slugs;
106
+ }
107
+ function filterPagesByPath(pages, path) {
108
+ const pagesList = pages ?? [];
109
+ return pagesList.filter((p) => {
110
+ const pth = typeof p._path === "string" ? p._path : "";
111
+ return pth.startsWith(path);
112
+ });
113
+ }
114
+ function createClient(options) {
115
+ const fetchSiteContent = createFetchSiteContent(options);
116
+ async function getContent(query) {
117
+ return await fetchSiteContent(query);
102
118
  }
103
- async function findPages(path, query) {
119
+ async function getPages(path, query) {
104
120
  if (!path) {
105
- throw new Error("[SleekCMS] path is required for findPages");
121
+ throw new Error("[SleekCMS] path is required for getPages");
106
122
  }
107
- if (cacheMode) {
108
- const data = await ensureCacheLoaded();
109
- const pages2 = data.pages ?? [];
110
- const filtered2 = pages2.filter((p) => {
111
- const pth = typeof p._path === "string" ? p._path : "";
112
- return pth.startsWith(path);
113
- });
114
- return applyJmes(filtered2, query);
123
+ const data = await fetchSiteContent();
124
+ const filtered = filterPagesByPath(data.pages, path);
125
+ return applyJmes(filtered, query);
126
+ }
127
+ async function getPage(path) {
128
+ if (!path) {
129
+ throw new Error("[SleekCMS] path is required for getPage");
115
130
  }
116
- const pages = await fetchSiteContent(
117
- options,
118
- "pages"
119
- );
120
- const filtered = (pages ?? []).filter((p) => {
131
+ const data = await fetchSiteContent();
132
+ const pages = data.pages ?? [];
133
+ const page = pages.find((p) => {
121
134
  const pth = typeof p._path === "string" ? p._path : "";
122
- return pth.startsWith(path);
135
+ return pth === path;
123
136
  });
124
- return applyJmes(filtered, query);
137
+ if (!page) {
138
+ throw new Error(`[SleekCMS] Page not found: ${path}`);
139
+ }
140
+ return page;
125
141
  }
126
- async function getImages() {
127
- if (cacheMode) {
128
- const data = await ensureCacheLoaded();
129
- return data.images ?? {};
142
+ async function getSlugs(path) {
143
+ if (!path) {
144
+ throw new Error("[SleekCMS] path is required for getSlugs");
130
145
  }
131
- const images = await fetchSiteContent(
132
- options,
133
- "images"
134
- );
135
- return images ?? {};
146
+ const data = await fetchSiteContent();
147
+ return extractSlugs(data.pages, path);
148
+ }
149
+ async function getImages() {
150
+ const data = await fetchSiteContent();
151
+ return data.images ?? {};
136
152
  }
137
153
  async function getImage(name) {
138
154
  if (!name) return void 0;
139
- if (cacheMode) {
140
- const data = await ensureCacheLoaded();
141
- return data.images ? data.images[name] : void 0;
142
- }
143
- const images = await fetchSiteContent(
144
- options,
145
- "images"
146
- );
147
- return images ? images[name] : void 0;
155
+ const data = await fetchSiteContent();
156
+ return data.images ? data.images[name] : void 0;
148
157
  }
149
158
  async function getList(name) {
150
159
  if (!name) return void 0;
151
- if (cacheMode) {
152
- const data = await ensureCacheLoaded();
153
- const lists2 = data.lists ?? {};
154
- const list2 = lists2[name];
155
- return Array.isArray(list2) ? list2 : void 0;
156
- }
157
- const lists = await fetchSiteContent(
158
- options,
159
- "lists"
160
- );
161
- const list = lists ? lists[name] : void 0;
160
+ const data = await fetchSiteContent();
161
+ const lists = data.lists ?? {};
162
+ const list = lists[name];
162
163
  return Array.isArray(list) ? list : void 0;
163
164
  }
164
165
  return {
165
166
  getContent,
166
- findPages,
167
+ getPages,
168
+ getPage,
169
+ getSlugs,
167
170
  getImages,
168
171
  getImage,
169
172
  getList
170
173
  };
171
174
  }
172
175
  async function createSyncClient(options) {
173
- const data = await fetchSiteContent(options);
176
+ const fetchSiteContent = createFetchSiteContent(options);
177
+ const data = await fetchSiteContent();
174
178
  function getContent(query) {
175
179
  return applyJmes(data, query);
176
180
  }
177
- function findPages(path, query) {
181
+ function getPages(path, query) {
178
182
  if (!path) {
179
- throw new Error("[SleekCMS] path is required for findPages");
183
+ throw new Error("[SleekCMS] path is required for getPages");
184
+ }
185
+ const filtered = filterPagesByPath(data.pages, path);
186
+ return applyJmes(filtered, query);
187
+ }
188
+ function getPage(path) {
189
+ if (!path) {
190
+ throw new Error("[SleekCMS] path is required for getPage");
180
191
  }
181
192
  const pages = data.pages ?? [];
182
- const filtered = pages.filter((p) => {
193
+ const page = pages.find((p) => {
183
194
  const pth = typeof p._path === "string" ? p._path : "";
184
- return pth.startsWith(path);
195
+ return pth === path;
185
196
  });
186
- return applyJmes(filtered, query);
197
+ return page ?? null;
198
+ }
199
+ function getSlugs(path) {
200
+ if (!path) {
201
+ throw new Error("[SleekCMS] path is required for getSlugs");
202
+ }
203
+ return extractSlugs(data.pages, path);
187
204
  }
188
205
  function getImages() {
189
206
  return data.images ?? {};
@@ -200,7 +217,9 @@ async function createSyncClient(options) {
200
217
  }
201
218
  return {
202
219
  getContent,
203
- findPages,
220
+ getPages,
221
+ getPage,
222
+ getSlugs,
204
223
  getImages,
205
224
  getImage,
206
225
  getList
package/index.d.cts CHANGED
@@ -32,8 +32,10 @@ interface ClientOptions {
32
32
  * Async SleekCMS client: methods return Promises.
33
33
  */
34
34
  interface SleekClient {
35
- getContent<T = SleekSiteContent>(query?: string): Promise<T>;
36
- findPages<T = unknown>(path: string, query?: string): Promise<T>;
35
+ getContent(query?: string): Promise<SleekSiteContent>;
36
+ getPages(path: string, query?: string): Promise<SleekSiteContent["pages"]>;
37
+ getPage(path: string): Promise<Page>;
38
+ getSlugs(path: string): Promise<string[]>;
37
39
  getImages(): Promise<SleekSiteContent["images"]>;
38
40
  getImage(name: string): Promise<unknown | undefined>;
39
41
  getList<T = unknown>(name: string): Promise<T[] | undefined>;
@@ -42,8 +44,10 @@ interface SleekClient {
42
44
  * Sync client: prefetches full content once; subsequent calls are in-memory only.
43
45
  */
44
46
  interface SleekSyncClient {
45
- getContent<T = SleekSiteContent>(query?: string): T;
46
- findPages<T = unknown>(path: string, query?: string): T;
47
+ getContent(query?: string): SleekSiteContent;
48
+ getPages(path: string, query?: string): SleekSiteContent["pages"];
49
+ getPage(path: string): Page | null;
50
+ getSlugs(path: string): string[];
47
51
  getImages(): SleekSiteContent["images"];
48
52
  getImage(name: string): unknown | undefined;
49
53
  getList<T = unknown>(name: string): T[] | undefined;
package/index.d.ts CHANGED
@@ -32,8 +32,10 @@ interface ClientOptions {
32
32
  * Async SleekCMS client: methods return Promises.
33
33
  */
34
34
  interface SleekClient {
35
- getContent<T = SleekSiteContent>(query?: string): Promise<T>;
36
- findPages<T = unknown>(path: string, query?: string): Promise<T>;
35
+ getContent(query?: string): Promise<SleekSiteContent>;
36
+ getPages(path: string, query?: string): Promise<SleekSiteContent["pages"]>;
37
+ getPage(path: string): Promise<Page>;
38
+ getSlugs(path: string): Promise<string[]>;
37
39
  getImages(): Promise<SleekSiteContent["images"]>;
38
40
  getImage(name: string): Promise<unknown | undefined>;
39
41
  getList<T = unknown>(name: string): Promise<T[] | undefined>;
@@ -42,8 +44,10 @@ interface SleekClient {
42
44
  * Sync client: prefetches full content once; subsequent calls are in-memory only.
43
45
  */
44
46
  interface SleekSyncClient {
45
- getContent<T = SleekSiteContent>(query?: string): T;
46
- findPages<T = unknown>(path: string, query?: string): T;
47
+ getContent(query?: string): SleekSiteContent;
48
+ getPages(path: string, query?: string): SleekSiteContent["pages"];
49
+ getPage(path: string): Page | null;
50
+ getSlugs(path: string): string[];
47
51
  getImages(): SleekSiteContent["images"];
48
52
  getImage(name: string): unknown | undefined;
49
53
  getList<T = unknown>(name: string): T[] | undefined;
package/index.mjs ADDED
@@ -0,0 +1,195 @@
1
+ // src/lib.ts
2
+ import * as jmespath from "jmespath";
3
+ function isDevToken(token) {
4
+ return token.startsWith("dev-");
5
+ }
6
+ function getBaseUrl(token) {
7
+ let [env, siteId, ...rest] = token.split("-");
8
+ return `https://${env}.sleekcms.com/${siteId}`;
9
+ }
10
+ function applyJmes(data, query) {
11
+ if (!query) return data;
12
+ return jmespath.search(data, query);
13
+ }
14
+ function createFetchSiteContent(options) {
15
+ const { siteToken, env = "latest", mock } = options;
16
+ const dev = isDevToken(siteToken);
17
+ let cacheMode = !!options.cache || !!mock && dev;
18
+ let cachedContent = null;
19
+ return async function fetchSiteContent(searchQuery) {
20
+ if (!siteToken) {
21
+ throw new Error("[SleekCMS] siteToken is required");
22
+ }
23
+ if (cachedContent) {
24
+ return applyJmes(cachedContent, searchQuery);
25
+ }
26
+ const baseUrl = getBaseUrl(siteToken).replace(/\/$/, "");
27
+ const url = new URL(`${baseUrl}/${env}`);
28
+ if (searchQuery && !cacheMode && !cachedContent) {
29
+ url.searchParams.set("search", searchQuery);
30
+ }
31
+ if (mock && dev) {
32
+ url.searchParams.set("mock", "true");
33
+ }
34
+ const res = await fetch(url.toString(), {
35
+ method: "GET",
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ Authorization: siteToken
39
+ }
40
+ });
41
+ if (!res.ok) {
42
+ let message = res.statusText;
43
+ try {
44
+ const data2 = await res.json();
45
+ if (data2 && data2.message) message = data2.message;
46
+ } catch {
47
+ }
48
+ throw new Error(`[SleekCMS] Request failed (${res.status}): ${message}`);
49
+ }
50
+ const data = await res.json();
51
+ if (!searchQuery) {
52
+ cachedContent = data;
53
+ cacheMode = true;
54
+ }
55
+ return data;
56
+ };
57
+ }
58
+
59
+ // src/index.ts
60
+ function extractSlugs(pages, path) {
61
+ const slugs = [];
62
+ const pagesList = pages ?? [];
63
+ for (const page of pagesList) {
64
+ const pth = typeof page._path === "string" ? page._path : "";
65
+ if (pth.startsWith(path) && "_slug" in page && typeof page._slug === "string") {
66
+ slugs.push(page._slug);
67
+ }
68
+ }
69
+ return slugs;
70
+ }
71
+ function filterPagesByPath(pages, path) {
72
+ const pagesList = pages ?? [];
73
+ return pagesList.filter((p) => {
74
+ const pth = typeof p._path === "string" ? p._path : "";
75
+ return pth.startsWith(path);
76
+ });
77
+ }
78
+ function createClient(options) {
79
+ const fetchSiteContent = createFetchSiteContent(options);
80
+ async function getContent(query) {
81
+ return await fetchSiteContent(query);
82
+ }
83
+ async function getPages(path, query) {
84
+ if (!path) {
85
+ throw new Error("[SleekCMS] path is required for getPages");
86
+ }
87
+ const data = await fetchSiteContent();
88
+ const filtered = filterPagesByPath(data.pages, path);
89
+ return applyJmes(filtered, query);
90
+ }
91
+ async function getPage(path) {
92
+ if (!path) {
93
+ throw new Error("[SleekCMS] path is required for getPage");
94
+ }
95
+ const data = await fetchSiteContent();
96
+ const pages = data.pages ?? [];
97
+ const page = pages.find((p) => {
98
+ const pth = typeof p._path === "string" ? p._path : "";
99
+ return pth === path;
100
+ });
101
+ if (!page) {
102
+ throw new Error(`[SleekCMS] Page not found: ${path}`);
103
+ }
104
+ return page;
105
+ }
106
+ async function getSlugs(path) {
107
+ if (!path) {
108
+ throw new Error("[SleekCMS] path is required for getSlugs");
109
+ }
110
+ const data = await fetchSiteContent();
111
+ return extractSlugs(data.pages, path);
112
+ }
113
+ async function getImages() {
114
+ const data = await fetchSiteContent();
115
+ return data.images ?? {};
116
+ }
117
+ async function getImage(name) {
118
+ if (!name) return void 0;
119
+ const data = await fetchSiteContent();
120
+ return data.images ? data.images[name] : void 0;
121
+ }
122
+ async function getList(name) {
123
+ if (!name) return void 0;
124
+ const data = await fetchSiteContent();
125
+ const lists = data.lists ?? {};
126
+ const list = lists[name];
127
+ return Array.isArray(list) ? list : void 0;
128
+ }
129
+ return {
130
+ getContent,
131
+ getPages,
132
+ getPage,
133
+ getSlugs,
134
+ getImages,
135
+ getImage,
136
+ getList
137
+ };
138
+ }
139
+ async function createSyncClient(options) {
140
+ const fetchSiteContent = createFetchSiteContent(options);
141
+ const data = await fetchSiteContent();
142
+ function getContent(query) {
143
+ return applyJmes(data, query);
144
+ }
145
+ function getPages(path, query) {
146
+ if (!path) {
147
+ throw new Error("[SleekCMS] path is required for getPages");
148
+ }
149
+ const filtered = filterPagesByPath(data.pages, path);
150
+ return applyJmes(filtered, query);
151
+ }
152
+ function getPage(path) {
153
+ if (!path) {
154
+ throw new Error("[SleekCMS] path is required for getPage");
155
+ }
156
+ const pages = data.pages ?? [];
157
+ const page = pages.find((p) => {
158
+ const pth = typeof p._path === "string" ? p._path : "";
159
+ return pth === path;
160
+ });
161
+ return page ?? null;
162
+ }
163
+ function getSlugs(path) {
164
+ if (!path) {
165
+ throw new Error("[SleekCMS] path is required for getSlugs");
166
+ }
167
+ return extractSlugs(data.pages, path);
168
+ }
169
+ function getImages() {
170
+ return data.images ?? {};
171
+ }
172
+ function getImage(name) {
173
+ if (!name) return void 0;
174
+ return data.images ? data.images[name] : void 0;
175
+ }
176
+ function getList(name) {
177
+ if (!name) return void 0;
178
+ const lists = data.lists ?? {};
179
+ const list = lists[name];
180
+ return Array.isArray(list) ? list : void 0;
181
+ }
182
+ return {
183
+ getContent,
184
+ getPages,
185
+ getPage,
186
+ getSlugs,
187
+ getImages,
188
+ getImage,
189
+ getList
190
+ };
191
+ }
192
+ export {
193
+ createClient,
194
+ createSyncClient
195
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sleekcms/client",
3
- "version": "0.1.5",
3
+ "version": "1.0.0",
4
4
  "description": "Official SleekCMS content client for Node 18+ and browser",
5
5
  "type": "module",
6
6
  "main": "index.cjs",
@@ -15,7 +15,7 @@
15
15
  }
16
16
  },
17
17
  "scripts": {
18
- "build": "npm run clean && tsup src/index.ts --dts --format esm,cjs && cp README.md dist/ && jq '.private = false | .files = [\"index.cjs\", \"index.mjs\", \"index.d.ts\", \"index.d.cts\", \"README.md\"]' package.json > dist/package.json",
18
+ "build": "npm run clean && tsup && cp README.md dist/ && cp .npmrc dist/ && jq '.private = false | .files = [\"index.cjs\", \"index.mjs\", \"index.d.ts\", \"index.d.cts\", \"README.md\"]' package.json > dist/package.json",
19
19
  "clean": "rimraf dist || true",
20
20
  "test": "vitest run",
21
21
  "test:watch": "vitest",