synapse-storage 3.0.8 → 3.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/api.cjs CHANGED
@@ -1,890 +1 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/api/index.ts
21
- var api_exports = {};
22
- __export(api_exports, {
23
- ApiClient: () => ApiClient,
24
- ResponseFormat: () => ResponseFormat,
25
- apiLogger: () => apiLogger,
26
- createUniqueId: () => createUniqueId,
27
- headersToObject: () => headersToObject
28
- });
29
- module.exports = __toCommonJS(api_exports);
30
-
31
- // src/api/utils/api-helpers.ts
32
- var apiLogger = {
33
- debug: (message, ...args) => {
34
- if (process.env.NODE_ENV !== "production") {
35
- console.debug(`[API] ${message}`, ...args);
36
- }
37
- },
38
- log: (message, ...args) => {
39
- if (process.env.NODE_ENV !== "production") {
40
- console.log(`[API] ${message}`, ...args);
41
- }
42
- },
43
- info: (message, ...args) => {
44
- console.info(`[API] ${message}`, ...args);
45
- },
46
- warn: (message, ...args) => {
47
- console.warn(`[API] ${message}`, ...args);
48
- },
49
- error: (message, ...args) => {
50
- console.error(`[API] ${message}`, ...args);
51
- }
52
- };
53
- function createUniqueId(name) {
54
- return `${name ? `${name}|` : ""}${Math.random().toString(36).substring(2, 9) + Date.now().toString(36)}`;
55
- }
56
- function headersToObject(headers) {
57
- const result = {};
58
- headers.forEach((value, key) => {
59
- result[key.toLowerCase()] = value;
60
- });
61
- return result;
62
- }
63
-
64
- // src/api/utils/create-header-context.ts
65
- function createHeaderContext(context = {}, optionContext = {}) {
66
- return {
67
- ...context,
68
- ...optionContext,
69
- getFromStorage: context.getFromStorage || ((key) => {
70
- try {
71
- const item = localStorage.getItem(key);
72
- return item ? JSON.parse(item) : void 0;
73
- } catch (error) {
74
- console.warn(`[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0438\u0437 localStorage: ${error}`);
75
- return void 0;
76
- }
77
- }),
78
- getCookie: context.getCookie || ((name) => {
79
- try {
80
- const matches = document.cookie.match(new RegExp(`(?:^|; )${name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, "\\$1")}=([^;]*)`));
81
- return matches ? decodeURIComponent(matches[1]) : void 0;
82
- } catch (error) {
83
- console.warn(`[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F cookie: ${error}`);
84
- return void 0;
85
- }
86
- })
87
- };
88
- }
89
-
90
- // src/api/utils/endpoint-headers.ts
91
- async function prepareRequestHeaders(prepareHeadersFn, context) {
92
- let headers = new Headers();
93
- const headerContext = context || createHeaderContext({}, {});
94
- if (prepareHeadersFn) {
95
- try {
96
- headers = await Promise.resolve(prepareHeadersFn(headers, headerContext));
97
- } catch (error) {
98
- console.warn("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432", error);
99
- }
100
- }
101
- return headers;
102
- }
103
- function createPrepareHeaders(globalPrepareHeaders, endpointPrepareHeaders) {
104
- return async (headers, context) => {
105
- let processedHeaders = new Headers(headers);
106
- if (globalPrepareHeaders) {
107
- try {
108
- processedHeaders = await Promise.resolve(globalPrepareHeaders(processedHeaders, context));
109
- } catch (error) {
110
- console.warn("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0435 \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0445 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432", error);
111
- }
112
- }
113
- if (endpointPrepareHeaders) {
114
- try {
115
- processedHeaders = await Promise.resolve(endpointPrepareHeaders(processedHeaders, context));
116
- } catch (error) {
117
- console.warn("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432 \u044D\u043D\u0434\u043F\u043E\u0438\u043D\u0442\u0430", error);
118
- }
119
- }
120
- return processedHeaders;
121
- };
122
- }
123
-
124
- // src/api/types/api.interface.ts
125
- var ResponseFormat = /* @__PURE__ */ ((ResponseFormat2) => {
126
- ResponseFormat2["Json"] = "json";
127
- ResponseFormat2["Blob"] = "blob";
128
- ResponseFormat2["ArrayBuffer"] = "arrayBuffer";
129
- ResponseFormat2["Text"] = "text";
130
- ResponseFormat2["FormData"] = "formData";
131
- ResponseFormat2["Raw"] = "raw";
132
- return ResponseFormat2;
133
- })(ResponseFormat || {});
134
-
135
- // src/api/utils/file-utils.ts
136
- function getResponseFormatForMimeType(contentType) {
137
- const type = contentType.toLowerCase().split(";")[0].trim();
138
- if (type.includes("application/json")) {
139
- return "json" /* Json */;
140
- }
141
- if (type.includes("text/")) {
142
- return "text" /* Text */;
143
- }
144
- if (type.includes("multipart/form-data")) {
145
- return "formData" /* FormData */;
146
- }
147
- if (type.includes("application/octet-stream") || type.includes("application/pdf") || type.includes("image/") || type.includes("audio/") || type.includes("video/")) {
148
- return "blob" /* Blob */;
149
- }
150
- return void 0;
151
- }
152
- function isFileResponse(headers) {
153
- const contentType = headers.get("content-type") || "";
154
- const contentDisposition = headers.get("content-disposition") || "";
155
- const isFileContentType = contentType.includes("application/octet-stream") || contentType.includes("application/pdf") || contentType.includes("image/") || contentType.includes("audio/") || contentType.includes("video/");
156
- const isAttachment = contentDisposition.includes("attachment") || contentDisposition.includes("filename=");
157
- return isFileContentType || isAttachment;
158
- }
159
- function extractFilenameFromHeaders(headers) {
160
- const contentDisposition = headers.get("content-disposition");
161
- if (!contentDisposition) return void 0;
162
- const filenameMatch = contentDisposition.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);
163
- if (filenameMatch && filenameMatch[1]) {
164
- return filenameMatch[1].replace(/['"]/g, "").trim();
165
- }
166
- return void 0;
167
- }
168
- function getFileMetadataFromHeaders(headers) {
169
- const contentType = headers.get("content-type") || "";
170
- const contentDisposition = headers.get("content-disposition") || "";
171
- const contentLength = headers.get("content-length");
172
- if (!isFileResponse(headers)) {
173
- return void 0;
174
- }
175
- const filename = extractFilenameFromHeaders(headers);
176
- return {
177
- filename,
178
- contentType,
179
- contentDisposition,
180
- size: contentLength ? parseInt(contentLength, 10) : void 0
181
- };
182
- }
183
-
184
- // src/api/utils/fetch-base-query.ts
185
- async function getResponseData(response, format) {
186
- let responseFormat = format;
187
- const contentType = response.headers.get("content-type") || "";
188
- if (!responseFormat && contentType) {
189
- if (isFileResponse(response.headers)) {
190
- responseFormat = "blob" /* Blob */;
191
- } else {
192
- responseFormat = getResponseFormatForMimeType(contentType);
193
- }
194
- }
195
- if (!responseFormat) {
196
- responseFormat = "json" /* Json */;
197
- }
198
- try {
199
- let fileMetadata;
200
- if (responseFormat === "blob" /* Blob */ || responseFormat === "arrayBuffer" /* ArrayBuffer */) {
201
- fileMetadata = getFileMetadataFromHeaders(response.headers);
202
- }
203
- switch (responseFormat) {
204
- case "json" /* Json */: {
205
- try {
206
- const data = await response.json();
207
- return response.ok ? { data, fileMetadata } : { error: data, fileMetadata };
208
- } catch (error) {
209
- const text = await response.text();
210
- return response.ok ? { data: text, fileMetadata } : { error: text, fileMetadata };
211
- }
212
- }
213
- case "text" /* Text */: {
214
- const text = await response.text();
215
- return response.ok ? { data: text, fileMetadata } : { error: text, fileMetadata };
216
- }
217
- case "blob" /* Blob */: {
218
- const blob2 = await response.blob();
219
- return response.ok ? { data: blob2, fileMetadata } : { error: blob2, fileMetadata };
220
- }
221
- case "arrayBuffer" /* ArrayBuffer */: {
222
- const buffer = await response.arrayBuffer();
223
- return response.ok ? { data: buffer, fileMetadata } : { error: buffer, fileMetadata };
224
- }
225
- case "formData" /* FormData */: {
226
- const formData = await response.formData();
227
- return response.ok ? { data: formData, fileMetadata } : { error: formData, fileMetadata };
228
- }
229
- case "raw" /* Raw */: {
230
- return response.ok ? { data: response, fileMetadata } : { error: response, fileMetadata };
231
- }
232
- default:
233
- const blob = await response.blob();
234
- return response.ok ? { data: blob, fileMetadata } : { error: blob, fileMetadata };
235
- }
236
- } catch (err) {
237
- console.error(`[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0438\u0437\u0432\u043B\u0435\u0447\u0435\u043D\u0438\u044F \u0434\u0430\u043D\u043D\u044B\u0445 \u0438\u0437 \u043E\u0442\u0432\u0435\u0442\u0430 (\u0444\u043E\u0440\u043C\u0430\u0442: ${responseFormat})`, err);
238
- return response.ok ? { data: void 0 } : { error: err };
239
- }
240
- }
241
- function fetchBaseQuery(options) {
242
- const { baseUrl, timeout = 3e4, fetchFn = fetch, credentials = "same-origin" } = options;
243
- return async (args, queryOptions = {}, headers) => {
244
- const { path, method, body, query, responseFormat: reqResponseFormat } = args;
245
- const { signal, timeout: requestTimeout = timeout, responseFormat: optResponseFormat } = queryOptions;
246
- const responseFormat = optResponseFormat || reqResponseFormat;
247
- const url = new URL(path.startsWith("http") ? path : `${baseUrl}${path}`);
248
- if (query) {
249
- Object.entries(query).forEach(([key, value]) => {
250
- if (value !== void 0 && value !== null) {
251
- if (Array.isArray(value)) {
252
- value.forEach((item) => url.searchParams.append(key, String(item)));
253
- } else {
254
- url.searchParams.append(key, String(value));
255
- }
256
- }
257
- });
258
- }
259
- let serializedBody;
260
- if (body !== void 0) {
261
- if (body instanceof FormData || body instanceof Blob) {
262
- serializedBody = body;
263
- } else if (typeof body === "object" && body !== null) {
264
- try {
265
- serializedBody = JSON.stringify(body);
266
- if (!headers.has("Content-Type")) {
267
- headers.set("Content-Type", "application/json");
268
- }
269
- } catch (error) {
270
- console.error("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0441\u0435\u0440\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u043B\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u0430", error);
271
- serializedBody = String(body);
272
- }
273
- } else {
274
- serializedBody = String(body);
275
- }
276
- }
277
- let timeoutId;
278
- const timeoutPromise = new Promise((_, reject) => {
279
- if (requestTimeout) {
280
- timeoutId = window.setTimeout(() => {
281
- reject(new Error(`\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D\u043E \u0432\u0440\u0435\u043C\u044F \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u0430 (${requestTimeout}\u043C\u0441)`));
282
- }, requestTimeout);
283
- }
284
- });
285
- try {
286
- const fetchPromise = fetchFn(url.toString(), {
287
- method,
288
- headers,
289
- body: serializedBody,
290
- signal,
291
- credentials
292
- });
293
- const response = await Promise.race([fetchPromise, timeoutPromise]);
294
- const { data, error, fileMetadata } = await getResponseData(response, responseFormat);
295
- const result = {
296
- data,
297
- error,
298
- ok: response.ok,
299
- status: response.status,
300
- statusText: response.statusText,
301
- headers: response.headers,
302
- fileDownloadResult: fileMetadata
303
- };
304
- return result;
305
- } catch (err) {
306
- const error = err;
307
- console.error("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u0430", error);
308
- return {
309
- error,
310
- ok: false,
311
- status: 0,
312
- statusText: error.message,
313
- headers: new Headers()
314
- };
315
- } finally {
316
- if (timeoutId) {
317
- window.clearTimeout(timeoutId);
318
- }
319
- }
320
- };
321
- }
322
-
323
- // src/api/utils/get-cacheable-headers.ts
324
- function getCacheableHeaders(headers, cacheableHeaders = []) {
325
- const result = {};
326
- if (!headers || cacheableHeaders.length === 0) {
327
- return result;
328
- }
329
- cacheableHeaders.forEach((key) => {
330
- if (headers.has(key)) {
331
- result[key] = headers.get(key) || "";
332
- }
333
- });
334
- return result;
335
- }
336
-
337
- // src/api/components/endpoint.ts
338
- var EndpointClass = class {
339
- constructor(name, queryStorage, configCurrentEndpoint, cacheableHeaderKeys, globalCacheConfig, baseQueryConfig) {
340
- this.name = name;
341
- this.queryStorage = queryStorage;
342
- this.configCurrentEndpoint = configCurrentEndpoint;
343
- this.cacheableHeaderKeys = cacheableHeaderKeys;
344
- this.globalCacheConfig = globalCacheConfig;
345
- this.baseQueryConfig = baseQueryConfig;
346
- this.prepareHeaders = createPrepareHeaders(baseQueryConfig.prepareHeaders, configCurrentEndpoint.prepareHeaders);
347
- this.queryFunction = fetchBaseQuery({
348
- baseUrl: baseQueryConfig.baseUrl,
349
- fetchFn: baseQueryConfig.fetchFn,
350
- timeout: baseQueryConfig.timeout,
351
- credentials: baseQueryConfig.credentials
352
- });
353
- this.cacheableHeaders = [...cacheableHeaderKeys || [], ...configCurrentEndpoint.includeCacheableHeaderKeys || []].filter(
354
- (key) => !configCurrentEndpoint.excludeCacheableHeaderKeys?.includes(key)
355
- );
356
- this.meta.name = name;
357
- this.meta.tags = configCurrentEndpoint.tags ?? this.meta.tags;
358
- this.meta.invalidatesTags = configCurrentEndpoint.invalidatesTags ?? this.meta.invalidatesTags;
359
- this.meta.cache = this.queryStorage.createCacheConfig(this.configCurrentEndpoint) ?? this.meta.cache;
360
- }
361
- endpointSubscribers = /* @__PURE__ */ new Set();
362
- /** Сколько раз был вызван метод request */
363
- fetchCounts = 0;
364
- meta = {
365
- cache: false,
366
- invalidatesTags: [],
367
- name: "",
368
- tags: []
369
- };
370
- queryFunction;
371
- /** Массив заголовков, которые нужно включить в ключ кэширования */
372
- cacheableHeaders;
373
- prepareHeaders;
374
- request(params, options) {
375
- this.fetchCounts++;
376
- const requestId = createUniqueId(this.name);
377
- const controller = new AbortController();
378
- const requestSubscribers = /* @__PURE__ */ new Set();
379
- const currentState = {
380
- status: "idle",
381
- requestParams: params,
382
- headers: {},
383
- error: void 0,
384
- data: void 0,
385
- fromCache: false
386
- };
387
- const headerContext = createHeaderContext({ requestParams: params }, options?.context || {});
388
- const notifyRequestSubscribers = (newState) => {
389
- Object.assign(currentState, newState);
390
- requestSubscribers.forEach((cb) => {
391
- cb({ ...currentState });
392
- });
393
- };
394
- const waitPromise = new Promise(async (resolve, reject) => {
395
- try {
396
- const headers = await prepareRequestHeaders(this.prepareHeaders, headerContext);
397
- const headersForCache = getCacheableHeaders(headers, options?.cacheableHeaderKeys ? options.cacheableHeaderKeys : this.cacheableHeaders);
398
- const shouldCache = this.queryStorage.shouldCache(this.configCurrentEndpoint, options);
399
- const [cacheKey, cacheParams] = this.queryStorage.createCacheKey(this.name, { ...params, ...headersForCache });
400
- let cachedResult;
401
- if (shouldCache) {
402
- cachedResult = await this.queryStorage.getCachedResult(cacheKey);
403
- }
404
- if (cachedResult) {
405
- notifyRequestSubscribers({
406
- fromCache: true,
407
- status: "success",
408
- data: cachedResult.data,
409
- error: void 0,
410
- headers: cachedResult.headers,
411
- requestParams: params
412
- });
413
- resolve({
414
- ...cachedResult,
415
- fromCache: true
416
- });
417
- } else {
418
- notifyRequestSubscribers({
419
- fromCache: false,
420
- status: "loading"
421
- });
422
- const requestDefinition = this.configCurrentEndpoint.request(params, options?.context);
423
- const mergedOptions = { ...options, signal: controller.signal };
424
- const response = await this.queryFunction(requestDefinition, mergedOptions, headers);
425
- if (response.ok) {
426
- const { headers: headers2, ...restResponse } = response;
427
- if (shouldCache) {
428
- const currentCacheConfig = this.queryStorage.createCacheConfig(this.configCurrentEndpoint);
429
- await this.queryStorage.setCachedResult(
430
- cacheKey,
431
- { ...restResponse, headers: headersToObject(headers2) },
432
- currentCacheConfig,
433
- cacheParams ?? {},
434
- this.configCurrentEndpoint.tags ?? [],
435
- this.configCurrentEndpoint.invalidatesTags ?? []
436
- );
437
- }
438
- notifyRequestSubscribers({
439
- fromCache: false,
440
- status: "success",
441
- data: response.data,
442
- error: void 0,
443
- headers: response.headers,
444
- requestParams: params
445
- });
446
- this.endpointSubscribers.forEach((cb) => {
447
- const endpointState = {
448
- status: "success",
449
- fetchCounts: this.fetchCounts,
450
- meta: this.meta,
451
- cacheableHeaders: this.cacheableHeaders,
452
- error: void 0
453
- };
454
- cb(endpointState);
455
- });
456
- resolve({
457
- ...response,
458
- fromCache: false
459
- });
460
- } else {
461
- notifyRequestSubscribers({
462
- fromCache: false,
463
- status: "error",
464
- data: void 0,
465
- error: response.error,
466
- headers: response.headers,
467
- requestParams: params
468
- });
469
- this.endpointSubscribers.forEach((cb) => {
470
- const endpointState = {
471
- status: "error",
472
- fetchCounts: this.fetchCounts,
473
- meta: this.meta,
474
- cacheableHeaders: this.cacheableHeaders,
475
- error: response.error
476
- };
477
- cb(endpointState);
478
- });
479
- reject(response.error);
480
- }
481
- }
482
- } catch (error) {
483
- notifyRequestSubscribers({
484
- fromCache: false,
485
- status: "error",
486
- data: void 0,
487
- error,
488
- headers: void 0,
489
- requestParams: params
490
- });
491
- reject(error);
492
- }
493
- });
494
- return {
495
- id: requestId,
496
- subscribe(listener, options2 = {}) {
497
- const { autoUnsubscribe = true } = options2;
498
- requestSubscribers.add(listener);
499
- listener(currentState);
500
- const unsubscribe = () => requestSubscribers.delete(listener);
501
- if (autoUnsubscribe) {
502
- waitPromise.finally(() => {
503
- unsubscribe();
504
- });
505
- }
506
- return unsubscribe;
507
- },
508
- wait: () => waitPromise,
509
- waitWithCallbacks(handlers = {}) {
510
- const { idle, loading, success, error } = handlers;
511
- this.subscribe(
512
- (state) => {
513
- switch (state.status) {
514
- case "idle":
515
- idle?.(state);
516
- break;
517
- case "loading":
518
- loading?.(state);
519
- break;
520
- case "success":
521
- success?.(state.data, state);
522
- break;
523
- case "error":
524
- error?.(state.error, state);
525
- break;
526
- }
527
- },
528
- { autoUnsubscribe: true }
529
- );
530
- return waitPromise;
531
- },
532
- abort: () => {
533
- if (controller && !controller.signal.aborted) {
534
- controller.abort();
535
- }
536
- },
537
- then: (onfulfilled, onrejected) => waitPromise.then(onfulfilled, onrejected),
538
- catch: (onrejected) => waitPromise.catch(onrejected),
539
- finally: (onfinally) => waitPromise.finally(onfinally)
540
- };
541
- }
542
- subscribe(cb) {
543
- this.endpointSubscribers.add(cb);
544
- const currentState = {
545
- status: "idle",
546
- fetchCounts: this.fetchCounts,
547
- meta: this.meta,
548
- cacheableHeaders: this.cacheableHeaders,
549
- error: void 0
550
- };
551
- cb(currentState);
552
- return () => this.endpointSubscribers.delete(cb);
553
- }
554
- reset() {
555
- this.fetchCounts = 0;
556
- return Promise.resolve();
557
- }
558
- destroy() {
559
- this.endpointSubscribers.clear();
560
- }
561
- };
562
-
563
- // src/core/storage/utils/storage-key.ts
564
- var StorageKey = class {
565
- constructor(value, isRawKey = false) {
566
- this.value = value;
567
- this.isRawKey = isRawKey;
568
- }
569
- toString() {
570
- return this.value;
571
- }
572
- toJSON() {
573
- return this.value;
574
- }
575
- valueOf() {
576
- return this.value;
577
- }
578
- isUnparseable() {
579
- return this.isRawKey;
580
- }
581
- };
582
-
583
- // src/core/storage/utils/cache.util.ts
584
- var CacheUtils = class {
585
- static createMetadata(ttl = 0, tags = []) {
586
- const now = Date.now();
587
- const expiresAt = ttl > 0 ? now + ttl : Infinity;
588
- return {
589
- createdAt: now,
590
- updatedAt: now,
591
- expiresAt,
592
- tags,
593
- createdAtDateTime: this.formatDateTime(now),
594
- updatedAtDateTime: this.formatDateTime(now),
595
- expiresAtDateTime: expiresAt === Infinity ? "never" : this.formatDateTime(expiresAt)
596
- };
597
- }
598
- static formatDateTime(timestamp) {
599
- return new Date(timestamp).toISOString();
600
- }
601
- static isExpired(metadata) {
602
- return Date.now() > metadata.expiresAt;
603
- }
604
- static updateMetadata(metadata) {
605
- return {
606
- ...metadata,
607
- updatedAt: Date.now()
608
- };
609
- }
610
- static createKey(...parts) {
611
- return new StorageKey(parts.join("_"));
612
- }
613
- static createApiKey(endpoint, params) {
614
- if (!params) return [new StorageKey(endpoint, true), params];
615
- const sortedParams = Object.entries(params).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}=${v}`).join("&");
616
- return [new StorageKey(`${endpoint}_${sortedParams}`, true), params];
617
- }
618
- // Функция для проверки, есть ли у записи определенные теги
619
- static hasAnyTag(metadata, tags = []) {
620
- if (!metadata.tags || !tags.length) return false;
621
- return tags.some((tag) => metadata.tags?.includes(tag));
622
- }
623
- };
624
-
625
- // src/api/components/query-storage.ts
626
- var QueryStorage = class {
627
- constructor(storageExternal, globalCacheConfig) {
628
- this.storageExternal = storageExternal;
629
- this.globalCacheConfig = globalCacheConfig;
630
- }
631
- /** Экземпляр хранилища */
632
- storage = null;
633
- cleanupInterval = null;
634
- /** Настройки кэша по умолчанию */
635
- defaultCacheOptions = {
636
- ttl: 5 * 60 * 1e3,
637
- // 5 минут по умолчанию
638
- cleanup: {
639
- enabled: true,
640
- interval: 10 * 60 * 1e3
641
- // 10 минут
642
- },
643
- invalidateOnError: true
644
- };
645
- async initialize() {
646
- await this.createStorage();
647
- this.startCleanupInterval();
648
- return this;
649
- }
650
- async createStorage() {
651
- try {
652
- const s = this.storageExternal;
653
- await s.initialize();
654
- this.storage = s;
655
- } catch (error) {
656
- console.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430", error);
657
- throw error;
658
- }
659
- }
660
- startCleanupInterval() {
661
- if (this.cleanupInterval) {
662
- clearInterval(this.cleanupInterval);
663
- this.cleanupInterval = null;
664
- }
665
- const cleanupConfig = typeof this.globalCacheConfig === "object" ? this.globalCacheConfig.cleanup : this.defaultCacheOptions.cleanup;
666
- if (cleanupConfig?.enabled && cleanupConfig.interval) {
667
- this.cleanupInterval = setInterval(() => {
668
- this.cleanup().catch((err) => console.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0447\u0438\u0441\u0442\u043A\u0435 \u043A\u044D\u0448\u0430:", err));
669
- }, cleanupConfig.interval);
670
- }
671
- }
672
- /**
673
- * Получает экземпляр хранилища
674
- */
675
- getStorage() {
676
- return this.storage;
677
- }
678
- /**
679
- * Создает ключ кэша для запроса с учетом заголовков
680
- * @param endpoint Имя эндпоинта
681
- * @param params Параметры запроса (все что посчитаем нужным)
682
- */
683
- createCacheKey(endpoint, params) {
684
- return CacheUtils.createApiKey(endpoint, params);
685
- }
686
- /**
687
- * Получает результат запроса из кэша
688
- */
689
- async getCachedResult(cacheKey) {
690
- if (!this.storage) throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");
691
- const cachedEntry = await this.storage.get(cacheKey);
692
- if (!cachedEntry) return void 0;
693
- if (CacheUtils.isExpired(cachedEntry.metadata)) {
694
- await this.storage.delete(cacheKey);
695
- return void 0;
696
- }
697
- const updatedEntry = {
698
- ...cachedEntry,
699
- metadata: CacheUtils.updateMetadata(cachedEntry.metadata)
700
- };
701
- await this.storage.set(cacheKey, updatedEntry);
702
- return cachedEntry.data;
703
- }
704
- /**
705
- * Сохраняет результат запроса в кэш
706
- * @param cacheKey Ключ кэша
707
- * @param data Данные для кэширования
708
- * @param cacheOptions Метаданные
709
- * @param cacheParams Параметры которые влияли на созадние ключа
710
- * @param tags Тэги эндпоинта
711
- * @param invalidatesTags Тэги которые нужно инвалидировать
712
- */
713
- async setCachedResult(cacheKey, data, cacheOptions, cacheParams, tags, invalidatesTags) {
714
- if (!this.storage) throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");
715
- if (invalidatesTags?.length) {
716
- await this.invalidateCacheByTags(invalidatesTags);
717
- }
718
- const cacheMetadata = CacheUtils.createMetadata(cacheOptions.ttl, tags);
719
- const cacheEntry = {
720
- data,
721
- metadata: cacheMetadata,
722
- params: cacheParams
723
- };
724
- await this.storage.set(cacheKey, cacheEntry);
725
- }
726
- /**
727
- * Проверяет, должен ли запрос быть кэширован
728
- * @param endpointConfig Конфигурация эндпоинта
729
- * @param options Опции запроса
730
- * @returns true если запрос должен кэшироваться
731
- */
732
- shouldCache(endpointConfig, options) {
733
- if (this.globalCacheConfig === false) return false;
734
- if (endpointConfig?.cache === false) return false;
735
- if (typeof endpointConfig?.cache === "object" && endpointConfig?.cache.ttl === 0) return false;
736
- if (options?.disableCache === true) return false;
737
- if (this.globalCacheConfig === void 0 && endpointConfig?.cache === void 0) return false;
738
- return true;
739
- }
740
- /**
741
- * Создает итоговую конфигурацию кэширования для конкретного эндпоинта
742
- * Объединяет глабальный конфиг с текущим
743
- * @param endpointConfig Конфигурация эндпоинта
744
- */
745
- createCacheConfig(endpointConfig) {
746
- let resultConfig = this.defaultCacheOptions;
747
- if (typeof this.globalCacheConfig === "object") {
748
- resultConfig = this.globalCacheConfig;
749
- }
750
- if (typeof endpointConfig?.cache === "object") {
751
- const endpointCache = endpointConfig.cache;
752
- resultConfig = {
753
- // @ts-ignore
754
- ...resultConfig,
755
- ...endpointCache
756
- };
757
- }
758
- return resultConfig;
759
- }
760
- /**
761
- * Инвалидирует кэш по тегам
762
- * @param tags Теги для инвалидации
763
- */
764
- async invalidateCacheByTags(tags) {
765
- if (!this.storage) throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");
766
- const keys = await this.storage.keys();
767
- for (const key of keys) {
768
- const cachedEntry = await this.storage.get(key);
769
- if (cachedEntry && CacheUtils.hasAnyTag(cachedEntry.metadata, tags)) {
770
- await this.storage.delete(key);
771
- }
772
- }
773
- }
774
- /**
775
- * Инвалидирует кэш по ключу
776
- * @param cacheKey Ключ кэша
777
- */
778
- async invalidateCache(cacheKey) {
779
- if (!this.storage) throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");
780
- await this.storage.delete(cacheKey);
781
- }
782
- /**
783
- * Выполняет очистку всех просроченных записей кэша
784
- */
785
- async cleanup() {
786
- if (!this.storage) {
787
- throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");
788
- }
789
- const keys = await this.storage.keys();
790
- for (const key of keys) {
791
- const value = await this.storage.get(key);
792
- if (value && CacheUtils.isExpired(value.metadata)) {
793
- await this.storage.delete(key);
794
- }
795
- }
796
- }
797
- /**
798
- * Уничтожает хранилище и освобождает ресурсы
799
- */
800
- async destroy() {
801
- if (this.cleanupInterval) {
802
- window.clearInterval(this.cleanupInterval);
803
- this.cleanupInterval = null;
804
- }
805
- if (this.storage) {
806
- await this.storage.destroy();
807
- this.storage = null;
808
- }
809
- }
810
- };
811
-
812
- // src/api/api.module.ts
813
- var ApiClient = class {
814
- /** Хранилище запросов */
815
- // @ts-ignore
816
- queryStorage;
817
- cacheableHeaderKeys;
818
- globalCacheConfig;
819
- baseQueryConfig;
820
- storageExternal;
821
- createEndpoints;
822
- /** Реестр эндпоинтов */
823
- endpoints = {};
824
- constructor(options) {
825
- this.cacheableHeaderKeys = options.cacheableHeaderKeys;
826
- this.globalCacheConfig = options.cache;
827
- this.baseQueryConfig = options.baseQuery;
828
- this.storageExternal = options.storage;
829
- this.createEndpoints = options.endpoints;
830
- }
831
- async init() {
832
- this.queryStorage = await new QueryStorage(this.storageExternal, this.globalCacheConfig).initialize();
833
- await this.initializeEndpoints();
834
- return this;
835
- }
836
- async initializeEndpoints() {
837
- const create = (config) => config;
838
- const endpointsConfig = await this.createEndpoints(create) || {};
839
- for (const [endpointKey, endpointConfig] of Object.entries(endpointsConfig)) {
840
- const key = endpointKey;
841
- this.endpoints[key] = new EndpointClass(endpointKey, this.queryStorage, endpointConfig, this.cacheableHeaderKeys, this.globalCacheConfig, this.baseQueryConfig);
842
- }
843
- }
844
- /**
845
- * Получает все эндпоинты с улучшенной типизацией
846
- * @returns Типизированный объект эндпоинтов
847
- */
848
- getEndpoints() {
849
- return this.endpoints;
850
- }
851
- /**
852
- * Выполняет запрос к API с типизацией и обработкой ошибок
853
- * @param endpointName Имя эндпоинта (с подсказками TypeScript)
854
- * @param params Параметры запроса (с типизацией)
855
- * @param options Опции запроса
856
- * @returns Promise с типизированным результатом запроса
857
- */
858
- async request(endpointName, params, options) {
859
- const endpoints = this.getEndpoints();
860
- const endpoint = endpoints[endpointName];
861
- if (!endpoint) {
862
- throw new Error(`\u042D\u043D\u0434\u043F\u043E\u0438\u043D\u0442 ${String(endpointName)} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D`);
863
- }
864
- try {
865
- const stateRequest = endpoint.request(params, options);
866
- return await stateRequest.wait();
867
- } catch (error) {
868
- apiLogger.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u0430 \u043A ${String(endpointName)}`, { error, params });
869
- throw error;
870
- }
871
- }
872
- async destroy() {
873
- await Promise.all(
874
- Object.values(this.endpoints).map(async (endpoint) => {
875
- endpoint.destroy();
876
- return Promise.resolve();
877
- })
878
- );
879
- this.endpoints = {};
880
- await this.queryStorage.destroy();
881
- }
882
- };
883
- // Annotate the CommonJS export names for ESM import in node:
884
- 0 && (module.exports = {
885
- ApiClient,
886
- ResponseFormat,
887
- apiLogger,
888
- createUniqueId,
889
- headersToObject
890
- });
1
+ "use strict";var H=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var _=(r,e)=>{for(var t in e)H(r,t,{get:e[t],enumerable:!0})},V=(r,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of z(e))!N.call(r,n)&&n!==t&&H(r,n,{get:()=>e[n],enumerable:!(a=J(e,n))||a.enumerable});return r};var W=r=>V(H({},"__esModule",{value:!0}),r);var Y={};_(Y,{ApiClient:()=>K,ResponseFormat:()=>T,apiLogger:()=>k,createUniqueId:()=>O,headersToObject:()=>I});module.exports=W(Y);var k={debug:(r,...e)=>{process.env.NODE_ENV!=="production"&&console.debug(`[API] ${r}`,...e)},log:(r,...e)=>{process.env.NODE_ENV!=="production"&&console.log(`[API] ${r}`,...e)},info:(r,...e)=>{console.info(`[API] ${r}`,...e)},warn:(r,...e)=>{console.warn(`[API] ${r}`,...e)},error:(r,...e)=>{console.error(`[API] ${r}`,...e)}};function O(r){return`${r?`${r}|`:""}${Math.random().toString(36).substring(2,9)+Date.now().toString(36)}`}function I(r){let e={};return r.forEach((t,a)=>{e[a.toLowerCase()]=t}),e}function q(r={},e={}){return{...r,...e,getFromStorage:r.getFromStorage||(t=>{try{let a=localStorage.getItem(t);return a?JSON.parse(a):void 0}catch(a){console.warn(`[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0438\u0437 localStorage: ${a}`);return}}),getCookie:r.getCookie||(t=>{try{let a=document.cookie.match(new RegExp(`(?:^|; )${t.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g,"\\$1")}=([^;]*)`));return a?decodeURIComponent(a[1]):void 0}catch(a){console.warn(`[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F cookie: ${a}`);return}})}}async function Q(r,e){let t=new Headers,a=e||q({},{});if(r)try{t=await Promise.resolve(r(t,a))}catch(n){console.warn("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432",n)}return t}function B(r,e){return async(t,a)=>{let n=new Headers(t);if(r)try{n=await Promise.resolve(r(n,a))}catch(i){console.warn("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0435 \u0433\u043B\u043E\u0431\u0430\u043B\u044C\u043D\u044B\u0445 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432",i)}if(e)try{n=await Promise.resolve(e(n,a))}catch(i){console.warn("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432 \u044D\u043D\u0434\u043F\u043E\u0438\u043D\u0442\u0430",i)}return n}}var T=(s=>(s.Json="json",s.Blob="blob",s.ArrayBuffer="arrayBuffer",s.Text="text",s.FormData="formData",s.Raw="raw",s))(T||{});function M(r){let e=r.toLowerCase().split(";")[0].trim();if(e.includes("application/json"))return"json";if(e.includes("text/"))return"text";if(e.includes("multipart/form-data"))return"formData";if(e.includes("application/octet-stream")||e.includes("application/pdf")||e.includes("image/")||e.includes("audio/")||e.includes("video/"))return"blob"}function D(r){let e=r.get("content-type")||"",t=r.get("content-disposition")||"",a=e.includes("application/octet-stream")||e.includes("application/pdf")||e.includes("image/")||e.includes("audio/")||e.includes("video/"),n=t.includes("attachment")||t.includes("filename=");return a||n}function G(r){let e=r.get("content-disposition");if(!e)return;let t=e.match(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/);if(t&&t[1])return t[1].replace(/['"]/g,"").trim()}function $(r){let e=r.get("content-type")||"",t=r.get("content-disposition")||"",a=r.get("content-length");return D(r)?{filename:G(r),contentType:e,contentDisposition:t,size:a?parseInt(a,10):void 0}:void 0}async function X(r,e){let t=e,a=r.headers.get("content-type")||"";!t&&a&&(D(r.headers)?t="blob":t=M(a)),t||(t="json");try{let n;switch((t==="blob"||t==="arrayBuffer")&&(n=$(r.headers)),t){case"json":try{let s=await r.json();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}catch{let l=await r.text();return r.ok?{data:l,fileMetadata:n}:{error:l,fileMetadata:n}}case"text":{let s=await r.text();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"blob":{let s=await r.blob();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"arrayBuffer":{let s=await r.arrayBuffer();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"formData":{let s=await r.formData();return r.ok?{data:s,fileMetadata:n}:{error:s,fileMetadata:n}}case"raw":return r.ok?{data:r,fileMetadata:n}:{error:r,fileMetadata:n};default:let i=await r.blob();return r.ok?{data:i,fileMetadata:n}:{error:i,fileMetadata:n}}}catch(n){return console.error(`[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0438\u0437\u0432\u043B\u0435\u0447\u0435\u043D\u0438\u044F \u0434\u0430\u043D\u043D\u044B\u0445 \u0438\u0437 \u043E\u0442\u0432\u0435\u0442\u0430 (\u0444\u043E\u0440\u043C\u0430\u0442: ${t})`,n),r.ok?{data:void 0}:{error:n}}}function U(r){let{baseUrl:e,timeout:t=3e4,fetchFn:a=fetch,credentials:n="same-origin"}=r;return async(i,s={},l)=>{let{path:h,method:C,body:o,query:u,responseFormat:f}=i,{signal:b,timeout:R=t,responseFormat:p}=s,A=p||f,m=new URL(h.startsWith("http")?h:`${e}${h}`);u&&Object.entries(u).forEach(([d,c])=>{c!=null&&(Array.isArray(c)?c.forEach(w=>m.searchParams.append(d,String(w))):m.searchParams.append(d,String(c)))});let E;if(o!==void 0)if(o instanceof FormData||o instanceof Blob)E=o;else if(typeof o=="object"&&o!==null)try{E=JSON.stringify(o),l.has("Content-Type")||l.set("Content-Type","application/json")}catch(d){console.error("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0441\u0435\u0440\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u0442\u0435\u043B\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u0430",d),E=String(o)}else E=String(o);let P,g=new Promise((d,c)=>{R&&(P=window.setTimeout(()=>{c(new Error(`\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D\u043E \u0432\u0440\u0435\u043C\u044F \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u0430 (${R}\u043C\u0441)`))},R))});try{let d=a(m.toString(),{method:C,headers:l,body:E,signal:b,credentials:n}),c=await Promise.race([d,g]),{data:w,error:F,fileMetadata:L}=await X(c,A);return{data:w,error:F,ok:c.ok,status:c.status,statusText:c.statusText,headers:c.headers,fileDownloadResult:L}}catch(d){let c=d;return console.error("[API] \u041E\u0448\u0438\u0431\u043A\u0430 \u0432\u044B\u043F\u043E\u043B\u043D\u0435\u043D\u0438\u044F \u0437\u0430\u043F\u0440\u043E\u0441\u0430",c),{error:c,ok:!1,status:0,statusText:c.message,headers:new Headers}}finally{P&&window.clearTimeout(P)}}}function j(r,e=[]){let t={};return!r||e.length===0||e.forEach(a=>{r.has(a)&&(t[a]=r.get(a)||"")}),t}var v=class{constructor(e,t,a,n,i,s){this.name=e;this.queryStorage=t;this.configCurrentEndpoint=a;this.cacheableHeaderKeys=n;this.globalCacheConfig=i;this.baseQueryConfig=s;this.prepareHeaders=B(s.prepareHeaders,a.prepareHeaders),this.queryFunction=U({baseUrl:s.baseUrl,fetchFn:s.fetchFn,timeout:s.timeout,credentials:s.credentials}),this.cacheableHeaders=[...n||[],...a.includeCacheableHeaderKeys||[]].filter(l=>!a.excludeCacheableHeaderKeys?.includes(l)),this.meta.name=e,this.meta.tags=a.tags??this.meta.tags,this.meta.invalidatesTags=a.invalidatesTags??this.meta.invalidatesTags,this.meta.cache=this.queryStorage.createCacheConfig(this.configCurrentEndpoint)??this.meta.cache}endpointSubscribers=new Set;fetchCounts=0;meta={cache:!1,invalidatesTags:[],name:"",tags:[]};queryFunction;cacheableHeaders;prepareHeaders;request(e,t){this.fetchCounts++;let a=O(this.name),n=new AbortController,i=new Set,s={status:"idle",requestParams:e,headers:{},error:void 0,data:void 0,fromCache:!1},l=q({requestParams:e},t?.context||{}),h=o=>{Object.assign(s,o),i.forEach(u=>{u({...s})})},C=new Promise(async(o,u)=>{try{let f=await Q(this.prepareHeaders,l),b=j(f,t?.cacheableHeaderKeys?t.cacheableHeaderKeys:this.cacheableHeaders),R=this.queryStorage.shouldCache(this.configCurrentEndpoint,t),[p,A]=this.queryStorage.createCacheKey(this.name,{...e,...b}),m;if(R&&(m=await this.queryStorage.getCachedResult(p)),m)h({fromCache:!0,status:"success",data:m.data,error:void 0,headers:m.headers,requestParams:e}),o({...m,fromCache:!0});else{h({fromCache:!1,status:"loading"});let E=this.configCurrentEndpoint.request(e,t?.context),P={...t,signal:n.signal},g=await this.queryFunction(E,P,f);if(g.ok){let{headers:d,...c}=g;if(R){let w=this.queryStorage.createCacheConfig(this.configCurrentEndpoint);await this.queryStorage.setCachedResult(p,{...c,headers:I(d)},w,A??{},this.configCurrentEndpoint.tags??[],this.configCurrentEndpoint.invalidatesTags??[])}h({fromCache:!1,status:"success",data:g.data,error:void 0,headers:g.headers,requestParams:e}),this.endpointSubscribers.forEach(w=>{let F={status:"success",fetchCounts:this.fetchCounts,meta:this.meta,cacheableHeaders:this.cacheableHeaders,error:void 0};w(F)}),o({...g,fromCache:!1})}else h({fromCache:!1,status:"error",data:void 0,error:g.error,headers:g.headers,requestParams:e}),this.endpointSubscribers.forEach(d=>{let c={status:"error",fetchCounts:this.fetchCounts,meta:this.meta,cacheableHeaders:this.cacheableHeaders,error:g.error};d(c)}),u(g.error)}}catch(f){h({fromCache:!1,status:"error",data:void 0,error:f,headers:void 0,requestParams:e}),u(f)}});return{id:a,subscribe(o,u={}){let{autoUnsubscribe:f=!0}=u;i.add(o),o(s);let b=()=>i.delete(o);return f&&C.finally(()=>{b()}),b},wait:()=>C,waitWithCallbacks(o={}){let{idle:u,loading:f,success:b,error:R}=o;return this.subscribe(p=>{switch(p.status){case"idle":u?.(p);break;case"loading":f?.(p);break;case"success":b?.(p.data,p);break;case"error":R?.(p.error,p);break}},{autoUnsubscribe:!0}),C},abort:()=>{n&&!n.signal.aborted&&n.abort()},then:(o,u)=>C.then(o,u),catch:o=>C.catch(o),finally:o=>C.finally(o)}}subscribe(e){this.endpointSubscribers.add(e);let t={status:"idle",fetchCounts:this.fetchCounts,meta:this.meta,cacheableHeaders:this.cacheableHeaders,error:void 0};return e(t),()=>this.endpointSubscribers.delete(e)}reset(){return this.fetchCounts=0,Promise.resolve()}destroy(){this.endpointSubscribers.clear()}};var x=class{constructor(e,t=!1){this.value=e;this.isRawKey=t}toString(){return this.value}toJSON(){return this.value}valueOf(){return this.value}isUnparseable(){return this.isRawKey}};var y=class{static createMetadata(e=0,t=[]){let a=Date.now(),n=e>0?a+e:1/0;return{createdAt:a,updatedAt:a,expiresAt:n,tags:t,createdAtDateTime:this.formatDateTime(a),updatedAtDateTime:this.formatDateTime(a),expiresAtDateTime:n===1/0?"never":this.formatDateTime(n)}}static formatDateTime(e){return new Date(e).toISOString()}static isExpired(e){return Date.now()>e.expiresAt}static updateMetadata(e){return{...e,updatedAt:Date.now()}}static createKey(...e){return new x(e.join("_"))}static createApiKey(e,t){if(!t)return[new x(e,!0),t];let a=Object.entries(t).sort(([n],[i])=>n.localeCompare(i)).map(([n,i])=>`${n}=${i}`).join("&");return[new x(`${e}_${a}`,!0),t]}static hasAnyTag(e,t=[]){return!e.tags||!t.length?!1:t.some(a=>e.tags?.includes(a))}};var S=class{constructor(e,t){this.storageExternal=e;this.globalCacheConfig=t}storage=null;cleanupInterval=null;defaultCacheOptions={ttl:5*60*1e3,cleanup:{enabled:!0,interval:10*60*1e3},invalidateOnError:!0};async initialize(){return await this.createStorage(),this.startCleanupInterval(),this}async createStorage(){try{let e=this.storageExternal;await e.initialize(),this.storage=e}catch(e){throw console.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0430\u0446\u0438\u0438 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0430",e),e}}startCleanupInterval(){this.cleanupInterval&&(clearInterval(this.cleanupInterval),this.cleanupInterval=null);let e=typeof this.globalCacheConfig=="object"?this.globalCacheConfig.cleanup:this.defaultCacheOptions.cleanup;e?.enabled&&e.interval&&(this.cleanupInterval=setInterval(()=>{this.cleanup().catch(t=>console.error("\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0447\u0438\u0441\u0442\u043A\u0435 \u043A\u044D\u0448\u0430:",t))},e.interval))}getStorage(){return this.storage}createCacheKey(e,t){return y.createApiKey(e,t)}async getCachedResult(e){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let t=await this.storage.get(e);if(!t)return;if(y.isExpired(t.metadata)){await this.storage.delete(e);return}let a={...t,metadata:y.updateMetadata(t.metadata)};return await this.storage.set(e,a),t.data}async setCachedResult(e,t,a,n,i,s){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");s?.length&&await this.invalidateCacheByTags(s);let l=y.createMetadata(a.ttl,i),h={data:t,metadata:l,params:n};await this.storage.set(e,h)}shouldCache(e,t){return!(this.globalCacheConfig===!1||e?.cache===!1||typeof e?.cache=="object"&&e?.cache.ttl===0||t?.disableCache===!0||this.globalCacheConfig===void 0&&e?.cache===void 0)}createCacheConfig(e){let t=this.defaultCacheOptions;if(typeof this.globalCacheConfig=="object"&&(t=this.globalCacheConfig),typeof e?.cache=="object"){let a=e.cache;t={...t,...a}}return t}async invalidateCacheByTags(e){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let t=await this.storage.keys();for(let a of t){let n=await this.storage.get(a);n&&y.hasAnyTag(n.metadata,e)&&await this.storage.delete(a)}}async invalidateCache(e){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");await this.storage.delete(e)}async cleanup(){if(!this.storage)throw new Error("\u0425\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D\u043E");let e=await this.storage.keys();for(let t of e){let a=await this.storage.get(t);a&&y.isExpired(a.metadata)&&await this.storage.delete(t)}}async destroy(){this.cleanupInterval&&(window.clearInterval(this.cleanupInterval),this.cleanupInterval=null),this.storage&&(await this.storage.destroy(),this.storage=null)}};var K=class{queryStorage;cacheableHeaderKeys;globalCacheConfig;baseQueryConfig;storageExternal;createEndpoints;endpoints={};constructor(e){this.cacheableHeaderKeys=e.cacheableHeaderKeys,this.globalCacheConfig=e.cache,this.baseQueryConfig=e.baseQuery,this.storageExternal=e.storage,this.createEndpoints=e.endpoints}async init(){return this.queryStorage=await new S(this.storageExternal,this.globalCacheConfig).initialize(),await this.initializeEndpoints(),this}async initializeEndpoints(){let e=a=>a,t=await this.createEndpoints(e)||{};for(let[a,n]of Object.entries(t)){let i=a;this.endpoints[i]=new v(a,this.queryStorage,n,this.cacheableHeaderKeys,this.globalCacheConfig,this.baseQueryConfig)}}getEndpoints(){return this.endpoints}async request(e,t,a){let i=this.getEndpoints()[e];if(!i)throw new Error(`\u042D\u043D\u0434\u043F\u043E\u0438\u043D\u0442 ${String(e)} \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D`);try{return await i.request(t,a).wait()}catch(s){throw k.error(`\u041E\u0448\u0438\u0431\u043A\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u0430 \u043A ${String(e)}`,{error:s,params:t}),s}}async destroy(){await Promise.all(Object.values(this.endpoints).map(async e=>(e.destroy(),Promise.resolve()))),this.endpoints={},await this.queryStorage.destroy()}};0&&(module.exports={ApiClient,ResponseFormat,apiLogger,createUniqueId,headersToObject});