@sleekcms/client 1.0.1 → 2.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.
Files changed (6) hide show
  1. package/README.md +134 -325
  2. package/index.cjs +123 -104
  3. package/index.d.cts +22 -34
  4. package/index.d.ts +22 -34
  5. package/index.mjs +121 -102
  6. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SleekCMS Client
2
2
 
3
- Official JavaScript/TypeScript client library for [SleekCMS](https://sleekcms.com) - a modern headless CMS.
3
+ Official JavaScript/TypeScript client for [SleekCMS](https://sleekcms.com) - a headless CMS that lets you manage content and deliver it via API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,280 +13,176 @@ npm install @sleekcms/client
13
13
  ```typescript
14
14
  import { createClient } from '@sleekcms/client';
15
15
 
16
- const client = createClient({
16
+ const client = await createClient({
17
17
  siteToken: 'your-site-token',
18
- env: 'latest', // optional: default 'latest'. Ignored for dev- tokens
18
+ env: 'latest'
19
19
  });
20
20
 
21
- // Fetch all content
22
- const content = await client.getContent();
21
+ // Get a page
22
+ const page = client.getPage('/about');
23
23
 
24
- // Get specific pages
25
- const blogPosts = await client.getPages('/blog');
24
+ // Get all blog posts
25
+ const posts = client.getPages('/blog');
26
+
27
+ // Get an entry
28
+ const footer = client.getEntry('footer');
26
29
  ```
27
30
 
28
- ## Client Types
31
+ ## Sync vs Async Clients
29
32
 
30
- ### Async Client (Recommended)
33
+ ### Sync Client (Recommended for SSG)
31
34
 
32
- The default client that fetches content on-demand. Ideal for server-side rendering and applications where you want fresh content on each request.
35
+ **`createClient()`** fetches all content upfront and returns a client with synchronous methods. Best for static site generation where you build once and want instant access to content.
33
36
 
34
37
  ```typescript
35
- import { createClient } from '@sleekcms/client';
36
-
37
- const client = createClient({
38
- siteToken: 'your-site-token',
39
- env: 'latest',
40
- cache: false, // optional: enable in-memory caching
41
- mock: false, // optional: use mock data (dev tokens only)
38
+ // Async initialization, sync usage
39
+ const client = await createClient({
40
+ siteToken: 'your-site-token'
42
41
  });
42
+
43
+ // All methods return data immediately (no await)
44
+ const page = client.getPage('/pricing');
45
+ const slugs = client.getSlugs('/blog');
43
46
  ```
44
47
 
45
- ### Sync Client
48
+ **Use when:**
49
+ - Building static sites (Next.js SSG, Astro, 11ty)
50
+ - You need all content at build time
51
+ - You want predictable performance
46
52
 
47
- Prefetches all content once and provides synchronous methods. Perfect for static site generation and client-side applications.
53
+ ### Async Client (Recommended for SSR)
48
54
 
49
- ```typescript
50
- import { createSyncClient } from '@sleekcms/client';
55
+ **`createAsyncClient()`** fetches content on-demand. Best for server-side rendering where you want fresh content per request without loading everything.
51
56
 
52
- // Note: createSyncClient is async, but returns a sync client
53
- const client = await createSyncClient({
57
+ ```typescript
58
+ const client = createAsyncClient({
54
59
  siteToken: 'your-site-token',
55
- env: 'latest',
60
+ cdn: true // optional: cache-friendly URLs
56
61
  });
57
62
 
58
- // All methods are now synchronous
59
- const content = client.getContent();
60
- const images = client.getImages();
63
+ // All methods are async
64
+ const page = await client.getPage('/pricing');
65
+ const posts = await client.getPages('/blog');
61
66
  ```
62
67
 
63
- ## Configuration Options
68
+ **Use when:**
69
+ - Server-side rendering (Next.js SSR, SvelteKit, Remix)
70
+ - You only need specific content per request
71
+ - You want the latest content on each request
72
+
73
+ ## Configuration
64
74
 
65
75
  | Option | Type | Default | Description |
66
76
  |--------|------|---------|-------------|
67
- | `siteToken` | `string` | *required* | Your SleekCMS site token |
68
- | `env` | `string` | `'latest'` | Environment: default is `'latest'`. Ignored for dev- tokens
69
- | `cache` | `boolean` | `false` | Enable in-memory caching for async client |
70
- | `mock` | `boolean` | `false` | Use mock data (only works with dev tokens) |
71
-
72
- ## API Methods
73
-
74
- ### `getContent<T>(query?)`
75
-
76
- Fetch the entire site content or filter it using a JMESPath query.
77
+ | `siteToken` | `string` | required | Your site token from SleekCMS |
78
+ | `env` | `string` | `'latest'` | Environment/alias name |
79
+ | `cdn` | `boolean` | `false` | Resolve env name to bypass CDN cache. Adds latency. |
80
+ | `lang` | `string` | - | Language code for internationalized content (e.g., `'en'`, `'es'`, `'fr'`) |
77
81
 
78
- **Parameters:**
79
- - `query` (optional): JMESPath query string to filter/transform content
80
-
81
- **Returns:** `Promise<T>` (async) or `T` (sync)
82
-
83
- **Examples:**
82
+ **Internationalization Example:**
84
83
 
85
84
  ```typescript
86
- // Get all content
87
- const content = await client.getContent();
88
-
89
- // Get only pages
90
- const pages = await client.getContent('pages');
91
-
92
- // Get specific page by path
93
- const homePage = await client.getContent('pages[?_path == `/`] | [0]');
85
+ // Fetch Spanish content
86
+ const client = await createClient({
87
+ siteToken: 'your-site-token',
88
+ lang: 'es'
89
+ });
94
90
 
95
- // Get config title
96
- const siteTitle = await client.getContent<string>('config.title');
91
+ const page = client.getPage('/about');
92
+ // Returns Spanish version of the page
97
93
  ```
98
94
 
99
- ### `getPages(path, query?)`
95
+ ## API Reference
100
96
 
101
- Get pages that start with the specified path.
97
+ ### `getContent(search?)`
102
98
 
103
- **Parameters:**
104
- - `path` (required): Path prefix to filter pages (e.g., `/blog`, `/products`)
105
- - `query` (optional): JMESPath query to further filter results
106
-
107
- **Returns:** `Promise<SleekSiteContent["pages"]>` (async) or `SleekSiteContent["pages"]` (sync)
108
-
109
- **Examples:**
99
+ Get all content or use a [JMESPath](https://jmespath.org/) search/query to filter it.
110
100
 
111
101
  ```typescript
112
- // Get all blog posts
113
- const blogPosts = await client.getPages('/blog');
114
-
115
- // Get blog posts with custom query
116
- const publishedPosts = await client.getPages(
117
- '/blog',
118
- '[?published == `true`]'
119
- );
120
-
121
- // Get post titles only
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:**
102
+ // Get everything
103
+ const content = client.getContent();
137
104
 
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
- }
105
+ // Get only pages using JMESPath
106
+ const pages = client.getContent('pages');
146
107
 
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
- }
108
+ // Get config title
109
+ const title = client.getContent('config.title');
153
110
  ```
154
111
 
155
- ### `getImages()`
156
-
157
- Retrieve all images from the CMS.
112
+ ### `getPages(path)`
158
113
 
159
- **Returns:** `Promise<Record<string, Image>>` (async) or `Record<string, Image>` (sync)
160
-
161
- **Example:**
114
+ Get all pages that start with a specific path.
162
115
 
163
116
  ```typescript
