lynkow 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 ADDED
@@ -0,0 +1,314 @@
1
+ # Lynkow SDK
2
+
3
+ Official TypeScript SDK for [Lynkow](https://lynkow.com) Headless CMS.
4
+
5
+ ## Features
6
+
7
+ - **Zero dependencies** - Uses native `fetch()` API
8
+ - **Type-safe** - Full TypeScript support with comprehensive types
9
+ - **Framework-agnostic** - Works with Next.js, Nuxt, Astro, SvelteKit, etc.
10
+ - **Tree-shakeable** - Only import what you need
11
+ - **Spam protection** - Built-in honeypot fields for form submissions
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install lynkow
17
+ # or
18
+ yarn add lynkow
19
+ # or
20
+ pnpm add lynkow
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```typescript
26
+ import { createLynkowClient } from 'lynkow'
27
+
28
+ const lynkow = createLynkowClient({
29
+ siteId: 'your-site-uuid',
30
+ locale: 'fr', // optional default locale
31
+ })
32
+
33
+ // Fetch blog posts
34
+ const { data: posts, meta } = await lynkow.contents.list({
35
+ page: 1,
36
+ perPage: 10,
37
+ category: 'tech',
38
+ })
39
+
40
+ // Fetch a single post
41
+ const post = await lynkow.contents.getBySlug('my-article')
42
+ ```
43
+
44
+ ## Configuration
45
+
46
+ ```typescript
47
+ interface LynkowConfig {
48
+ // Required: Your site UUID
49
+ siteId: string
50
+
51
+ // Optional: API base URL (default: https://api.lynkow.com)
52
+ baseUrl?: string
53
+
54
+ // Optional: Default locale for all requests
55
+ locale?: string
56
+
57
+ // Optional: Custom fetch options (for Next.js cache, etc.)
58
+ fetchOptions?: RequestInit
59
+ }
60
+ ```
61
+
62
+ ### Next.js App Router Example
63
+
64
+ ```typescript
65
+ const lynkow = createLynkowClient({
66
+ siteId: process.env.LYNKOW_SITE_ID!,
67
+ locale: 'fr',
68
+ fetchOptions: {
69
+ next: { revalidate: 60 }, // ISR: revalidate every 60 seconds
70
+ },
71
+ })
72
+ ```
73
+
74
+ ## Services
75
+
76
+ ### Contents (Blog Posts)
77
+
78
+ ```typescript
79
+ // List contents with filters
80
+ const { data, meta } = await lynkow.contents.list({
81
+ page: 1,
82
+ perPage: 10,
83
+ category: 'tech',
84
+ tag: 'javascript',
85
+ search: 'tutorial',
86
+ sort: 'published_at',
87
+ order: 'desc',
88
+ })
89
+
90
+ // Get by slug
91
+ const content = await lynkow.contents.getBySlug('my-article')
92
+ ```
93
+
94
+ ### Categories
95
+
96
+ ```typescript
97
+ // List all categories
98
+ const { data } = await lynkow.categories.list()
99
+
100
+ // Get category tree (nested)
101
+ const { data: tree } = await lynkow.categories.tree()
102
+
103
+ // Get category with its contents
104
+ const { category, contents } = await lynkow.categories.getBySlug('tech', {
105
+ page: 1,
106
+ perPage: 10,
107
+ })
108
+ ```
109
+
110
+ ### Tags
111
+
112
+ ```typescript
113
+ const { data: tags } = await lynkow.tags.list()
114
+ ```
115
+
116
+ ### Pages (Site Blocks)
117
+
118
+ ```typescript
119
+ // List all pages
120
+ const { data } = await lynkow.pages.list()
121
+
122
+ // Get page by slug
123
+ const page = await lynkow.pages.getBySlug('about')
124
+
125
+ // Get page by path
126
+ const page = await lynkow.pages.getByPath('/services/consulting')
127
+
128
+ // Get JSON-LD data
129
+ const jsonLd = await lynkow.pages.getJsonLd('about')
130
+ ```
131
+
132
+ ### Global Blocks (Header, Footer)
133
+
134
+ ```typescript
135
+ // Get site config with all global blocks
136
+ const { data } = await lynkow.blocks.siteConfig()
137
+ const header = data.globals['header']
138
+ const footer = data.globals['footer']
139
+
140
+ // Get a specific global block
141
+ const { data: header } = await lynkow.blocks.global('header')
142
+ ```
143
+
144
+ ### Forms
145
+
146
+ ```typescript
147
+ // Get form schema
148
+ const form = await lynkow.forms.getBySlug('contact')
149
+
150
+ // Submit form (spam protection is automatic)
151
+ const result = await lynkow.forms.submit('contact', {
152
+ name: 'John Doe',
153
+ email: 'john@example.com',
154
+ message: 'Hello!',
155
+ })
156
+
157
+ // With reCAPTCHA token
158
+ const result = await lynkow.forms.submit(
159
+ 'contact',
160
+ { name: 'John', email: 'john@example.com' },
161
+ { recaptchaToken: 'token-from-recaptcha' }
162
+ )
163
+ ```
164
+
165
+ ### Reviews
166
+
167
+ ```typescript
168
+ // List approved reviews
169
+ const { data, meta } = await lynkow.reviews.list({
170
+ minRating: 4,
171
+ perPage: 10,
172
+ })
173
+
174
+ // Get review settings
175
+ const settings = await lynkow.reviews.settings()
176
+
177
+ // Submit a review
178
+ const result = await lynkow.reviews.submit({
179
+ authorName: 'Alice',
180
+ rating: 5,
181
+ content: 'Excellent service!',
182
+ })
183
+ ```
184
+
185
+ ### Site Configuration
186
+
187
+ ```typescript
188
+ const config = await lynkow.site.getConfig()
189
+ console.log(config.enabledLocales) // ['fr', 'en']
190
+ console.log(config.defaultLocale) // 'fr'
191
+ ```
192
+
193
+ ### Legal Documents
194
+
195
+ ```typescript
196
+ // List all legal documents
197
+ const { data } = await lynkow.legal.list()
198
+
199
+ // Get specific document
200
+ const privacy = await lynkow.legal.getByType('privacy')
201
+ const terms = await lynkow.legal.getByType('terms')
202
+ ```
203
+
204
+ ### Cookie Consent
205
+
206
+ ```typescript
207
+ // Get cookie banner config
208
+ const config = await lynkow.cookies.getConfig()
209
+
210
+ // Log user consent
211
+ await lynkow.cookies.logConsent({
212
+ necessary: true,
213
+ analytics: true,
214
+ marketing: false,
215
+ })
216
+ ```
217
+
218
+ ### SEO (Sitemap, Robots)
219
+
220
+ ```typescript
221
+ // Get sitemap XML
222
+ const xml = await lynkow.seo.sitemap()
223
+
224
+ // Get robots.txt
225
+ const txt = await lynkow.seo.robots()
226
+ ```
227
+
228
+ ### Paths (SSG)
229
+
230
+ ```typescript
231
+ // Get all paths for static generation
232
+ const { paths } = await lynkow.paths.list()
233
+
234
+ // Resolve a path to content or category
235
+ const result = await lynkow.paths.resolve('/blog/tech/my-article')
236
+ if (result.type === 'content') {
237
+ // Render article
238
+ } else {
239
+ // Render category listing
240
+ }
241
+
242
+ // Check for redirects
243
+ const redirect = await lynkow.paths.matchRedirect('/old-page')
244
+ if (redirect) {
245
+ // Redirect to redirect.target with redirect.statusCode
246
+ }
247
+ ```
248
+
249
+ ## Error Handling
250
+
251
+ ```typescript
252
+ import { LynkowError, isLynkowError } from 'lynkow'
253
+
254
+ try {
255
+ const post = await lynkow.contents.getBySlug('not-found')
256
+ } catch (error) {
257
+ if (isLynkowError(error)) {
258
+ console.log(error.status) // 404
259
+ console.log(error.code) // 'NOT_FOUND'
260
+ console.log(error.message) // 'Content not found'
261
+ console.log(error.errors) // [{ message: '...' }]
262
+ }
263
+ }
264
+ ```
265
+
266
+ ### Error Codes
267
+
268
+ | Code | HTTP Status | Description |
269
+ |------|-------------|-------------|
270
+ | `BAD_REQUEST` | 400 | Invalid request |
271
+ | `UNAUTHORIZED` | 401 | Authentication required |
272
+ | `FORBIDDEN` | 403 | Access denied |
273
+ | `NOT_FOUND` | 404 | Resource not found |
274
+ | `VALIDATION_ERROR` | 422 | Validation failed |
275
+ | `TOO_MANY_REQUESTS` | 429 | Rate limited |
276
+ | `INTERNAL_ERROR` | 500 | Server error |
277
+ | `SERVICE_UNAVAILABLE` | 503 | Service unavailable |
278
+ | `NETWORK_ERROR` | 0 | Network error |
279
+
280
+ ## Type Guards
281
+
282
+ ```typescript
283
+ import { isContentResolve, isCategoryResolve } from 'lynkow'
284
+
285
+ const result = await lynkow.paths.resolve('/blog/tech')
286
+
287
+ if (isContentResolve(result)) {
288
+ // result.content is available
289
+ } else if (isCategoryResolve(result)) {
290
+ // result.category and result.contents are available
291
+ }
292
+ ```
293
+
294
+ ## TypeScript
295
+
296
+ All types are exported for your convenience:
297
+
298
+ ```typescript
299
+ import type {
300
+ Content,
301
+ ContentSummary,
302
+ Category,
303
+ Page,
304
+ Form,
305
+ Review,
306
+ LynkowConfig,
307
+ ContentsFilters,
308
+ // ... and many more
309
+ } from 'lynkow'
310
+ ```
311
+
312
+ ## License
313
+
314
+ MIT