@localess/client 3.0.8-dev.20260514092749 → 3.0.9-dev.20260520210048

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/SKILL.md CHANGED
@@ -80,11 +80,37 @@ const t = await client.getTranslations('en');
80
80
 
81
81
  ```typescript
82
82
  import { localessClient } from "@localess/client";
83
+ import type { AssetTransformParams } from "@localess/client";
83
84
 
85
+ // Basic — no transform
84
86
  const url = client.assetLink(content.data.image);
85
87
  // Returns: https://my-localess.web.app/api/v1/spaces/{spaceId}/assets/{uri}
88
+
89
+ // With transform params
90
+ const url = client.assetLink(content.data.image, { w: 800, h: 600, f: 'webp', q: 90 });
91
+ // Returns: .../assets/{uri}?w=800&h=600&q=90&f=webp
92
+
93
+ // Download
94
+ const url = client.assetLink(content.data.file, { download: true });
95
+ // Returns: .../assets/{uri}?download
96
+
97
+ // Accepts ContentAsset or raw URI string
98
+ const url = client.assetLink('my-image.png', { w: 400 });
86
99
  ```
87
100
 
101
+ #### AssetTransformParams
102
+
103
+ | Param | Type | Description |
104
+ |-------------|---------------------------------------|-----------------------------------------------------------------------------|
105
+ | `w` | `number` | Target width in pixels. With `h` → cover crop. Without → scale proportionally. |
106
+ | `h` | `number` | Target height in pixels. With `w` → cover crop. Without → scale proportionally. |
107
+ | `q` | `number` (1–100) | Output quality. Applies to JPEG, WebP, AVIF. Ignored for PNG. Default: 85. |
108
+ | `f` | `'webp' \| 'jpeg' \| 'png' \| 'avif'` | Convert to this output format. |
109
+ | `download` | `boolean` | `true` → force browser download (Content-Disposition: form-data). |
110
+ | `thumbnail` | `boolean` | `true` → extract first frame from animated WebP/GIF or video frame via FFmpeg. |
111
+
112
+ SVG files are always passed through unchanged. `w`/`h`/`f` are ignored for SVG.
113
+
88
114
  ---
89
115
 
90
116
  ## Content Fetch Parameters
@@ -291,6 +317,7 @@ export { localessEditable, localessEditableField } // Visual editor helpers
291
317
  export { llEditable, llEditableField } // Deprecated aliases
292
318
  export { loadLocalessSync } // Sync script injector
293
319
  export { isBrowser, isServer, isIframe } // Environment utilities