164
- const images = await client.getImages();
165
- // { "logo": { url: "https://...", ... }, ... }
117
+ const posts = client.getPages('/blog');
118
+ const products = client.getPages('/shop/products');
166
119
  ```
167
120
 
168
- ### `getImage(name)`
169
-
170
- Get a specific image by name.
171
-
172
- **Parameters:**
173
- - `name` (required): Image name/key
174
-
175
- **Returns:** `Promise<Image | undefined>` (async) or `Image | undefined` (sync)
121
+ ### `getPage(path)`
176
122
 
177
- **Example:**
123
+ Get a single page by exact path. Returns `null` if not found.
178
124
 
179
125
  ```typescript
180
- const logo = await client.getImage('logo');
181
- // { url: "https://...", width: 200, height: 100, ... }
126
+ const about = client.getPage('/about');
127
+ const post = client.getPage('/blog/hello-world');
182
128
  ```
183
129
 
184
- ### `getList<T>(name)`
185
-
186
- Retrieve a specific list (e.g., dropdown options, categories).
130
+ ### `getEntry(handle)`
187
131
 
188
- **Parameters:**
189
- - `name` (required): List name
190
-
191
- **Returns:** `Promise<T[] | undefined>` (async) or `T[] | undefined` (sync)
192
-
193
- **Example:**
132
+ Get an entry by handle. Entries can be single objects or arrays.
194
133
 
195
134
  ```typescript
