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 +314 -0
- package/dist/index.d.mts +1384 -0
- package/dist/index.d.ts +1384 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +58 -0
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
|