@localess/client 3.0.0-dev.20260323210102 → 3.0.0-dev.20260323212026
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 +24 -0
- package/SKILL.md +282 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -373,6 +373,30 @@ A key-value map of translation keys to translated string values.
|
|
|
373
373
|
|
|
374
374
|
---
|
|
375
375
|
|
|
376
|
+
## AI Coding Agents
|
|
377
|
+
|
|
378
|
+
This package ships a [`SKILL.md`](./SKILL.md) file that provides AI coding agents (GitHub Copilot, Claude Code, Cursor, and others) with accurate, up-to-date APIs, patterns, and best practices. Most agents automatically read `SKILL.md` when starting a session.
|
|
379
|
+
|
|
380
|
+
### Using SKILL.md in your project
|
|
381
|
+
|
|
382
|
+
`SKILL.md` is included in the npm package, so it is available locally after installation. Reference it from your project's `AGENTS.md` to ensure your agent reads accurate Localess documentation every session:
|
|
383
|
+
|
|
384
|
+
```markdown
|
|
385
|
+
## Localess
|
|
386
|
+
|
|
387
|
+
@node_modules/@localess/client/SKILL.md
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The `@` prefix is the syntax used by most agent tools (GitHub Copilot, Claude Code, Cursor) to import file contents inline into the agent context.
|
|
391
|
+
|
|
392
|
+
When you change the public API of this package, update `SKILL.md` alongside your code:
|
|
393
|
+
|
|
394
|
+
- **New option or parameter** → add it to the relevant options table and usage example
|
|
395
|
+
- **Changed behaviour** → update the description and any affected code snippets
|
|
396
|
+
- **Deprecated API** → mark it clearly and point to the replacement
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
376
400
|
## License
|
|
377
401
|
|
|
378
402
|
[MIT](../../LICENSE)
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# SKILL: @localess/client
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`@localess/client` is the **core JavaScript/TypeScript SDK** for the Localess headless CMS. It is a **server-side-only** library — never use it in browser/client-side code because it requires an API token that must remain secret.
|
|
6
|
+
|
|
7
|
+
**Zero production dependencies.** Requires Node.js >= 20.0.0.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @localess/client
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Initialization
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { localessClient } from "@localess/client";
|
|
23
|
+
|
|
24
|
+
const client = localessClient({
|
|
25
|
+
origin: 'https://my-localess.web.app', // Full URL with protocol (required)
|
|
26
|
+
spaceId: 'YOUR_SPACE_ID', // From Space settings (required)
|
|
27
|
+
token: 'YOUR_API_TOKEN', // API token — NEVER expose client-side (required)
|
|
28
|
+
version: 'draft', // undefined = published (default), 'draft' for preview
|
|
29
|
+
debug: false, // Logs requests; default: false
|
|
30
|
+
cacheTTL: 300000, // Cache TTL in ms; false to disable; default: 5 min
|
|
31
|
+
});
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## API Methods
|
|
37
|
+
|
|
38
|
+
### Fetch Content by Slug
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
const content = await client.getContentBySlug<Page>('home', {
|
|
42
|
+
locale: 'en',
|
|
43
|
+
resolveReference: true, // Inline referenced content
|
|
44
|
+
resolveLink: true, // Inline linked content
|
|
45
|
+
version: 'draft', // Override client default per-request
|
|
46
|
+
});
|
|
47
|
+
// content.data is typed as Page
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Fetch Content by ID
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
const content = await client.getContentById<Article>('content-id-here', {
|
|
54
|
+
locale: 'en',
|
|
55
|
+
resolveReference: true,
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Fetch Navigation Links
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
const links = await client.getLinks({
|
|
63
|
+
kind: 'DOCUMENT', // 'DOCUMENT' | 'FOLDER'
|
|
64
|
+
parentSlug: 'blog', // Filter to children of a slug
|
|
65
|
+
excludeChildren: false, // Exclude nested sub-slugs
|
|
66
|
+
});
|
|
67
|
+
// links: { [id: string]: ContentMetadata }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Fetch Translations
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const t = await client.getTranslations('en');
|
|
74
|
+
// t: { [key: string]: string }
|
|
75
|
+
// Usage: t['common.submit'] => 'Submit'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Asset URL
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { localessClient } from "@localess/client";
|
|
82
|
+
|
|
83
|
+
const url = client.assetLink(content.data.image);
|
|
84
|
+
// Returns: https://my-localess.web.app/api/v1/spaces/{spaceId}/assets/{uri}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Content Fetch Parameters
|
|
90
|
+
|
|
91
|
+
| Parameter | Type | Default | Description |
|
|
92
|
+
|--------------------|-----------|---------------|----------------------------------------|
|
|
93
|
+
| `version` | `'draft' \| undefined` | `undefined` | `'draft'` for preview, omit for published |
|
|
94
|
+
| `locale` | `string` | — | ISO 639-1 code: `'en'`, `'de'`, etc. |
|
|
95
|
+
| `resolveReference` | `boolean` | `false` | Inline referenced content objects |
|
|
96
|
+
| `resolveLink` | `boolean` | `false` | Inline linked content metadata |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Caching
|
|
101
|
+
|
|
102
|
+
- Default: TTL-based, **5 minutes** (300,000 ms)
|
|
103
|
+
- Cache key = full request URL (includes all parameters)
|
|
104
|
+
- Adjust for content update frequency:
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
localessClient({ cacheTTL: 60000 }) // 1 minute — frequently updated
|
|
108
|
+
localessClient({ cacheTTL: 3600000 }) // 1 hour — rarely updated
|
|
109
|
+
localessClient({ cacheTTL: false }) // Disabled — always fresh (draft mode)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Visual Editor Integration
|
|
115
|
+
|
|
116
|
+
### Inject Sync Script
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { loadLocalessSync } from "@localess/client";
|
|
120
|
+
|
|
121
|
+
// Call in browser context (e.g., inside useEffect or layout script)
|
|
122
|
+
loadLocalessSync('https://my-localess.web.app');
|
|
123
|
+
// Injects the Localess sync script into <head>; no-op if not in iframe
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Mark Elements as Editable
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
import { localessEditable, localessEditableField } from "@localess/client";
|
|
130
|
+
|
|
131
|
+
// Root element of a content block
|
|
132
|
+
<section {...localessEditable(data)}>
|
|
133
|
+
{/* Adds: data-ll-id (from _id), data-ll-schema (from _schema) */}
|
|
134
|
+
|
|
135
|
+
{/* Individual editable field */}
|
|
136
|
+
<h1 {...localessEditableField<Page>('title')}>
|
|
137
|
+
{/* Adds: data-ll-field="title" */}
|
|
138
|
+
{data.title}
|
|
139
|
+
</h1>
|
|
140
|
+
</section>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
> **Note:** `localessEditable` reads `content._id` and `content._schema`.
|
|
144
|
+
|
|
145
|
+
### Listen to Editor Events
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Only available when app is loaded inside the Localess Visual Editor iframe
|
|
149
|
+
if (window.localess) {
|
|
150
|
+
window.localess.on(['input', 'change'], (event) => {
|
|
151
|
+
if (event.type === 'input' || event.type === 'change') {
|
|
152
|
+
setPageData(event.data); // Real-time preview update
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
// No .off() method — subscribe once on mount
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Event types:**
|
|
160
|
+
|
|
161
|
+
| Event | When |
|
|
162
|
+
|---------------|---------------------------------------------|
|
|
163
|
+
| `input` | User is typing in a field (real-time) |
|
|
164
|
+
| `change` | Field value confirmed |
|
|
165
|
+
| `save` | Content saved |
|
|
166
|
+
| `publish` | Content published |
|
|
167
|
+
| `pong` | Editor heartbeat response |
|
|
168
|
+
| `enterSchema` | User enters a schema element |
|
|
169
|
+
| `hoverSchema` | User hovers over a schema element |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Key Data Types
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
// Content response wrapper
|
|
177
|
+
interface Content<T extends ContentData> extends ContentMetadata {
|
|
178
|
+
data?: T;
|
|
179
|
+
links?: Links;
|
|
180
|
+
references?: References;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Base schema fields every content data object has
|
|
184
|
+
interface ContentDataSchema {
|
|
185
|
+
_id: string;
|
|
186
|
+
_schema: string;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Asset reference
|
|
190
|
+
interface ContentAsset {
|
|
191
|
+
kind: 'ASSET';
|
|
192
|
+
uri: string;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Internal or external link
|
|
196
|
+
interface ContentLink {
|
|
197
|
+
kind: 'LINK';
|
|
198
|
+
type: 'url' | 'content';
|
|
199
|
+
target: '_blank' | '_self';
|
|
200
|
+
uri: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Rich text (Tiptap JSON format)
|
|
204
|
+
interface ContentRichText {
|
|
205
|
+
type?: string;
|
|
206
|
+
content?: ContentRichText[];
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Reference to another content item
|
|
210
|
+
interface ContentReference {
|
|
211
|
+
kind: 'REFERENCE';
|
|
212
|
+
uri: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Navigation links map
|
|
216
|
+
interface Links {
|
|
217
|
+
[contentId: string]: ContentMetadata;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Translations flat map
|
|
221
|
+
interface Translations {
|
|
222
|
+
[key: string]: string;
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Environment Safety Utilities
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import { isBrowser, isServer, isIframe } from "@localess/client";
|
|
232
|
+
|
|
233
|
+
isBrowser() // true if window is defined
|
|
234
|
+
isServer() // true if window is undefined
|
|
235
|
+
isIframe() // true if running inside an iframe (browser only)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## Best Practices
|
|
241
|
+
|
|
242
|
+
1. **Never import `@localess/client` in browser bundles.** Use it only in server-side code: Next.js Server Components, API routes, `getServerSideProps`, Remix loaders, etc.
|
|
243
|
+
|
|
244
|
+
2. **Store credentials in environment variables**, not hardcoded:
|
|
245
|
+
```
|
|
246
|
+
LOCALESS_ORIGIN=https://my-localess.web.app
|
|
247
|
+
LOCALESS_SPACE_ID=your-space-id
|
|
248
|
+
LOCALESS_TOKEN=your-api-token
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
3. **Create one client instance** and reuse it — the cache is instance-bound.
|
|
252
|
+
|
|
253
|
+
4. **Use generated types** from `@localess/cli` (`localess types generate`) for full type safety:
|
|
254
|
+
```typescript
|
|
255
|
+
import type { Page } from './.localess/localess';
|
|
256
|
+
const content = await client.getContentBySlug<Page>('home');
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
5. **Use `version: 'draft'` and `cacheTTL: false` for preview/editing** environments.
|
|
260
|
+
|
|
261
|
+
6. **Use `resolveReference: true`** only when you need inline reference data — it increases payload size.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Exports Reference
|
|
266
|
+
|
|
267
|
+
```typescript
|
|
268
|
+
export { localessClient } // Client factory
|
|
269
|
+
export { localessEditable, localessEditableField } // Visual editor helpers
|
|
270
|
+
export { llEditable, llEditableField } // Deprecated aliases
|
|
271
|
+
export { loadLocalessSync } // Sync script injector
|
|
272
|
+
export { isBrowser, isServer, isIframe } // Environment utilities
|
|
273
|
+
export type {
|
|
274
|
+
LocalessClient, LocalessClientOptions,
|
|
275
|
+
ContentFetchParams, LinksFetchParams,
|
|
276
|
+
Content, ContentData, ContentDataSchema, ContentDataField,
|
|
277
|
+
ContentMetadata, ContentAsset, ContentLink,
|
|
278
|
+
ContentRichText, ContentReference,
|
|
279
|
+
Links, References, Translations,
|
|
280
|
+
LocalessSync, EventToApp, EventCallback, EventToAppType,
|
|
281
|
+
}
|
|
282
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@localess/client",
|
|
3
|
-
"version": "3.0.0-dev.
|
|
3
|
+
"version": "3.0.0-dev.20260323212026",
|
|
4
4
|
"description": "Universal JavaScript/TypeScript SDK for Localess's API.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"localess",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"homepage": "https://github.com/Lessify/localess-js",
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"SKILL.md"
|
|
18
19
|
],
|
|
19
20
|
"main": "dist/index.js",
|
|
20
21
|
"module": "dist/index.mjs",
|