@localess/client 3.0.0 → 3.0.1-dev.20260325211243

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 CHANGED
@@ -303,8 +303,7 @@ Base type for all content schema data objects.
303
303
  ```ts
304
304
  interface ContentDataSchema {
305
305
  _id: string;
306
- _schema?: string;
307
- schema: string;
306
+ _schema: string;
308
307
  }
309
308
 
310
309
  interface ContentData extends ContentDataSchema {
@@ -374,6 +373,30 @@ A key-value map of translation keys to translated string values.
374
373
 
375
374
  ---
376
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
+
377
400
  ## License
378
401
 
379
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/dist/index.d.mts CHANGED
@@ -74,11 +74,7 @@ interface ContentDataSchema {
74
74
  /**
75
75
  * Unique identifier for the Schema object.
76
76
  */
77
- _schema?: string;
78
- /**
79
- * Unique identifier for the Schema object.
80
- */
81
- schema: string;
77
+ _schema: string;
82
78
  }
83
79
  /**
84
80
  * ContentData defined Object to connect all possible root Schemas.
@@ -233,7 +229,7 @@ type ContentFetchParams = {
233
229
  * Content version to fetch, leave empty for 'published' or 'draft' for the latest draft.
234
230
  * Overrides the version set in the client options.
235
231
  */
236
- version?: 'draft' | string;
232
+ version?: 'draft';
237
233
  /**
238
234
  * Locale identifier (ISO 639-1) to fetch content in, leave empty for default locale.
239
235
  *
@@ -293,16 +289,6 @@ declare function localessEditable(content: ContentDataSchema): {
293
289
  'data-ll-id': string;
294
290
  'data-ll-schema': string;
295
291
  };
296
- /**
297
- * Adds Localess editable attributes to a content item.
298
- * @param content
299
- * @returns An object containing data-ll-id and data-ll-schema attributes.
300
- * @deprecated use localessEditable instead
301
- */
302
- declare function llEditable(content: ContentDataSchema): {
303
- 'data-ll-id': string;
304
- 'data-ll-schema': string;
305
- };
306
292
  /**
307
293
  * Adds Localess editable field attribute to a specific field.
308
294
  * Added type safety to ensure fieldName is a valid key of the content data excluding base schema fields.
@@ -312,15 +298,6 @@ declare function llEditable(content: ContentDataSchema): {
312
298
  declare function localessEditableField<T extends ContentData = ContentData>(fieldName: Exclude<keyof T, keyof ContentDataSchema>): {
313
299
  'data-ll-field': Exclude<keyof T, keyof ContentDataSchema>;
314
300
  };
315
- /**
316
- * Adds Localess editable field attribute to a specific field.
317
- * @param fieldName
318
- * @returns An object containing data-ll-field attribute.
319
- * @deprecated use localessEditableField instead
320
- */
321
- declare function llEditableField(fieldName: string): {
322
- 'data-ll-field': string;
323
- };
324
301
 
325
302
  /**
326
303
  * Inject Localess Sync Script in Header
@@ -356,4 +333,4 @@ declare global {
356
333
  }
357
334
  }
358
335
 
359
- export { type Content, type ContentAsset, type ContentData, type ContentDataField, type ContentDataSchema, type ContentFetchParams, type ContentLink, type ContentMetadata, type ContentReference, type ContentRichText, type EventCallback, type EventToApp, type EventToAppType, type Links, type LinksFetchParams, type Locale, type LocalessClient, type LocalessClientOptions, type LocalessSync, type References, type Translations, isBrowser, isIframe, isServer, llEditable, llEditableField, loadLocalessSync, localessClient, localessEditable, localessEditableField };
336
+ export { type Content, type ContentAsset, type ContentData, type ContentDataField, type ContentDataSchema, type ContentFetchParams, type ContentLink, type ContentMetadata, type ContentReference, type ContentRichText, type EventCallback, type EventToApp, type EventToAppType, type Links, type LinksFetchParams, type Locale, type LocalessClient, type LocalessClientOptions, type LocalessSync, type References, type Translations, isBrowser, isIframe, isServer, loadLocalessSync, localessClient, localessEditable, localessEditableField };
package/dist/index.d.ts CHANGED
@@ -74,11 +74,7 @@ interface ContentDataSchema {
74
74
  /**
75
75
  * Unique identifier for the Schema object.
76
76
  */
77
- _schema?: string;
78
- /**
79
- * Unique identifier for the Schema object.
80
- */
81
- schema: string;
77
+ _schema: string;
82
78
  }
83
79
  /**
84
80
  * ContentData defined Object to connect all possible root Schemas.
@@ -233,7 +229,7 @@ type ContentFetchParams = {
233
229
  * Content version to fetch, leave empty for 'published' or 'draft' for the latest draft.
234
230
  * Overrides the version set in the client options.
235
231
  */
236
- version?: 'draft' | string;
232
+ version?: 'draft';
237
233
  /**
238
234
  * Locale identifier (ISO 639-1) to fetch content in, leave empty for default locale.
239
235
  *
@@ -293,16 +289,6 @@ declare function localessEditable(content: ContentDataSchema): {
293
289
  'data-ll-id': string;
294
290
  'data-ll-schema': string;
295
291
  };
296
- /**
297
- * Adds Localess editable attributes to a content item.
298
- * @param content
299
- * @returns An object containing data-ll-id and data-ll-schema attributes.
300
- * @deprecated use localessEditable instead
301
- */
302
- declare function llEditable(content: ContentDataSchema): {
303
- 'data-ll-id': string;
304
- 'data-ll-schema': string;
305
- };
306
292
  /**
307
293
  * Adds Localess editable field attribute to a specific field.
308
294
  * Added type safety to ensure fieldName is a valid key of the content data excluding base schema fields.
@@ -312,15 +298,6 @@ declare function llEditable(content: ContentDataSchema): {
312
298
  declare function localessEditableField<T extends ContentData = ContentData>(fieldName: Exclude<keyof T, keyof ContentDataSchema>): {
313
299
  'data-ll-field': Exclude<keyof T, keyof ContentDataSchema>;
314
300
  };
315
- /**
316
- * Adds Localess editable field attribute to a specific field.
317
- * @param fieldName
318
- * @returns An object containing data-ll-field attribute.
319
- * @deprecated use localessEditableField instead
320
- */
321
- declare function llEditableField(fieldName: string): {
322
- 'data-ll-field': string;
323
- };
324
301
 
325
302
  /**
326
303
  * Inject Localess Sync Script in Header
@@ -356,4 +333,4 @@ declare global {
356
333
  }
357
334
  }
358
335
 
359
- export { type Content, type ContentAsset, type ContentData, type ContentDataField, type ContentDataSchema, type ContentFetchParams, type ContentLink, type ContentMetadata, type ContentReference, type ContentRichText, type EventCallback, type EventToApp, type EventToAppType, type Links, type LinksFetchParams, type Locale, type LocalessClient, type LocalessClientOptions, type LocalessSync, type References, type Translations, isBrowser, isIframe, isServer, llEditable, llEditableField, loadLocalessSync, localessClient, localessEditable, localessEditableField };
336
+ export { type Content, type ContentAsset, type ContentData, type ContentDataField, type ContentDataSchema, type ContentFetchParams, type ContentLink, type ContentMetadata, type ContentReference, type ContentRichText, type EventCallback, type EventToApp, type EventToAppType, type Links, type LinksFetchParams, type Locale, type LocalessClient, type LocalessClientOptions, type LocalessSync, type References, type Translations, isBrowser, isIframe, isServer, loadLocalessSync, localessClient, localessEditable, localessEditableField };
package/dist/index.js CHANGED
@@ -23,8 +23,6 @@ __export(index_exports, {
23
23
  isBrowser: () => isBrowser,
24
24
  isIframe: () => isIframe,
25
25
  isServer: () => isServer,
26
- llEditable: () => llEditable,
27
- llEditableField: () => llEditableField,
28
26
  loadLocalessSync: () => loadLocalessSync,
29
27
  localessClient: () => localessClient,
30
28
  localessEditable: () => localessEditable,
@@ -83,6 +81,7 @@ function localessClient(options) {
83
81
  if (options.debug) {
84
82
  console.log(LOG_GROUP, "Client Options : ", options);
85
83
  }
84
+ const normalizedOrigin = options.origin.replace(/\/+$/, "");
86
85
  const fetchOptions = {
87
86
  redirect: "follow",
88
87
  headers: {
@@ -110,7 +109,7 @@ function localessClient(options) {
110
109
  if (params?.excludeChildren) {
111
110
  excludeChildren = `&excludeChildren=${params.excludeChildren}`;
112
111
  }
113
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
112
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
114
113
  if (options.debug) {
115
114
  console.log(LOG_GROUP, "getLinks fetch url : ", url);
116
115
  }
@@ -148,7 +147,7 @@ function localessClient(options) {
148
147
  const locale = params?.locale ? `&locale=${params.locale}` : "";
149
148
  const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
150
149
  const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
151
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/slugs/${slug}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
150
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/contents/slugs/${slug}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
152
151
  if (options.debug) {
153
152
  console.log(LOG_GROUP, "getContentBySlug fetch url : ", url);
154
153
  }
@@ -186,7 +185,7 @@ function localessClient(options) {
186
185
  const locale = params?.locale ? `&locale=${params.locale}` : "";
187
186
  const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
188
187
  const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
189
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/${id}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
188
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/contents/${id}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
190
189
  if (options.debug) {
191
190
  console.log(LOG_GROUP, "getContentById fetch url : ", url);
192
191
  }
@@ -213,7 +212,7 @@ function localessClient(options) {
213
212
  if (options.debug) {
214
213
  console.log(LOG_GROUP, "getTranslations() locale : ", locale);
215
214
  }
216
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
215
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
217
216
  if (options.debug) {
218
217
  console.log(LOG_GROUP, "getTranslations fetch url : ", url);
219
218
  }
@@ -237,13 +236,13 @@ function localessClient(options) {
237
236
  }
238
237
  },
239
238
  syncScriptUrl() {
240
- return `${options.origin}/scripts/sync-v1.js`;
239
+ return `${normalizedOrigin}/scripts/sync-v1.js`;
241
240
  },
242
241
  assetLink(asset) {
243
242
  if (typeof asset === "string") {
244
- return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
243
+ return `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
245
244
  } else {
246
- return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
245
+ return `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
247
246
  }
248
247
  }
249
248
  };
@@ -253,13 +252,7 @@ function localessClient(options) {
253
252
  function localessEditable(content) {
254
253
  return {
255
254
  "data-ll-id": content._id,
256
- "data-ll-schema": content._schema || content.schema
257
- };
258
- }
259
- function llEditable(content) {
260
- return {
261
- "data-ll-id": content._id,
262
- "data-ll-schema": content._schema || content.schema
255
+ "data-ll-schema": content._schema
263
256
  };
264
257
  }
265
258
  function localessEditableField(fieldName) {
@@ -267,11 +260,6 @@ function localessEditableField(fieldName) {
267
260
  "data-ll-field": fieldName
268
261
  };
269
262
  }
270
- function llEditableField(fieldName) {
271
- return {
272
- "data-ll-field": fieldName
273
- };
274
- }
275
263
 
276
264
  // src/sync.ts
277
265
  var JS_SYNC_ID = "localess-js-sync";
@@ -296,8 +284,6 @@ function loadLocalessSync(origin, force = false) {
296
284
  isBrowser,
297
285
  isIframe,
298
286
  isServer,
299
- llEditable,
300
- llEditableField,
301
287
  loadLocalessSync,
302
288
  localessClient,
303
289
  localessEditable,
package/dist/index.mjs CHANGED
@@ -49,6 +49,7 @@ function localessClient(options) {
49
49
  if (options.debug) {
50
50
  console.log(LOG_GROUP, "Client Options : ", options);
51
51
  }
52
+ const normalizedOrigin = options.origin.replace(/\/+$/, "");
52
53
  const fetchOptions = {
53
54
  redirect: "follow",
54
55
  headers: {
@@ -76,7 +77,7 @@ function localessClient(options) {
76
77
  if (params?.excludeChildren) {
77
78
  excludeChildren = `&excludeChildren=${params.excludeChildren}`;
78
79
  }
79
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
80
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
80
81
  if (options.debug) {
81
82
  console.log(LOG_GROUP, "getLinks fetch url : ", url);
82
83
  }
@@ -114,7 +115,7 @@ function localessClient(options) {
114
115
  const locale = params?.locale ? `&locale=${params.locale}` : "";
115
116
  const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
116
117
  const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
117
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/slugs/${slug}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
118
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/contents/slugs/${slug}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
118
119
  if (options.debug) {
119
120
  console.log(LOG_GROUP, "getContentBySlug fetch url : ", url);
120
121
  }
@@ -152,7 +153,7 @@ function localessClient(options) {
152
153
  const locale = params?.locale ? `&locale=${params.locale}` : "";
153
154
  const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
154
155
  const resolveLink = params?.resolveLink ? `&resolveLink=${params.resolveLink}` : "";
155
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/contents/${id}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
156
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/contents/${id}?token=${options.token}${version}${locale}${resolveReference}${resolveLink}`;
156
157
  if (options.debug) {
157
158
  console.log(LOG_GROUP, "getContentById fetch url : ", url);
158
159
  }
@@ -179,7 +180,7 @@ function localessClient(options) {
179
180
  if (options.debug) {
180
181
  console.log(LOG_GROUP, "getTranslations() locale : ", locale);
181
182
  }
182
- let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
183
+ let url = `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
183
184
  if (options.debug) {
184
185
  console.log(LOG_GROUP, "getTranslations fetch url : ", url);
185
186
  }
@@ -203,13 +204,13 @@ function localessClient(options) {
203
204
  }
204
205
  },
205
206
  syncScriptUrl() {
206
- return `${options.origin}/scripts/sync-v1.js`;
207
+ return `${normalizedOrigin}/scripts/sync-v1.js`;
207
208
  },
208
209
  assetLink(asset) {
209
210
  if (typeof asset === "string") {
210
- return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
211
+ return `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
211
212
  } else {
212
- return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
213
+ return `${normalizedOrigin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
213
214
  }
214
215
  }
215
216
  };
@@ -219,13 +220,7 @@ function localessClient(options) {
219
220
  function localessEditable(content) {
220
221
  return {
221
222
  "data-ll-id": content._id,
222
- "data-ll-schema": content._schema || content.schema
223
- };
224
- }
225
- function llEditable(content) {
226
- return {
227
- "data-ll-id": content._id,
228
- "data-ll-schema": content._schema || content.schema
223
+ "data-ll-schema": content._schema
229
224
  };
230
225
  }
231
226
  function localessEditableField(fieldName) {
@@ -233,11 +228,6 @@ function localessEditableField(fieldName) {
233
228
  "data-ll-field": fieldName
234
229
  };
235
230
  }
236
- function llEditableField(fieldName) {
237
- return {
238
- "data-ll-field": fieldName
239
- };
240
- }
241
231
 
242
232
  // src/sync.ts
243
233
  var JS_SYNC_ID = "localess-js-sync";
@@ -261,8 +251,6 @@ export {
261
251
  isBrowser,
262
252
  isIframe,
263
253
  isServer,
264
- llEditable,
265
- llEditableField,
266
254
  loadLocalessSync,
267
255
  localessClient,
268
256
  localessEditable,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localess/client",
3
- "version": "3.0.0",
3
+ "version": "3.0.1-dev.20260325211243",
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",