@localazy/cdn-client 1.5.13 → 1.5.15

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