196
- const categories = await client.getList('categories');
197
- // [{ label: "Technology", value: "tech" }, ...]
135
+ const header = client.getEntry('header');
136
+ const team = client.getEntry('team-members'); // could be an array
198
137
  ```
199
138
 
200
139
  ### `getSlugs(path)`
201
140
 
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:**
141
+ Extract slugs from pages under a path. Useful for static site generation.
210
142
 
211
143
  ```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"]
144
+ const slugs = client.getSlugs('/blog');
145
+ // ['hello-world', 'nextjs-tips', 'typescript-guide']
219
146
  ```
220
147
 
221
- ## Content Structure
148
+ ### `getImage(name)`
222
149
 
223
- The SleekCMS content has the following structure:
150
+ Get an image by name.
224
151
 
225
152
  ```typescript
226
- interface SleekSiteContent {
227
- entries?: Record<string, Entry> | Record<string, Entry[]>;
228
- pages?: Array<{
229
- _path: string;
230
- [key: string]: unknown;
231
- }>;
232
- images?: Record<string, {
233
- url: string;
234
- [key: string]: unknown;
235
- }>;
236
- lists?: Record<string, Array<{
237
- label: string;
238
- value: string;
239
- }>>;
240
- config?: {
241
- title?: string;
242
- };
243
- }
153
+ const logo = client.getImage('logo');
154
+ // { url: 'https://...', alt: '...', ... }
244
155
  ```
245
156
 
246
- ## JMESPath Queries
157
+ ### `getList(name)`
247
158
 
248
- All methods support optional JMESPath queries for powerful data filtering and transformation. Learn more at [JMESPath.org](https://jmespath.org/).
249
-
250
- **Common patterns:**
159
+ Get a list (array of label/value pairs).
251
160
 
252
161
  ```typescript
253
- // Filter array
254
- 'pages[?published == `true`]'
255
-
256
- // Get first item
257
- 'pages[0]'
258
-
259
- // Project specific fields
260
- 'pages[].{title: title, path: _path}'
261
-
262
- // Sort results
263
- 'sort_by(pages, &date)'
264
-
265
- // Nested queries
266
- 'pages[?category == `blog`].{title: title, image: images.hero.url}'
162
+ const categories = client.getList('categories');
163
+ // [{ label: 'Tech', value: 'tech' }, ...]
267
164
  ```
268
165
 
269
- ## Usage Examples
166
+ ## Framework Examples
270
167
 
271
- ### Next.js (App Router)
168
+ ### Next.js App Router (SSG)
272
169
 
273
170
  ```typescript
171
+ // app/blog/page.tsx
274
172
  import { createClient } from '@sleekcms/client';
275
173
 
