@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.
Files changed (3) hide show
  1. package/README.md +24 -0
  2. package/SKILL.md +282 -0
  3. 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.20260323210102",
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",