320
+ export { buildAssetQueryString } // Asset query string serialiser
294
321
  export type {
295
322
  LocalessClient, LocalessClientOptions,
296
323
  ContentFetchParams, LinksFetchParams,
@@ -299,5 +326,6 @@ export type {
299
326
  ContentRichText, ContentReference,
300
327
  Links, References, Translations,
301
328
  LocalessSync, EventToApp, EventCallback, EventToAppType,
329
+ AssetTransformParams,
302
330
  }
303
331
  ```
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Content, ContentAsset, ContentData, Links, Translations } from './models';
1
+ import { AssetTransformParams, Content, ContentAsset, ContentData, Links, Translations } from './models';
2
2
  export type LocalessClientOptions = {
3
3
  /**
4
4
  * A fully qualified domain name with protocol (http/https) and port.
@@ -103,7 +103,7 @@ export interface LocalessClient {
103
103
  */
104
104
  getTranslations(locale: string): Promise<Translations>;
105
105
  syncScriptUrl(): string;
106
- assetLink(asset: ContentAsset | string): string;
106
+ assetLink(asset: ContentAsset | string, params?: AssetTransformParams): string;
107
107
  }
108
108
  /**
109
109
  * Create a Localess API Client
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ export * from './client';
3
3
  export * from './editable';
4
4
  export * from './models';
5
5
  export * from './sync';
6
- export { isBrowser, isIframe, isServer } from './utils';
6
+ export { buildAssetQueryString, isBrowser, isIframe, isServer } from './utils';
7
7
  export type EventToAppType = 'save' | 'publish' | 'pong' | 'input' | 'change' | 'enterSchema' | 'hoverSchema';
8
8
  export type EventCallback = (event: EventToApp) => void;
9
9
  export type EventToApp = {
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class{cache=new Map;set(e,t){this.cache.set(e,t)}get(e){return this.cache.get(e)}has(e){return this.cache.has(e)}},t=class{set(e,t){}get(e){}has(e){return!1}},n=class{cache=new Map;constructor(e=3e5){this.ttlMs=e}set(e,t){this.cache.set(e,{value:t,expiresAt:Date.now()+this.ttlMs})}get(e){let t=this.cache.get(e);if(t){if(Date.now()>t.expiresAt){this.cache.delete(e);return}return t.value}}has(e){return this.get(e)!==void 0}},r=`\x1B[0m`,i=`\x1B[34m`,a=()=>typeof window<`u`,o=()=>typeof window>`u`,s=()=>a()&&window.self!==window.top,c=`${i}[Localess:Client]${r}`;function l(e){e.debug&&console.log(c,`Client Options : `,e);let r=e.origin.replace(/\/+$/,``),i={redirect:`follow`,headers:{"Content-Type":`application/json`,Accept:`application/json`,"X-Localess-Agent":`Localess-JS-Client`,"X-Localess-Agent-Version":`0.9.0`}},a=typeof e.cacheTTL==`number`?e.cacheTTL*1e3:void 0,o=e.cacheTTL===!1?new t:new n(a);return{async getLinks(t){e.debug&&console.log(c,`getLinks() params : `,JSON.stringify(t));let n=``;t?.kind&&(n=`&kind=${t.kind}`);let a=``;t?.parentSlug&&(a=`&parentSlug=${t.parentSlug}`);let s=``;t?.excludeChildren&&(s=`&excludeChildren=${t.excludeChildren}`);let l=`${r}/api/v1/spaces/${e.spaceId}/links?token=${e.token}${n}${a}${s}`;if(e.debug&&console.log(c,`getLinks fetch url : `,l),o.has(l))return e.debug&&console.log(c,`getLinks cache hit`),o.get(l);try{let t=await fetch(l,i);e.debug&&console.log(c,`getLinks status : `,t.status);let n=await t.json();return o.set(l,n),n}catch(e){return console.error(c,`getLinks error : `,e),{}}},async getContentBySlug(t,n){e.debug&&(console.log(c,`getContentBySlug() slug : `,t),console.log(c,`getContentBySlug() params : `,JSON.stringify(n)));let a=``;e?.version&&e.version==`draft`&&(a=`&version=${e.version}`),n?.version&&n.version==`draft`&&(a=`&version=${n.version}`);let s=n?.locale?`&locale=${n.locale}`:``,l=n?.resolveReference?`&resolveReference=${n.resolveReference}`:``,u=n?.resolveLink?`&resolveLink=${n.resolveLink}`:``,d=`${r}/api/v1/spaces/${e.spaceId}/contents/slugs/${t}?token=${e.token}${a}${s}${l}${u}`;if(e.debug&&console.log(c,`getContentBySlug fetch url : `,d),o.has(d))return e.debug&&console.log(c,`getContentBySlug cache hit`),o.get(d);try{let t=await fetch(d,i);e.debug&&console.log(c,`getContentBySlug status : `,t.status);let n=await t.json();return o.set(d,n),n}catch(e){return console.error(c,`getContentBySlug error : `,e),{}}},async getContentById(t,n){e.debug&&(console.log(c,`getContentById() id : `,t),console.log(c,`getContentById() params : `,JSON.stringify(n)));let a=``;e?.version&&e.version==`draft`&&(a=`&version=${e.version}`),n?.version&&n.version==`draft`&&(a=`&version=${n.version}`);let s=n?.locale?`&locale=${n.locale}`:``,l=n?.resolveReference?`&resolveReference=${n.resolveReference}`:``,u=n?.resolveLink?`&resolveLink=${n.resolveLink}`:``,d=`${r}/api/v1/spaces/${e.spaceId}/contents/${t}?token=${e.token}${a}${s}${l}${u}`;if(e.debug&&console.log(c,`getContentById fetch url : `,d),o.has(d))return e.debug&&console.log(c,`getContentById cache hit`),o.get(d);try{let t=await fetch(d,i);e.debug&&console.log(c,`getContentById status : `,t.status);let n=await t.json();return o.set(d,n),n}catch(e){return console.error(c,`getContentById error : `,e),{}}},async getTranslations(t){e.debug&&console.log(c,`getTranslations() locale : `,t);let n=`${r}/api/v1/spaces/${e.spaceId}/translations/${t}?token=${e.token}`;if(e.debug&&console.log(c,`getTranslations fetch url : `,n),o.has(n))return e.debug&&console.log(c,`getTranslations cache hit`),o.get(n);try{let t=await fetch(n,i);e.debug&&console.log(c,`getTranslations status : `,t.status);let r=await t.json();return o.set(n,r),r}catch(e){return console.error(c,`getTranslations error : `,e),{}}},syncScriptUrl(){return`${r}/scripts/sync-v1.js`},assetLink(t){return typeof t==`string`?`${r}/api/v1/spaces/${e.spaceId}/assets/${t}`:`${r}/api/v1/spaces/${e.spaceId}/assets/${t.uri}`}}}function u(e){return{"data-ll-id":e._id,"data-ll-schema":e._schema}}function d(e){return{"data-ll-field":e}}var f=`localess-js-sync`;async function p(e,t=!1){return new Promise((t,n)=>{if(o()){n(void 0);return}if(!s()){console.warn(`Localess Sync is loaded only in Visual Editor.`),n(void 0);return}if(window.localess!==void 0){n(void 0);return}if(document.getElementById(f)){n(void 0);return}let r=document.createElement(`script`);r.id=f,r.type=`text/javascript`,r.src=`${e}/scripts/sync-v1.js`,r.async=!0,r.onerror=e=>n(e),r.onload=e=>{console.info(`Localess Sync Script loaded`),t()},document.head.appendChild(r)})}exports.Cache=e,exports.NoCache=t,exports.TTLCache=n,exports.isBrowser=a,exports.isIframe=s,exports.isServer=o,exports.loadLocalessSync=p,exports.localessClient=l,exports.localessEditable=u,exports.localessEditableField=d;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=class{cache=new Map;set(e,t){this.cache.set(e,t)}get(e){return this.cache.get(e)}has(e){return this.cache.has(e)}},t=class{set(e,t){}get(e){}has(e){return!1}},n=class{cache=new Map;constructor(e=3e5){this.ttlMs=e}set(e,t){this.cache.set(e,{value:t,expiresAt:Date.now()+this.ttlMs})}get(e){let t=this.cache.get(e);if(t){if(Date.now()>t.expiresAt){this.cache.delete(e);return}return t.value}}has(e){return this.get(e)!==void 0}},r=`\x1B[0m`,i=`\x1B[34m`,a=()=>typeof window<`u`,o=()=>typeof window>`u`,s=()=>a()&&window.self!==window.top;function c(e){if(!e)return``;let t=[];return e.w!==void 0&&t.push(`w=${e.w}`),e.h!==void 0&&t.push(`h=${e.h}`),e.q!==void 0&&t.push(`q=${e.q}`),e.f!==void 0&&t.push(`f=${e.f}`),e.download&&t.push(`download`),e.thumbnail&&t.push(`thumbnail`),t.join(`&`)}var l=`${i}[Localess:Client]${r}`;function u(e){e.debug&&console.log(l,`Client Options : `,e);let r=e.origin.replace(/\/+$/,``),i={redirect:`follow`,headers:{"Content-Type":`application/json`,Accept:`application/json`,"X-Localess-Agent":`Localess-JS-Client`,"X-Localess-Agent-Version":`0.9.0`}},a=typeof e.cacheTTL==`number`?e.cacheTTL*1e3:void 0,o=e.cacheTTL===!1?new t:new n(a);return{async getLinks(t){e.debug&&console.log(l,`getLinks() params : `,JSON.stringify(t));let n=``;t?.kind&&(n=`&kind=${t.kind}`);let a=``;t?.parentSlug&&(a=`&parentSlug=${t.parentSlug}`);let s=``;t?.excludeChildren&&(s=`&excludeChildren=${t.excludeChildren}`);let c=`${r}/api/v1/spaces/${e.spaceId}/links?token=${e.token}${n}${a}${s}`;if(e.debug&&console.log(l,`getLinks fetch url : `,c),o.has(c))return e.debug&&console.log(l,`getLinks cache hit`),o.get(c);try{let t=await fetch(c,i);e.debug&&console.log(l,`getLinks status : `,t.status);let n=await t.json();return o.set(c,n),n}catch(e){return console.error(l,`getLinks error : `,e),{}}},async getContentBySlug(t,n){e.debug&&(console.log(l,`getContentBySlug() slug : `,t),console.log(l,`getContentBySlug() params : `,JSON.stringify(n)));let a=``;e?.version&&e.version==`draft`&&(a=`&version=${e.version}`),n?.version&&n.version==`draft`&&(a=`&version=${n.version}`);let s=n?.locale?`&locale=${n.locale}`:``,c=n?.resolveReference?`&resolveReference=${n.resolveReference}`:``,u=n?.resolveLink?`&resolveLink=${n.resolveLink}`:``,d=`${r}/api/v1/spaces/${e.spaceId}/contents/slugs/${t}?token=${e.token}${a}${s}${c}${u}`;if(e.debug&&console.log(l,`getContentBySlug fetch url : `,d),o.has(d))return e.debug&&console.log(l,`getContentBySlug cache hit`),o.get(d);try{let t=await fetch(d,i);e.debug&&console.log(l,`getContentBySlug status : `,t.status);let n=await t.json();return o.set(d,n),n}catch(e){return console.error(l,`getContentBySlug error : `,e),{}}},async getContentById(t,n){e.debug&&(console.log(l,`getContentById() id : `,t),console.log(l,`getContentById() params : `,JSON.stringify(n)));let a=``;e?.version&&e.version==`draft`&&(a=`&version=${e.version}`),n?.version&&n.version==`draft`&&(a=`&version=${n.version}`);let s=n?.locale?`&locale=${n.locale}`:``,c=n?.resolveReference?`&resolveReference=${n.resolveReference}`:``,u=n?.resolveLink?`&resolveLink=${n.resolveLink}`:``,d=`${r}/api/v1/spaces/${e.spaceId}/contents/${t}?token=${e.token}${a}${s}${c}${u}`;if(e.debug&&console.log(l,`getContentById fetch url : `,d),o.has(d))return e.debug&&console.log(l,`getContentById cache hit`),o.get(d);try{let t=await fetch(d,i);e.debug&&console.log(l,`getContentById status : `,t.status);let n=await t.json();return o.set(d,n),n}catch(e){return console.error(l,`getContentById error : `,e),{}}},async getTranslations(t){e.debug&&console.log(l,`getTranslations() locale : `,t);let n=`${r}/api/v1/spaces/${e.spaceId}/translations/${t}?token=${e.token}`;if(e.debug&&console.log(l,`getTranslations fetch url : `,n),o.has(n))return e.debug&&console.log(l,`getTranslations cache hit`),o.get(n);try{let t=await fetch(n,i);e.debug&&console.log(l,`getTranslations status : `,t.status);let r=await t.json();return o.set(n,r),r}catch(e){return console.error(l,`getTranslations error : `,e),{}}},syncScriptUrl(){return`${r}/scripts/sync-v1.js`},assetLink(t,n){let i=typeof t==`string`?t:t.uri,a=`${r}/api/v1/spaces/${e.spaceId}/assets/${i}`,o=c(n);return o?`${a}?${o}`:a}}}function d(e){return{"data-ll-id":e._id,"data-ll-schema":e._schema}}function f(e){return{"data-ll-field":e}}var p=`localess-js-sync`;async function m(e,t=!1){return new Promise((t,n)=>{if(o()){n(void 0);return}if(!s()){console.warn(`Localess Sync is loaded only in Visual Editor.`),n(void 0);return}if(window.localess!==void 0){n(void 0);return}if(document.getElementById(p)){n(void 0);return}let r=document.createElement(`script`);r.id=p,r.type=`text/javascript`,r.src=`${e}/scripts/sync-v1.js`,r.async=!0,r.onerror=e=>n(e),r.onload=e=>{console.info(`Localess Sync Script loaded`),t()},document.head.appendChild(r)})}exports.Cache=e,exports.NoCache=t,exports.TTLCache=n,exports.buildAssetQueryString=c,exports.isBrowser=a,exports.isIframe=s,exports.isServer=o,exports.loadLocalessSync=m,exports.localessClient=u,exports.localessEditable=d,exports.localessEditableField=f;
package/dist/index.mjs CHANGED
@@ -40,9 +40,17 @@ var e = class {
40
40
  has(e) {
41
41
  return this.get(e) !== void 0;
42
42
  }
43
- }, r = "\x1B[0m", i = "\x1B[34m", a = () => typeof window < "u", o = () => typeof window > "u", s = () => a() && window.self !== window.top, c = `${i}[Localess:Client]${r}`;
44
- function l(e) {
45
- e.debug && console.log(c, "Client Options : ", e);
43
+ }, r = "\x1B[0m", i = "\x1B[34m", a = () => typeof window < "u", o = () => typeof window > "u", s = () => a() && window.self !== window.top;
44
+ function c(e) {
45
+ if (!e) return "";
46
+ let t = [];
47
+ return e.w !== void 0 && t.push(`w=${e.w}`), e.h !== void 0 && t.push(`h=${e.h}`), e.q !== void 0 && t.push(`q=${e.q}`), e.f !== void 0 && t.push(`f=${e.f}`), e.download && t.push("download"), e.thumbnail && t.push("thumbnail"), t.join("&");
48
+ }
49
+ //#endregion
50
+ //#region src/client.ts
51
+ var l = `${i}[Localess:Client]${r}`;
52
+ function u(e) {
53
+ e.debug && console.log(l, "Client Options : ", e);
46
54
  let r = e.origin.replace(/\/+$/, ""), i = {
47
55
  redirect: "follow",
48
56
  headers: {
@@ -54,90 +62,91 @@ function l(e) {
54
62
  }, a = typeof e.cacheTTL == "number" ? e.cacheTTL * 1e3 : void 0, o = e.cacheTTL === !1 ? new t() : new n(a);
55
63
  return {
56
64
  async getLinks(t) {
57
- e.debug && console.log(c, "getLinks() params : ", JSON.stringify(t));
65
+ e.debug && console.log(l, "getLinks() params : ", JSON.stringify(t));
58
66
  let n = "";
59
67
  t?.kind && (n = `&kind=${t.kind}`);
60
68
  let a = "";
61
69
  t?.parentSlug && (a = `&parentSlug=${t.parentSlug}`);
62
70
  let s = "";
63
71
  t?.excludeChildren && (s = `&excludeChildren=${t.excludeChildren}`);
64
- let l = `${r}/api/v1/spaces/${e.spaceId}/links?token=${e.token}${n}${a}${s}`;
65
- if (e.debug && console.log(c, "getLinks fetch url : ", l), o.has(l)) return e.debug && console.log(c, "getLinks cache hit"), o.get(l);
72
+ let c = `${r}/api/v1/spaces/${e.spaceId}/links?token=${e.token}${n}${a}${s}`;
73
+ if (e.debug && console.log(l, "getLinks fetch url : ", c), o.has(c)) return e.debug && console.log(l, "getLinks cache hit"), o.get(c);
66
74
  try {
67
- let t = await fetch(l, i);
68
- e.debug && console.log(c, "getLinks status : ", t.status);
75
+ let t = await fetch(c, i);
76
+ e.debug && console.log(l, "getLinks status : ", t.status);
69
77
  let n = await t.json();
70
- return o.set(l, n), n;
78
+ return o.set(c, n), n;
71
79
  } catch (e) {
72
- return console.error(c, "getLinks error : ", e), {};
80
+ return console.error(l, "getLinks error : ", e), {};
73
81
  }
74
82
  },
75
83
  async getContentBySlug(t, n) {
76
- e.debug && (console.log(c, "getContentBySlug() slug : ", t), console.log(c, "getContentBySlug() params : ", JSON.stringify(n)));
84
+ e.debug && (console.log(l, "getContentBySlug() slug : ", t), console.log(l, "getContentBySlug() params : ", JSON.stringify(n)));
77
85
  let a = "";
78
86
  e?.version && e.version == "draft" && (a = `&version=${e.version}`), n?.version && n.version == "draft" && (a = `&version=${n.version}`);
79
- let s = n?.locale ? `&locale=${n.locale}` : "", l = n?.resolveReference ? `&resolveReference=${n.resolveReference}` : "", u = n?.resolveLink ? `&resolveLink=${n.resolveLink}` : "", d = `${r}/api/v1/spaces/${e.spaceId}/contents/slugs/${t}?token=${e.token}${a}${s}${l}${u}`;
80
- if (e.debug && console.log(c, "getContentBySlug fetch url : ", d), o.has(d)) return e.debug && console.log(c, "getContentBySlug cache hit"), o.get(d);
87
+ let s = n?.locale ? `&locale=${n.locale}` : "", c = n?.resolveReference ? `&resolveReference=${n.resolveReference}` : "", u = n?.resolveLink ? `&resolveLink=${n.resolveLink}` : "", d = `${r}/api/v1/spaces/${e.spaceId}/contents/slugs/${t}?token=${e.token}${a}${s}${c}${u}`;
88
+ if (e.debug && console.log(l, "getContentBySlug fetch url : ", d), o.has(d)) return e.debug && console.log(l, "getContentBySlug cache hit"), o.get(d);
81
89
  try {
82
90
  let t = await fetch(d, i);
83
- e.debug && console.log(c, "getContentBySlug status : ", t.status);
91
+ e.debug && console.log(l, "getContentBySlug status : ", t.status);
84
92
  let n = await t.json();
85
93
  return o.set(d, n), n;
86
94
  } catch (e) {
87
- return console.error(c, "getContentBySlug error : ", e), {};
95
+ return console.error(l, "getContentBySlug error : ", e), {};
88
96
  }
89
97
  },
90
98
  async getContentById(t, n) {
91
- e.debug && (console.log(c, "getContentById() id : ", t), console.log(c, "getContentById() params : ", JSON.stringify(n)));
99
+ e.debug && (console.log(l, "getContentById() id : ", t), console.log(l, "getContentById() params : ", JSON.stringify(n)));
92
100
  let a = "";
93
101
  e?.version && e.version == "draft" && (a = `&version=${e.version}`), n?.version && n.version == "draft" && (a = `&version=${n.version}`);
94
- let s = n?.locale ? `&locale=${n.locale}` : "", l = n?.resolveReference ? `&resolveReference=${n.resolveReference}` : "", u = n?.resolveLink ? `&resolveLink=${n.resolveLink}` : "", d = `${r}/api/v1/spaces/${e.spaceId}/contents/${t}?token=${e.token}${a}${s}${l}${u}`;
95
- if (e.debug && console.log(c, "getContentById fetch url : ", d), o.has(d)) return e.debug && console.log(c, "getContentById cache hit"), o.get(d);
102
+ let s = n?.locale ? `&locale=${n.locale}` : "", c = n?.resolveReference ? `&resolveReference=${n.resolveReference}` : "", u = n?.resolveLink ? `&resolveLink=${n.resolveLink}` : "", d = `${r}/api/v1/spaces/${e.spaceId}/contents/${t}?token=${e.token}${a}${s}${c}${u}`;
103
+ if (e.debug && console.log(l, "getContentById fetch url : ", d), o.has(d)) return e.debug && console.log(l, "getContentById cache hit"), o.get(d);
96
104
  try {
97
105
  let t = await fetch(d, i);
98
- e.debug && console.log(c, "getContentById status : ", t.status);
106
+ e.debug && console.log(l, "getContentById status : ", t.status);
99
107
  let n = await t.json();
100
108
  return o.set(d, n), n;
101
109
  } catch (e) {
102
- return console.error(c, "getContentById error : ", e), {};
110
+ return console.error(l, "getContentById error : ", e), {};
103
111
  }
104
112
  },
105
113
  async getTranslations(t) {
106
- e.debug && console.log(c, "getTranslations() locale : ", t);
114
+ e.debug && console.log(l, "getTranslations() locale : ", t);
107
115
  let n = `${r}/api/v1/spaces/${e.spaceId}/translations/${t}?token=${e.token}`;
108
- if (e.debug && console.log(c, "getTranslations fetch url : ", n), o.has(n)) return e.debug && console.log(c, "getTranslations cache hit"), o.get(n);
116
+ if (e.debug && console.log(l, "getTranslations fetch url : ", n), o.has(n)) return e.debug && console.log(l, "getTranslations cache hit"), o.get(n);
109
117
  try {
110
118
  let t = await fetch(n, i);
111
- e.debug && console.log(c, "getTranslations status : ", t.status);
119
+ e.debug && console.log(l, "getTranslations status : ", t.status);
112
120
  let r = await t.json();
113
121
  return o.set(n, r), r;
114
122
  } catch (e) {
115
- return console.error(c, "getTranslations error : ", e), {};
123
+ return console.error(l, "getTranslations error : ", e), {};
116
124
  }
117
125
  },
118
126
  syncScriptUrl() {
119
127
  return `${r}/scripts/sync-v1.js`;
120
128
  },
121
- assetLink(t) {
122
- return typeof t == "string" ? `${r}/api/v1/spaces/${e.spaceId}/assets/${t}` : `${r}/api/v1/spaces/${e.spaceId}/assets/${t.uri}`;
129
+ assetLink(t, n) {
130
+ let i = typeof t == "string" ? t : t.uri, a = `${r}/api/v1/spaces/${e.spaceId}/assets/${i}`, o = c(n);
131
+ return o ? `${a}?${o}` : a;
123
132
  }
124
133
  };
125
134
  }
126
135
  //#endregion
127
136
  //#region src/editable.ts
128
- function u(e) {
137
+ function d(e) {
129
138
  return {
130
139
  "data-ll-id": e._id,
131
140
  "data-ll-schema": e._schema
132
141
  };
133
142
  }
134
- function d(e) {
143
+ function f(e) {
135
144
  return { "data-ll-field": e };
136
145
  }
137
146
  //#endregion
138
147
  //#region src/sync.ts
139
- var f = "localess-js-sync";
140
- async function p(e, t = !1) {
148
+ var p = "localess-js-sync";
149
+ async function m(e, t = !1) {
141
150
  return new Promise((t, n) => {
142
151
  if (o()) {
143
152
  n(void 0);
@@ -151,15 +160,15 @@ async function p(e, t = !1) {
151
160
  n(void 0);
152
161
  return;
153
162
  }
154
- if (document.getElementById(f)) {
163
+ if (document.getElementById(p)) {
155
164
  n(void 0);
156
165
  return;
157
166
  }
158
167
  let r = document.createElement("script");
159
- r.id = f, r.type = "text/javascript", r.src = `${e}/scripts/sync-v1.js`, r.async = !0, r.onerror = (e) => n(e), r.onload = (e) => {
168
+ r.id = p, r.type = "text/javascript", r.src = `${e}/scripts/sync-v1.js`, r.async = !0, r.onerror = (e) => n(e), r.onload = (e) => {
160
169
  console.info("Localess Sync Script loaded"), t();
161
170
  }, document.head.appendChild(r);
162
171
  });
163
172
  }
164
173
  //#endregion
165
- export { e as Cache, t as NoCache, n as TTLCache, a as isBrowser, s as isIframe, o as isServer, p as loadLocalessSync, l as localessClient, u as localessEditable, d as localessEditableField };
174
+ export { e as Cache, t as NoCache, n as TTLCache, c as buildAssetQueryString, a as isBrowser, s as isIframe, o as isServer, m as loadLocalessSync, u as localessClient, d as localessEditable, f as localessEditableField };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Optional image transform parameters for asset URL generation.
3
+ * Appended as query parameters to the asset URL.
4
+ *
5
+ * @see https://docs.localess.io (Localess API — Asset Query Parameters)
6
+ */
7
+ export type AssetTransformParams = {
8
+ /**
9
+ * Target width in pixels (integer > 0).
10
+ * Scales to width with height auto when `h` is omitted (aspect ratio preserved).
11
+ * Combined with `h`, produces a cover crop to fill the exact box.
12
+ */
13
+ w?: number;
14
+ /**
15
+ * Target height in pixels (integer > 0).
16
+ * Scales to height with width auto when `w` is omitted (aspect ratio preserved).
17
+ * Combined with `w`, produces a cover crop to fill the exact box.
18
+ */
19
+ h?: number;
20
+ /**
21
+ * Output quality, 1–100. Default: 85.
22
+ * Applies to JPEG, WebP, AVIF. Ignored for PNG.
23
+ */
24
+ q?: number;
25
+ /**
26
+ * Output format. Converts the image to the specified format.
27
+ */
28
+ f?: 'webp' | 'jpeg' | 'png' | 'avif';
29
+ /**
30
+ * When true, sets Content-Disposition to `form-data`, forcing a browser download.
31
+ */
32
+ download?: boolean;
33
+ /**
34
+ * When true, extracts the first frame of animated WebP/GIF before resizing.
35
+ * For video with `w`, extracts a frame via FFmpeg then resizes with Sharp (output defaults to webp).
36
+ */
37
+ thumbnail?: boolean;
38
+ };
@@ -1,3 +1,4 @@
1
+ export * from './asset-transform-params';
1
2
  export * from './content';
2
3
  export * from './content-asset';
3
4
  export * from './content-data';
package/dist/utils.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { AssetTransformParams } from './models';
1
2
  export declare function proxyURIFromEnv(): string | undefined;
2
3
  export declare const RESET = "\u001B[0m";
3
4
  export declare const BRIGHT = "\u001B[1m";
@@ -41,3 +42,4 @@ export declare const BG_BRIGHT_WHITE = "\u001B[107m";
41
42
  export declare const isBrowser: () => boolean;
42
43
  export declare const isServer: () => boolean;
43
44
  export declare const isIframe: () => boolean;
45
+ export declare function buildAssetQueryString(params?: AssetTransformParams): string;
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@localess/client",
3
- "version": "3.0.8-dev.20260514092749",
3
+ "version": "3.0.9-dev.20260520210048",
4
4
  "description": "Universal JavaScript/TypeScript SDK for Localess's API.",
5
5
  "keywords": [
6
6
  "localess",
@@ -36,7 +36,8 @@
36
36
  "url": "https://github.com/Lessify/localess-js/issues"
37
37
  },
38
38
  "scripts": {
39
- "build": "vite build"
39
+ "build": "vite build",
40
+ "test": "vitest"
40
41
  },
41
42
  "license": "MIT",
42
43
  "devDependencies": {