@scaleflex/dam-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +34 -0
  2. package/dist/api/archive.service.d.ts +44 -0
  3. package/dist/api/archive.service.d.ts.map +1 -0
  4. package/dist/api/archive.test.d.ts +2 -0
  5. package/dist/api/archive.test.d.ts.map +1 -0
  6. package/dist/api/dam-client.d.ts +27 -0
  7. package/dist/api/dam-client.d.ts.map +1 -0
  8. package/dist/api/filerobot-browse.service.d.ts +84 -0
  9. package/dist/api/filerobot-browse.service.d.ts.map +1 -0
  10. package/dist/api/files.service.d.ts +63 -0
  11. package/dist/api/files.service.d.ts.map +1 -0
  12. package/dist/api/files.service.test.d.ts +2 -0
  13. package/dist/api/files.service.test.d.ts.map +1 -0
  14. package/dist/api/folders.service.d.ts +21 -0
  15. package/dist/api/folders.service.d.ts.map +1 -0
  16. package/dist/api/index.d.ts +8 -0
  17. package/dist/api/index.d.ts.map +1 -0
  18. package/dist/api/labels.service.d.ts +10 -0
  19. package/dist/api/labels.service.d.ts.map +1 -0
  20. package/dist/api/variations.service.d.ts +23 -0
  21. package/dist/api/variations.service.d.ts.map +1 -0
  22. package/dist/api/variations.service.test.d.ts +2 -0
  23. package/dist/api/variations.service.test.d.ts.map +1 -0
  24. package/dist/auth/auth.service.d.ts +34 -0
  25. package/dist/auth/auth.service.d.ts.map +1 -0
  26. package/dist/auth/auth.service.test.d.ts +2 -0
  27. package/dist/auth/auth.service.test.d.ts.map +1 -0
  28. package/dist/auth/auth.types.d.ts +44 -0
  29. package/dist/auth/auth.types.d.ts.map +1 -0
  30. package/dist/auth/index.d.ts +3 -0
  31. package/dist/auth/index.d.ts.map +1 -0
  32. package/dist/helpers/cdn.d.ts +50 -0
  33. package/dist/helpers/cdn.d.ts.map +1 -0
  34. package/dist/helpers/cdn.test.d.ts +2 -0
  35. package/dist/helpers/cdn.test.d.ts.map +1 -0
  36. package/dist/helpers/debounce.d.ts +4 -0
  37. package/dist/helpers/debounce.d.ts.map +1 -0
  38. package/dist/helpers/format.d.ts +7 -0
  39. package/dist/helpers/format.d.ts.map +1 -0
  40. package/dist/helpers/format.test.d.ts +2 -0
  41. package/dist/helpers/format.test.d.ts.map +1 -0
  42. package/dist/helpers/index.d.ts +6 -0
  43. package/dist/helpers/index.d.ts.map +1 -0
  44. package/dist/helpers/thumbnail.d.ts +19 -0
  45. package/dist/helpers/thumbnail.d.ts.map +1 -0
  46. package/dist/helpers/thumbnail.test.d.ts +2 -0
  47. package/dist/helpers/thumbnail.test.d.ts.map +1 -0
  48. package/dist/helpers/variations.d.ts +24 -0
  49. package/dist/helpers/variations.d.ts.map +1 -0
  50. package/dist/helpers/variations.test.d.ts +2 -0
  51. package/dist/helpers/variations.test.d.ts.map +1 -0
  52. package/dist/index.cjs +2 -0
  53. package/dist/index.cjs.map +1 -0
  54. package/dist/index.d.ts +6 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +1189 -0
  57. package/dist/index.js.map +1 -0
  58. package/dist/store/browse-store.d.ts +199 -0
  59. package/dist/store/browse-store.d.ts.map +1 -0
  60. package/dist/store/browse-store.test.d.ts +2 -0
  61. package/dist/store/browse-store.test.d.ts.map +1 -0
  62. package/dist/store/index.d.ts +4 -0
  63. package/dist/store/index.d.ts.map +1 -0
  64. package/dist/store/local-favourites.d.ts +12 -0
  65. package/dist/store/local-favourites.d.ts.map +1 -0
  66. package/dist/types/api.types.d.ts +99 -0
  67. package/dist/types/api.types.d.ts.map +1 -0
  68. package/dist/types/asset.types.d.ts +20 -0
  69. package/dist/types/asset.types.d.ts.map +1 -0
  70. package/dist/types/filerobot.types.d.ts +133 -0
  71. package/dist/types/filerobot.types.d.ts.map +1 -0
  72. package/dist/types/folder.types.d.ts +10 -0
  73. package/dist/types/folder.types.d.ts.map +1 -0
  74. package/dist/types/index.d.ts +7 -0
  75. package/dist/types/index.d.ts.map +1 -0
  76. package/dist/types/label.types.d.ts +13 -0
  77. package/dist/types/label.types.d.ts.map +1 -0
  78. package/dist/types/variation.types.d.ts +28 -0
  79. package/dist/types/variation.types.d.ts.map +1 -0
  80. package/package.json +31 -0
