@localess/client 0.9.2-dev.20260216094809
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 +62 -0
- package/dist/index.d.mts +359 -0
- package/dist/index.d.ts +359 -0
- package/dist/index.js +305 -0
- package/dist/index.mjs +270 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<br/>
|
|
2
|
+
<br/>
|
|
3
|
+
<img src="https://github.com/Lessify/localess/wiki/img/logo-adaptive.svg" alt="logo">
|
|
4
|
+
<br/>
|
|
5
|
+
<br/>
|
|
6
|
+
|
|
7
|
+
----
|
|
8
|
+
|
|
9
|
+
# Localess JavaScript / TypeScript Client SDK
|
|
10
|
+
|
|
11
|
+
This client SDK is designed to work with the Localess API. It provides a simple way to interact with the Localess API from your JavaScript or TypeScript application.
|
|
12
|
+
|
|
13
|
+
> **Important:**
|
|
14
|
+
> The Client is designed to be used on the server side only, as it requires your **Localess API Token** to be kept secret.
|
|
15
|
+
> Do not use this client in your frontend application, as it exposes your API Token to the public.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
### NPM
|
|
20
|
+
````bash
|
|
21
|
+
npm install @localess/client@latest
|
|
22
|
+
````
|
|
23
|
+
|
|
24
|
+
### Yarn
|
|
25
|
+
````bash
|
|
26
|
+
yarn add @localess/client@latest
|
|
27
|
+
````
|
|
28
|
+
|
|
29
|
+
## Client
|
|
30
|
+
|
|
31
|
+
````ts
|
|
32
|
+
import {localessClient} from "@localess/client";
|
|
33
|
+
|
|
34
|
+
const llClient = localessClient({
|
|
35
|
+
// A fully qualified domain name with protocol (http/https) and port.
|
|
36
|
+
origin: 'https://my-localess.web.app',
|
|
37
|
+
// Localess space ID, cna be found in the Localess Space settings
|
|
38
|
+
spaceId: 'I1LoVe2LocaLess4Rever',
|
|
39
|
+
// Localess API token, can be found in the Localess Space settings
|
|
40
|
+
token: 'Baz00KaT0KeN8S3CureLL'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Fetch all Content Links
|
|
44
|
+
llClient.getLinks()
|
|
45
|
+
// Fetch content by SLUG
|
|
46
|
+
llClient.getContentBySlug('docs/overview')
|
|
47
|
+
// Fetch content by ID
|
|
48
|
+
llClient.getContentById('FRnIT7CUABoRCdSVVGGs')
|
|
49
|
+
// Fetch translations by locale
|
|
50
|
+
llClient.getTranslations('en')
|
|
51
|
+
````
|
|
52
|
+
|
|
53
|
+
## Sync with Visual Editor
|
|
54
|
+
|
|
55
|
+
It will automatically inject Localess Sync Script in to the HTML page.
|
|
56
|
+
|
|
57
|
+
````ts
|
|
58
|
+
import {loadLocalessSync} from "@localess/client";
|
|
59
|
+
|
|
60
|
+
// A fully qualified domain name with protocol (http/https) and port.
|
|
61
|
+
loadLocalessSync('https://my-localess.web.app')
|
|
62
|
+
````
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Asset defines reference to an Asset.
|
|
3
|
+
*/
|
|
4
|
+
interface ContentAsset {
|
|
5
|
+
/**
|
|
6
|
+
* Define the type of Asset
|
|
7
|
+
*/
|
|
8
|
+
kind: 'ASSET';
|
|
9
|
+
/**
|
|
10
|
+
* Unique identifier for the asset.
|
|
11
|
+
*/
|
|
12
|
+
uri: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Content Link define reference to a Link.
|
|
17
|
+
*/
|
|
18
|
+
interface ContentLink {
|
|
19
|
+
/**
|
|
20
|
+
* Define the type of Link
|
|
21
|
+
*/
|
|
22
|
+
kind: 'LINK';
|
|
23
|
+
/**
|
|
24
|
+
* Define the target of the link. _blank for the new tab and _self for the same tab.
|
|
25
|
+
*/
|
|
26
|
+
target: '_blank' | '_self';
|
|
27
|
+
/**
|
|
28
|
+
* Define the type of Link. URL for external links and Content for internal links.
|
|
29
|
+
*/
|
|
30
|
+
type: 'url' | 'content';
|
|
31
|
+
/**
|
|
32
|
+
* If the type is content, then it will be Content ID. Otherwise, it will be URL.
|
|
33
|
+
*/
|
|
34
|
+
uri: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Content RichText define content as JSON Object.
|
|
39
|
+
*/
|
|
40
|
+
interface ContentRichText {
|
|
41
|
+
/**
|
|
42
|
+
* Define the type of Content Node
|
|
43
|
+
*/
|
|
44
|
+
type?: string;
|
|
45
|
+
/**
|
|
46
|
+
* List of Content Nodes
|
|
47
|
+
*/
|
|
48
|
+
content?: ContentRichText[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Content Reference defines reference to a Content.
|
|
53
|
+
*/
|
|
54
|
+
interface ContentReference {
|
|
55
|
+
/**
|
|
56
|
+
* Define the type of REFERENCE
|
|
57
|
+
*/
|
|
58
|
+
kind: 'REFERENCE';
|
|
59
|
+
/**
|
|
60
|
+
* Unique identifier for the Content Document.
|
|
61
|
+
*/
|
|
62
|
+
uri: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type ContentDataField = any | string | string[] | number | boolean | ContentLink | ContentRichText | ContentData | ContentData[] | ContentAsset | ContentAsset[] | ContentReference | ContentReference[];
|
|
66
|
+
/**
|
|
67
|
+
* Content Data Schema related information.
|
|
68
|
+
*/
|
|
69
|
+
interface ContentDataSchema {
|
|
70
|
+
/**
|
|
71
|
+
* Unique identifier of a component in a content.
|
|
72
|
+
*/
|
|
73
|
+
_id: string;
|
|
74
|
+
/**
|
|
75
|
+
* Unique identifier for the Schema object.
|
|
76
|
+
*/
|
|
77
|
+
_schema?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Unique identifier for the Schema object.
|
|
80
|
+
*/
|
|
81
|
+
schema: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* ContentData defined Object to connect all possible root Schemas.
|
|
85
|
+
*/
|
|
86
|
+
interface ContentData extends ContentDataSchema {
|
|
87
|
+
/**
|
|
88
|
+
* Other Schema-specific fields
|
|
89
|
+
*/
|
|
90
|
+
[field: string]: ContentDataField | undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Content Metadata defines short information about a Content for navigation reason.
|
|
95
|
+
*/
|
|
96
|
+
interface ContentMetadata {
|
|
97
|
+
/**
|
|
98
|
+
* Date and Time at which the Content was created.
|
|
99
|
+
*/
|
|
100
|
+
createdAt: string;
|
|
101
|
+
/**
|
|
102
|
+
* Combination of SLUG and Parent SLUG of the Content
|
|
103
|
+
*/
|
|
104
|
+
fullSlug: string;
|
|
105
|
+
/**
|
|
106
|
+
* Unique identifier for the object.
|
|
107
|
+
*/
|
|
108
|
+
id: string;
|
|
109
|
+
/**
|
|
110
|
+
* Define the type of Content, whether it is a FOLDER or DOCUMENT.
|
|
111
|
+
*/
|
|
112
|
+
kind: 'FOLDER' | 'DOCUMENT';
|
|
113
|
+
/**
|
|
114
|
+
* Name of the Content
|
|
115
|
+
*/
|
|
116
|
+
name: string;
|
|
117
|
+
/**
|
|
118
|
+
* Parent SLUG of the Content
|
|
119
|
+
*/
|
|
120
|
+
parentSlug: string;
|
|
121
|
+
/**
|
|
122
|
+
* Date and Time at which the Content was published.
|
|
123
|
+
*/
|
|
124
|
+
publishedAt?: string;
|
|
125
|
+
/**
|
|
126
|
+
* SLUG of the Content
|
|
127
|
+
*/
|
|
128
|
+
slug: string;
|
|
129
|
+
/**
|
|
130
|
+
* Date and Time at which the Content was updated.
|
|
131
|
+
*/
|
|
132
|
+
updatedAt: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Key-Value Object. Where Key is a Unique identifier for the Content object and Value is Content Metadata.
|
|
137
|
+
*/
|
|
138
|
+
interface Links {
|
|
139
|
+
[key: string]: ContentMetadata;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Key-Value Object. Where Key is a Unique identifier for the Content object and Value is Content.
|
|
144
|
+
*/
|
|
145
|
+
interface References {
|
|
146
|
+
[key: string]: Content;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Content defines a shared object for all possible Content Types.
|
|
151
|
+
*/
|
|
152
|
+
interface Content<T extends ContentData = ContentData> extends ContentMetadata {
|
|
153
|
+
/**
|
|
154
|
+
* Content Data
|
|
155
|
+
*/
|
|
156
|
+
data?: T;
|
|
157
|
+
/**
|
|
158
|
+
* All links used in the content.
|
|
159
|
+
*/
|
|
160
|
+
links?: Links;
|
|
161
|
+
/**
|
|
162
|
+
* All references used in the content.
|
|
163
|
+
*/
|
|
164
|
+
references?: References;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface Locale {
|
|
168
|
+
/**
|
|
169
|
+
* Unique identifier for the Locale.
|
|
170
|
+
*/
|
|
171
|
+
id: string;
|
|
172
|
+
/**
|
|
173
|
+
* Name of the Locale.
|
|
174
|
+
*/
|
|
175
|
+
name: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Key-Value Object. Where Key is Translation ID and Value is Translated Content
|
|
180
|
+
*/
|
|
181
|
+
interface Translations {
|
|
182
|
+
[key: string]: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type LocalessClientOptions = {
|
|
186
|
+
/**
|
|
187
|
+
* A fully qualified domain name with protocol (http/https) and port.
|
|
188
|
+
*
|
|
189
|
+
* Example: https://my-localess.web.app
|
|
190
|
+
*/
|
|
191
|
+
origin: string;
|
|
192
|
+
/**
|
|
193
|
+
* Localess space ID can be found in the Localess Space settings
|
|
194
|
+
*/
|
|
195
|
+
spaceId: string;
|
|
196
|
+
/**
|
|
197
|
+
* Localess API token can be found in the Localess Space settings
|
|
198
|
+
*/
|
|
199
|
+
token: string;
|
|
200
|
+
/**
|
|
201
|
+
* Content version to fetch, leave empty for 'published' or 'draft' for the latest draft
|
|
202
|
+
*/
|
|
203
|
+
version?: 'draft' | string;
|
|
204
|
+
/**
|
|
205
|
+
* Enable debug mode
|
|
206
|
+
*/
|
|
207
|
+
debug?: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Cache TTL (time to live) for API responses. Default is 5 minutes (300000 ms).
|
|
210
|
+
* Set to false to disable caching.
|
|
211
|
+
*/
|
|
212
|
+
cacheTTL?: number | false;
|
|
213
|
+
};
|
|
214
|
+
type LinksFetchParams = {
|
|
215
|
+
/**
|
|
216
|
+
* Content Kind. FOLDER or DOCUMENT. If not provided, it will return all.
|
|
217
|
+
* @example 'DOCUMENT'
|
|
218
|
+
*/
|
|
219
|
+
kind?: 'DOCUMENT' | 'FOLDER';
|
|
220
|
+
/**
|
|
221
|
+
* Content parent slug.
|
|
222
|
+
* @example 'legal/policy'
|
|
223
|
+
*/
|
|
224
|
+
parentSlug?: string;
|
|
225
|
+
/**
|
|
226
|
+
* If **true**, exclude all sub slugs, otherwise include all content under current selected **parent slug**.
|
|
227
|
+
* @example false
|
|
228
|
+
*/
|
|
229
|
+
excludeChildren?: boolean;
|
|
230
|
+
};
|
|
231
|
+
type ContentFetchParams = {
|
|
232
|
+
/**
|
|
233
|
+
* Content version to fetch, leave empty for 'published' or 'draft' for the latest draft.
|
|
234
|
+
* Overrides the version set in the client options.
|
|
235
|
+
*/
|
|
236
|
+
version?: 'draft' | string;
|
|
237
|
+
/**
|
|
238
|
+
* Locale identifier (ISO 639-1) to fetch content in, leave empty for default locale.
|
|
239
|
+
*
|
|
240
|
+
* Example: en
|
|
241
|
+
*/
|
|
242
|
+
locale?: string;
|
|
243
|
+
/**
|
|
244
|
+
* Resolve references in the content data. Default is false.
|
|
245
|
+
*/
|
|
246
|
+
resolveReference?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Resolve links in the content data. Default is false.
|
|
249
|
+
*/
|
|
250
|
+
resolveLink?: boolean;
|
|
251
|
+
};
|
|
252
|
+
interface LocalessClient {
|
|
253
|
+
/**
|
|
254
|
+
* Get all links
|
|
255
|
+
* @param params{LinksFetchParams} - Fetch parameters
|
|
256
|
+
* @returns {Promise<Links>}
|
|
257
|
+
*/
|
|
258
|
+
getLinks(params?: LinksFetchParams): Promise<Links>;
|
|
259
|
+
/**
|
|
260
|
+
* Get content by SLUG
|
|
261
|
+
* @param slug{string} - Content SLUG
|
|
262
|
+
* @param params{ContentFetchParams} - Fetch parameters
|
|
263
|
+
* @returns {Promise<Content>}
|
|
264
|
+
*/
|
|
265
|
+
getContentBySlug<T extends ContentData = ContentData>(slug: string, params?: ContentFetchParams): Promise<Content<T>>;
|
|
266
|
+
/**
|
|
267
|
+
* Get content by ID
|
|
268
|
+
* @param id{string} - Content ID
|
|
269
|
+
* @param params{ContentFetchParams} - Fetch parameters
|
|
270
|
+
* @returns {Promise<Content>}
|
|
271
|
+
*/
|
|
272
|
+
getContentById<T extends ContentData = ContentData>(id: string, params?: ContentFetchParams): Promise<Content<T>>;
|
|
273
|
+
/**
|
|
274
|
+
* Get translations for the given locale
|
|
275
|
+
* @param locale{string} - Locale identifier (ISO 639-1)
|
|
276
|
+
*/
|
|
277
|
+
getTranslations(locale: string): Promise<Translations>;
|
|
278
|
+
syncScriptUrl(): string;
|
|
279
|
+
assetLink(asset: ContentAsset | string): string;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Create a Localess API Client
|
|
283
|
+
* @param {LocalessClientOptions} options connection details
|
|
284
|
+
*/
|
|
285
|
+
declare function localessClient(options: LocalessClientOptions): LocalessClient;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Adds Localess editable attributes to a content item.
|
|
289
|
+
* @param content
|
|
290
|
+
* @returns An object containing data-ll-id and data-ll-schema attributes.
|
|
291
|
+
*/
|
|
292
|
+
declare function localessEditable(content: ContentDataSchema): {
|
|
293
|
+
'data-ll-id': string;
|
|
294
|
+
'data-ll-schema': string;
|
|
295
|
+
};
|
|
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
|
+
/**
|
|
307
|
+
* Adds Localess editable field attribute to a specific field.
|
|
308
|
+
* Added type safety to ensure fieldName is a valid key of the content data excluding base schema fields.
|
|
309
|
+
* @param fieldName
|
|
310
|
+
* @returns An object containing data-ll-field attribute.
|
|
311
|
+
*/
|
|
312
|
+
declare function localessEditableField<T extends ContentData = ContentData>(fieldName: Exclude<keyof T, keyof ContentDataSchema>): {
|
|
313
|
+
'data-ll-field': Exclude<keyof T, keyof ContentDataSchema>;
|
|
314
|
+
};
|
|
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
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Inject Localess Sync Script in Header
|
|
327
|
+
* @param {string} origin A fully qualified domain name with protocol (http/https) and port.
|
|
328
|
+
* @param {boolean} force Force Script Injection even if the application is not in Visual Editor.
|
|
329
|
+
*/
|
|
330
|
+
declare function loadLocalessSync(origin: string, force?: boolean): void;
|
|
331
|
+
|
|
332
|
+
declare const isBrowser: () => boolean;
|
|
333
|
+
declare const isServer: () => boolean;
|
|
334
|
+
declare const isIframe: () => boolean;
|
|
335
|
+
|
|
336
|
+
type EventToAppType = 'save' | 'publish' | 'pong' | 'input' | 'change' | 'enterSchema' | 'hoverSchema';
|
|
337
|
+
type EventCallback = (event: EventToApp) => void;
|
|
338
|
+
type EventToApp = {
|
|
339
|
+
type: 'save' | 'publish' | 'pong';
|
|
340
|
+
} | {
|
|
341
|
+
type: 'input' | 'change';
|
|
342
|
+
data: any;
|
|
343
|
+
} | {
|
|
344
|
+
type: 'enterSchema' | 'hoverSchema';
|
|
345
|
+
id: string;
|
|
346
|
+
schema: string;
|
|
347
|
+
field?: string;
|
|
348
|
+
};
|
|
349
|
+
interface LocalessSync {
|
|
350
|
+
onChange: (callback: EventCallback) => void;
|
|
351
|
+
on: (event: EventToAppType | EventToAppType[], callback: EventCallback) => void;
|
|
352
|
+
}
|
|
353
|
+
declare global {
|
|
354
|
+
interface Window {
|
|
355
|
+
localess?: LocalessSync;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
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 };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Asset defines reference to an Asset.
|
|
3
|
+
*/
|
|
4
|
+
interface ContentAsset {
|
|
5
|
+
/**
|
|
6
|
+
* Define the type of Asset
|
|
7
|
+
*/
|
|
8
|
+
kind: 'ASSET';
|
|
9
|
+
/**
|
|
10
|
+
* Unique identifier for the asset.
|
|
11
|
+
*/
|
|
12
|
+
uri: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Content Link define reference to a Link.
|
|
17
|
+
*/
|
|
18
|
+
interface ContentLink {
|
|
19
|
+
/**
|
|
20
|
+
* Define the type of Link
|
|
21
|
+
*/
|
|
22
|
+
kind: 'LINK';
|
|
23
|
+
/**
|
|
24
|
+
* Define the target of the link. _blank for the new tab and _self for the same tab.
|
|
25
|
+
*/
|
|
26
|
+
target: '_blank' | '_self';
|
|
27
|
+
/**
|
|
28
|
+
* Define the type of Link. URL for external links and Content for internal links.
|
|
29
|
+
*/
|
|
30
|
+
type: 'url' | 'content';
|
|
31
|
+
/**
|
|
32
|
+
* If the type is content, then it will be Content ID. Otherwise, it will be URL.
|
|
33
|
+
*/
|
|
34
|
+
uri: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Content RichText define content as JSON Object.
|
|
39
|
+
*/
|
|
40
|
+
interface ContentRichText {
|
|
41
|
+
/**
|
|
42
|
+
* Define the type of Content Node
|
|
43
|
+
*/
|
|
44
|
+
type?: string;
|
|
45
|
+
/**
|
|
46
|
+
* List of Content Nodes
|
|
47
|
+
*/
|
|
48
|
+
content?: ContentRichText[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Content Reference defines reference to a Content.
|
|
53
|
+
*/
|
|
54
|
+
interface ContentReference {
|
|
55
|
+
/**
|
|
56
|
+
* Define the type of REFERENCE
|
|
57
|
+
*/
|
|
58
|
+
kind: 'REFERENCE';
|
|
59
|
+
/**
|
|
60
|
+
* Unique identifier for the Content Document.
|
|
61
|
+
*/
|
|
62
|
+
uri: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type ContentDataField = any | string | string[] | number | boolean | ContentLink | ContentRichText | ContentData | ContentData[] | ContentAsset | ContentAsset[] | ContentReference | ContentReference[];
|
|
66
|
+
/**
|
|
67
|
+
* Content Data Schema related information.
|
|
68
|
+
*/
|
|
69
|
+
interface ContentDataSchema {
|
|
70
|
+
/**
|
|
71
|
+
* Unique identifier of a component in a content.
|
|
72
|
+
*/
|
|
73
|
+
_id: string;
|
|
74
|
+
/**
|
|
75
|
+
* Unique identifier for the Schema object.
|
|
76
|
+
*/
|
|
77
|
+
_schema?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Unique identifier for the Schema object.
|
|
80
|
+
*/
|
|
81
|
+
schema: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* ContentData defined Object to connect all possible root Schemas.
|
|
85
|
+
*/
|
|
86
|
+
interface ContentData extends ContentDataSchema {
|
|
87
|
+
/**
|
|
88
|
+
* Other Schema-specific fields
|
|
89
|
+
*/
|
|
90
|
+
[field: string]: ContentDataField | undefined;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Content Metadata defines short information about a Content for navigation reason.
|
|
95
|
+
*/
|
|
96
|
+
interface ContentMetadata {
|
|
97
|
+
/**
|
|
98
|
+
* Date and Time at which the Content was created.
|
|
99
|
+
*/
|
|
100
|
+
createdAt: string;
|
|
101
|
+
/**
|
|
102
|
+
* Combination of SLUG and Parent SLUG of the Content
|
|
103
|
+
*/
|
|
104
|
+
fullSlug: string;
|
|
105
|
+
/**
|
|
106
|
+
* Unique identifier for the object.
|
|
107
|
+
*/
|
|
108
|
+
id: string;
|
|
109
|
+
/**
|
|
110
|
+
* Define the type of Content, whether it is a FOLDER or DOCUMENT.
|
|
111
|
+
*/
|
|
112
|
+
kind: 'FOLDER' | 'DOCUMENT';
|
|
113
|
+
/**
|
|
114
|
+
* Name of the Content
|
|
115
|
+
*/
|
|
116
|
+
name: string;
|
|
117
|
+
/**
|
|
118
|
+
* Parent SLUG of the Content
|
|
119
|
+
*/
|
|
120
|
+
parentSlug: string;
|
|
121
|
+
/**
|
|
122
|
+
* Date and Time at which the Content was published.
|
|
123
|
+
*/
|
|
124
|
+
publishedAt?: string;
|
|
125
|
+
/**
|
|
126
|
+
* SLUG of the Content
|
|
127
|
+
*/
|
|
128
|
+
slug: string;
|
|
129
|
+
/**
|
|
130
|
+
* Date and Time at which the Content was updated.
|
|
131
|
+
*/
|
|
132
|
+
updatedAt: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Key-Value Object. Where Key is a Unique identifier for the Content object and Value is Content Metadata.
|
|
137
|
+
*/
|
|
138
|
+
interface Links {
|
|
139
|
+
[key: string]: ContentMetadata;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Key-Value Object. Where Key is a Unique identifier for the Content object and Value is Content.
|
|
144
|
+
*/
|
|
145
|
+
interface References {
|
|
146
|
+
[key: string]: Content;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Content defines a shared object for all possible Content Types.
|
|
151
|
+
*/
|
|
152
|
+
interface Content<T extends ContentData = ContentData> extends ContentMetadata {
|
|
153
|
+
/**
|
|
154
|
+
* Content Data
|
|
155
|
+
*/
|
|
156
|
+
data?: T;
|
|
157
|
+
/**
|
|
158
|
+
* All links used in the content.
|
|
159
|
+
*/
|
|
160
|
+
links?: Links;
|
|
161
|
+
/**
|
|
162
|
+
* All references used in the content.
|
|
163
|
+
*/
|
|
164
|
+
references?: References;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
interface Locale {
|
|
168
|
+
/**
|
|
169
|
+
* Unique identifier for the Locale.
|
|
170
|
+
*/
|
|
171
|
+
id: string;
|
|
172
|
+
/**
|
|
173
|
+
* Name of the Locale.
|
|
174
|
+
*/
|
|
175
|
+
name: string;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Key-Value Object. Where Key is Translation ID and Value is Translated Content
|
|
180
|
+
*/
|
|
181
|
+
interface Translations {
|
|
182
|
+
[key: string]: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type LocalessClientOptions = {
|
|
186
|
+
/**
|
|
187
|
+
* A fully qualified domain name with protocol (http/https) and port.
|
|
188
|
+
*
|
|
189
|
+
* Example: https://my-localess.web.app
|
|
190
|
+
*/
|
|
191
|
+
origin: string;
|
|
192
|
+
/**
|
|
193
|
+
* Localess space ID can be found in the Localess Space settings
|
|
194
|
+
*/
|
|
195
|
+
spaceId: string;
|
|
196
|
+
/**
|
|
197
|
+
* Localess API token can be found in the Localess Space settings
|
|
198
|
+
*/
|
|
199
|
+
token: string;
|
|
200
|
+
/**
|
|
201
|
+
* Content version to fetch, leave empty for 'published' or 'draft' for the latest draft
|
|
202
|
+
*/
|
|
203
|
+
version?: 'draft' | string;
|
|
204
|
+
/**
|
|
205
|
+
* Enable debug mode
|
|
206
|
+
*/
|
|
207
|
+
debug?: boolean;
|
|
208
|
+
/**
|
|
209
|
+
* Cache TTL (time to live) for API responses. Default is 5 minutes (300000 ms).
|
|
210
|
+
* Set to false to disable caching.
|
|
211
|
+
*/
|
|
212
|
+
cacheTTL?: number | false;
|
|
213
|
+
};
|
|
214
|
+
type LinksFetchParams = {
|
|
215
|
+
/**
|
|
216
|
+
* Content Kind. FOLDER or DOCUMENT. If not provided, it will return all.
|
|
217
|
+
* @example 'DOCUMENT'
|
|
218
|
+
*/
|
|
219
|
+
kind?: 'DOCUMENT' | 'FOLDER';
|
|
220
|
+
/**
|
|
221
|
+
* Content parent slug.
|
|
222
|
+
* @example 'legal/policy'
|
|
223
|
+
*/
|
|
224
|
+
parentSlug?: string;
|
|
225
|
+
/**
|
|
226
|
+
* If **true**, exclude all sub slugs, otherwise include all content under current selected **parent slug**.
|
|
227
|
+
* @example false
|
|
228
|
+
*/
|
|
229
|
+
excludeChildren?: boolean;
|
|
230
|
+
};
|
|
231
|
+
type ContentFetchParams = {
|
|
232
|
+
/**
|
|
233
|
+
* Content version to fetch, leave empty for 'published' or 'draft' for the latest draft.
|
|
234
|
+
* Overrides the version set in the client options.
|
|
235
|
+
*/
|
|
236
|
+
version?: 'draft' | string;
|
|
237
|
+
/**
|
|
238
|
+
* Locale identifier (ISO 639-1) to fetch content in, leave empty for default locale.
|
|
239
|
+
*
|
|
240
|
+
* Example: en
|
|
241
|
+
*/
|
|
242
|
+
locale?: string;
|
|
243
|
+
/**
|
|
244
|
+
* Resolve references in the content data. Default is false.
|
|
245
|
+
*/
|
|
246
|
+
resolveReference?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Resolve links in the content data. Default is false.
|
|
249
|
+
*/
|
|
250
|
+
resolveLink?: boolean;
|
|
251
|
+
};
|
|
252
|
+
interface LocalessClient {
|
|
253
|
+
/**
|
|
254
|
+
* Get all links
|
|
255
|
+
* @param params{LinksFetchParams} - Fetch parameters
|
|
256
|
+
* @returns {Promise<Links>}
|
|
257
|
+
*/
|
|
258
|
+
getLinks(params?: LinksFetchParams): Promise<Links>;
|
|
259
|
+
/**
|
|
260
|
+
* Get content by SLUG
|
|
261
|
+
* @param slug{string} - Content SLUG
|
|
262
|
+
* @param params{ContentFetchParams} - Fetch parameters
|
|
263
|
+
* @returns {Promise<Content>}
|
|
264
|
+
*/
|
|
265
|
+
getContentBySlug<T extends ContentData = ContentData>(slug: string, params?: ContentFetchParams): Promise<Content<T>>;
|
|
266
|
+
/**
|
|
267
|
+
* Get content by ID
|
|
268
|
+
* @param id{string} - Content ID
|
|
269
|
+
* @param params{ContentFetchParams} - Fetch parameters
|
|
270
|
+
* @returns {Promise<Content>}
|
|
271
|
+
*/
|
|
272
|
+
getContentById<T extends ContentData = ContentData>(id: string, params?: ContentFetchParams): Promise<Content<T>>;
|
|
273
|
+
/**
|
|
274
|
+
* Get translations for the given locale
|
|
275
|
+
* @param locale{string} - Locale identifier (ISO 639-1)
|
|
276
|
+
*/
|
|
277
|
+
getTranslations(locale: string): Promise<Translations>;
|
|
278
|
+
syncScriptUrl(): string;
|
|
279
|
+
assetLink(asset: ContentAsset | string): string;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Create a Localess API Client
|
|
283
|
+
* @param {LocalessClientOptions} options connection details
|
|
284
|
+
*/
|
|
285
|
+
declare function localessClient(options: LocalessClientOptions): LocalessClient;
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Adds Localess editable attributes to a content item.
|
|
289
|
+
* @param content
|
|
290
|
+
* @returns An object containing data-ll-id and data-ll-schema attributes.
|
|
291
|
+
*/
|
|
292
|
+
declare function localessEditable(content: ContentDataSchema): {
|
|
293
|
+
'data-ll-id': string;
|
|
294
|
+
'data-ll-schema': string;
|
|
295
|
+
};
|
|
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
|
+
/**
|
|
307
|
+
* Adds Localess editable field attribute to a specific field.
|
|
308
|
+
* Added type safety to ensure fieldName is a valid key of the content data excluding base schema fields.
|
|
309
|
+
* @param fieldName
|
|
310
|
+
* @returns An object containing data-ll-field attribute.
|
|
311
|
+
*/
|
|
312
|
+
declare function localessEditableField<T extends ContentData = ContentData>(fieldName: Exclude<keyof T, keyof ContentDataSchema>): {
|
|
313
|
+
'data-ll-field': Exclude<keyof T, keyof ContentDataSchema>;
|
|
314
|
+
};
|
|
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
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Inject Localess Sync Script in Header
|
|
327
|
+
* @param {string} origin A fully qualified domain name with protocol (http/https) and port.
|
|
328
|
+
* @param {boolean} force Force Script Injection even if the application is not in Visual Editor.
|
|
329
|
+
*/
|
|
330
|
+
declare function loadLocalessSync(origin: string, force?: boolean): void;
|
|
331
|
+
|
|
332
|
+
declare const isBrowser: () => boolean;
|
|
333
|
+
declare const isServer: () => boolean;
|
|
334
|
+
declare const isIframe: () => boolean;
|
|
335
|
+
|
|
336
|
+
type EventToAppType = 'save' | 'publish' | 'pong' | 'input' | 'change' | 'enterSchema' | 'hoverSchema';
|
|
337
|
+
type EventCallback = (event: EventToApp) => void;
|
|
338
|
+
type EventToApp = {
|
|
339
|
+
type: 'save' | 'publish' | 'pong';
|
|
340
|
+
} | {
|
|
341
|
+
type: 'input' | 'change';
|
|
342
|
+
data: any;
|
|
343
|
+
} | {
|
|
344
|
+
type: 'enterSchema' | 'hoverSchema';
|
|
345
|
+
id: string;
|
|
346
|
+
schema: string;
|
|
347
|
+
field?: string;
|
|
348
|
+
};
|
|
349
|
+
interface LocalessSync {
|
|
350
|
+
onChange: (callback: EventCallback) => void;
|
|
351
|
+
on: (event: EventToAppType | EventToAppType[], callback: EventCallback) => void;
|
|
352
|
+
}
|
|
353
|
+
declare global {
|
|
354
|
+
interface Window {
|
|
355
|
+
localess?: LocalessSync;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
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 };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
isBrowser: () => isBrowser,
|
|
24
|
+
isIframe: () => isIframe,
|
|
25
|
+
isServer: () => isServer,
|
|
26
|
+
llEditable: () => llEditable,
|
|
27
|
+
llEditableField: () => llEditableField,
|
|
28
|
+
loadLocalessSync: () => loadLocalessSync,
|
|
29
|
+
localessClient: () => localessClient,
|
|
30
|
+
localessEditable: () => localessEditable,
|
|
31
|
+
localessEditableField: () => localessEditableField
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(index_exports);
|
|
34
|
+
|
|
35
|
+
// src/utils.ts
|
|
36
|
+
var RESET = "\x1B[0m";
|
|
37
|
+
var FG_BLUE = "\x1B[34m";
|
|
38
|
+
var isBrowser = () => typeof window !== "undefined";
|
|
39
|
+
var isServer = () => typeof window === "undefined";
|
|
40
|
+
var isIframe = () => isBrowser() && window.self !== window.top;
|
|
41
|
+
|
|
42
|
+
// src/cache.ts
|
|
43
|
+
var NoCache = class {
|
|
44
|
+
set(key, value) {
|
|
45
|
+
}
|
|
46
|
+
get(key) {
|
|
47
|
+
return void 0;
|
|
48
|
+
}
|
|
49
|
+
has(key) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var TTLCache = class {
|
|
54
|
+
/**
|
|
55
|
+
* Creates a TTLCache with a specified time-to-live (TTL) for each entry.
|
|
56
|
+
* default is 5 minutes (300000 ms).
|
|
57
|
+
* @param ttlMs
|
|
58
|
+
*/
|
|
59
|
+
constructor(ttlMs = 3e5) {
|
|
60
|
+
this.ttlMs = ttlMs;
|
|
61
|
+
}
|
|
62
|
+
cache = /* @__PURE__ */ new Map();
|
|
63
|
+
set(key, value) {
|
|
64
|
+
this.cache.set(key, { value, expiresAt: Date.now() + this.ttlMs });
|
|
65
|
+
}
|
|
66
|
+
get(key) {
|
|
67
|
+
const entry = this.cache.get(key);
|
|
68
|
+
if (!entry) return void 0;
|
|
69
|
+
if (Date.now() > entry.expiresAt) {
|
|
70
|
+
this.cache.delete(key);
|
|
71
|
+
return void 0;
|
|
72
|
+
}
|
|
73
|
+
return entry.value;
|
|
74
|
+
}
|
|
75
|
+
has(key) {
|
|
76
|
+
return this.get(key) !== void 0;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// src/client.ts
|
|
81
|
+
var LOG_GROUP = `${FG_BLUE}[Localess:Client]${RESET}`;
|
|
82
|
+
function localessClient(options) {
|
|
83
|
+
if (options.debug) {
|
|
84
|
+
console.log(LOG_GROUP, "Client Options : ", options);
|
|
85
|
+
}
|
|
86
|
+
const fetchOptions = {
|
|
87
|
+
redirect: "follow",
|
|
88
|
+
headers: {
|
|
89
|
+
"Content-Type": "application/json",
|
|
90
|
+
"Accept": "application/json",
|
|
91
|
+
"X-Localess-Agent": "Localess-JS-Client",
|
|
92
|
+
"X-Localess-Agent-Version": "0.9.0"
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const cache = options.cacheTTL === false ? new NoCache() : new TTLCache(options.cacheTTL);
|
|
96
|
+
return {
|
|
97
|
+
async getLinks(params) {
|
|
98
|
+
if (options.debug) {
|
|
99
|
+
console.log(LOG_GROUP, "getLinks() params : ", JSON.stringify(params));
|
|
100
|
+
}
|
|
101
|
+
let kind = "";
|
|
102
|
+
if (params?.kind) {
|
|
103
|
+
kind = `&kind=${params.kind}`;
|
|
104
|
+
}
|
|
105
|
+
let parentSlug = "";
|
|
106
|
+
if (params?.parentSlug) {
|
|
107
|
+
parentSlug = `&parentSlug=${params.parentSlug}`;
|
|
108
|
+
}
|
|
109
|
+
let excludeChildren = "";
|
|
110
|
+
if (params?.excludeChildren) {
|
|
111
|
+
excludeChildren = `&excludeChildren=${params.excludeChildren}`;
|
|
112
|
+
}
|
|
113
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
|
|
114
|
+
if (options.debug) {
|
|
115
|
+
console.log(LOG_GROUP, "getLinks fetch url : ", url);
|
|
116
|
+
}
|
|
117
|
+
if (cache.has(url)) {
|
|
118
|
+
if (options.debug) {
|
|
119
|
+
console.log(LOG_GROUP, "getLinks cache hit");
|
|
120
|
+
}
|
|
121
|
+
return cache.get(url);
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
const response = await fetch(url, fetchOptions);
|
|
125
|
+
if (options.debug) {
|
|
126
|
+
console.log(LOG_GROUP, "getLinks status : ", response.status);
|
|
127
|
+
}
|
|
128
|
+
const data = await response.json();
|
|
129
|
+
cache.set(url, data);
|
|
130
|
+
return data;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
console.error(LOG_GROUP, "getLinks error : ", error);
|
|
133
|
+
return {};
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
async getContentBySlug(slug, params) {
|
|
137
|
+
if (options.debug) {
|
|
138
|
+
console.log(LOG_GROUP, "getContentBySlug() slug : ", slug);
|
|
139
|
+
console.log(LOG_GROUP, "getContentBySlug() params : ", JSON.stringify(params));
|
|
140
|
+
}
|
|
141
|
+
let version = "";
|
|
142
|
+
if (options?.version && options.version == "draft") {
|
|
143
|
+
version = `&version=${options.version}`;
|
|
144
|
+
}
|
|
145
|
+
if (params?.version && params.version == "draft") {
|
|
146
|
+
version = `&version=${params.version}`;
|
|
147
|
+
}
|
|
148
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
149
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
150
|
+
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}`;
|
|
152
|
+
if (options.debug) {
|
|
153
|
+
console.log(LOG_GROUP, "getContentBySlug fetch url : ", url);
|
|
154
|
+
}
|
|
155
|
+
if (cache.has(url)) {
|
|
156
|
+
if (options.debug) {
|
|
157
|
+
console.log(LOG_GROUP, "getContentBySlug cache hit");
|
|
158
|
+
}
|
|
159
|
+
return cache.get(url);
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const response = await fetch(url, fetchOptions);
|
|
163
|
+
if (options.debug) {
|
|
164
|
+
console.log(LOG_GROUP, "getContentBySlug status : ", response.status);
|
|
165
|
+
}
|
|
166
|
+
const data = await response.json();
|
|
167
|
+
cache.set(url, data);
|
|
168
|
+
return data;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(LOG_GROUP, "getContentBySlug error : ", error);
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
},
|
|
174
|
+
async getContentById(id, params) {
|
|
175
|
+
if (options.debug) {
|
|
176
|
+
console.log(LOG_GROUP, "getContentById() id : ", id);
|
|
177
|
+
console.log(LOG_GROUP, "getContentById() params : ", JSON.stringify(params));
|
|
178
|
+
}
|
|
179
|
+
let version = "";
|
|
180
|
+
if (options?.version && options.version == "draft") {
|
|
181
|
+
version = `&version=${options.version}`;
|
|
182
|
+
}
|
|
183
|
+
if (params?.version && params.version == "draft") {
|
|
184
|
+
version = `&version=${params.version}`;
|
|
185
|
+
}
|
|
186
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
187
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
188
|
+
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}`;
|
|
190
|
+
if (options.debug) {
|
|
191
|
+
console.log(LOG_GROUP, "getContentById fetch url : ", url);
|
|
192
|
+
}
|
|
193
|
+
if (cache.has(url)) {
|
|
194
|
+
if (options.debug) {
|
|
195
|
+
console.log(LOG_GROUP, "getContentById cache hit");
|
|
196
|
+
}
|
|
197
|
+
return cache.get(url);
|
|
198
|
+
}
|
|
199
|
+
try {
|
|
200
|
+
const response = await fetch(url, fetchOptions);
|
|
201
|
+
if (options.debug) {
|
|
202
|
+
console.log(LOG_GROUP, "getContentById status : ", response.status);
|
|
203
|
+
}
|
|
204
|
+
const data = await response.json();
|
|
205
|
+
cache.set(url, data);
|
|
206
|
+
return data;
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error(LOG_GROUP, "getContentById error : ", error);
|
|
209
|
+
return {};
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
async getTranslations(locale) {
|
|
213
|
+
if (options.debug) {
|
|
214
|
+
console.log(LOG_GROUP, "getTranslations() locale : ", locale);
|
|
215
|
+
}
|
|
216
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
|
|
217
|
+
if (options.debug) {
|
|
218
|
+
console.log(LOG_GROUP, "getTranslations fetch url : ", url);
|
|
219
|
+
}
|
|
220
|
+
if (cache.has(url)) {
|
|
221
|
+
if (options.debug) {
|
|
222
|
+
console.log(LOG_GROUP, "getTranslations cache hit");
|
|
223
|
+
}
|
|
224
|
+
return cache.get(url);
|
|
225
|
+
}
|
|
226
|
+
try {
|
|
227
|
+
const response = await fetch(url, fetchOptions);
|
|
228
|
+
if (options.debug) {
|
|
229
|
+
console.log(LOG_GROUP, "getTranslations status : ", response.status);
|
|
230
|
+
}
|
|
231
|
+
const data = await response.json();
|
|
232
|
+
cache.set(url, data);
|
|
233
|
+
return data;
|
|
234
|
+
} catch (error) {
|
|
235
|
+
console.error(LOG_GROUP, "getTranslations error : ", error);
|
|
236
|
+
return {};
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
syncScriptUrl() {
|
|
240
|
+
return `${options.origin}/scripts/sync-v1.js`;
|
|
241
|
+
},
|
|
242
|
+
assetLink(asset) {
|
|
243
|
+
if (typeof asset === "string") {
|
|
244
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
|
|
245
|
+
} else {
|
|
246
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/editable.ts
|
|
253
|
+
function localessEditable(content) {
|
|
254
|
+
return {
|
|
255
|
+
"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
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
function localessEditableField(fieldName) {
|
|
266
|
+
return {
|
|
267
|
+
"data-ll-field": fieldName
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function llEditableField(fieldName) {
|
|
271
|
+
return {
|
|
272
|
+
"data-ll-field": fieldName
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/sync.ts
|
|
277
|
+
var JS_SYNC_ID = "localess-js-sync";
|
|
278
|
+
function loadLocalessSync(origin, force = false) {
|
|
279
|
+
if (isServer()) return;
|
|
280
|
+
if (!isIframe()) return;
|
|
281
|
+
const isSyncLoaded = typeof window.localess !== "undefined";
|
|
282
|
+
if (isSyncLoaded) return;
|
|
283
|
+
const scriptEl = document.getElementById(JS_SYNC_ID);
|
|
284
|
+
if (scriptEl) return;
|
|
285
|
+
const script = document.createElement("script");
|
|
286
|
+
script.id = JS_SYNC_ID;
|
|
287
|
+
script.type = "text/javascript";
|
|
288
|
+
script.src = `${origin}/scripts/sync-v1.js`;
|
|
289
|
+
script.async = true;
|
|
290
|
+
script.onerror = (error) => console.error(error);
|
|
291
|
+
script.onload = (event) => console.info("Localess Sync Script loaded");
|
|
292
|
+
document.head.appendChild(script);
|
|
293
|
+
}
|
|
294
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
295
|
+
0 && (module.exports = {
|
|
296
|
+
isBrowser,
|
|
297
|
+
isIframe,
|
|
298
|
+
isServer,
|
|
299
|
+
llEditable,
|
|
300
|
+
llEditableField,
|
|
301
|
+
loadLocalessSync,
|
|
302
|
+
localessClient,
|
|
303
|
+
localessEditable,
|
|
304
|
+
localessEditableField
|
|
305
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
var RESET = "\x1B[0m";
|
|
3
|
+
var FG_BLUE = "\x1B[34m";
|
|
4
|
+
var isBrowser = () => typeof window !== "undefined";
|
|
5
|
+
var isServer = () => typeof window === "undefined";
|
|
6
|
+
var isIframe = () => isBrowser() && window.self !== window.top;
|
|
7
|
+
|
|
8
|
+
// src/cache.ts
|
|
9
|
+
var NoCache = class {
|
|
10
|
+
set(key, value) {
|
|
11
|
+
}
|
|
12
|
+
get(key) {
|
|
13
|
+
return void 0;
|
|
14
|
+
}
|
|
15
|
+
has(key) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var TTLCache = class {
|
|
20
|
+
/**
|
|
21
|
+
* Creates a TTLCache with a specified time-to-live (TTL) for each entry.
|
|
22
|
+
* default is 5 minutes (300000 ms).
|
|
23
|
+
* @param ttlMs
|
|
24
|
+
*/
|
|
25
|
+
constructor(ttlMs = 3e5) {
|
|
26
|
+
this.ttlMs = ttlMs;
|
|
27
|
+
}
|
|
28
|
+
cache = /* @__PURE__ */ new Map();
|
|
29
|
+
set(key, value) {
|
|
30
|
+
this.cache.set(key, { value, expiresAt: Date.now() + this.ttlMs });
|
|
31
|
+
}
|
|
32
|
+
get(key) {
|
|
33
|
+
const entry = this.cache.get(key);
|
|
34
|
+
if (!entry) return void 0;
|
|
35
|
+
if (Date.now() > entry.expiresAt) {
|
|
36
|
+
this.cache.delete(key);
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
return entry.value;
|
|
40
|
+
}
|
|
41
|
+
has(key) {
|
|
42
|
+
return this.get(key) !== void 0;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// src/client.ts
|
|
47
|
+
var LOG_GROUP = `${FG_BLUE}[Localess:Client]${RESET}`;
|
|
48
|
+
function localessClient(options) {
|
|
49
|
+
if (options.debug) {
|
|
50
|
+
console.log(LOG_GROUP, "Client Options : ", options);
|
|
51
|
+
}
|
|
52
|
+
const fetchOptions = {
|
|
53
|
+
redirect: "follow",
|
|
54
|
+
headers: {
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
"Accept": "application/json",
|
|
57
|
+
"X-Localess-Agent": "Localess-JS-Client",
|
|
58
|
+
"X-Localess-Agent-Version": "0.9.0"
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const cache = options.cacheTTL === false ? new NoCache() : new TTLCache(options.cacheTTL);
|
|
62
|
+
return {
|
|
63
|
+
async getLinks(params) {
|
|
64
|
+
if (options.debug) {
|
|
65
|
+
console.log(LOG_GROUP, "getLinks() params : ", JSON.stringify(params));
|
|
66
|
+
}
|
|
67
|
+
let kind = "";
|
|
68
|
+
if (params?.kind) {
|
|
69
|
+
kind = `&kind=${params.kind}`;
|
|
70
|
+
}
|
|
71
|
+
let parentSlug = "";
|
|
72
|
+
if (params?.parentSlug) {
|
|
73
|
+
parentSlug = `&parentSlug=${params.parentSlug}`;
|
|
74
|
+
}
|
|
75
|
+
let excludeChildren = "";
|
|
76
|
+
if (params?.excludeChildren) {
|
|
77
|
+
excludeChildren = `&excludeChildren=${params.excludeChildren}`;
|
|
78
|
+
}
|
|
79
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/links?token=${options.token}${kind}${parentSlug}${excludeChildren}`;
|
|
80
|
+
if (options.debug) {
|
|
81
|
+
console.log(LOG_GROUP, "getLinks fetch url : ", url);
|
|
82
|
+
}
|
|
83
|
+
if (cache.has(url)) {
|
|
84
|
+
if (options.debug) {
|
|
85
|
+
console.log(LOG_GROUP, "getLinks cache hit");
|
|
86
|
+
}
|
|
87
|
+
return cache.get(url);
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
const response = await fetch(url, fetchOptions);
|
|
91
|
+
if (options.debug) {
|
|
92
|
+
console.log(LOG_GROUP, "getLinks status : ", response.status);
|
|
93
|
+
}
|
|
94
|
+
const data = await response.json();
|
|
95
|
+
cache.set(url, data);
|
|
96
|
+
return data;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
console.error(LOG_GROUP, "getLinks error : ", error);
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
async getContentBySlug(slug, params) {
|
|
103
|
+
if (options.debug) {
|
|
104
|
+
console.log(LOG_GROUP, "getContentBySlug() slug : ", slug);
|
|
105
|
+
console.log(LOG_GROUP, "getContentBySlug() params : ", JSON.stringify(params));
|
|
106
|
+
}
|
|
107
|
+
let version = "";
|
|
108
|
+
if (options?.version && options.version == "draft") {
|
|
109
|
+
version = `&version=${options.version}`;
|
|
110
|
+
}
|
|
111
|
+
if (params?.version && params.version == "draft") {
|
|
112
|
+
version = `&version=${params.version}`;
|
|
113
|
+
}
|
|
114
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
115
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
116
|
+
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
|
+
if (options.debug) {
|
|
119
|
+
console.log(LOG_GROUP, "getContentBySlug fetch url : ", url);
|
|
120
|
+
}
|
|
121
|
+
if (cache.has(url)) {
|
|
122
|
+
if (options.debug) {
|
|
123
|
+
console.log(LOG_GROUP, "getContentBySlug cache hit");
|
|
124
|
+
}
|
|
125
|
+
return cache.get(url);
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const response = await fetch(url, fetchOptions);
|
|
129
|
+
if (options.debug) {
|
|
130
|
+
console.log(LOG_GROUP, "getContentBySlug status : ", response.status);
|
|
131
|
+
}
|
|
132
|
+
const data = await response.json();
|
|
133
|
+
cache.set(url, data);
|
|
134
|
+
return data;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error(LOG_GROUP, "getContentBySlug error : ", error);
|
|
137
|
+
return {};
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
async getContentById(id, params) {
|
|
141
|
+
if (options.debug) {
|
|
142
|
+
console.log(LOG_GROUP, "getContentById() id : ", id);
|
|
143
|
+
console.log(LOG_GROUP, "getContentById() params : ", JSON.stringify(params));
|
|
144
|
+
}
|
|
145
|
+
let version = "";
|
|
146
|
+
if (options?.version && options.version == "draft") {
|
|
147
|
+
version = `&version=${options.version}`;
|
|
148
|
+
}
|
|
149
|
+
if (params?.version && params.version == "draft") {
|
|
150
|
+
version = `&version=${params.version}`;
|
|
151
|
+
}
|
|
152
|
+
const locale = params?.locale ? `&locale=${params.locale}` : "";
|
|
153
|
+
const resolveReference = params?.resolveReference ? `&resolveReference=${params.resolveReference}` : "";
|
|
154
|
+
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
|
+
if (options.debug) {
|
|
157
|
+
console.log(LOG_GROUP, "getContentById fetch url : ", url);
|
|
158
|
+
}
|
|
159
|
+
if (cache.has(url)) {
|
|
160
|
+
if (options.debug) {
|
|
161
|
+
console.log(LOG_GROUP, "getContentById cache hit");
|
|
162
|
+
}
|
|
163
|
+
return cache.get(url);
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
const response = await fetch(url, fetchOptions);
|
|
167
|
+
if (options.debug) {
|
|
168
|
+
console.log(LOG_GROUP, "getContentById status : ", response.status);
|
|
169
|
+
}
|
|
170
|
+
const data = await response.json();
|
|
171
|
+
cache.set(url, data);
|
|
172
|
+
return data;
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.error(LOG_GROUP, "getContentById error : ", error);
|
|
175
|
+
return {};
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
async getTranslations(locale) {
|
|
179
|
+
if (options.debug) {
|
|
180
|
+
console.log(LOG_GROUP, "getTranslations() locale : ", locale);
|
|
181
|
+
}
|
|
182
|
+
let url = `${options.origin}/api/v1/spaces/${options.spaceId}/translations/${locale}?token=${options.token}`;
|
|
183
|
+
if (options.debug) {
|
|
184
|
+
console.log(LOG_GROUP, "getTranslations fetch url : ", url);
|
|
185
|
+
}
|
|
186
|
+
if (cache.has(url)) {
|
|
187
|
+
if (options.debug) {
|
|
188
|
+
console.log(LOG_GROUP, "getTranslations cache hit");
|
|
189
|
+
}
|
|
190
|
+
return cache.get(url);
|
|
191
|
+
}
|
|
192
|
+
try {
|
|
193
|
+
const response = await fetch(url, fetchOptions);
|
|
194
|
+
if (options.debug) {
|
|
195
|
+
console.log(LOG_GROUP, "getTranslations status : ", response.status);
|
|
196
|
+
}
|
|
197
|
+
const data = await response.json();
|
|
198
|
+
cache.set(url, data);
|
|
199
|
+
return data;
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error(LOG_GROUP, "getTranslations error : ", error);
|
|
202
|
+
return {};
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
syncScriptUrl() {
|
|
206
|
+
return `${options.origin}/scripts/sync-v1.js`;
|
|
207
|
+
},
|
|
208
|
+
assetLink(asset) {
|
|
209
|
+
if (typeof asset === "string") {
|
|
210
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset}`;
|
|
211
|
+
} else {
|
|
212
|
+
return `${options.origin}/api/v1/spaces/${options.spaceId}/assets/${asset.uri}`;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// src/editable.ts
|
|
219
|
+
function localessEditable(content) {
|
|
220
|
+
return {
|
|
221
|
+
"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
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function localessEditableField(fieldName) {
|
|
232
|
+
return {
|
|
233
|
+
"data-ll-field": fieldName
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function llEditableField(fieldName) {
|
|
237
|
+
return {
|
|
238
|
+
"data-ll-field": fieldName
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/sync.ts
|
|
243
|
+
var JS_SYNC_ID = "localess-js-sync";
|
|
244
|
+
function loadLocalessSync(origin, force = false) {
|
|
245
|
+
if (isServer()) return;
|
|
246
|
+
if (!isIframe()) return;
|
|
247
|
+
const isSyncLoaded = typeof window.localess !== "undefined";
|
|
248
|
+
if (isSyncLoaded) return;
|
|
249
|
+
const scriptEl = document.getElementById(JS_SYNC_ID);
|
|
250
|
+
if (scriptEl) return;
|
|
251
|
+
const script = document.createElement("script");
|
|
252
|
+
script.id = JS_SYNC_ID;
|
|
253
|
+
script.type = "text/javascript";
|
|
254
|
+
script.src = `${origin}/scripts/sync-v1.js`;
|
|
255
|
+
script.async = true;
|
|
256
|
+
script.onerror = (error) => console.error(error);
|
|
257
|
+
script.onload = (event) => console.info("Localess Sync Script loaded");
|
|
258
|
+
document.head.appendChild(script);
|
|
259
|
+
}
|
|
260
|
+
export {
|
|
261
|
+
isBrowser,
|
|
262
|
+
isIframe,
|
|
263
|
+
isServer,
|
|
264
|
+
llEditable,
|
|
265
|
+
llEditableField,
|
|
266
|
+
loadLocalessSync,
|
|
267
|
+
localessClient,
|
|
268
|
+
localessEditable,
|
|
269
|
+
localessEditableField
|
|
270
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@localess/client",
|
|
3
|
+
"version": "0.9.2-dev.20260216094809",
|
|
4
|
+
"description": "Universal JavaScript/TypeScript SDK for Localess's API.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"localess",
|
|
7
|
+
"sdk",
|
|
8
|
+
"api",
|
|
9
|
+
"client",
|
|
10
|
+
"javascript",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"author": "Lessify",
|
|
14
|
+
"homepage": "https://github.com/Lessify/localess-js",
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"main": "dist/index.js",
|
|
20
|
+
"module": "dist/index.mjs",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.mjs",
|
|
26
|
+
"require": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/Lessify/localess-js.git",
|
|
32
|
+
"directory": "packages/client"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/Lessify/localess-js/issues"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsup src/index.ts --format cjs,esm --dts"
|
|
39
|
+
},
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"openapi3-ts": "^4.5.0"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@types/node": "^20",
|
|
46
|
+
"tsup": "^8.5.1",
|
|
47
|
+
"typescript": "^5.0.0"
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">= 20.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|