276
174
  export default async function BlogPage() {
277
- const client = createClient({
278
- siteToken: process.env.SLEEKCMS_TOKEN!,
279
- env: 'published',
175
+ const client = await createClient({
176
+ siteToken: process.env.SLEEKCMS_SITE_TOKEN!
280
177
  });
281
178
 
282
- const posts = await client.getPages('/blog');
179
+ const posts = client.getPages('/blog');
283
180
 
284
181
  return (
285
182
  <div>
286
- {posts.map((post: any) => (
183
+ {posts?.map((post) => (
287
184
  <article key={post._path}>
288
185
  <h2>{post.title}</h2>
289
- <p>{post.excerpt}</p>
290
186
  </article>
291
187
  ))}
292
188
  </div>
@@ -294,175 +190,88 @@ export default async function BlogPage() {
294
190
  }
295
191
  ```
296
192
 
297
- ### Static Site Generation
298
-
299
- ```typescript
300
- import { createSyncClient } from '@sleekcms/client';
301
-
302
- // At build time
303
- const client = await createSyncClient({
304
- siteToken: process.env.SLEEKCMS_TOKEN!,
305
- env: 'published',
306
- });
307
-
308
- // Generate static pages
309
- const pages = client.getPages('/');
310
- const images = client.getImages();
311
-
312
- // All subsequent calls are synchronous and instant
313
- ```
314
-
315
- ### Next.js Static Params (generateStaticParams)
316
-
317
- Use `getSlugs()` to generate static paths for dynamic routes in Next.js:
193
+ ### Generate Static Paths
318
194
 
319
195
  ```typescript
320
196
  // app/blog/[slug]/page.tsx
321
197
  import { createClient } from '@sleekcms/client';
322
198
 
323
- // Generate static paths at build time
324
199
  export async function generateStaticParams() {
325
- const client = createClient({
326
- siteToken: process.env.SLEEKCMS_TOKEN!,
327
- env: 'published',
200
+ const client = await createClient({
201
+ siteToken: process.env.SLEEKCMS_SITE_TOKEN!
328
202
  });
329
203
 
330
- const slugs = await client.getSlugs('/blog');
204
+ const slugs = client.getSlugs('/blog');
331
205
 
332
- return slugs.map((slug) => ({
333
- slug: slug,
334
- }));
206
+ return slugs.map((slug) => ({ slug }));
335
207
  }
336
208
 
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',
209
+ export default async function Post({ params }: { params: { slug: string } }) {
210
+ const client = await createClient({
211
+ siteToken: process.env.SLEEKCMS_SITE_TOKEN!
342
212
  });
343
213
 
344
- const post = await client.getPage(`/blog/${params.slug}`);
214
+ const post = client.getPage(`/blog/${params.slug}`);
345
215
 
346
- return (
347
- <article>
348
- <h1>{post.title}</h1>
349
- <div>{post.content}</div>
350
- </article>
351
- );
216
+ return <h1>{post?.title}</h1>;
352
217
  }
353
218
  ```
354
219
 
355
- **Pages Router Example:**
220
+ ### SvelteKit (SSR)
356
221
 
357
222
  ```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
- });
223
+ // +page.server.ts
224
+ import { createAsyncClient } from '@sleekcms/client';
367
225
 
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
- };
226
+ const client = createAsyncClient({
227
+ siteToken: process.env.SLEEKCMS_SITE_TOKEN,
228
+ cdn: true
229
+ });
388
230
 
389
- export default function BlogPost({ post }: any) {
390
- return (
391
- <article>
392
- <h1>{post.title}</h1>
393
- <div>{post.content}</div>
394
- </article>
395
- );
231
+ export async function load() {
232
+ const posts = await client.getPages('/blog');
233
+ return { posts };
396
234
  }
397
235
  ```
398
236
 
399
- ### Browser Usage
237
+ ### Astro
400
238
 
401
- ```typescript
239
+ ```astro
240
+ ---
241
+ // src/pages/blog/index.astro
402
242
  import { createClient } from '@sleekcms/client';
403
243
 
404
- const client = createClient({
405
- siteToken: 'your-public-token',
406
- cache: true, // Enable caching for better performance
244
+ const client = await createClient({
245
+ siteToken: import.meta.env.SLEEKCMS_SITE_TOKEN
407
246
  });
408
247
 
409
- // Fetch data on mount
410
- async function loadContent() {
411
- const content = await client.getContent();
412
- // Subsequent calls will use cache
413
- }
414
- ```
415
-
416
- ## Caching Behavior
417
-
418
- ### Async Client
419
- - By default, each call fetches fresh data
420
- - Set `cache: true` to enable in-memory caching
421
- - First call fetches data, subsequent calls use cache
422
- - When using `mock: true` with dev tokens, caching is automatic
248
+ const posts = client.getPages('/blog');
249
+ ---
423
250
 
424
- ### Sync Client
425
- - Always caches content on initialization
426
- - All methods are synchronous and use cached data
427
- - No network requests after initial fetch
428
-
429
- ## Error Handling
430
-
431
- ```typescript
432
- try {
433
- const content = await client.getContent();
434
- } catch (error) {
435
- // Error format: [SleekCMS] <message>
436
- console.error(error.message);
437
- }
251
+ <div>
252
+ {posts?.map((post) => (
253
+ <article>
254
+ <h2>{post.title}</h2>
255
+ </article>
256
+ ))}
257
+ </div>
438
258
  ```
439
259
 
440
- ## TypeScript Support
260
+ ## TypeScript
441
261
 
442
- Fully typed with TypeScript. Import types for better IDE support:
262
+ The client is fully typed:
443
263
 
444
264
  ```typescript
445
- import type { SleekSiteContent, ClientOptions } from '@sleekcms/client';
446
-
447
- // Type your content
448
- interface BlogPost {
449
- title: string;
450
- excerpt: string;
451
- _path: string;
452
- }
453
-
454
- const posts = await client.getPages('/blog');
455
-
456
- // Get a single page with error handling
457
- const aboutPage = await client.getPage('/about');
265
+ import type {
266
+ SleekClient,
267
+ SleekAsyncClient,
268
+ Page,
269
+ Entry,
270
+ Image,
271
+ List
272
+ } from '@sleekcms/client';
458
273
  ```
459
274
 
460
275
  ## License
461
276
 
462
277
  MIT
463
-
464
- ## Links
465
-
466
- - [SleekCMS Website](https://sleekcms.com)
467
- - [Documentation](https://docs.sleekcms.com)
468
- - [GitHub Repository](https://github.com/sleekcms/sleekcms-client)