@localazy/cdn-client 1.5.12 → 1.5.14

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.
@@ -1,620 +1,569 @@
1
- "use strict";
1
+ /* @localazy/cdn-client@1.5.14
2
+ * (c) 2026 Localazy <team@localazy.com>
3
+ * @license MIT */
2
4
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- class Api {
4
- context;
5
- constructor(context) {
6
- this.context = context;
7
- }
8
- async fetchLocale(options) {
9
- if (this.context.cache.has(options)) {
10
- return new Promise((resolve) => {
11
- resolve(this.context.cache.get(options));
12
- });
13
- }
14
- return this.context.client.get(options.metafileLocale.uri);
15
- }
16
- async fetchMetafile() {
17
- return await this.context.client.get(this.context.metafile.params.jsonPath);
18
- }
19
- }
20
- class MemoryCacheAdapter {
21
- map;
22
- constructor() {
23
- this.map = /* @__PURE__ */ new Map();
24
- }
25
- get(key) {
26
- return this.map.get(key);
27
- }
28
- has(key) {
29
- return this.map.has(key);
30
- }
31
- set(key, value) {
32
- this.map.set(key, value);
33
- }
34
- flush() {
35
- this.map = /* @__PURE__ */ new Map();
36
- }
37
- }
38
- const isString = (value) => typeof value === "string";
39
- const isUndefined = (value) => typeof value === "undefined";
40
- const isArray = (value) => Array.isArray(value);
41
- const isPlainObject = (value) => Object.prototype.toString.call(value) === "[object Object]";
42
- const uniq = (array) => [...new Set(array)];
43
- const uniqBy = (array, predicate) => {
44
- const seen = {};
45
- return array.filter((item) => {
46
- const key = predicate(item);
47
- if (!Object.hasOwn(seen, key)) {
48
- seen[key] = true;
49
- return true;
50
- }
51
- return false;
52
- });
5
+ //#region src/cdn/api/api.ts
6
+ var Api = class {
7
+ context;
8
+ constructor(context) {
9
+ this.context = context;
10
+ }
11
+ async fetchLocale(options) {
12
+ if (this.context.cache.has(options)) return new Promise((resolve) => {
13
+ resolve(this.context.cache.get(options));
14
+ });
15
+ return this.context.client.get(options.metafileLocale.uri);
16
+ }
17
+ async fetchMetafile() {
18
+ return await this.context.client.get(this.context.metafile.params.jsonPath);
19
+ }
53
20
  };
54
- class LocalesCache {
55
- context;
56
- cacheAdapter;
57
- constructor(context) {
58
- this.context = context;
59
- this.cacheAdapter = new MemoryCacheAdapter();
60
- }
61
- setIfMissed(options) {
62
- const { metafileFile, metafileLocale, data } = options;
63
- const key = this.keyFromMetafile({
64
- metafileFile,
65
- metafileLocale
66
- });
67
- if (!this.cacheAdapter.has(key)) {
68
- this.cacheAdapter.set(key, data);
69
- }
70
- }
71
- has(options) {
72
- const key = this.keyFromMetafile(options);
73
- return this.cacheAdapter.has(key);
74
- }
75
- get(options) {
76
- const key = this.keyFromMetafile(options);
77
- return this.cacheAdapter.get(key);
78
- }
79
- flush() {
80
- this.cacheAdapter.flush();
81
- }
82
- keyFromMetafile(options) {
83
- const { metafileFile, metafileLocale } = options;
84
- const productFlavors = [...uniq(metafileFile.productFlavors)].sort().join("-");
85
- const indices = [
86
- this.context.metafile.params.cdnId,
87
- metafileFile.id,
88
- metafileFile.file,
89
- metafileFile.path,
90
- metafileFile.library,
91
- metafileFile.module,
92
- metafileFile.buildType,
93
- productFlavors,
94
- metafileLocale.locale,
95
- metafileLocale.timestamp.toString()
96
- ];
97
- return indices.filter((key) => key !== "").join("-");
98
- }
99
- }
100
- class ResponseFactory {
101
- context;
102
- constructor(context) {
103
- this.context = context;
104
- }
105
- createCdnResponse(options) {
106
- const {
107
- requests,
108
- responses,
109
- hasSingleFileResponse,
110
- hasSingleLocaleResponse
111
- } = options;
112
- if (responses.length === 0 || typeof responses[0] === "undefined") {
113
- return {};
114
- }
115
- this.cacheResponses(requests, responses);
116
- return hasSingleFileResponse && hasSingleLocaleResponse ? responses[0] : ResponseFactory.transformResponses(options);
117
- }
118
- cacheResponses(requests, responses) {
119
- responses.forEach((response, index) => {
120
- if (typeof requests[index] !== "undefined") {
121
- const { metafileFile, metafileLocale } = requests[index];
122
- if (metafileFile && metafileLocale) {
123
- this.context.cache.setIfMissed({ metafileFile, metafileLocale, data: response });
124
- }
125
- }
126
- });
127
- }
128
- static transformResponses(options) {
129
- const { requests, responses, hasSingleFileResponse } = options;
130
- return responses.reduce((acc, cur, index) => {
131
- if (typeof requests[index] !== "undefined") {
132
- const { metafileFile, metafileLocale } = requests[index];
133
- if (metafileFile && metafileLocale) {
134
- if (hasSingleFileResponse) {
135
- acc[metafileLocale.locale] = cur;
136
- } else {
137
- if (!acc[metafileFile.id]) {
138
- acc[metafileFile.id] = {};
139
- }
140
- acc[metafileFile.id][metafileLocale.locale] = cur;
141
- }
142
- }
143
- }
144
- return acc;
145
- }, {});
146
- }
147
- }
148
- class Context {
149
- metafile;
150
- cdn;
151
- client;
152
- api;
153
- cache;
154
- responseFactory;
155
- constructor(options) {
156
- this.metafile = options.metafileContext;
157
- this.cdn = options.cdn;
158
- this.client = options.client;
159
- this.api = new Api(this);
160
- this.cache = new LocalesCache(this);
161
- this.responseFactory = new ResponseFactory(this);
162
- }
163
- }
164
- class MetafileFile {
165
- id;
166
- file;
167
- path;
168
- library;
169
- module;
170
- buildType;
171
- timestamp;
172
- productFlavors;
173
- locales;
174
- baseUrl;
175
- constructor(options) {
176
- this.id = options.id;
177
- this.file = options.file;
178
- this.path = options.path;
179
- this.library = options.library;
180
- this.module = options.module;
181
- this.buildType = options.buildType;
182
- this.timestamp = options.timestamp;
183
- this.productFlavors = options.productFlavors;
184
- this.locales = options.locales;
185
- this.baseUrl = options.baseUrl;
186
- }
187
- toCdnFile() {
188
- return {
189
- id: this.id,
190
- file: this.file,
191
- path: this.path,
192
- library: this.library,
193
- module: this.module,
194
- buildType: this.buildType,
195
- productFlavors: this.productFlavors,
196
- locales: this.locales.map(
197
- (locale) => ({
198
- locale: locale.locale,
199
- isBaseLocale: locale.isBaseLocale,
200
- uri: `${this.baseUrl}${locale.uri}`
201
- })
202
- )
203
- };
204
- }
205
- }
206
- class MetafileLocale {
207
- language;
208
- region;
209
- script;
210
- isRtl;
211
- name;
212
- localizedName;
213
- uri;
214
- timestamp;
215
- baseLocale;
216
- constructor(options, baseLocale) {
217
- this.language = options.language;
218
- this.region = options.region;
219
- this.script = options.script;
220
- this.isRtl = options.isRtl;
221
- this.name = options.name;
222
- this.localizedName = options.localizedName;
223
- this.uri = options.uri;
224
- this.timestamp = options.timestamp;
225
- this.baseLocale = baseLocale;
226
- }
227
- get locale() {
228
- if (this.language && this.region && this.script) {
229
- return `${this.language}_${this.region}#${this.script}`;
230
- }
231
- if (this.language && this.script) {
232
- return `${this.language}#${this.script}`;
233
- }
234
- if (this.language && this.region) {
235
- return `${this.language}_${this.region}`;
236
- }
237
- return this.language;
238
- }
239
- get isBaseLocale() {
240
- return this.locale === this.baseLocale;
241
- }
242
- toCdnLocale() {
243
- return {
244
- locale: this.locale,
245
- isBaseLocale: this.isBaseLocale,
246
- language: this.language,
247
- region: this.region,
248
- script: this.script,
249
- isRtl: this.isRtl,
250
- name: this.name,
251
- localizedName: this.localizedName
252
- };
253
- }
254
- }
255
- class MetafileData {
256
- projectUrl;
257
- baseLocale;
258
- locales;
259
- timestamp;
260
- files;
261
- filesMap;
262
- constructor(options, params) {
263
- this.projectUrl = options.projectUrl;
264
- this.timestamp = options.timestamp;
265
- this.files = MetafileData.filesFactory(options.files, options.baseLocale, params);
266
- this.filesMap = MetafileData.filesMapFactory(this.files);
267
- this.locales = MetafileData.localesFactory(this.files);
268
- this.baseLocale = this.locales.find((locale) => locale.isBaseLocale);
269
- }
270
- static createEmpty(params) {
271
- return new MetafileData(
272
- {
273
- projectUrl: "",
274
- baseLocale: "",
275
- timestamp: 0,
276
- files: {}
277
- },
278
- params
279
- );
280
- }
281
- static filesFactory(files, baseLocale, params) {
282
- return Object.keys(files).reduce((acc, cur) => {
283
- if (typeof files[cur] !== "undefined") {
284
- const locales = files[cur].locales.map(
285
- (locale) => new MetafileLocale(locale, baseLocale)
286
- );
287
- acc.push(
288
- new MetafileFile({
289
- ...files[cur],
290
- id: cur,
291
- locales,
292
- baseUrl: params.baseUrl
293
- })
294
- );
295
- }
296
- return acc;
297
- }, []);
298
- }
299
- static filesMapFactory(files) {
300
- return files.reduce((acc, cur) => {
301
- acc[cur.id] = cur;
302
- return acc;
303
- }, {});
304
- }
305
- static localesFactory(files) {
306
- const locales = files.reduce((acc, cur) => {
307
- acc.push(...cur.locales.map((locale) => locale.toCdnLocale()));
308
- return acc;
309
- }, []);
310
- return uniqBy(locales, (cdnLocale) => cdnLocale.locale);
311
- }
312
- }
313
- class MetafileParams {
314
- options;
315
- constructor(metafileUrl) {
316
- this.options = MetafileParams.parseMetafileUrl(metafileUrl);
317
- }
318
- get url() {
319
- return this.options.url;
320
- }
321
- get baseUrl() {
322
- return this.options.baseUrl;
323
- }
324
- get cdnId() {
325
- return this.options.cdnId;
326
- }
327
- get jsonPath() {
328
- return this.options.jsonPath;
329
- }
330
- static parseMetafileUrl(metafileUrl) {
331
- let url;
332
- try {
333
- url = new URL(metafileUrl);
334
- } catch {
335
- throw new Error('Invalid param: "options.metafile" cannot be parsed as url.');
336
- }
337
- const matches = /^\/(.*?)\/(.*?)\.(v2.json|js|ts)$/.exec(url.pathname);
338
- if (matches === null || matches.length !== 4 || typeof matches[1] === "undefined" || typeof matches[2] === "undefined") {
339
- throw new Error('Invalid param: "options.metafile" contains invalid metafile url.');
340
- }
341
- const cdnId = matches[1];
342
- const tagId = matches[2];
343
- return {
344
- url: metafileUrl,
345
- baseUrl: url.origin,
346
- cdnId,
347
- jsonPath: `/${cdnId}/${tagId}.v2.json`
348
- };
349
- }
350
- }
351
- class MetafileContext {
352
- params;
353
- parsedData;
354
- data;
355
- constructor(options) {
356
- this.params = new MetafileParams(options.metafile);
357
- this.parsedData = null;
358
- this.data = MetafileData.createEmpty(this.params);
359
- }
360
- setMetafile(metafile) {
361
- this.parsedData = metafile;
362
- this.data = new MetafileData(metafile, this.params);
363
- }
364
- }
365
- class FetchHttpAdapter {
366
- baseUrl;
367
- constructor(baseUrl) {
368
- this.baseUrl = baseUrl;
369
- }
370
- async get(url) {
371
- const response = await fetch(`${this.baseUrl}${url}`);
372
- const contentType = response.headers.get("content-type");
373
- const isJson = contentType === "application/json5" || contentType === "application/json";
374
- if (response.status >= 400) {
375
- throw new Error(`Request failed with status code ${response.status.toString()}`);
376
- }
377
- let result;
378
- if (isJson) {
379
- result = await response.json();
380
- } else {
381
- result = await response.text();
382
- }
383
- return result;
384
- }
385
- }
386
- class CdnBase {
387
- context;
388
- constructor(context) {
389
- this.context = context;
390
- }
391
- }
392
- class CdnCache extends CdnBase {
393
- flush = () => {
394
- this.context.cache.flush();
395
- };
396
- }
397
- class CdnMetafile extends CdnBase {
398
- get projectUrl() {
399
- return this.context.metafile.data.projectUrl;
400
- }
401
- get baseLocale() {
402
- return this.context.metafile.data.baseLocale;
403
- }
404
- get url() {
405
- return this.context.metafile.params.url;
406
- }
407
- get files() {
408
- return this.context.metafile.data.files.map((file) => file.toCdnFile());
409
- }
410
- locales = (options) => {
411
- const { excludeBaseLocale } = options || {};
412
- const { locales } = this.context.metafile.data;
413
- return excludeBaseLocale ? locales.filter((cdnLocale) => !cdnLocale.isBaseLocale) : locales;
414
- };
415
- refresh = async () => {
416
- const response = await this.context.api.fetchMetafile();
417
- this.context.metafile.setMetafile(response);
418
- };
419
- switch = async (options) => {
420
- this.context.metafile.params = new MetafileParams(options.metafile);
421
- await this.refresh();
422
- };
423
- }
424
- class LocalesMap {
425
- data;
426
- context;
427
- constructor(options) {
428
- this.context = options.context;
429
- this.data = options.data || {};
430
- }
431
- }
432
- class Request {
433
- files;
434
- localesMap;
435
- hasSingleFileResponse;
436
- hasSingleLocaleResponse;
437
- context;
438
- constructor(context) {
439
- this.files = [];
440
- this.localesMap = new LocalesMap({ context });
441
- this.hasSingleFileResponse = false;
442
- this.hasSingleLocaleResponse = false;
443
- this.context = context;
444
- }
445
- async execute() {
446
- const payload = this.getPromises();
447
- const promises = payload.map(
448
- (item) => item[0]
449
- );
450
- const requests = payload.map(
451
- (item) => item[1]
452
- );
453
- const responses = await Promise.all(promises);
454
- return this.context.responseFactory.createCdnResponse({
455
- requests,
456
- responses,
457
- localesMap: this.localesMap,
458
- hasSingleFileResponse: this.hasSingleFileResponse,
459
- hasSingleLocaleResponse: this.hasSingleLocaleResponse
460
- });
461
- }
462
- getPromises() {
463
- return this.files.reduce(
464
- (acc, cur) => {
465
- if (typeof this.localesMap.data?.[cur.id] !== "undefined") {
466
- acc.push(
467
- ...this.localesMap.data[cur.id].map(
468
- (metafileLocale) => {
469
- const request = {
470
- metafileFile: cur,
471
- metafileLocale
472
- };
473
- return [this.context.api.fetchLocale(request), request];
474
- }
475
- )
476
- );
477
- }
478
- return acc;
479
- },
480
- []
481
- );
482
- }
483
- }
484
- class RequestBuilder {
485
- context;
486
- request;
487
- constructor(context) {
488
- this.context = context;
489
- this.request = new Request(this.context);
490
- }
491
- addFiles(files) {
492
- if (!(isPlainObject(files) || isString(files) || isUndefined(files) || isArray(files))) {
493
- throw new Error('Invalid param: "request.files" must be object, array, string or undefined.');
494
- }
495
- if (isArray(files)) {
496
- files.forEach((i) => {
497
- if (!(isPlainObject(i) || isString(i))) {
498
- throw new Error('Invalid param: array "request.files" must contain objects or strings.');
499
- }
500
- });
501
- }
502
- if (isString(files)) {
503
- this.request.hasSingleFileResponse = true;
504
- const file = this.context.metafile.data.files.find(
505
- (i) => i.id === files
506
- );
507
- if (!(file instanceof MetafileFile)) {
508
- throw new Error(`File not found: "${files}".`);
509
- }
510
- this.request.files = [file];
511
- } else if (isUndefined(files)) {
512
- this.request.files = [...this.context.metafile.data.files];
513
- } else if (isArray(files)) {
514
- this.request.files = files.map((file) => {
515
- let metafileFile;
516
- if (isString(file)) {
517
- const foundFile = this.context.metafile.data.files.find(
518
- (i) => i.id === file
519
- );
520
- if (isUndefined(foundFile)) {
521
- throw new Error(`File not found: "${file}".`);
522
- }
523
- metafileFile = foundFile;
524
- } else {
525
- const foundFile = this.context.metafile.data.files.find(
526
- (i) => i.id === file.id
527
- );
528
- if (isUndefined(foundFile)) {
529
- throw new Error(`File not found: "${file.id}".`);
530
- }
531
- metafileFile = foundFile;
532
- }
533
- return metafileFile;
534
- });
535
- } else if (isPlainObject(files)) {
536
- this.request.hasSingleFileResponse = true;
537
- const foundFile = this.context.metafile.data.files.find(
538
- (i) => i.id === files.id
539
- );
540
- if (isUndefined(foundFile)) {
541
- throw new Error(`File not found: "${files.id}".`);
542
- }
543
- this.request.files = [foundFile];
544
- }
545
- return this;
546
- }
547
- addLocales(locales, excludeBaseLocale) {
548
- if (!(isString(locales) || isUndefined(locales) || isArray(locales))) {
549
- throw new Error('Invalid param: "request.locales" must be array, string or undefined.');
550
- }
551
- if (isArray(locales)) {
552
- locales.forEach((i) => {
553
- if (!isString(i)) {
554
- throw new Error('Invalid param: array "request.locales" must contain strings.');
555
- }
556
- });
557
- }
558
- if (isString(locales)) {
559
- this.request.hasSingleLocaleResponse = true;
560
- this.request.files.reduce((acc, cur) => {
561
- acc.data[cur.id] = cur.locales.filter(
562
- (metafileLocale) => metafileLocale.locale === locales
563
- );
564
- return acc;
565
- }, this.request.localesMap);
566
- } else if (isUndefined(locales)) {
567
- this.request.files.reduce((acc, cur) => {
568
- acc.data[cur.id] = excludeBaseLocale ? cur.locales.filter(
569
- (metafileLocale) => !metafileLocale.isBaseLocale
570
- ) : cur.locales;
571
- return acc;
572
- }, this.request.localesMap);
573
- } else if (isArray(locales)) {
574
- this.request.files.reduce((acc, cur) => {
575
- acc.data[cur.id] = cur.locales.filter(
576
- (metafileLocale) => locales.includes(metafileLocale.locale)
577
- );
578
- return acc;
579
- }, this.request.localesMap);
580
- }
581
- return this;
582
- }
583
- getCdnRequest() {
584
- const result = this.request;
585
- this.request = new Request(this.context);
586
- return result;
587
- }
588
- }
589
- class CdnClient {
590
- metafile;
591
- cache;
592
- context;
593
- static version = "1.5.12";
594
- constructor(options) {
595
- const metafileContext = new MetafileContext(options);
596
- const client = new FetchHttpAdapter(metafileContext.params.baseUrl);
597
- this.context = new Context({ metafileContext, cdn: this, client });
598
- this.metafile = new CdnMetafile(this.context);
599
- this.cache = new CdnCache(this.context);
600
- }
601
- fetch = async (options) => {
602
- const { files, locales, excludeBaseLocale } = options || {};
603
- const requestBuilder = new RequestBuilder(this.context).addFiles(files).addLocales(locales, excludeBaseLocale);
604
- return requestBuilder.getCdnRequest().execute();
605
- };
606
- static async create(options) {
607
- if (!options) {
608
- throw new Error('Invalid param: missing required "options" parameter.');
609
- }
610
- if (!isString(options.metafile)) {
611
- throw new Error('Invalid param: "options.metafile" must be string.');
612
- }
613
- const cdn = new CdnClient(options);
614
- await cdn.metafile.refresh();
615
- return cdn;
616
- }
617
- }
21
+ //#endregion
22
+ //#region src/cdn/cache/memory-cache-adapter.ts
23
+ var MemoryCacheAdapter = class {
24
+ map;
25
+ constructor() {
26
+ this.map = /* @__PURE__ */ new Map();
27
+ }
28
+ get(key) {
29
+ return this.map.get(key);
30
+ }
31
+ has(key) {
32
+ return this.map.has(key);
33
+ }
34
+ set(key, value) {
35
+ this.map.set(key, value);
36
+ }
37
+ flush() {
38
+ this.map = /* @__PURE__ */ new Map();
39
+ }
40
+ };
41
+ //#endregion
42
+ //#region src/cdn/utils.ts
43
+ var isString = (value) => typeof value === "string";
44
+ var isUndefined = (value) => typeof value === "undefined";
45
+ var isArray = (value) => Array.isArray(value);
46
+ var isPlainObject = (value) => Object.prototype.toString.call(value) === "[object Object]";
47
+ var uniq = (array) => [...new Set(array)];
48
+ var uniqBy = (array, predicate) => {
49
+ const seen = {};
50
+ return array.filter((item) => {
51
+ const key = predicate(item);
52
+ if (!Object.hasOwn(seen, key)) {
53
+ seen[key] = true;
54
+ return true;
55
+ }
56
+ return false;
57
+ });
58
+ };
59
+ //#endregion
60
+ //#region src/cdn/cache/locales-cache.ts
61
+ var LocalesCache = class {
62
+ context;
63
+ cacheAdapter;
64
+ constructor(context) {
65
+ this.context = context;
66
+ this.cacheAdapter = new MemoryCacheAdapter();
67
+ }
68
+ setIfMissed(options) {
69
+ const { metafileFile, metafileLocale, data } = options;
70
+ const key = this.keyFromMetafile({
71
+ metafileFile,
72
+ metafileLocale
73
+ });
74
+ if (!this.cacheAdapter.has(key)) this.cacheAdapter.set(key, data);
75
+ }
76
+ has(options) {
77
+ const key = this.keyFromMetafile(options);
78
+ return this.cacheAdapter.has(key);
79
+ }
80
+ get(options) {
81
+ const key = this.keyFromMetafile(options);
82
+ return this.cacheAdapter.get(key);
83
+ }
84
+ flush() {
85
+ this.cacheAdapter.flush();
86
+ }
87
+ keyFromMetafile(options) {
88
+ const { metafileFile, metafileLocale } = options;
89
+ const productFlavors = [...uniq(metafileFile.productFlavors)].sort().join("-");
90
+ return [
91
+ this.context.metafile.params.cdnId,
92
+ metafileFile.id,
93
+ metafileFile.file,
94
+ metafileFile.path,
95
+ metafileFile.library,
96
+ metafileFile.module,
97
+ metafileFile.buildType,
98
+ productFlavors,
99
+ metafileLocale.locale,
100
+ metafileLocale.timestamp.toString()
101
+ ].filter((key) => key !== "").join("-");
102
+ }
103
+ };
104
+ //#endregion
105
+ //#region src/cdn/response/response-factory.ts
106
+ var ResponseFactory = class ResponseFactory {
107
+ context;
108
+ constructor(context) {
109
+ this.context = context;
110
+ }
111
+ createCdnResponse(options) {
112
+ const { requests, responses, hasSingleFileResponse, hasSingleLocaleResponse } = options;
113
+ if (responses.length === 0 || typeof responses[0] === "undefined") return {};
114
+ this.cacheResponses(requests, responses);
115
+ return hasSingleFileResponse && hasSingleLocaleResponse ? responses[0] : ResponseFactory.transformResponses(options);
116
+ }
117
+ cacheResponses(requests, responses) {
118
+ responses.forEach((response, index) => {
119
+ if (typeof requests[index] !== "undefined") {
120
+ const { metafileFile, metafileLocale } = requests[index];
121
+ if (metafileFile && metafileLocale) this.context.cache.setIfMissed({
122
+ metafileFile,
123
+ metafileLocale,
124
+ data: response
125
+ });
126
+ }
127
+ });
128
+ }
129
+ static transformResponses(options) {
130
+ const { requests, responses, hasSingleFileResponse } = options;
131
+ return responses.reduce((acc, cur, index) => {
132
+ if (typeof requests[index] !== "undefined") {
133
+ const { metafileFile, metafileLocale } = requests[index];
134
+ if (metafileFile && metafileLocale) if (hasSingleFileResponse) acc[metafileLocale.locale] = cur;
135
+ else {
136
+ if (!acc[metafileFile.id]) acc[metafileFile.id] = {};
137
+ acc[metafileFile.id][metafileLocale.locale] = cur;
138
+ }
139
+ }
140
+ return acc;
141
+ }, {});
142
+ }
143
+ };
144
+ //#endregion
145
+ //#region src/cdn/context/context.ts
146
+ var Context = class {
147
+ metafile;
148
+ cdn;
149
+ client;
150
+ api;
151
+ cache;
152
+ responseFactory;
153
+ constructor(options) {
154
+ this.metafile = options.metafileContext;
155
+ this.cdn = options.cdn;
156
+ this.client = options.client;
157
+ this.api = new Api(this);
158
+ this.cache = new LocalesCache(this);
159
+ this.responseFactory = new ResponseFactory(this);
160
+ }
161
+ };
162
+ //#endregion
163
+ //#region src/cdn/metafile/metafile-file.ts
164
+ var MetafileFile = class {
165
+ id;
166
+ file;
167
+ path;
168
+ library;
169
+ module;
170
+ buildType;
171
+ timestamp;
172
+ productFlavors;
173
+ locales;
174
+ baseUrl;
175
+ constructor(options) {
176
+ this.id = options.id;
177
+ this.file = options.file;
178
+ this.path = options.path;
179
+ this.library = options.library;
180
+ this.module = options.module;
181
+ this.buildType = options.buildType;
182
+ this.timestamp = options.timestamp;
183
+ this.productFlavors = options.productFlavors;
184
+ this.locales = options.locales;
185
+ this.baseUrl = options.baseUrl;
186
+ }
187
+ toCdnFile() {
188
+ return {
189
+ id: this.id,
190
+ file: this.file,
191
+ path: this.path,
192
+ library: this.library,
193
+ module: this.module,
194
+ buildType: this.buildType,
195
+ productFlavors: this.productFlavors,
196
+ locales: this.locales.map((locale) => ({
197
+ locale: locale.locale,
198
+ isBaseLocale: locale.isBaseLocale,
199
+ uri: `${this.baseUrl}${locale.uri}`
200
+ }))
201
+ };
202
+ }
203
+ };
204
+ //#endregion
205
+ //#region src/cdn/metafile/metafile-locale.ts
206
+ var MetafileLocale = class {
207
+ language;
208
+ region;
209
+ script;
210
+ isRtl;
211
+ name;
212
+ localizedName;
213
+ uri;
214
+ timestamp;
215
+ baseLocale;
216
+ constructor(options, baseLocale) {
217
+ this.language = options.language;
218
+ this.region = options.region;
219
+ this.script = options.script;
220
+ this.isRtl = options.isRtl;
221
+ this.name = options.name;
222
+ this.localizedName = options.localizedName;
223
+ this.uri = options.uri;
224
+ this.timestamp = options.timestamp;
225
+ this.baseLocale = baseLocale;
226
+ }
227
+ get locale() {
228
+ if (this.language && this.region && this.script) return `${this.language}_${this.region}#${this.script}`;
229
+ if (this.language && this.script) return `${this.language}#${this.script}`;
230
+ if (this.language && this.region) return `${this.language}_${this.region}`;
231
+ return this.language;
232
+ }
233
+ get isBaseLocale() {
234
+ return this.locale === this.baseLocale;
235
+ }
236
+ toCdnLocale() {
237
+ return {
238
+ locale: this.locale,
239
+ isBaseLocale: this.isBaseLocale,
240
+ language: this.language,
241
+ region: this.region,
242
+ script: this.script,
243
+ isRtl: this.isRtl,
244
+ name: this.name,
245
+ localizedName: this.localizedName
246
+ };
247
+ }
248
+ };
249
+ //#endregion
250
+ //#region src/cdn/metafile/metafile-data.ts
251
+ var MetafileData = class MetafileData {
252
+ projectUrl;
253
+ baseLocale;
254
+ locales;
255
+ timestamp;
256
+ files;
257
+ filesMap;
258
+ constructor(options, params) {
259
+ this.projectUrl = options.projectUrl;
260
+ this.timestamp = options.timestamp;
261
+ this.files = MetafileData.filesFactory(options.files, options.baseLocale, params);
262
+ this.filesMap = MetafileData.filesMapFactory(this.files);
263
+ this.locales = MetafileData.localesFactory(this.files);
264
+ this.baseLocale = this.locales.find((locale) => locale.isBaseLocale);
265
+ }
266
+ static createEmpty(params) {
267
+ return new MetafileData({
268
+ projectUrl: "",
269
+ baseLocale: "",
270
+ timestamp: 0,
271
+ files: {}
272
+ }, params);
273
+ }
274
+ static filesFactory(files, baseLocale, params) {
275
+ return Object.keys(files).reduce((acc, cur) => {
276
+ if (typeof files[cur] !== "undefined") {
277
+ const locales = files[cur].locales.map((locale) => new MetafileLocale(locale, baseLocale));
278
+ acc.push(new MetafileFile({
279
+ ...files[cur],
280
+ id: cur,
281
+ locales,
282
+ baseUrl: params.baseUrl
283
+ }));
284
+ }
285
+ return acc;
286
+ }, []);
287
+ }
288
+ static filesMapFactory(files) {
289
+ return files.reduce((acc, cur) => {
290
+ acc[cur.id] = cur;
291
+ return acc;
292
+ }, {});
293
+ }
294
+ static localesFactory(files) {
295
+ return uniqBy(files.reduce((acc, cur) => {
296
+ acc.push(...cur.locales.map((locale) => locale.toCdnLocale()));
297
+ return acc;
298
+ }, []), (cdnLocale) => cdnLocale.locale);
299
+ }
300
+ };
301
+ //#endregion
302
+ //#region src/cdn/metafile/metafile-params.ts
303
+ var MetafileParams = class MetafileParams {
304
+ options;
305
+ constructor(metafileUrl) {
306
+ this.options = MetafileParams.parseMetafileUrl(metafileUrl);
307
+ }
308
+ get url() {
309
+ return this.options.url;
310
+ }
311
+ get baseUrl() {
312
+ return this.options.baseUrl;
313
+ }
314
+ get cdnId() {
315
+ return this.options.cdnId;
316
+ }
317
+ get jsonPath() {
318
+ return this.options.jsonPath;
319
+ }
320
+ static parseMetafileUrl(metafileUrl) {
321
+ let url;
322
+ try {
323
+ url = new URL(metafileUrl);
324
+ } catch {
325
+ throw new Error("Invalid param: \"options.metafile\" cannot be parsed as url.");
326
+ }
327
+ const matches = /^\/(.*?)\/(.*?)\.(v2.json|js|ts)$/.exec(url.pathname);
328
+ if (matches === null || matches.length !== 4 || typeof matches[1] === "undefined" || typeof matches[2] === "undefined") throw new Error("Invalid param: \"options.metafile\" contains invalid metafile url.");
329
+ const cdnId = matches[1];
330
+ const tagId = matches[2];
331
+ return {
332
+ url: metafileUrl,
333
+ baseUrl: url.origin,
334
+ cdnId,
335
+ jsonPath: `/${cdnId}/${tagId}.v2.json`
336
+ };
337
+ }
338
+ };
339
+ //#endregion
340
+ //#region src/cdn/context/metafile-context.ts
341
+ var MetafileContext = class {
342
+ params;
343
+ parsedData;
344
+ data;
345
+ constructor(options) {
346
+ this.params = new MetafileParams(options.metafile);
347
+ this.parsedData = null;
348
+ this.data = MetafileData.createEmpty(this.params);
349
+ }
350
+ setMetafile(metafile) {
351
+ this.parsedData = metafile;
352
+ this.data = new MetafileData(metafile, this.params);
353
+ }
354
+ };
355
+ //#endregion
356
+ //#region src/cdn/http/fetch-http-adapter.ts
357
+ var FetchHttpAdapter = class {
358
+ baseUrl;
359
+ constructor(baseUrl) {
360
+ this.baseUrl = baseUrl;
361
+ }
362
+ async get(url) {
363
+ const response = await fetch(`${this.baseUrl}${url}`);
364
+ const contentType = response.headers.get("content-type");
365
+ const isJson = contentType === "application/json5" || contentType === "application/json";
366
+ if (response.status >= 400) throw new Error(`Request failed with status code ${response.status.toString()}`);
367
+ let result;
368
+ if (isJson) result = await response.json();
369
+ else result = await response.text();
370
+ return result;
371
+ }
372
+ };
373
+ //#endregion
374
+ //#region src/cdn/methods/cdn-base.ts
375
+ var CdnBase = class {
376
+ context;
377
+ constructor(context) {
378
+ this.context = context;
379
+ }
380
+ };
381
+ //#endregion
382
+ //#region src/cdn/methods/cdn-cache.ts
383
+ var CdnCache = class extends CdnBase {
384
+ flush = () => {
385
+ this.context.cache.flush();
386
+ };
387
+ };
388
+ //#endregion
389
+ //#region src/cdn/methods/cdn-metafile.ts
390
+ var CdnMetafile = class extends CdnBase {
391
+ get projectUrl() {
392
+ return this.context.metafile.data.projectUrl;
393
+ }
394
+ get baseLocale() {
395
+ return this.context.metafile.data.baseLocale;
396
+ }
397
+ get url() {
398
+ return this.context.metafile.params.url;
399
+ }
400
+ get files() {
401
+ return this.context.metafile.data.files.map((file) => file.toCdnFile());
402
+ }
403
+ locales = (options) => {
404
+ const { excludeBaseLocale } = options || {};
405
+ const { locales } = this.context.metafile.data;
406
+ return excludeBaseLocale ? locales.filter((cdnLocale) => !cdnLocale.isBaseLocale) : locales;
407
+ };
408
+ refresh = async () => {
409
+ const response = await this.context.api.fetchMetafile();
410
+ this.context.metafile.setMetafile(response);
411
+ };
412
+ switch = async (options) => {
413
+ this.context.metafile.params = new MetafileParams(options.metafile);
414
+ await this.refresh();
415
+ };
416
+ };
417
+ //#endregion
418
+ //#region src/cdn/request/locales-map.ts
419
+ var LocalesMap = class {
420
+ data;
421
+ context;
422
+ constructor(options) {
423
+ this.context = options.context;
424
+ this.data = options.data || {};
425
+ }
426
+ };
427
+ //#endregion
428
+ //#region src/cdn/request/request.ts
429
+ var Request = class {
430
+ files;
431
+ localesMap;
432
+ hasSingleFileResponse;
433
+ hasSingleLocaleResponse;
434
+ context;
435
+ constructor(context) {
436
+ this.files = [];
437
+ this.localesMap = new LocalesMap({ context });
438
+ this.hasSingleFileResponse = false;
439
+ this.hasSingleLocaleResponse = false;
440
+ this.context = context;
441
+ }
442
+ async execute() {
443
+ const payload = this.getPromises();
444
+ const promises = payload.map((item) => item[0]);
445
+ const requests = payload.map((item) => item[1]);
446
+ const responses = await Promise.all(promises);
447
+ return this.context.responseFactory.createCdnResponse({
448
+ requests,
449
+ responses,
450
+ localesMap: this.localesMap,
451
+ hasSingleFileResponse: this.hasSingleFileResponse,
452
+ hasSingleLocaleResponse: this.hasSingleLocaleResponse
453
+ });
454
+ }
455
+ getPromises() {
456
+ return this.files.reduce((acc, cur) => {
457
+ if (typeof this.localesMap.data?.[cur.id] !== "undefined") acc.push(...this.localesMap.data[cur.id].map((metafileLocale) => {
458
+ const request = {
459
+ metafileFile: cur,
460
+ metafileLocale
461
+ };
462
+ return [this.context.api.fetchLocale(request), request];
463
+ }));
464
+ return acc;
465
+ }, []);
466
+ }
467
+ };
468
+ //#endregion
469
+ //#region src/cdn/request/request-builder.ts
470
+ var RequestBuilder = class {
471
+ context;
472
+ request;
473
+ constructor(context) {
474
+ this.context = context;
475
+ this.request = new Request(this.context);
476
+ }
477
+ addFiles(files) {
478
+ if (!(isPlainObject(files) || isString(files) || isUndefined(files) || isArray(files))) throw new Error("Invalid param: \"request.files\" must be object, array, string or undefined.");
479
+ if (isArray(files)) files.forEach((i) => {
480
+ if (!(isPlainObject(i) || isString(i))) throw new Error("Invalid param: array \"request.files\" must contain objects or strings.");
481
+ });
482
+ if (isString(files)) {
483
+ this.request.hasSingleFileResponse = true;
484
+ const file = this.context.metafile.data.files.find((i) => i.id === files);
485
+ if (!(file instanceof MetafileFile)) throw new Error(`File not found: "${files}".`);
486
+ this.request.files = [file];
487
+ } else if (isUndefined(files)) this.request.files = [...this.context.metafile.data.files];
488
+ else if (isArray(files)) this.request.files = files.map((file) => {
489
+ let metafileFile;
490
+ if (isString(file)) {
491
+ const foundFile = this.context.metafile.data.files.find((i) => i.id === file);
492
+ if (isUndefined(foundFile)) throw new Error(`File not found: "${file}".`);
493
+ metafileFile = foundFile;
494
+ } else {
495
+ const foundFile = this.context.metafile.data.files.find((i) => i.id === file.id);
496
+ if (isUndefined(foundFile)) throw new Error(`File not found: "${file.id}".`);
497
+ metafileFile = foundFile;
498
+ }
499
+ return metafileFile;
500
+ });
501
+ else if (isPlainObject(files)) {
502
+ this.request.hasSingleFileResponse = true;
503
+ const foundFile = this.context.metafile.data.files.find((i) => i.id === files.id);
504
+ if (isUndefined(foundFile)) throw new Error(`File not found: "${files.id}".`);
505
+ this.request.files = [foundFile];
506
+ }
507
+ return this;
508
+ }
509
+ addLocales(locales, excludeBaseLocale) {
510
+ if (!(isString(locales) || isUndefined(locales) || isArray(locales))) throw new Error("Invalid param: \"request.locales\" must be array, string or undefined.");
511
+ if (isArray(locales)) locales.forEach((i) => {
512
+ if (!isString(i)) throw new Error("Invalid param: array \"request.locales\" must contain strings.");
513
+ });
514
+ if (isString(locales)) {
515
+ this.request.hasSingleLocaleResponse = true;
516
+ this.request.files.reduce((acc, cur) => {
517
+ acc.data[cur.id] = cur.locales.filter((metafileLocale) => metafileLocale.locale === locales);
518
+ return acc;
519
+ }, this.request.localesMap);
520
+ } else if (isUndefined(locales)) this.request.files.reduce((acc, cur) => {
521
+ acc.data[cur.id] = excludeBaseLocale ? cur.locales.filter((metafileLocale) => !metafileLocale.isBaseLocale) : cur.locales;
522
+ return acc;
523
+ }, this.request.localesMap);
524
+ else if (isArray(locales)) this.request.files.reduce((acc, cur) => {
525
+ acc.data[cur.id] = cur.locales.filter((metafileLocale) => locales.includes(metafileLocale.locale));
526
+ return acc;
527
+ }, this.request.localesMap);
528
+ return this;
529
+ }
530
+ getCdnRequest() {
531
+ const result = this.request;
532
+ this.request = new Request(this.context);
533
+ return result;
534
+ }
535
+ };
536
+ //#endregion
537
+ //#region src/cdn/cdn-client.ts
538
+ var CdnClient = class CdnClient {
539
+ metafile;
540
+ cache;
541
+ context;
542
+ static version = "1.5.14";
543
+ constructor(options) {
544
+ const metafileContext = new MetafileContext(options);
545
+ const client = new FetchHttpAdapter(metafileContext.params.baseUrl);
546
+ this.context = new Context({
547
+ metafileContext,
548
+ cdn: this,
549
+ client
550
+ });
551
+ this.metafile = new CdnMetafile(this.context);
552
+ this.cache = new CdnCache(this.context);
553
+ }
554
+ fetch = async (options) => {
555
+ const { files, locales, excludeBaseLocale } = options || {};
556
+ return new RequestBuilder(this.context).addFiles(files).addLocales(locales, excludeBaseLocale).getCdnRequest().execute();
557
+ };
558
+ static async create(options) {
559
+ if (!options) throw new Error("Invalid param: missing required \"options\" parameter.");
560
+ if (!isString(options.metafile)) throw new Error("Invalid param: \"options.metafile\" must be string.");
561
+ const cdn = new CdnClient(options);
562
+ await cdn.metafile.refresh();
563
+ return cdn;
564
+ }
565
+ };
566
+ //#endregion
618
567
  exports.Api = Api;
619
568
  exports.CdnBase = CdnBase;
620
569
  exports.CdnCache = CdnCache;
@@ -639,4 +588,5 @@ exports.isString = isString;
639
588
  exports.isUndefined = isUndefined;
640
589
  exports.uniq = uniq;
641
590
  exports.uniqBy = uniqBy;
642
- //# sourceMappingURL=localazy-cdn-client.cjs.map
591
+
592
+ //# sourceMappingURL=localazy-cdn-client.cjs.map