package/dist/index.js ADDED
@@ -0,0 +1,1189 @@
1
+ const N = "https://api.filerobot.com";
2
+ function B(s) {
3
+ return s === 404 || s === 408 || s === 429 || s >= 500;
4
+ }
5
+ const G = (s) => new Promise((e) => setTimeout(e, s));
6
+ function M(s, e) {
7
+ return `${(e || N).replace(/\/+$/, "")}/${s}`;
8
+ }
9
+ async function W(s, e, t, i = {}) {
10
+ const r = `${M(s, t)}/key/${encodeURIComponent(e)}`, o = i.retries ?? 2, l = i.retryDelayMs ?? 400;
11
+ let a = new Error("SASS key exchange failed");
12
+ for (let c = 0; c <= o; c++) {
13
+ c > 0 && await G(l * c);
14
+ const h = new AbortController(), f = setTimeout(() => h.abort(), 3e4);
15
+ try {
16
+ const d = await fetch(r, { signal: h.signal, cache: "no-store" });
17
+ if (clearTimeout(f), !d.ok) {
18
+ if (a = new Error(`SASS key exchange failed (HTTP ${d.status})`), B(d.status) && c < o) continue;
19
+ throw a;
20
+ }
21
+ const u = await d.json();
22
+ if (u.status === "error")
23
+ throw new Error(`SASS key exchange failed: ${u.msg || "Unknown error"}`);
24
+ return u.key;
25
+ } catch (d) {
26
+ if (clearTimeout(f), d instanceof DOMException && d.name === "AbortError")
27
+ throw new Error("SASS key exchange timed out");
28
+ if (d instanceof TypeError && c < o) {
29
+ a = d;
30
+ continue;
31
+ }
32
+ throw d;
33
+ }
34
+ }
35
+ throw a;
36
+ }
37
+ function T(s, e) {
38
+ const t = {};
39
+ switch (s.mode) {
40
+ case "security-template":
41
+ if (!e)
42
+ throw new Error(
43
+ "[dam-core] Cannot build auth headers for security-template mode: SASS key exchange has not been performed. Call resolveAuth() first, or use sass-key mode."
44
+ );
45
+ t["X-Filerobot-Key"] = e;
46
+ break;
47
+ case "sass-key":
48
+ t["X-Filerobot-Key"] = s.sassKey;
49
+ break;
50
+ }
51
+ return s.airboxPuid && (t["X-Filerobot-Airbox-Puid"] = s.airboxPuid), t;
52
+ }
53
+ function X(s) {
54
+ return s.mode === "securityTemplate" || s.mode === "sassKey";
55
+ }
56
+ function V(s) {
57
+ return X(s) ? s.mode === "securityTemplate" ? {
58
+ mode: "security-template",
59
+ container: s.projectToken,
60
+ securityTemplateId: s.securityTemplateKey,
61
+ airboxPuid: s.airboxPuid
62
+ } : {
63
+ mode: "sass-key",
64
+ container: s.projectToken,
65
+ sassKey: s.sassKey,
66
+ airboxPuid: s.airboxPuid
67
+ } : s;
68
+ }
69
+ async function I(s, e) {
70
+ const t = V(s), i = M(t.container, e);
71
+ if (t.mode === "security-template") {
72
+ const r = await W(t.container, t.securityTemplateId, e);
73
+ return { apiBase: i, headers: T(t, r), sassKey: r };
74
+ }
75
+ return { apiBase: i, headers: T(t) };
76
+ }
77
+ const H = 3e4;
78
+ class O {
79
+ constructor(e, t, i) {
80
+ this.baseUrl = `${e.apiBase}/v5`, this.headers = e.headers, this.auth = t, this.apiDomain = i;
81
+ }
82
+ /** Resolve an AuthConfig (performing key exchange if needed) and build a client. */
83
+ static async create(e, t) {
84
+ const i = await I(e, t);
85
+ return new O(i, e, t);
86
+ }
87
+ get(e, t) {
88
+ const i = new URL(`${this.baseUrl}${e}`);
89
+ if (t)
90
+ for (const [r, o] of Object.entries(t))
91
+ o != null && i.searchParams.set(r, Array.isArray(o) ? o.join(",") : String(o));
92
+ return this.send(i, { method: "GET" });
93
+ }
94
+ post(e, t) {
95
+ return this.sendJson("POST", e, t);
96
+ }
97
+ put(e, t) {
98
+ return this.sendJson("PUT", e, t);
99
+ }
100
+ delete(e, t) {
101
+ return this.sendJson("DELETE", e, t);
102
+ }
103
+ /**
104
+ * Absolute REST URL (incl. the `/v5` base) for a path — for building direct
105
+ * browser-download links (e.g. the archive ZIP) that bypass `fetch`.
106
+ */
107
+ absoluteUrl(e) {
108
+ return `${this.baseUrl}${e}`;
109
+ }
110
+ /** The Filerobot key (`X-Filerobot-Key`), for query-param auth on direct downloads. */
111
+ get authKey() {
112
+ return this.headers["X-Filerobot-Key"];
113
+ }
114
+ sendJson(e, t, i) {
115
+ return this.send(new URL(`${this.baseUrl}${t}`), {
116
+ method: e,
117
+ headers: { "Content-Type": "application/json" },
118
+ body: i === void 0 ? void 0 : JSON.stringify(i)
119
+ });
120
+ }
121
+ async send(e, t, i = !1) {
122
+ var l;
123
+ const r = new AbortController(), o = setTimeout(() => r.abort(), H);
124
+ try {
125
+ const a = await fetch(e.toString(), {
126
+ ...t,
127
+ headers: { ...this.headers, ...t.headers },
128
+ signal: r.signal
129
+ });
130
+ if (clearTimeout(o), a.status === 401 && !i && ((l = this.auth) == null ? void 0 : l.mode) === "security-template") {
131
+ const f = await I(this.auth, this.apiDomain);
132
+ return this.headers = f.headers, this.send(e, t, !0);
133
+ }
134
+ if (!a.ok) {
135
+ let f = `API error: ${a.status} ${a.statusText}`;
136
+ try {
137
+ const d = await a.json();
138
+ d != null && d.msg && (f = `API error: ${a.status} - ${d.msg}`);
139
+ } catch {
140
+ }
141
+ throw new Error(f);
142
+ }
143
+ if (a.status === 204) return;
144
+ const c = await a.text();
145
+ if (!c) return;
146
+ const h = JSON.parse(c);
147
+ if ((h == null ? void 0 : h.status) === "error")
148
+ throw new Error(`API error: ${h.msg || "Unknown error"}`);
149
+ return h;
150
+ } catch (a) {
151
+ throw clearTimeout(o), a instanceof DOMException && a.name === "AbortError" ? new Error("API request timed out") : a;
152
+ }
153
+ }
154
+ }
155
+ function J(s) {
156
+ const e = s.path ?? s.name, t = e.replace(/\/[^/]*$/, "") || "/";
157
+ return {
158
+ uuid: s.uuid,
159
+ name: s.name.split("/").pop() || s.name,
160
+ path: e,
161
+ parentPath: t,
162
+ createdAt: s.created_at,
163
+ modifiedAt: s.modified_at
164
+ };
165
+ }
166
+ async function b(s, e = {}) {
167
+ const t = e.sortBy ?? "name", i = e.sortDirection ?? "asc";
168
+ return ((await s.get("/folders", {
169
+ folder: e.folderPath ?? "/",
170
+ recursive: e.recursive ?? 0,
171
+ limit: e.limit ?? 1e3,
172
+ offset: e.offset ?? 0,
173
+ q: e.q,
174
+ sort: `${t}:${i}`
175
+ })).folders ?? []).map(J);
176
+ }
177
+ async function K(s, e, t) {
178
+ const i = t.replace(/\/+$/, ""), r = i ? `${i}/${e}` : `/${e}`, o = await s.post("/folders", { name: r });
179
+ if (o.status !== "success") throw new Error(o.msg || "Failed to create folder");
180
+ }
181
+ async function Y(s, e, t) {
182
+ const i = await s.put(`/folder/${encodeURIComponent(e)}/name`, {
183
+ name: t
184
+ });
185
+ if ((i == null ? void 0 : i.status) === "error") throw new Error(i.msg || "Failed to rename folder");
186
+ }
187
+ async function Z(s, e) {
188
+ const t = await s.delete("/folders", { folders_uuids: e });
189
+ if ((t == null ? void 0 : t.status) === "error") throw new Error(t.msg || "Failed to delete folders");
190
+ }
191
+ async function Q(s, e, t) {
192
+ const i = await s.post("/folders", {
193
+ folders_uuids: e,
194
+ new_folder_name: t
195
+ });
196
+ if ((i == null ? void 0 : i.status) === "error") throw new Error(i.msg || "Failed to move folders");
197
+ }
198
+ const R = {
199
+ small: [null, 1048576],
200
+ // < 1 MB
201
+ medium: [1048576, 10485760],
202
+ // 1–10 MB
203
+ large: [10485760, 104857600],
204
+ // 10–100 MB
205
+ huge: [104857600, null]
206
+ // > 100 MB
207
+ }, ee = {
208
+ today: 0,
209
+ week: 7,
210
+ month: 30,
211
+ year: 365
212
+ };
213
+ function y(s, e) {
214
+ const t = new Date(e);
215
+ return t.setUTCHours(0, 0, 0, 0), t.setUTCDate(t.getUTCDate() - ee[s]), t;
216
+ }
217
+ const L = ["cdn_permalink"], F = {}, m = (s, e) => e.split(" ").forEach((t) => F[t] = s);
218
+ m("image", "jpg jpeg png gif webp svg avif bmp tif tiff heic ico");
219
+ m("video", "mp4 webm mov m4v avi mkv ogv");
220
+ m("audio", "mp3 wav ogg oga m4a aac flac");
221
+ m("document", "pdf doc docx xls xlsx ppt pptx txt csv rtf md");
222
+ m("model", "glb gltf obj fbx stl usdz ply 3ds dae");
223
+ function te(s) {
224
+ const e = (s.name.split(".").pop() || "").toLowerCase();
225
+ if (F[e] === "model") return "model";
226
+ const t = (s.file_type || s.type || "").toLowerCase();
227
+ return t.startsWith("image") ? "image" : t.startsWith("video") ? "video" : t.startsWith("audio") ? "audio" : t.includes("pdf") || t.includes("document") || t.includes("text") ? "document" : F[e] ?? "other";
228
+ }
229
+ function z(s) {
230
+ var e, t, i, r, o;
231
+ return {
232
+ uuid: s.uuid,
233
+ name: s.name,
234
+ folder: s.folder ?? "/",
235
+ type: te(s),
236
+ fileType: s.file_type ?? s.type,
237
+ cdnUrl: s.cdn_permalink ?? s.cdn_url,
238
+ thumbnailUrl: ((e = s.info) == null ? void 0 : e.video_thumbnail) ?? ((t = s.info) == null ? void 0 : t.image_thumbnail) ?? ((i = s.info) == null ? void 0 : i.thumbnail) ?? ((r = s.info) == null ? void 0 : r.preview),
239
+ // Live API returns `size: { bytes, pretty }`; tolerate a plain number too.
240
+ size: typeof s.size == "object" ? (o = s.size) == null ? void 0 : o.bytes : s.size,
241
+ width: s.width,
242
+ height: s.height,
243
+ createdAt: s.created_at,
244
+ modifiedAt: s.modified_at
245
+ };
246
+ }
247
+ function se(s) {
248
+ var l;
249
+ const e = s.fields ?? L, t = s.sortBy ?? "created_at", i = s.sortDirection ?? "desc", r = [];
250
+ if (s.search && r.push(s.search), s.q && r.push(s.q), (l = s.types) != null && l.length && r.push(`type:${s.types.map((a) => `"${a}"`).join(",")}`), s.sizeBucket) {
251
+ const [a, c] = R[s.sizeBucket];
252
+ r.push(`size:"${a ?? ""}..${c ?? ""}"`);
253
+ }
254
+ const o = Date.now();
255
+ return s.createdWithin && r.push(`created>"${y(s.createdWithin, o).toISOString()}"`), s.updatedWithin && r.push(`updated>"${y(s.updatedWithin, o).toISOString()}"`), {
256
+ offset: s.offset ?? 0,
257
+ limit: s.limit ?? 100,
258
+ format: "json,regvar:api,select:internal",
259
+ preview: 2301,
260
+ // Filerobot preview-size preset for thumbnails
261
+ recursive: s.recursive ?? 1,
262
+ fields: e.length ? e : void 0,
263
+ sort: `${t}:${i}`,
264
+ folder: s.folder,
265
+ q: r.length ? r.join(" ") : void 0
266
+ };
267
+ }
268
+ async function w(s, e = {}) {
269
+ const t = se(e), i = await s.get("/files", t), r = (i.files ?? []).map(z), o = typeof i.total == "number" ? i.total : i.count ?? r.length;
270
+ return { assets: r, total: o };
271
+ }
272
+ async function $e(s, e = {}) {
273
+ return (await w(s, e)).assets;
274
+ }
275
+ const ie = {
276
+ image: "image",
277
+ video: "video",
278
+ audio: "audio",
279
+ document: "document",
280
+ model: "other",
281
+ // no dedicated 'model' facet — folds into "Other"
282
+ archive: "other",
283
+ font: "other",
284
+ other: "other"
285
+ };
286
+ function re(s, e, t) {
287
+ var i;
288
+ if ((i = e.types) != null && i.length && !e.types.includes(ie[s.type])) return !1;
289
+ if (e.sizeBucket) {
290
+ const [r, o] = R[e.sizeBucket];
291
+ if (s.size == null || r != null && s.size < r || o != null && s.size >= o) return !1;
292
+ }
293
+ return !(e.createdWithin && !((s.createdAt ? Date.parse(s.createdAt) : NaN) >= y(e.createdWithin, t).getTime()) || e.updatedWithin && !((s.modifiedAt ? Date.parse(s.modifiedAt) : NaN) >= y(e.updatedWithin, t).getTime()));
294
+ }
295
+ function ne(s, e, t) {
296
+ const i = t === "asc" ? 1 : -1, r = (o) => {
297
+ var l;
298
+ switch (e) {
299
+ case "name":
300
+ return ((l = o.name) == null ? void 0 : l.toLowerCase()) ?? "";
301
+ case "size":
302
+ return o.size ?? 0;
303
+ case "type":
304
+ return o.type;
305
+ case "modified_at":
306
+ return o.modifiedAt ? Date.parse(o.modifiedAt) : 0;
307
+ default:
308
+ return o.createdAt ? Date.parse(o.createdAt) : 0;
309
+ }
310
+ };
311
+ return [...s].sort((o, l) => {
312
+ const a = r(o), c = r(l);
313
+ return a < c ? -i : a > c ? i : 0;
314
+ });
315
+ }
316
+ async function oe(s, e, t = {}) {
317
+ const i = t.fields ?? L, r = new Array(e.length);
318
+ let o = 0;
319
+ const l = async () => {
320
+ for (; o < e.length; ) {
321
+ const c = o++;
322
+ try {
323
+ const h = await s.get(`/file/${encodeURIComponent(e[c])}`, {
324
+ format: "json,regvar:api,select:internal",
325
+ preview: 2301,
326
+ fields: i.length ? i : void 0
327
+ });
328
+ h != null && h.file && (r[c] = z(h.file));
329
+ } catch {
330
+ }
331
+ }
332
+ }, a = Math.min(t.concurrency ?? 8, e.length);
333
+ return await Promise.all(Array.from({ length: a }, l)), r.filter((c) => c !== void 0);
334
+ }
335
+ async function ae(s, e, t) {
336
+ const i = await s.put(`/file/${encodeURIComponent(e)}/name`, {
337
+ name: t
338
+ });
339
+ if ((i == null ? void 0 : i.status) === "error") throw new Error(i.msg || "Failed to rename file");
340
+ }
341
+ async function ce(s, e) {
342
+ const t = await s.delete("/files", { files_uuids: e });
343
+ if ((t == null ? void 0 : t.status) === "error") throw new Error(t.msg || "Failed to delete files");
344
+ }
345
+ async function le(s, e, t) {
346
+ const i = await s.post("/files", {
347
+ files_uuids: e,
348
+ new_folder_name: t
349
+ });
350
+ if ((i == null ? void 0 : i.status) === "error") throw new Error(i.msg || "Failed to move files");
351
+ }
352
+ async function de(s) {
353
+ return (await s.get("/labels")).labels ?? [];
354
+ }
355
+ function he(s) {
356
+ if (s.sid)
357
+ return `labels:${s.sid.replace(/^#/, "")}`;
358
+ }
359
+ function $(s, e) {
360
+ try {
361
+ const t = new URL(s);
362
+ return t.searchParams.set("p", e), t.toString();
363
+ } catch {
364
+ return s;
365
+ }
366
+ }
367
+ function x(s) {
368
+ var e, t, i, r, o;
369
+ return {
370
+ uuid: s.uuid,
371
+ name: s.name,
372
+ url: s.url,
373
+ previewUrl: s.preview ?? s.url,
374
+ width: (e = s.info) == null ? void 0 : e.img_w,
375
+ height: (t = s.info) == null ? void 0 : t.img_h,
376
+ size: (i = s.info) == null ? void 0 : i.size,
377
+ format: (r = s.info) == null ? void 0 : r.img_type,
378
+ isOriginal: !1,
379
+ isPreset: !1,
380
+ bgRemoved: ((o = s.info) == null ? void 0 : o.remove_background) === !0
381
+ };
382
+ }
383
+ function fe(s) {
384
+ return {
385
+ uuid: s.uuid,
386
+ name: s.name,
387
+ url: s.cdnUrl ?? "",
388
+ previewUrl: s.thumbnailUrl ?? s.cdnUrl,
389
+ width: s.width,
390
+ height: s.height,
391
+ size: s.size,
392
+ format: s.fileType,
393
+ isOriginal: !0,
394
+ isPreset: !1,
395
+ bgRemoved: !1
396
+ };
397
+ }
398
+ function ue(s, e) {
399
+ const t = s.cdnUrl ?? "";
400
+ return {
401
+ uuid: `preset-${e.name}`,
402
+ name: e.name,
403
+ url: $(t, e.name),
404
+ previewUrl: $(s.thumbnailUrl ?? t, e.name),
405
+ isOriginal: !1,
406
+ isPreset: !0,
407
+ bgRemoved: !1
408
+ };
409
+ }
410
+ function ve({
411
+ asset: s,
412
+ variants: e = [],
413
+ presets: t = []
414
+ }) {
415
+ const i = new Set(t.map((a) => a.name)), r = e.filter((a) => {
416
+ var c;
417
+ return !i.has(a.name) && ((c = a.info) == null ? void 0 : c.remove_background) !== !0;
418
+ }).map(x), o = e.filter((a) => {
419
+ var c;
420
+ return ((c = a.info) == null ? void 0 : c.remove_background) === !0 && !i.has(a.name);
421
+ }).map(x), l = t.map((a) => ue(s, a));
422
+ return [fe(s), ...r, ...o, ...l];
423
+ }
424
+ async function ge(s, e) {
425
+ const t = await s.get(
426
+ `/file/${encodeURIComponent(e)}/variants`
427
+ );
428
+ return (t == null ? void 0 : t.variants) ?? [];
429
+ }
430
+ function me(s) {
431
+ return Array.isArray(s) ? s.map(
432
+ (e) => typeof e == "string" ? { name: e } : e && typeof e.name == "string" ? { name: e.name, desc: e.desc } : null
433
+ ).filter((e) => e !== null) : [];
434
+ }
435
+ async function pe(s) {
436
+ var i, r, o;
437
+ const e = await s.get("/settings"), t = (e == null ? void 0 : e.presets) ?? ((i = e == null ? void 0 : e.cloudimg) == null ? void 0 : i.presets) ?? ((o = (r = e == null ? void 0 : e.settings) == null ? void 0 : r.cloudimg) == null ? void 0 : o.presets) ?? void 0;
438
+ return me(t);
439
+ }
440
+ async function xe(s, e) {
441
+ const [t, i] = await Promise.all([
442
+ ge(s, e.uuid),
443
+ pe(s)
444
+ ]);
445
+ return ve({ asset: e, variants: t, presets: i });
446
+ }
447
+ async function we(s, e) {
448
+ const t = await s.post("/file-archive", {
449
+ files_uuids: e.filesUuids ?? [],
450
+ folders_uuids: e.foldersUuids ?? [],
451
+ urls: e.urls ?? []
452
+ });
453
+ if (!(t != null && t.task_id)) throw new Error("Archive task was not created");
454
+ return t.task_id;
455
+ }
456
+ function ye(s, e) {
457
+ return s.get(`/file-archive/${encodeURIComponent(e)}`, {
458
+ status_only: 1
459
+ });
460
+ }
461
+ const Se = /* @__PURE__ */ new Set(["PENDING", "RUNNING", "PROCESSING", ""]);
462
+ function be(s) {
463
+ const e = ((s == null ? void 0 : s.task_status) ?? "").toUpperCase(), t = typeof (s == null ? void 0 : s.task_percent) == "number" ? s.task_percent : 0;
464
+ if (e === "DONE") return { done: !0, progress: 100 };
465
+ if (Se.has(e)) return { done: !1, progress: t };
466
+ throw new Error(`Archive job failed: ${(s == null ? void 0 : s.task_status) ?? "unknown status"}`);
467
+ }
468
+ async function _e(s, e, t = {}) {
469
+ var f, d;
470
+ const i = t.intervalMs ?? 1500, r = t.timeoutMs ?? 12e4, o = t.maxRetries ?? 5, l = t.sleep ?? ((u) => new Promise((g) => setTimeout(g, u))), a = t.now ?? Date.now, c = a() + r;
471
+ let h = 0;
472
+ for (; ; ) {
473
+ if ((f = t.signal) != null && f.aborted) throw new Error("Archive polling aborted");
474
+ if (a() > c) throw new Error("Archive polling timed out");
475
+ let u;
476
+ try {
477
+ u = await ye(s, e);
478
+ } catch (S) {
479
+ if (h++ < o) {
480
+ await l(i);
481
+ continue;
482
+ }
483
+ throw S;
484
+ }
485
+ const { done: g, progress: p } = be(u);
486
+ if ((d = t.onProgress) == null || d.call(t, p), g) return;
487
+ await l(i);
488
+ }
489
+ }
490
+ function Ae(s, e) {
491
+ const t = s.absoluteUrl(`/file-archive/${encodeURIComponent(e)}`), i = s.authKey;
492
+ if (!i) return t;
493
+ const r = t.includes("?") ? "&" : "?";
494
+ return `${t}${r}secret_key=${encodeURIComponent(i)}`;
495
+ }
496
+ async function Ce(s, e, t = {}) {
497
+ const i = await we(s, e);
498
+ return await _e(s, i, t), Ae(s, i);
499
+ }
500
+ const Fe = ["cdn_permalink"], q = {
501
+ created_at: "created_at",
502
+ modified_at: "modified_at",
503
+ name: "name",
504
+ size: "size",
505
+ type: "type"
506
+ };
507
+ function Pe(s) {
508
+ const e = s.fields ?? Fe, t = {
509
+ offset: s.offset ?? 0,
510
+ limit: s.limit ?? 100,
511
+ format: "json,regvar:api,select:internal",
512
+ preview: 2301,
513
+ recursive: s.recursive ?? 1
514
+ };
515
+ e.length > 0 && (t.fields = e);
516
+ const i = s.sort_by ?? "created_at", r = s.sort_direction ?? "desc";
517
+ t.sort = `${q[i] || i}:${r}`, s.folder && (t.folder = s.folder);
518
+ const o = [];
519
+ return s.search && !s.with_ai && o.push(s.search), s.q && o.push(s.q), o.length > 0 && (t.q = o.join(" ")), s.with_ai && (t.with_ai = !0, s.ai_query && (t.ai_query = s.ai_query), s.ai_lang && (t.ai_lang = s.ai_lang)), s.collection_uuid && (t.collection_uuid = s.collection_uuid), s.f64 && (t.f64 = s.f64), t;
520
+ }
521
+ function Ue(s, e) {
522
+ return s.get("/files", Pe(e));
523
+ }
524
+ function De(s, e) {
525
+ const t = { recursive: e.recursive ?? 1 };
526
+ e.folder && (t.folder = e.folder);
527
+ const i = [];
528
+ return e.search && !e.with_ai && i.push(e.search), e.q && i.push(e.q), i.length > 0 && (t.q = i.join(" ")), e.with_ai && (t.with_ai = !0, e.ai_query && (t.ai_query = e.ai_query), e.ai_lang && (t.ai_lang = e.ai_lang)), e.collection_uuid && (t.collection_uuid = e.collection_uuid), e.f64 && (t.f64 = e.f64), s.get("/files/stats", t);
529
+ }
530
+ function ke(s, e = {}) {
531
+ const t = {
532
+ recursive: e.recursive ?? 0,
533
+ folder: e.folderPath ?? "/",
534
+ limit: e.limit ?? 1e3,
535
+ offset: e.offset ?? 0
536
+ };
537
+ e.q && (t.q = e.q);
538
+ const i = e.sort_by ?? "created_at", r = e.sort_direction ?? "asc";
539
+ return t.sort = `${q[i] || i}:${r}`, s.get("/folders", t);
540
+ }
541
+ async function Me(s, e) {
542
+ return e.length === 0 ? {} : (await s.post("/folders/previews", {
543
+ folders: e
544
+ })).folders || {};
545
+ }
546
+ const C = 100, U = 1e3, D = { types: [], size: null, created: null, updated: null };
547
+ class P {
548
+ constructor(e, t = {}) {
549
+ this.client = e, this.listeners = /* @__PURE__ */ new Set(), this.loadSeq = 0, this.treeSeq = 0, this.fetchedCount = 0, this.selectionAnchor = null, this.favAdapter = t.favourites, this.onScopeChange = t.onScopeChange, this.state = {
550
+ scope: { type: "folder", value: t.rootFolder ?? "/" },
551
+ viewMode: t.viewMode ?? "grid",
552
+ gridSize: t.gridSize ?? "m",
553
+ sortBy: t.sortBy ?? "created_at",
554
+ sortDirection: t.sortDirection ?? "desc",
555
+ searchQuery: "",
556
+ filters: { ...D },
557
+ folders: [],
558
+ labels: [],
559
+ assets: [],
560
+ total: 0,
561
+ truncated: !1,
562
+ hasMore: !1,
563
+ loadingMore: !1,
564
+ treeChildren: {},
565
+ expandedFolders: /* @__PURE__ */ new Set(),
566
+ selection: /* @__PURE__ */ new Set(),
567
+ favourites: /* @__PURE__ */ new Set(),
568
+ loading: !1,
569
+ error: null
570
+ };
571
+ }
572
+ /** Load sidebar metadata (labels, favourites, root folder tree) then the scope. */
573
+ async init() {
574
+ await Promise.all([this.loadLabels(), this.loadFavourites(), this.loadFolderChildren("/")]), await this.load();
575
+ }
576
+ // ── folder tree (lazy) ──────────────────────────────────────────────────────
577
+ /** Fetch and cache a folder's children (no-op if already cached). */
578
+ async loadFolderChildren(e) {
579
+ if (!this.state.treeChildren[e])
580
+ try {
581
+ const t = await b(this.client, { folderPath: e });
582
+ this.set({ treeChildren: { ...this.state.treeChildren, [e]: t } });
583
+ } catch {
584
+ }
585
+ }
586
+ /** Expand/collapse a folder node, lazy-loading its children on first expand. */
587
+ async toggleFolder(e) {
588
+ const t = new Set(this.state.expandedFolders);
589
+ t.has(e) ? (t.delete(e), this.set({ expandedFolders: t })) : (await this.loadFolderChildren(e), t.add(e), this.set({ expandedFolders: t }));
590
+ }
591
+ async loadLabels() {
592
+ try {
593
+ this.set({ labels: await de(this.client) });
594
+ } catch {
595
+ }
596
+ }
597
+ async loadFavourites() {
598
+ if (this.favAdapter)
599
+ try {
600
+ this.set({ favourites: new Set(await this.favAdapter.list()) });
601
+ } catch {
602
+ }
603
+ }
604
+ /** Toggle an asset's favourite status (per-user, via the adapter). */
605
+ async toggleFavourite(e) {
606
+ const t = this.state.favourites.has(e), i = new Set(this.state.favourites);
607
+ t ? i.delete(e) : i.add(e), this.set({ favourites: i });
608
+ try {
609
+ this.favAdapter && (t ? await this.favAdapter.remove(e) : await this.favAdapter.add(e));
610
+ } catch {
611
+ const r = new Set(this.state.favourites);
612
+ t ? r.add(e) : r.delete(e), this.set({ favourites: r });
613
+ return;
614
+ }
615
+ this.state.scope.type === "favourites" && this.load();
616
+ }
617
+ getState() {
618
+ return this.state;
619
+ }
620
+ subscribe(e) {
621
+ return this.listeners.add(e), () => this.listeners.delete(e);
622
+ }
623
+ set(e) {
624
+ this.state = { ...this.state, ...e };
625
+ for (const t of this.listeners) t(this.state);
626
+ }
627
+ // ── navigation / scope ─────────────────────────────────────────────────────
628
+ setScope(e) {
629
+ var t;
630
+ this.selectionAnchor = null, this.set({ scope: e, selection: /* @__PURE__ */ new Set() }), (t = this.onScopeChange) == null || t.call(this, e), this.load();
631
+ }
632
+ openFolder(e) {
633
+ this.setScope({ type: "folder", value: e });
634
+ }
635
+ openLabel(e) {
636
+ this.setScope({ type: "label", value: e });
637
+ }
638
+ openFavourites() {
639
+ this.setScope({ type: "favourites" });
640
+ }
641
+ // ── view controls ──────────────────────────────────────────────────────────
642
+ setViewMode(e) {
643
+ this.set({ viewMode: e });
644
+ }
645
+ setGridSize(e) {
646
+ this.set({ gridSize: e });
647
+ }
648
+ setSort(e, t) {
649
+ this.set({ sortBy: e, sortDirection: t }), this.load();
650
+ }
651
+ setSearch(e) {
652
+ this.set({ searchQuery: e }), this.load();
653
+ }
654
+ /** Merge a partial facet patch into the active filters and reload from page 1. */
655
+ setFilters(e) {
656
+ this.set({ filters: { ...this.state.filters, ...e } }), this.load();
657
+ }
658
+ /** Toggle one file-type in the type facet. Reloads from page 1. */
659
+ toggleType(e) {
660
+ const t = this.state.filters.types;
661
+ this.setFilters({
662
+ types: t.includes(e) ? t.filter((i) => i !== e) : [...t, e]
663
+ });
664
+ }
665
+ /** Number of active facets across all groups (for the toolbar badge). */
666
+ get activeFilterCount() {
667
+ const { types: e, size: t, created: i, updated: r } = this.state.filters;
668
+ return e.length + (t ? 1 : 0) + (i ? 1 : 0) + (r ? 1 : 0);
669
+ }
670
+ /** Clear every facet in one update, then reload. No-op if nothing is active. */
671
+ clearFilters() {
672
+ this.activeFilterCount && (this.set({ filters: { ...D } }), this.load());
673
+ }
674
+ // ── selection ──────────────────────────────────────────────────────────────
675
+ toggleSelect(e, t = !1) {
676
+ const i = new Set(t ? this.state.selection : []), r = !i.has(e);
677
+ r ? i.add(e) : i.delete(e), r && (this.selectionAnchor = e), this.set({ selection: i });
678
+ }
679
+ /**
680
+ * Shift-click range selection: add every asset between the anchor (the last
681
+ * individually-selected item) and `uuid` — in the current display order — to
682
+ * the selection. Additive: existing selections are preserved, and the anchor
683
+ * stays put so the range can be re-adjusted with another shift-click. With no
684
+ * anchor yet, behaves like a plain multi-select toggle.
685
+ */
686
+ selectRange(e) {
687
+ const t = this.state.assets, i = t.findIndex((c) => c.uuid === e);
688
+ if (i < 0) return;
689
+ const r = this.selectionAnchor != null ? t.findIndex((c) => c.uuid === this.selectionAnchor) : -1;
690
+ if (r < 0) {
691
+ this.toggleSelect(e, !0);
692
+ return;
693
+ }
694
+ const [o, l] = r <= i ? [r, i] : [i, r], a = new Set(this.state.selection);
695
+ for (let c = o; c <= l; c++) a.add(t[c].uuid);
696
+ this.set({ selection: a });
697
+ }
698
+ /** Replace the whole selection in one update (e.g. "select all", marquee drag). */
699
+ setSelection(e) {
700
+ const t = new Set(e);
701
+ let i = null;
702
+ for (const r of t) i = r;
703
+ this.selectionAnchor = i, this.set({ selection: t });
704
+ }
705
+ clearSelection() {
706
+ this.selectionAnchor = null, this.set({ selection: /* @__PURE__ */ new Set() });
707
+ }
708
+ // ── mutations (light-dam's management layer) ───────────────────────────────
709
+ // Orchestrated in core so the CRUD lives with dam-core, and every mutation
710
+ // reloads the current scope. Endpoints verified against js-admin-react-filerobot-v5.
711
+ /** Path of the folder currently in view (root when not in folder scope). */
712
+ get currentFolderPath() {
713
+ return this.state.scope.type === "folder" ? this.state.scope.value ?? "/" : "/";
714
+ }
715
+ /**
716
+ * Folder mutations change the hierarchy — re-fetch the relevant tree nodes
717
+ * (root, current, expanded) and swap them in atomically. Unlike a blank-then-
718
+ * refill, this never shows an empty tree, keeps unrelated cached nodes, and a
719
+ * `treeSeq` guard discards a superseded refresh.
720
+ */
721
+ async refreshTree() {
722
+ const e = ++this.treeSeq, t = /* @__PURE__ */ new Set(["/", this.currentFolderPath, ...this.state.expandedFolders]), i = {};
723
+ await Promise.all(
724
+ [...t].map(async (r) => {
725
+ try {
726
+ i[r] = await b(this.client, { folderPath: r });
727
+ } catch {
728
+ }
729
+ })
730
+ ), e === this.treeSeq && this.set({ treeChildren: { ...this.state.treeChildren, ...i } });
731
+ }
732
+ static parentOf(e) {
733
+ return e.replace(/\/[^/]*$/, "") || "/";
734
+ }
735
+ /** Public: resolve a cached folder's path by uuid (e.g. for the move picker). */
736
+ findFolderPath(e) {
737
+ return this.folderPath(e);
738
+ }
739
+ /** Find a cached folder's path by uuid (across the tree cache + current list). */
740
+ folderPath(e) {
741
+ for (const t of [this.state.folders, ...Object.values(this.state.treeChildren)]) {
742
+ const i = t.find((r) => r.uuid === e);
743
+ if (i) return i.path;
744
+ }
745
+ }
746
+ /**
747
+ * After a folder is renamed/moved/deleted, keep the user out of a "ghost"
748
+ * scope: if they're viewing the affected folder (or a descendant), remap the
749
+ * scope to its new path (or the parent on delete). Returns true if it redirected
750
+ * (which itself triggers a reload), so the caller can skip its own load().
751
+ */
752
+ redirectScope(e, t) {
753
+ const { scope: i } = this.state;
754
+ if (i.type !== "folder" || !i.value) return !1;
755
+ const r = i.value;
756
+ return r !== e && !r.startsWith(e + "/") ? !1 : (t === null ? this.openFolder(P.parentOf(e)) : this.openFolder(r === e ? t : t + r.slice(e.length)), !0);
757
+ }
758
+ async createFolder(e) {
759
+ await K(this.client, e, this.currentFolderPath), await this.refreshTree(), await this.load();
760
+ }
761
+ async renameFolderById(e, t) {
762
+ const i = this.folderPath(e);
763
+ await Y(this.client, e, t), await this.refreshTree();
764
+ const r = i ? `${P.parentOf(i).replace(/\/$/, "")}/${t}` : null;
765
+ i && r && this.redirectScope(i, r) || await this.load();
766
+ }
767
+ async deleteFolderById(e) {
768
+ const t = this.folderPath(e);
769
+ await Z(this.client, [e]), await this.refreshTree(), t && this.redirectScope(t, null) || await this.load();
770
+ }
771
+ async moveFolderById(e, t) {
772
+ const i = this.folderPath(e);
773
+ await Q(this.client, [e], t), await this.refreshTree();
774
+ const r = (i == null ? void 0 : i.split("/").pop()) ?? "", o = i ? `${t.replace(/\/$/, "")}/${r}` : null;
775
+ i && o && this.redirectScope(i, o) || await this.load();
776
+ }
777
+ async renameAsset(e, t) {
778
+ await ae(this.client, e, t), await this.load();
779
+ }
780
+ async deleteAssets(e) {
781
+ await ce(this.client, e), this.clearSelection(), await this.load();
782
+ }
783
+ async moveAssets(e, t) {
784
+ await le(this.client, e, t), this.clearSelection(), await this.load();
785
+ }
786
+ // ── data loading ───────────────────────────────────────────────────────────
787
+ /** Translate the active filter facets into the api query shape (undefined = off). */
788
+ facetParams() {
789
+ const { types: e, size: t, created: i, updated: r } = this.state.filters;
790
+ return {
791
+ types: e.length ? e : void 0,
792
+ sizeBucket: t ?? void 0,
793
+ createdWithin: i ?? void 0,
794
+ updatedWithin: r ?? void 0
795
+ };
796
+ }
797
+ /**
798
+ * Fetch one page of the current scope's assets starting at server `offset`.
799
+ *
800
+ * Folder/label/all are server-paged (offset + PAGE_SIZE) so infinite scroll
801
+ * appends page by page. Favourites is a known uuid set, so it's fetched
802
+ * directly by uuid (cheap, bounded by MAX_FAVOURITES) and filtered/sorted in
803
+ * memory — no whole-library scan — and reports no further pages.
804
+ *
805
+ * `fetched` is the raw count returned by the server (before client dedupe), so
806
+ * the caller advances its offset cursor correctly even when dedupe drops items.
807
+ */
808
+ async fetchAssetsPage(e) {
809
+ const { scope: t, sortBy: i, sortDirection: r } = this.state, o = this.state.searchQuery || void 0, l = this.facetParams();
810
+ if (t.type === "favourites") {
811
+ const f = [...this.state.favourites], d = await oe(this.client, f.slice(0, U)), u = Date.now(), g = d.filter((S) => re(S, l, u)), p = ne(g, i, r);
812
+ return {
813
+ assets: p,
814
+ total: p.length,
815
+ truncated: f.length > U,
816
+ hasMore: !1,
817
+ fetched: 0
818
+ };
819
+ }
820
+ const a = { sortBy: i, sortDirection: r, search: o, ...l, offset: e, limit: C };
821
+ let c;
822
+ if (t.type === "folder")
823
+ c = await w(this.client, { ...a, folder: t.value ?? "/", recursive: 0 });
824
+ else if (t.type === "label") {
825
+ const f = this.state.labels.find((u) => u.uuid === t.value), d = f ? he(f) : void 0;
826
+ c = await w(this.client, { ...a, recursive: 1, q: d });
827
+ } else
828
+ c = await w(this.client, { ...a, recursive: 1 });
829
+ const h = c.assets.length === C;
830
+ return {
831
+ assets: c.assets,
832
+ total: c.total,
833
+ truncated: !1,
834
+ hasMore: h,
835
+ fetched: c.assets.length
836
+ };
837
+ }
838
+ /** Reload everything for the current scope from page 1. Stale responses are discarded. */
839
+ async load() {
840
+ const e = ++this.loadSeq;
841
+ this.set({ loading: !0, loadingMore: !1, error: null });
842
+ try {
843
+ const t = b(this.client, { folderPath: this.currentFolderPath }), i = this.fetchAssetsPage(0), [r, o] = await Promise.all([t, i]);
844
+ if (e !== this.loadSeq) return;
845
+ this.fetchedCount = o.fetched, this.set({
846
+ folders: r,
847
+ assets: o.assets,
848
+ total: o.total,
849
+ truncated: o.truncated,
850
+ hasMore: o.hasMore,
851
+ loading: !1,
852
+ // keep the tree cache warm for the folder we just listed
853
+ treeChildren: { ...this.state.treeChildren, [this.currentFolderPath]: r }
854
+ });
855
+ } catch (t) {
856
+ if (e !== this.loadSeq) return;
857
+ this.set({ error: t instanceof Error ? t.message : String(t), loading: !1 });
858
+ }
859
+ }
860
+ /**
861
+ * Append the next page of assets for the current scope (infinite scroll).
862
+ * No-op while already loading, when no more pages exist, or if the scope
863
+ * changes mid-flight (the `loadSeq` guard discards a stale page).
864
+ *
865
+ * Offset comes from `fetchedCount` (raw items fetched), NOT the displayed
866
+ * length, so dedupe dropping an item never re-requests the same page. Appended
867
+ * assets are still de-duplicated by uuid so a shifting window can't double a card.
868
+ */
869
+ async loadMore() {
870
+ if (this.state.loading || this.state.loadingMore || !this.state.hasMore) return;
871
+ const e = this.loadSeq;
872
+ this.set({ loadingMore: !0 });
873
+ try {
874
+ const t = await this.fetchAssetsPage(this.fetchedCount);
875
+ if (e !== this.loadSeq) return;
876
+ this.fetchedCount += t.fetched;
877
+ const i = new Set(this.state.assets.map((o) => o.uuid)), r = t.assets.filter((o) => !i.has(o.uuid));
878
+ this.set({
879
+ assets: [...this.state.assets, ...r],
880
+ total: t.total,
881
+ hasMore: t.hasMore,
882
+ loadingMore: !1,
883
+ error: null
884
+ // a recovered page clears any prior load-more failure
885
+ });
886
+ } catch (t) {
887
+ if (e !== this.loadSeq) return;
888
+ this.set({ error: t instanceof Error ? t.message : String(t), loadingMore: !1 });
889
+ }
890
+ }
891
+ }
892
+ class Oe {
893
+ constructor(e = "sfx-light-dam:favourites") {
894
+ this.key = e;
895
+ }
896
+ read() {
897
+ try {
898
+ const e = localStorage.getItem(this.key);
899
+ return new Set(e ? JSON.parse(e) : []);
900
+ } catch {
901
+ return /* @__PURE__ */ new Set();
902
+ }
903
+ }
904
+ write(e) {
905
+ try {
906
+ localStorage.setItem(this.key, JSON.stringify([...e]));
907
+ } catch {
908
+ }
909
+ }
910
+ list() {
911
+ return [...this.read()];
912
+ }
913
+ has(e) {
914
+ return this.read().has(e);
915
+ }
916
+ add(e) {
917
+ const t = this.read();
918
+ t.add(e), this.write(t);
919
+ }
920
+ remove(e) {
921
+ const t = this.read();
922
+ t.delete(e), this.write(t);
923
+ }
924
+ }
925
+ function Re(s, e) {
926
+ const t = new URL(s);
927
+ return e.width && t.searchParams.set("w", String(e.width)), e.height && t.searchParams.set("h", String(e.height)), e.quality !== void 0 && t.searchParams.set("q", String(e.quality)), t.toString();
928
+ }
929
+ const Le = { excellent: 90, good: 75, fair: 60 }, ze = { fullhd: 1920, large: 1200, medium: 600, small: 300 }, Ee = {
930
+ webp: "awebp,webp",
931
+ gif: "agif,gif"
932
+ };
933
+ function j(s, e) {
934
+ s.searchParams.delete("download"), e.width && s.searchParams.set("w", String(e.width)), e.height && s.searchParams.set("h", String(e.height)), e.quality != null && s.searchParams.set("q", String(e.quality)), e.format && s.searchParams.set("force_format", Ee[e.format] ?? e.format), e.strictSizes !== void 0 && (e.width || e.height) && s.searchParams.set("func", e.strictSizes ? "bound" : "cover");
935
+ }
936
+ function Te(s, e) {
937
+ if (!e) return s;
938
+ const t = e === "jpeg" ? "jpg" : e;
939
+ return `${s.replace(/\.[^./\\]+$/, "") || s}.${t}`;
940
+ }
941
+ function qe(s, e, t = {}) {
942
+ const i = new URL(s);
943
+ return j(i, t), i.searchParams.set("force_download", Te(e, t.format)), i.toString();
944
+ }
945
+ function je(s, e = {}) {
946
+ const t = new URL(s);
947
+ return j(t, e), t.toString();
948
+ }
949
+ const k = /^(https:\/\/)([a-z0-9_-]+)\.filerobot\.com\//i;
950
+ function _(s) {
951
+ if (!s) return "";
952
+ const e = (i) => i.replace(/(\.filerobot\.com\/[a-z0-9_-]+)\/v\d+\//i, "$1/");
953
+ if (s.includes("assets.filerobot.com")) return e(s);
954
+ const t = s.match(k);
955
+ return t ? e(s.replace(k, `$1assets.filerobot.com/${t[2]}/`)) : s;
956
+ }
957
+ function A(s, e) {
958
+ try {
959
+ const t = new URL(s);
960
+ for (const [i, r] of Object.entries(e)) t.searchParams.set(i, r);
961
+ return t.toString();
962
+ } catch {
963
+ return s;
964
+ }
965
+ }
966
+ function Ne(s, e = 240) {
967
+ const t = String(e);
968
+ if (s.type === "video")
969
+ return s.thumbnailUrl ? A(_(s.thumbnailUrl), { w: t, force_format: "webp,jpeg" }) : "";
970
+ if (s.type === "document" && /\.pdf$/i.test(s.name)) {
971
+ const i = _(s.cdnUrl ?? "");
972
+ if (!i) return "";
973
+ const r = i.replace(/([?&])func=proxy&?/, "$1").replace(/[?&]$/, "");
974
+ return A(r, {
975
+ w: t,
976
+ force_format: "webp,jpeg",
977
+ doc_page: "1",
978
+ bypass_process_proxy: "1"
979
+ });
980
+ }
981
+ if (s.type === "image" || s.thumbnailUrl) {
982
+ const i = s.thumbnailUrl ?? s.cdnUrl;
983
+ return i ? A(_(i), { w: t, func: "bound" }) : "";
984
+ }
985
+ return "";
986
+ }
987
+ const n = "https://scaleflex.cloudimg.io/v7/assets/file-types/v3/", Ie = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" fill="none"><path d="M24 4 42 14v20L24 44 6 34V14z" fill="#eef2ff" stroke="#6366f1" stroke-width="2" stroke-linejoin="round"/><path d="M24 4 42 14 24 24 6 14z" fill="#c7d2fe" stroke="#6366f1" stroke-width="2" stroke-linejoin="round"/><path d="M24 24v20M24 24 6 14M24 24 42 14" stroke="#6366f1" stroke-width="2" stroke-linejoin="round"/></svg>', v = `data:image/svg+xml,${encodeURIComponent(Ie)}`, E = {
988
+ _default: n + "GENERIC.svg?vh=9a518a",
989
+ // Images
990
+ png: n + "PNG.svg?vh=96cd9a",
991
+ jpg: n + "JPG.svg?vh=06e819",
992
+ jpg2: n + "JPG2.svg?vh=f0eb7f",
993
+ jpeg: n + "JPEG.svg?vh=6a65e9",
994
+ gif: n + "GIF.svg?vh=c3c2c3",
995
+ bmp: n + "BMP.svg?vh=d2243a",
996
+ webp: n + "WEBP.svg?vh=fedd74",
997
+ svg: n + "SVG.svg?vh=a15e46",
998
+ tiff: n + "TIFF.svg?vh=1f30c3",
999
+ tif: n + "TIF.svg?vh=b383c9",
1000
+ heic: n + "HEIC.svg?vh=84adfe",
1001
+ avif: n + "AVIF.svg?vh=536b30",
1002
+ ico: n + "ICO.svg?vh=79063d",
1003
+ psd: n + "PSD.svg?vh=be6140",
1004
+ psb: n + "PSB.svg?vh=678646",
1005
+ ai: n + "AI.svg?vh=84b254",
1006
+ dwg: n + "DWG.svg?vh=971fb3",
1007
+ // Video
1008
+ mp4: n + "MP4.svg?vh=42f175",
1009
+ webm: n + "WEBM.svg?vh=26a84a",
1010
+ avi: n + "AVI.svg?vh=d22ba8",
1011
+ mpeg: n + "MPEG.svg?vh=ba93bb",
1012
+ ogv: n + "OGV.svg?vh=74d453",
1013
+ "3gp": n + "3GP.svg?vh=f0d388",
1014
+ "3g2": n + "3G2.svg?vh=04c652",
1015
+ swf: n + "SWF.svg?vh=3955e2",
1016
+ fla: n + "FLA.svg?vh=daf585",
1017
+ m3u8: n + "M3U8.svg?vh=7d5e62",
1018
+ // Audio
1019
+ mp3: n + "MP3.svg?vh=66bbef",
1020
+ wav: n + "WAV.svg?vh=d7a7d5",
1021
+ aac: n + "AAC.svg?vh=07f3f9",
1022
+ oga: n + "OGA.svg?vh=a5c622",
1023
+ opus: n + "OPUS.svg?vh=9548b1",
1024
+ weba: n + "WEBA.svg?vh=4dcf70",
1025
+ mid: n + "MID.svg?vh=3f0e29",
1026
+ midi: n + "MIDI.svg?vh=9fedec",
1027
+ cda: n + "CDA.svg?vh=85b83b",
1028
+ // Documents
1029
+ pdf: n + "PDF.svg?vh=18c5f7",
1030
+ doc: n + "DOC.svg?vh=d1b47c",
1031
+ docx: n + "DOCX.svg?vh=1eb6b0",
1032
+ txt: n + "TXT.svg?vh=307979",
1033
+ rtf: n + "RTF.svg?vh=978c5f",
1034
+ xls: n + "XLS.svg?vh=13b5f7",
1035
+ xlsx: n + "XLSX.svg?vh=79d64a",
1036
+ ppt: n + "PPT.svg?vh=4ee29b",
1037
+ pptx: n + "PPTX.svg?vh=8b1568",
1038
+ csv: n + "CSV.svg?vh=4add78",
1039
+ odt: n + "ODT.svg?vh=940781",
1040
+ ods: n + "ODS.svg?vh=9fbe9a",
1041
+ odp: n + "ODP.svg?vh=bf892d",
1042
+ dbf: n + "DBF.svg?vh=457bd4",
1043
+ vsd: n + "VSD.svg?vh=8a9ccb",
1044
+ abw: n + "ABW.svg?vh=313dc7",
1045
+ epub: n + "EPUB.svg?vh=15263d",
1046
+ azw: n + "AZW.svg?vh=a018b1",
1047
+ ics: n + "ICS.svg?vh=909f63",
1048
+ ogx: n + "OGX.svg?vh=f694d2",
1049
+ // Archives
1050
+ zip: n + "ZIP.svg?vh=84f98b",
1051
+ rar: n + "RAR.svg?vh=1d6423",
1052
+ "7z": n + "7Z.svg?vh=e007e5",
1053
+ tar: n + "TAR.svg?vh=603aed",
1054
+ gz: n + "GZ.svg?vh=de13f7",
1055
+ bz: n + "BZ.svg?vh=0374ff",
1056
+ bz2: n + "BZ2.svg?vh=e14294",
1057
+ arc: n + "ARC.svg?vh=942fad",
1058
+ jar: n + "JAR.svg?vh=149796",
1059
+ mpkg: n + "MPKG.svg?vh=dea655",
1060
+ // Fonts
1061
+ ttf: n + "TTF.svg?vh=d2e2c1",
1062
+ otf: n + "OTF.svg?vh=c904fd",
1063
+ woff: n + "WOFF.svg?vh=4b8177",
1064
+ woff2: n + "WOFF2.svg?vh=b532d3",
1065
+ eot: n + "EOT.svg?vh=a54980",
1066
+ // Code / Scripts
1067
+ js: n + "JS.svg?vh=524691",
1068
+ mjs: n + "MJS.svg?vh=d57921",
1069
+ ts: n + "TS.svg?vh=9af3ae",
1070
+ css: n + "CSS.svg?vh=287863",
1071
+ html: n + "HTML.svg?vh=fa7a87",
1072
+ htm: n + "HTM.svg?vh=21323d",
1073
+ xhtml: n + "XHTML.svg?vh=e6d6a9",
1074
+ xul: n + "XUL.svg?vh=6c9c71",
1075
+ json: n + "JSON.svg?vh=104c9e",
1076
+ jsonld: n + "JSONLD.svg?vh=f30c0f",
1077
+ xml: n + "XML.svg?vh=7f7194",
1078
+ php: n + "PHP.svg?vh=503e36",
1079
+ sh: n + "SH.svg?vh=3b820e",
1080
+ csh: n + "CSH.svg?vh=08c0cc",
1081
+ // Executables / Disk images
1082
+ exe: n + "EXE.svg?vh=ccca53",
1083
+ iso: n + "ISO.svg?vh=064b8f",
1084
+ bin: n + "BIN.svg?vh=1e9618",
1085
+ // 3D models (local override — not in asset-picker's hosted set)
1086
+ glb: v,
1087
+ gltf: v,
1088
+ obj: v,
1089
+ fbx: v,
1090
+ stl: v,
1091
+ usdz: v,
1092
+ ply: v,
1093
+ "3ds": v,
1094
+ dae: v
1095
+ };
1096
+ function Be() {
1097
+ return E._default;
1098
+ }
1099
+ function Ge(s) {
1100
+ const e = (s.split(".").pop() || "").toLowerCase();
1101
+ return E[e] || E._default;
1102
+ }
1103
+ function We(s) {
1104
+ if (s == null || !Number.isFinite(s) || s < 0) return "—";
1105
+ const e = ["B", "KB", "MB", "GB", "TB"];
1106
+ let t = s, i = 0;
1107
+ for (; t >= 1024 && i < e.length - 1; )
1108
+ t /= 1024, i++;
1109
+ const r = (a, c) => {
1110
+ const h = c > 0 && Math.round(a * 10) / 10 < 10 ? 1 : 0, f = a.toFixed(h);
1111
+ return { str: f, rounded: Number(f) };
1112
+ }, o = r(t, i);
1113
+ let l = o.str;
1114
+ return o.rounded >= 1024 && i < e.length - 1 && (t /= 1024, i++, l = r(t, i).str), `${l} ${e[i]}`;
1115
+ }
1116
+ function Xe(s) {
1117
+ if (!s) return "—";
1118
+ const e = new Date(s);
1119
+ return Number.isNaN(e.getTime()) ? s : e.toLocaleDateString(void 0, { year: "numeric", month: "short", day: "numeric" });
1120
+ }
1121
+ function Ve(s, e) {
1122
+ return s && e ? `${s} × ${e}` : "—";
1123
+ }
1124
+ function He(s, e) {
1125
+ let t;
1126
+ const i = ((...r) => {
1127
+ clearTimeout(t), t = setTimeout(() => s(...r), e);
1128
+ });
1129
+ return i.cancel = () => clearTimeout(t), i;
1130
+ }
1131
+ export {
1132
+ P as BrowseStore,
1133
+ O as DamClient,
1134
+ Oe as LocalFavouritesAdapter,
1135
+ U as MAX_FAVOURITES,
1136
+ C as PAGE_SIZE,
1137
+ Le as QUALITY_LEVELS,
1138
+ ze as RESIZE_PRESETS,
1139
+ Re as addCdnParams,
1140
+ Ae as archiveDownloadUrl,
1141
+ be as archiveStatusOutcome,
1142
+ ve as assembleVariations,
1143
+ re as assetMatchesFacets,
1144
+ T as buildAuthHeaders,
1145
+ je as buildEmbedUrl,
1146
+ qe as buildTransformedDownloadUrl,
1147
+ Ce as createAndPollArchive,
1148
+ we as createArchive,
1149
+ K as createFolder,
1150
+ He as debounce,
1151
+ ce as deleteFiles,
1152
+ Z as deleteFolders,
1153
+ W as exchangeSassKey,
1154
+ Xe as formatDate,
1155
+ Ve as formatDimensions,
1156
+ We as formatFileSize,
1157
+ M as getApiBase,
1158
+ ye as getArchiveStatus,
1159
+ Be as getDefaultFileTypeIconUrl,
1160
+ Ge as getFileTypeIconUrl,
1161
+ ge as getFileVariations,
1162
+ $e as getFiles,
1163
+ oe as getFilesByUuids,
1164
+ w as getFilesPage,
1165
+ Ue as getFilesRaw,
1166
+ De as getFilesStats,
1167
+ Me as getFolderPreviews,
1168
+ b as getFolders,
1169
+ ke as getFoldersRaw,
1170
+ _ as getFormattedPreviewUrl,
1171
+ de as getLabels,
1172
+ pe as getPresets,
1173
+ Ne as getThumbnailUrl,
1174
+ he as labelFilterQuery,
1175
+ xe as loadVariations,
1176
+ le as moveFiles,
1177
+ Q as moveFolders,
1178
+ V as normalizeAuth,
1179
+ me as normalizePresets,
1180
+ x as normalizeVariation,
1181
+ _e as pollArchive,
1182
+ $ as presetUrl,
1183
+ ae as renameFile,
1184
+ Y as renameFolder,
1185
+ I as resolveAuth,
1186
+ ne as sortAssets,
1187
+ Te as transformedFileName
1188
+ };
1189
+ //# sourceMappingURL=index.js.map