itd-api 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +114 -489
  2. package/dist/index.cjs +8781 -415
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +4990 -1
  5. package/dist/index.d.ts +4990 -1
  6. package/dist/index.js +8688 -2
  7. package/dist/index.js.map +1 -1
  8. package/dist/multi-storage-BhcA2Izn.d.ts +198 -0
  9. package/dist/multi-storage-CyMe404l.js +805 -0
  10. package/dist/multi-storage-CyMe404l.js.map +1 -0
  11. package/dist/multi-storage-D1keK2Op.cjs +930 -0
  12. package/dist/multi-storage-D1keK2Op.cjs.map +1 -0
  13. package/dist/multi-storage-NDqzRQcD.d.cts +198 -0
  14. package/dist/node.cjs +225 -548
  15. package/dist/node.cjs.map +1 -1
  16. package/dist/node.d.cts +46 -59
  17. package/dist/node.d.ts +46 -59
  18. package/dist/node.js +223 -126
  19. package/dist/node.js.map +1 -1
  20. package/dist/runtime-CFEsf-jD.cjs +185 -0
  21. package/dist/runtime-CFEsf-jD.cjs.map +1 -0
  22. package/dist/runtime-DHxDn8gf.js +126 -0
  23. package/dist/runtime-DHxDn8gf.js.map +1 -0
  24. package/dist/storage-BjNRlkbE.d.cts +82 -0
  25. package/dist/storage-BjNRlkbE.d.ts +82 -0
  26. package/dist/storage-D9tfHx7Z.js +424 -0
  27. package/dist/storage-D9tfHx7Z.js.map +1 -0
  28. package/dist/storage-ycBqLBRB.cjs +615 -0
  29. package/dist/storage-ycBqLBRB.cjs.map +1 -0
  30. package/dist/web.cjs +87 -0
  31. package/dist/web.cjs.map +1 -0
  32. package/dist/web.d.cts +27 -0
  33. package/dist/web.d.ts +27 -0
  34. package/dist/web.js +86 -0
  35. package/dist/web.js.map +1 -0
  36. package/package.json +34 -14
  37. package/dist/chunk-6FB4HTKH.js +0 -7763
  38. package/dist/chunk-6FB4HTKH.js.map +0 -1
  39. package/dist/chunk-73CISRBG.cjs +0 -7873
  40. package/dist/chunk-73CISRBG.cjs.map +0 -1
  41. package/dist/index-BZF4K90s.d.cts +0 -4961
  42. package/dist/index-BZF4K90s.d.ts +0 -4961
  43. package/guides/README.md +0 -24
  44. package/guides/authentication/README.md +0 -176
  45. package/guides/authentication/examples/bot-with-session.mjs +0 -98
  46. package/guides/authentication/examples/turnstile-login.mjs +0 -56
  47. package/guides/integrations/README.md +0 -62
  48. package/guides/integrations/examples/proxy.mjs +0 -26
  49. package/guides/multi-accounts/README.md +0 -143
  50. package/guides/multi-accounts/examples/multi-accounts.mjs +0 -71
  51. package/guides/plugins/README.md +0 -253
  52. package/guides/plugins/examples/cache.mjs +0 -33
  53. package/guides/plugins/examples/crypto.mjs +0 -54
  54. package/guides/quickstart/README.md +0 -124
  55. package/guides/quickstart/examples/quick-start.mjs +0 -44
  56. package/guides/quickstart/examples/typescript.ts +0 -90
  57. package/guides/realtime/README.md +0 -109
  58. package/guides/realtime/examples/notifications.mjs +0 -62
  59. package/guides/reference/README.md +0 -67
  60. package/guides/reference/accounts.md +0 -101
  61. package/guides/reference/auth.md +0 -141
  62. package/guides/reference/builders.md +0 -135
  63. package/guides/reference/client.md +0 -184
  64. package/guides/reference/comments.md +0 -58
  65. package/guides/reference/discovery.md +0 -81
  66. package/guides/reference/enums.md +0 -103
  67. package/guides/reference/errors.md +0 -107
  68. package/guides/reference/files.md +0 -73
  69. package/guides/reference/models.md +0 -448
  70. package/guides/reference/notifications.md +0 -77
  71. package/guides/reference/pagination.md +0 -82
  72. package/guides/reference/platform.md +0 -47
  73. package/guides/reference/posts.md +0 -157
  74. package/guides/reference/realtime.md +0 -78
  75. package/guides/reference/reports.md +0 -28
  76. package/guides/reference/subscription.md +0 -41
  77. package/guides/reference/users.md +0 -146
  78. package/guides/reference/verification.md +0 -24
  79. package/guides/text-markup/README.md +0 -214
  80. package/guides/text-markup/examples/create-post.mjs +0 -64
@@ -0,0 +1,615 @@
1
+ //#region src/core/errors.ts
2
+ /** Бренд, по которому ошибки библиотеки распознаются надёжнее, чем через `instanceof`. */
3
+ const ITD_ERROR = Symbol.for("itd.error");
4
+ /**
5
+ * Категория ошибки. Определяет, какие поля у неё есть.
6
+ *
7
+ * Значение, а не только тип: категорию нужно с чем-то сравнивать в рантайме.
8
+ */
9
+ const ItdErrorKind = Object.freeze({
10
+ /** Сервер ответил статусом ≥ 400. */
11
+ Api: "api",
12
+ /** Запрос не дошёл до сервера. */
13
+ Network: "network",
14
+ /** Истёк таймаут запроса. */
15
+ Timeout: "timeout",
16
+ /** Запрос отменён через `AbortSignal`. */
17
+ Abort: "abort",
18
+ /** Не удалось получить или подготовить содержимое вложения. */
19
+ File: "file",
20
+ /** Некорректная конфигурация или аргументы — обнаружено до обращения к сети. */
21
+ Config: "config"
22
+ });
23
+ /**
24
+ * Разновидность ошибки API — то же, что класс ошибки, но в виде данных.
25
+ *
26
+ * Существует потому, что `instanceof` подводит, когда в дереве зависимостей оказались
27
+ * две копии пакета или смешаны сборки ESM и CJS: классы тогда разные, хотя ошибка та же.
28
+ * Проверки {@link isItdValidationError} и соседние опираются на это поле, а не на класс.
29
+ */
30
+ const ItdApiErrorKind = Object.freeze({
31
+ /** Ни одна из специализаций не подошла. */
32
+ Generic: "generic",
33
+ Validation: "validation",
34
+ Auth: "auth",
35
+ Forbidden: "forbidden",
36
+ NotFound: "not_found",
37
+ Conflict: "conflict",
38
+ RateLimit: "rate_limit",
39
+ PhoneVerification: "phone_verification",
40
+ Server: "server"
41
+ });
42
+ /**
43
+ * Базовый класс всех ошибок библиотеки.
44
+ *
45
+ * Ловить его имеет смысл, чтобы отделить проблемы обращения к итд.com от прочих исключений.
46
+ * Для разбора конкретной причины используйте {@link isItdApiError} и поле {@link ItdApiError.code}.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * try {
51
+ * await itd.posts.like(id);
52
+ * } catch (e) {
53
+ * if (isItdError(e)) console.error('итд.com:', e.message);
54
+ * else throw e;
55
+ * }
56
+ * ```
57
+ */
58
+ var ItdError = class extends Error {
59
+ /** @internal */
60
+ [ITD_ERROR] = true;
61
+ /** Категория ошибки. */
62
+ kind;
63
+ constructor(kind, message, options) {
64
+ super(message, options);
65
+ this.kind = kind;
66
+ this.name = "ItdError";
67
+ }
68
+ };
69
+ /**
70
+ * Ошибка, возвращённая сервером итд.com (HTTP-статус ≥ 400).
71
+ *
72
+ * API отдаёт ошибки в двух разных формах — `{ error: { … } }` и `{ code, message, violations }`.
73
+ * Библиотека сводит обе к этому классу, поэтому разбирать форму ответа вручную не нужно.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * try {
78
+ * await itd.users.updateMe({ username: 'занятое_имя' });
79
+ * } catch (e) {
80
+ * if (e instanceof ItdValidationError) {
81
+ * console.log(e.fieldErrors.username); // ['Имя уже занято']
82
+ * }
83
+ * }
84
+ * ```
85
+ */
86
+ var ItdApiError = class extends ItdError {
87
+ /**
88
+ * Разновидность ошибки: та же информация, что и класс, но пригодная для сравнения.
89
+ *
90
+ * Позволяет разбирать ошибку через `switch`, а проверкам вроде {@link isItdAuthError} —
91
+ * работать даже когда в проекте оказались две копии библиотеки.
92
+ */
93
+ apiKind;
94
+ /** HTTP-статус ответа. */
95
+ status;
96
+ /** Строковый код ошибки, например `VALIDATION_ERROR`. */
97
+ code;
98
+ /** Расширенное описание, если сервер его прислал. */
99
+ detail;
100
+ /** Заголовок ошибки, если сервер его прислал. */
101
+ title;
102
+ /** Ошибки по полям. Пустой объект, если сервер их не прислал. */
103
+ fieldErrors;
104
+ /** Идентификатор запроса из заголовков ответа. */
105
+ requestId;
106
+ /** HTTP-метод запроса. */
107
+ method;
108
+ /** Путь запроса без базового URL. */
109
+ path;
110
+ /** Тело ответа как оно пришло. */
111
+ raw;
112
+ /** Объект ответа. Тело уже прочитано и повторно прочитано быть не может. */
113
+ response;
114
+ /** Пауза из заголовка `Retry-After` в миллисекундах. Сервер итд.com его не присылает. */
115
+ retryAfter;
116
+ /**
117
+ * Сколько запросов разрешено в окне — заголовок `x-ratelimit-limit`.
118
+ *
119
+ * Времени сброса окна сервер не сообщает, поэтому точный момент повтора неизвестен.
120
+ */
121
+ rateLimit;
122
+ /** Сколько запросов осталось в окне — заголовок `x-ratelimit-remaining`. */
123
+ rateLimitRemaining;
124
+ /**
125
+ * @param apiKind разновидность; подставляется подклассами, снаружи задавать не нужно
126
+ */
127
+ constructor(init, apiKind = ItdApiErrorKind.Generic) {
128
+ super(ItdErrorKind.Api, init.message);
129
+ this.name = "ItdApiError";
130
+ this.apiKind = apiKind;
131
+ this.status = init.status;
132
+ this.code = init.code;
133
+ this.detail = init.detail;
134
+ this.title = init.title;
135
+ this.fieldErrors = init.fieldErrors ?? {};
136
+ this.requestId = init.requestId;
137
+ this.method = init.method;
138
+ this.path = init.path;
139
+ this.raw = init.raw;
140
+ this.response = init.response;
141
+ this.retryAfter = init.retryAfter;
142
+ this.rateLimit = init.rateLimit;
143
+ this.rateLimitRemaining = init.rateLimitRemaining;
144
+ }
145
+ /**
146
+ * Проверяет код ошибки. Удобнее, чем сравнивать строки вручную.
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * if (err.hasCode('OTP_INVALID', 'MISSING_FLOW_TOKEN')) await restartOtpFlow();
151
+ * ```
152
+ */
153
+ hasCode(...codes) {
154
+ return codes.includes(this.code);
155
+ }
156
+ /** Имеет ли смысл повторить запрос: `429` и серверные ошибки `5xx`. */
157
+ get isRetryable() {
158
+ return this.status === 429 || this.status >= 500;
159
+ }
160
+ };
161
+ /** `400` / `422` — данные не прошли валидацию. Подробности в {@link ItdApiError.fieldErrors}. */
162
+ var ItdValidationError = class extends ItdApiError {
163
+ constructor(init) {
164
+ super(init, ItdApiErrorKind.Validation);
165
+ this.name = "ItdValidationError";
166
+ }
167
+ };
168
+ /** `401` — токен отсутствует, истёк или отозван. */
169
+ var ItdAuthError = class extends ItdApiError {
170
+ constructor(init) {
171
+ super(init, ItdApiErrorKind.Auth);
172
+ this.name = "ItdAuthError";
173
+ }
174
+ };
175
+ /** `403` — доступ запрещён либо действие ограничено настройками приватности. */
176
+ var ItdForbiddenError = class extends ItdApiError {
177
+ constructor(init) {
178
+ super(init, ItdApiErrorKind.Forbidden);
179
+ this.name = "ItdForbiddenError";
180
+ }
181
+ };
182
+ /** `404` — сущность не найдена. */
183
+ var ItdNotFoundError = class extends ItdApiError {
184
+ constructor(init) {
185
+ super(init, ItdApiErrorKind.NotFound);
186
+ this.name = "ItdNotFoundError";
187
+ }
188
+ };
189
+ /** `409` — сущность уже существует. */
190
+ var ItdConflictError = class extends ItdApiError {
191
+ constructor(init) {
192
+ super(init, ItdApiErrorKind.Conflict);
193
+ this.name = "ItdConflictError";
194
+ }
195
+ };
196
+ /**
197
+ * `429` — превышен лимит запросов.
198
+ *
199
+ * Если сервер прислал `Retry-After`, пауза доступна в {@link ItdApiError.retryAfter}
200
+ * (в миллисекундах). При включённых ретраях библиотека выдерживает её автоматически.
201
+ */
202
+ var ItdRateLimitError = class extends ItdApiError {
203
+ constructor(init) {
204
+ super(init, ItdApiErrorKind.RateLimit);
205
+ this.name = "ItdRateLimitError";
206
+ }
207
+ };
208
+ /**
209
+ * Действие требует подтверждённого телефона (`PHONE_VERIFICATION_REQUIRED`).
210
+ *
211
+ * Подтверждение проходит через Telegram-бота: ссылка лежит в {@link verificationUrl}.
212
+ */
213
+ var ItdPhoneVerificationError = class extends ItdApiError {
214
+ /** Ссылка на бота подтверждения, если удалось определить идентификатор пользователя. */
215
+ verificationUrl;
216
+ constructor(init) {
217
+ super(init, ItdApiErrorKind.PhoneVerification);
218
+ this.name = "ItdPhoneVerificationError";
219
+ this.verificationUrl = init.userId ? `https://t.me/itd_verification_bot?start=${encodeURIComponent(init.userId)}` : void 0;
220
+ }
221
+ };
222
+ /** `5xx` — ошибка на стороне сервера. */
223
+ var ItdServerError = class extends ItdApiError {
224
+ constructor(init) {
225
+ super(init, ItdApiErrorKind.Server);
226
+ this.name = "ItdServerError";
227
+ }
228
+ };
229
+ /** Причина ошибки получения вложения. */
230
+ const ItdFileErrorReason = Object.freeze({
231
+ /** Сетевой сбой при получении источника. */
232
+ Network: "network",
233
+ /** Источник ответил ошибочным HTTP-статусом. */
234
+ Http: "http",
235
+ /** Источник превысил разрешённый размер. */
236
+ TooLarge: "too_large",
237
+ /** Среда или источник не предоставили поток. */
238
+ StreamUnavailable: "stream_unavailable",
239
+ /** Поток источника завершился ошибкой. */
240
+ Read: "read"
241
+ });
242
+ /** Не удалось получить или прочитать содержимое вложения. */
243
+ var ItdFileError = class extends ItdError {
244
+ reason;
245
+ /** Адрес источника, если файл получался по сети. */
246
+ url;
247
+ /** HTTP-статус источника. */
248
+ status;
249
+ /** Разрешённый размер в байтах. */
250
+ limit;
251
+ /** Обнаруженный размер в байтах. */
252
+ actual;
253
+ /** Имеет ли смысл повторить получение источника. */
254
+ retryable;
255
+ constructor(message, init) {
256
+ super(ItdErrorKind.File, message, { cause: init.cause });
257
+ this.name = "ItdFileError";
258
+ this.reason = init.reason;
259
+ this.url = init.url;
260
+ this.status = init.status;
261
+ this.limit = init.limit;
262
+ this.actual = init.actual;
263
+ this.retryable = init.retryable ?? false;
264
+ }
265
+ };
266
+ /** Запрос не дошёл до сервера: DNS, обрыв соединения, отсутствие сети. */
267
+ var ItdNetworkError = class extends ItdError {
268
+ /** HTTP-метод запроса. */
269
+ method;
270
+ /** Путь запроса без базового URL. */
271
+ path;
272
+ constructor(message, init) {
273
+ super(ItdErrorKind.Network, message, { cause: init.cause });
274
+ this.name = "ItdNetworkError";
275
+ this.method = init.method;
276
+ this.path = init.path;
277
+ }
278
+ };
279
+ /** Истёк таймаут запроса, заданный опцией `timeout`. */
280
+ var ItdTimeoutError = class extends ItdError {
281
+ /** Значение таймаута в миллисекундах. */
282
+ timeout;
283
+ /** HTTP-метод запроса. */
284
+ method;
285
+ /** Путь запроса без базового URL. */
286
+ path;
287
+ constructor(init) {
288
+ super(ItdErrorKind.Timeout, `Запрос ${init.method} ${init.path} превысил таймаут ${init.timeout} мс`);
289
+ this.name = "ItdTimeoutError";
290
+ this.timeout = init.timeout;
291
+ this.method = init.method;
292
+ this.path = init.path;
293
+ }
294
+ };
295
+ /** Запрос отменён через переданный `AbortSignal`. */
296
+ var ItdAbortError = class extends ItdError {
297
+ constructor(message = "Запрос отменён", options) {
298
+ super(ItdErrorKind.Abort, message, options);
299
+ this.name = "ItdAbortError";
300
+ }
301
+ };
302
+ /**
303
+ * Некорректная конфигурация или аргументы — обнаружено до обращения к сети.
304
+ *
305
+ * Этим же классом сообщают о нарушенных инвариантах билдеры: например, опрос
306
+ * с одним вариантом ответа.
307
+ */
308
+ var ItdConfigError = class extends ItdError {
309
+ constructor(message) {
310
+ super(ItdErrorKind.Config, message);
311
+ this.name = "ItdConfigError";
312
+ }
313
+ };
314
+ /** Любая ошибка, порождённая этой библиотекой. */
315
+ function isItdError(value) {
316
+ return typeof value === "object" && value !== null && ITD_ERROR in value;
317
+ }
318
+ /** Ошибка, пришедшая от сервера итд.com (статус ≥ 400). */
319
+ function isItdApiError(value) {
320
+ return isItdError(value) && value.kind === ItdErrorKind.Api;
321
+ }
322
+ /** Ошибка получения или чтения вложения. */
323
+ function isItdFileError(value) {
324
+ return isItdError(value) && value.kind === ItdErrorKind.File;
325
+ }
326
+ /**
327
+ * Проверяет разновидность ошибки API.
328
+ *
329
+ * Намеренно не `instanceof`: две копии пакета в дереве зависимостей или смешение сборок
330
+ * ESM и CJS дают разные классы для одной и той же ошибки, и проверка по классу молча
331
+ * перестаёт срабатывать. Поле {@link ItdApiError.apiKind} от этого не зависит.
332
+ */
333
+ function hasApiKind(value, kind) {
334
+ return isItdApiError(value) && value.apiKind === kind;
335
+ }
336
+ /** Ошибка валидации: `VALIDATION_ERROR` либо статус `400`/`422`. */
337
+ function isItdValidationError(value) {
338
+ return hasApiKind(value, ItdApiErrorKind.Validation);
339
+ }
340
+ /** Ошибка авторизации: истёкший или отозванный токен. */
341
+ function isItdAuthError(value) {
342
+ return hasApiKind(value, ItdApiErrorKind.Auth);
343
+ }
344
+ /** Доступ запрещён либо действие ограничено настройками приватности. */
345
+ function isItdForbiddenError(value) {
346
+ return hasApiKind(value, ItdApiErrorKind.Forbidden);
347
+ }
348
+ /** Сущность не найдена. */
349
+ function isItdNotFoundError(value) {
350
+ return hasApiKind(value, ItdApiErrorKind.NotFound);
351
+ }
352
+ /** Сущность уже существует. */
353
+ function isItdConflictError(value) {
354
+ return hasApiKind(value, ItdApiErrorKind.Conflict);
355
+ }
356
+ /** Превышен лимит запросов. */
357
+ function isItdRateLimitError(value) {
358
+ return hasApiKind(value, ItdApiErrorKind.RateLimit);
359
+ }
360
+ /** Действие требует подтверждённого телефона. Ссылка — в `verificationUrl`. */
361
+ function isItdPhoneVerificationError(value) {
362
+ return hasApiKind(value, ItdApiErrorKind.PhoneVerification);
363
+ }
364
+ /** Ошибка на стороне сервера (`5xx`). */
365
+ function isItdServerError(value) {
366
+ return hasApiKind(value, ItdApiErrorKind.Server);
367
+ }
368
+ //#endregion
369
+ //#region src/core/storage.ts
370
+ /**
371
+ * Создаёт независимый снимок сессии.
372
+ *
373
+ * Сессии пересекают границу пользовательского кода и внутреннего состояния клиента.
374
+ * Возвращать или сохранять их по ссылке нельзя: последующая мутация объекта или массива
375
+ * cookie меняла бы уже сохранённую сессию без вызова `set()`.
376
+ *
377
+ * @internal
378
+ */
379
+ function copySession(session) {
380
+ return {
381
+ ...session,
382
+ ...session.cookies ? { cookies: [...session.cookies] } : {}
383
+ };
384
+ }
385
+ /**
386
+ * Хранилище в памяти процесса — вариант по умолчанию.
387
+ *
388
+ * Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`
389
+ * из `itd-api/node`, для браузера — `LocalStorageTokenStorage` из `itd-api/web`.
390
+ */
391
+ var MemoryTokenStorage = class {
392
+ #session = null;
393
+ constructor(initial) {
394
+ this.#session = initial ? copySession(initial) : null;
395
+ }
396
+ get() {
397
+ return this.#session ? copySession(this.#session) : null;
398
+ }
399
+ set(session) {
400
+ this.#session = copySession(session);
401
+ }
402
+ clear() {
403
+ this.#session = null;
404
+ }
405
+ };
406
+ /**
407
+ * Собирает {@link TokenStorage} из трёх функций — когда заводить класс избыточно.
408
+ *
409
+ * @example
410
+ * ```ts
411
+ * const storage = createTokenStorage({
412
+ * get: () => db.getSession(userId),
413
+ * set: (session) => db.saveSession(userId, session),
414
+ * clear: () => db.deleteSession(userId),
415
+ * });
416
+ * ```
417
+ */
418
+ function createTokenStorage(handlers) {
419
+ return handlers;
420
+ }
421
+ //#endregion
422
+ Object.defineProperty(exports, "ItdAbortError", {
423
+ enumerable: true,
424
+ get: function() {
425
+ return ItdAbortError;
426
+ }
427
+ });
428
+ Object.defineProperty(exports, "ItdApiError", {
429
+ enumerable: true,
430
+ get: function() {
431
+ return ItdApiError;
432
+ }
433
+ });
434
+ Object.defineProperty(exports, "ItdApiErrorKind", {
435
+ enumerable: true,
436
+ get: function() {
437
+ return ItdApiErrorKind;
438
+ }
439
+ });
440
+ Object.defineProperty(exports, "ItdAuthError", {
441
+ enumerable: true,
442
+ get: function() {
443
+ return ItdAuthError;
444
+ }
445
+ });
446
+ Object.defineProperty(exports, "ItdConfigError", {
447
+ enumerable: true,
448
+ get: function() {
449
+ return ItdConfigError;
450
+ }
451
+ });
452
+ Object.defineProperty(exports, "ItdConflictError", {
453
+ enumerable: true,
454
+ get: function() {
455
+ return ItdConflictError;
456
+ }
457
+ });
458
+ Object.defineProperty(exports, "ItdError", {
459
+ enumerable: true,
460
+ get: function() {
461
+ return ItdError;
462
+ }
463
+ });
464
+ Object.defineProperty(exports, "ItdErrorKind", {
465
+ enumerable: true,
466
+ get: function() {
467
+ return ItdErrorKind;
468
+ }
469
+ });
470
+ Object.defineProperty(exports, "ItdFileError", {
471
+ enumerable: true,
472
+ get: function() {
473
+ return ItdFileError;
474
+ }
475
+ });
476
+ Object.defineProperty(exports, "ItdFileErrorReason", {
477
+ enumerable: true,
478
+ get: function() {
479
+ return ItdFileErrorReason;
480
+ }
481
+ });
482
+ Object.defineProperty(exports, "ItdForbiddenError", {
483
+ enumerable: true,
484
+ get: function() {
485
+ return ItdForbiddenError;
486
+ }
487
+ });
488
+ Object.defineProperty(exports, "ItdNetworkError", {
489
+ enumerable: true,
490
+ get: function() {
491
+ return ItdNetworkError;
492
+ }
493
+ });
494
+ Object.defineProperty(exports, "ItdNotFoundError", {
495
+ enumerable: true,
496
+ get: function() {
497
+ return ItdNotFoundError;
498
+ }
499
+ });
500
+ Object.defineProperty(exports, "ItdPhoneVerificationError", {
501
+ enumerable: true,
502
+ get: function() {
503
+ return ItdPhoneVerificationError;
504
+ }
505
+ });
506
+ Object.defineProperty(exports, "ItdRateLimitError", {
507
+ enumerable: true,
508
+ get: function() {
509
+ return ItdRateLimitError;
510
+ }
511
+ });
512
+ Object.defineProperty(exports, "ItdServerError", {
513
+ enumerable: true,
514
+ get: function() {
515
+ return ItdServerError;
516
+ }
517
+ });
518
+ Object.defineProperty(exports, "ItdTimeoutError", {
519
+ enumerable: true,
520
+ get: function() {
521
+ return ItdTimeoutError;
522
+ }
523
+ });
524
+ Object.defineProperty(exports, "ItdValidationError", {
525
+ enumerable: true,
526
+ get: function() {
527
+ return ItdValidationError;
528
+ }
529
+ });
530
+ Object.defineProperty(exports, "MemoryTokenStorage", {
531
+ enumerable: true,
532
+ get: function() {
533
+ return MemoryTokenStorage;
534
+ }
535
+ });
536
+ Object.defineProperty(exports, "copySession", {
537
+ enumerable: true,
538
+ get: function() {
539
+ return copySession;
540
+ }
541
+ });
542
+ Object.defineProperty(exports, "createTokenStorage", {
543
+ enumerable: true,
544
+ get: function() {
545
+ return createTokenStorage;
546
+ }
547
+ });
548
+ Object.defineProperty(exports, "isItdApiError", {
549
+ enumerable: true,
550
+ get: function() {
551
+ return isItdApiError;
552
+ }
553
+ });
554
+ Object.defineProperty(exports, "isItdAuthError", {
555
+ enumerable: true,
556
+ get: function() {
557
+ return isItdAuthError;
558
+ }
559
+ });
560
+ Object.defineProperty(exports, "isItdConflictError", {
561
+ enumerable: true,
562
+ get: function() {
563
+ return isItdConflictError;
564
+ }
565
+ });
566
+ Object.defineProperty(exports, "isItdError", {
567
+ enumerable: true,
568
+ get: function() {
569
+ return isItdError;
570
+ }
571
+ });
572
+ Object.defineProperty(exports, "isItdFileError", {
573
+ enumerable: true,
574
+ get: function() {
575
+ return isItdFileError;
576
+ }
577
+ });
578
+ Object.defineProperty(exports, "isItdForbiddenError", {
579
+ enumerable: true,
580
+ get: function() {
581
+ return isItdForbiddenError;
582
+ }
583
+ });
584
+ Object.defineProperty(exports, "isItdNotFoundError", {
585
+ enumerable: true,
586
+ get: function() {
587
+ return isItdNotFoundError;
588
+ }
589
+ });
590
+ Object.defineProperty(exports, "isItdPhoneVerificationError", {
591
+ enumerable: true,
592
+ get: function() {
593
+ return isItdPhoneVerificationError;
594
+ }
595
+ });
596
+ Object.defineProperty(exports, "isItdRateLimitError", {
597
+ enumerable: true,
598
+ get: function() {
599
+ return isItdRateLimitError;
600
+ }
601
+ });
602
+ Object.defineProperty(exports, "isItdServerError", {
603
+ enumerable: true,
604
+ get: function() {
605
+ return isItdServerError;
606
+ }
607
+ });
608
+ Object.defineProperty(exports, "isItdValidationError", {
609
+ enumerable: true,
610
+ get: function() {
611
+ return isItdValidationError;
612
+ }
613
+ });
614
+
615
+ //# sourceMappingURL=storage-ycBqLBRB.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-ycBqLBRB.cjs","names":["#session"],"sources":["../src/core/errors.ts","../src/core/storage.ts"],"sourcesContent":["import type { ItdErrorCode } from '../types/enums.js';\n\n/** Бренд, по которому ошибки библиотеки распознаются надёжнее, чем через `instanceof`. */\nconst ITD_ERROR = Symbol.for('itd.error');\n\n/**\n * Категория ошибки. Определяет, какие поля у неё есть.\n *\n * Значение, а не только тип: категорию нужно с чем-то сравнивать в рантайме.\n */\nexport const ItdErrorKind = Object.freeze({\n /** Сервер ответил статусом ≥ 400. */\n Api: 'api',\n /** Запрос не дошёл до сервера. */\n Network: 'network',\n /** Истёк таймаут запроса. */\n Timeout: 'timeout',\n /** Запрос отменён через `AbortSignal`. */\n Abort: 'abort',\n /** Не удалось получить или подготовить содержимое вложения. */\n File: 'file',\n /** Некорректная конфигурация или аргументы — обнаружено до обращения к сети. */\n Config: 'config',\n} as const);\nexport type ItdErrorKind = (typeof ItdErrorKind)[keyof typeof ItdErrorKind];\n\n/**\n * Разновидность ошибки API — то же, что класс ошибки, но в виде данных.\n *\n * Существует потому, что `instanceof` подводит, когда в дереве зависимостей оказались\n * две копии пакета или смешаны сборки ESM и CJS: классы тогда разные, хотя ошибка та же.\n * Проверки {@link isItdValidationError} и соседние опираются на это поле, а не на класс.\n */\nexport const ItdApiErrorKind = Object.freeze({\n /** Ни одна из специализаций не подошла. */\n Generic: 'generic',\n Validation: 'validation',\n Auth: 'auth',\n Forbidden: 'forbidden',\n NotFound: 'not_found',\n Conflict: 'conflict',\n RateLimit: 'rate_limit',\n PhoneVerification: 'phone_verification',\n Server: 'server',\n} as const);\nexport type ItdApiErrorKind = (typeof ItdApiErrorKind)[keyof typeof ItdApiErrorKind];\n\n/** Ошибки по полям формы: `{ email: ['уже занят'] }`. */\nexport type ItdFieldErrors = Record<string, string[]>;\n\n/**\n * Базовый класс всех ошибок библиотеки.\n *\n * Ловить его имеет смысл, чтобы отделить проблемы обращения к итд.com от прочих исключений.\n * Для разбора конкретной причины используйте {@link isItdApiError} и поле {@link ItdApiError.code}.\n *\n * @example\n * ```ts\n * try {\n * await itd.posts.like(id);\n * } catch (e) {\n * if (isItdError(e)) console.error('итд.com:', e.message);\n * else throw e;\n * }\n * ```\n */\nexport class ItdError extends Error {\n /** @internal */\n readonly [ITD_ERROR] = true as const;\n\n /** Категория ошибки. */\n readonly kind: ItdErrorKind;\n\n constructor(kind: ItdErrorKind, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.kind = kind;\n this.name = 'ItdError';\n }\n}\n\n/** Параметры конструктора {@link ItdApiError}. */\nexport interface ItdApiErrorInit {\n /** HTTP-статус ответа. */\n status: number;\n /** Строковый код ошибки из тела ответа. */\n code: ItdErrorCode;\n /** Человекочитаемое сообщение. */\n message: string;\n /** Расширенное описание, если сервер его прислал. */\n detail?: string | undefined;\n /** Заголовок ошибки, если сервер его прислал. */\n title?: string | undefined;\n /** Ошибки по конкретным полям (сведены из `errors` и `violations`). */\n fieldErrors?: ItdFieldErrors | undefined;\n /** Идентификатор запроса из заголовков ответа, если есть. */\n requestId?: string | undefined;\n /** HTTP-метод запроса. */\n method: string;\n /** Путь запроса без базового URL. */\n path: string;\n /** Тело ответа как оно пришло — на случай, если документация разошлась с реальностью. */\n raw: unknown;\n /** Сам объект ответа. Тело уже прочитано. */\n response?: Response | undefined;\n /** Значение `Retry-After` в миллисекундах, если заголовок был. */\n retryAfter?: number | undefined;\n /** Сколько запросов разрешено в окне (`x-ratelimit-limit`). */\n rateLimit?: number | undefined;\n /** Сколько запросов осталось в окне (`x-ratelimit-remaining`). */\n rateLimitRemaining?: number | undefined;\n}\n\n/**\n * Ошибка, возвращённая сервером итд.com (HTTP-статус ≥ 400).\n *\n * API отдаёт ошибки в двух разных формах — `{ error: { … } }` и `{ code, message, violations }`.\n * Библиотека сводит обе к этому классу, поэтому разбирать форму ответа вручную не нужно.\n *\n * @example\n * ```ts\n * try {\n * await itd.users.updateMe({ username: 'занятое_имя' });\n * } catch (e) {\n * if (e instanceof ItdValidationError) {\n * console.log(e.fieldErrors.username); // ['Имя уже занято']\n * }\n * }\n * ```\n */\nexport class ItdApiError extends ItdError {\n /**\n * Разновидность ошибки: та же информация, что и класс, но пригодная для сравнения.\n *\n * Позволяет разбирать ошибку через `switch`, а проверкам вроде {@link isItdAuthError} —\n * работать даже когда в проекте оказались две копии библиотеки.\n */\n readonly apiKind: ItdApiErrorKind;\n /** HTTP-статус ответа. */\n readonly status: number;\n /** Строковый код ошибки, например `VALIDATION_ERROR`. */\n readonly code: ItdErrorCode;\n /** Расширенное описание, если сервер его прислал. */\n readonly detail: string | undefined;\n /** Заголовок ошибки, если сервер его прислал. */\n readonly title: string | undefined;\n /** Ошибки по полям. Пустой объект, если сервер их не прислал. */\n readonly fieldErrors: ItdFieldErrors;\n /** Идентификатор запроса из заголовков ответа. */\n readonly requestId: string | undefined;\n /** HTTP-метод запроса. */\n readonly method: string;\n /** Путь запроса без базового URL. */\n readonly path: string;\n /** Тело ответа как оно пришло. */\n readonly raw: unknown;\n /** Объект ответа. Тело уже прочитано и повторно прочитано быть не может. */\n readonly response: Response | undefined;\n /** Пауза из заголовка `Retry-After` в миллисекундах. Сервер итд.com его не присылает. */\n readonly retryAfter: number | undefined;\n /**\n * Сколько запросов разрешено в окне — заголовок `x-ratelimit-limit`.\n *\n * Времени сброса окна сервер не сообщает, поэтому точный момент повтора неизвестен.\n */\n readonly rateLimit: number | undefined;\n /** Сколько запросов осталось в окне — заголовок `x-ratelimit-remaining`. */\n readonly rateLimitRemaining: number | undefined;\n\n /**\n * @param apiKind разновидность; подставляется подклассами, снаружи задавать не нужно\n */\n constructor(init: ItdApiErrorInit, apiKind: ItdApiErrorKind = ItdApiErrorKind.Generic) {\n super(ItdErrorKind.Api, init.message);\n this.name = 'ItdApiError';\n this.apiKind = apiKind;\n this.status = init.status;\n this.code = init.code;\n this.detail = init.detail;\n this.title = init.title;\n this.fieldErrors = init.fieldErrors ?? {};\n this.requestId = init.requestId;\n this.method = init.method;\n this.path = init.path;\n this.raw = init.raw;\n this.response = init.response;\n this.retryAfter = init.retryAfter;\n this.rateLimit = init.rateLimit;\n this.rateLimitRemaining = init.rateLimitRemaining;\n }\n\n /**\n * Проверяет код ошибки. Удобнее, чем сравнивать строки вручную.\n *\n * @example\n * ```ts\n * if (err.hasCode('OTP_INVALID', 'MISSING_FLOW_TOKEN')) await restartOtpFlow();\n * ```\n */\n hasCode(...codes: ItdErrorCode[]): boolean {\n return codes.includes(this.code);\n }\n\n /** Имеет ли смысл повторить запрос: `429` и серверные ошибки `5xx`. */\n get isRetryable(): boolean {\n return this.status === 429 || this.status >= 500;\n }\n}\n\n/** `400` / `422` — данные не прошли валидацию. Подробности в {@link ItdApiError.fieldErrors}. */\nexport class ItdValidationError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.Validation);\n this.name = 'ItdValidationError';\n }\n}\n\n/** `401` — токен отсутствует, истёк или отозван. */\nexport class ItdAuthError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.Auth);\n this.name = 'ItdAuthError';\n }\n}\n\n/** `403` — доступ запрещён либо действие ограничено настройками приватности. */\nexport class ItdForbiddenError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.Forbidden);\n this.name = 'ItdForbiddenError';\n }\n}\n\n/** `404` — сущность не найдена. */\nexport class ItdNotFoundError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.NotFound);\n this.name = 'ItdNotFoundError';\n }\n}\n\n/** `409` — сущность уже существует. */\nexport class ItdConflictError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.Conflict);\n this.name = 'ItdConflictError';\n }\n}\n\n/**\n * `429` — превышен лимит запросов.\n *\n * Если сервер прислал `Retry-After`, пауза доступна в {@link ItdApiError.retryAfter}\n * (в миллисекундах). При включённых ретраях библиотека выдерживает её автоматически.\n */\nexport class ItdRateLimitError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.RateLimit);\n this.name = 'ItdRateLimitError';\n }\n}\n\n/**\n * Действие требует подтверждённого телефона (`PHONE_VERIFICATION_REQUIRED`).\n *\n * Подтверждение проходит через Telegram-бота: ссылка лежит в {@link verificationUrl}.\n */\nexport class ItdPhoneVerificationError extends ItdApiError {\n /** Ссылка на бота подтверждения, если удалось определить идентификатор пользователя. */\n readonly verificationUrl: string | undefined;\n\n constructor(init: ItdApiErrorInit & { userId?: string | undefined }) {\n super(init, ItdApiErrorKind.PhoneVerification);\n this.name = 'ItdPhoneVerificationError';\n this.verificationUrl = init.userId\n ? `https://t.me/itd_verification_bot?start=${encodeURIComponent(init.userId)}`\n : undefined;\n }\n}\n\n/** `5xx` — ошибка на стороне сервера. */\nexport class ItdServerError extends ItdApiError {\n constructor(init: ItdApiErrorInit) {\n super(init, ItdApiErrorKind.Server);\n this.name = 'ItdServerError';\n }\n}\n\n/** Причина ошибки получения вложения. */\nexport const ItdFileErrorReason = Object.freeze({\n /** Сетевой сбой при получении источника. */\n Network: 'network',\n /** Источник ответил ошибочным HTTP-статусом. */\n Http: 'http',\n /** Источник превысил разрешённый размер. */\n TooLarge: 'too_large',\n /** Среда или источник не предоставили поток. */\n StreamUnavailable: 'stream_unavailable',\n /** Поток источника завершился ошибкой. */\n Read: 'read',\n} as const);\nexport type ItdFileErrorReason = (typeof ItdFileErrorReason)[keyof typeof ItdFileErrorReason];\n\n/** Не удалось получить или прочитать содержимое вложения. */\nexport class ItdFileError extends ItdError {\n readonly reason: ItdFileErrorReason;\n /** Адрес источника, если файл получался по сети. */\n readonly url: string | undefined;\n /** HTTP-статус источника. */\n readonly status: number | undefined;\n /** Разрешённый размер в байтах. */\n readonly limit: number | undefined;\n /** Обнаруженный размер в байтах. */\n readonly actual: number | undefined;\n /** Имеет ли смысл повторить получение источника. */\n readonly retryable: boolean;\n\n constructor(\n message: string,\n init: {\n reason: ItdFileErrorReason;\n url?: string | undefined;\n status?: number | undefined;\n limit?: number | undefined;\n actual?: number | undefined;\n retryable?: boolean | undefined;\n cause?: unknown;\n },\n ) {\n super(ItdErrorKind.File, message, { cause: init.cause });\n this.name = 'ItdFileError';\n this.reason = init.reason;\n this.url = init.url;\n this.status = init.status;\n this.limit = init.limit;\n this.actual = init.actual;\n this.retryable = init.retryable ?? false;\n }\n}\n\n/** Запрос не дошёл до сервера: DNS, обрыв соединения, отсутствие сети. */\nexport class ItdNetworkError extends ItdError {\n /** HTTP-метод запроса. */\n readonly method: string;\n /** Путь запроса без базового URL. */\n readonly path: string;\n\n constructor(message: string, init: { method: string; path: string; cause?: unknown }) {\n super(ItdErrorKind.Network, message, { cause: init.cause });\n this.name = 'ItdNetworkError';\n this.method = init.method;\n this.path = init.path;\n }\n}\n\n/** Истёк таймаут запроса, заданный опцией `timeout`. */\nexport class ItdTimeoutError extends ItdError {\n /** Значение таймаута в миллисекундах. */\n readonly timeout: number;\n /** HTTP-метод запроса. */\n readonly method: string;\n /** Путь запроса без базового URL. */\n readonly path: string;\n\n constructor(init: { timeout: number; method: string; path: string }) {\n super(\n ItdErrorKind.Timeout,\n `Запрос ${init.method} ${init.path} превысил таймаут ${init.timeout} мс`,\n );\n this.name = 'ItdTimeoutError';\n this.timeout = init.timeout;\n this.method = init.method;\n this.path = init.path;\n }\n}\n\n/** Запрос отменён через переданный `AbortSignal`. */\nexport class ItdAbortError extends ItdError {\n constructor(message = 'Запрос отменён', options?: { cause?: unknown }) {\n super(ItdErrorKind.Abort, message, options);\n this.name = 'ItdAbortError';\n }\n}\n\n/**\n * Некорректная конфигурация или аргументы — обнаружено до обращения к сети.\n *\n * Этим же классом сообщают о нарушенных инвариантах билдеры: например, опрос\n * с одним вариантом ответа.\n */\nexport class ItdConfigError extends ItdError {\n constructor(message: string) {\n super(ItdErrorKind.Config, message);\n this.name = 'ItdConfigError';\n }\n}\n\n/** Любая ошибка, порождённая этой библиотекой. */\nexport function isItdError(value: unknown): value is ItdError {\n return typeof value === 'object' && value !== null && ITD_ERROR in value;\n}\n\n/** Ошибка, пришедшая от сервера итд.com (статус ≥ 400). */\nexport function isItdApiError(value: unknown): value is ItdApiError {\n return isItdError(value) && value.kind === ItdErrorKind.Api;\n}\n\n/** Ошибка получения или чтения вложения. */\nexport function isItdFileError(value: unknown): value is ItdFileError {\n return isItdError(value) && value.kind === ItdErrorKind.File;\n}\n\n/**\n * Проверяет разновидность ошибки API.\n *\n * Намеренно не `instanceof`: две копии пакета в дереве зависимостей или смешение сборок\n * ESM и CJS дают разные классы для одной и той же ошибки, и проверка по классу молча\n * перестаёт срабатывать. Поле {@link ItdApiError.apiKind} от этого не зависит.\n */\nfunction hasApiKind(value: unknown, kind: ItdApiErrorKind): boolean {\n return isItdApiError(value) && value.apiKind === kind;\n}\n\n/** Ошибка валидации: `VALIDATION_ERROR` либо статус `400`/`422`. */\nexport function isItdValidationError(value: unknown): value is ItdValidationError {\n return hasApiKind(value, ItdApiErrorKind.Validation);\n}\n\n/** Ошибка авторизации: истёкший или отозванный токен. */\nexport function isItdAuthError(value: unknown): value is ItdAuthError {\n return hasApiKind(value, ItdApiErrorKind.Auth);\n}\n\n/** Доступ запрещён либо действие ограничено настройками приватности. */\nexport function isItdForbiddenError(value: unknown): value is ItdForbiddenError {\n return hasApiKind(value, ItdApiErrorKind.Forbidden);\n}\n\n/** Сущность не найдена. */\nexport function isItdNotFoundError(value: unknown): value is ItdNotFoundError {\n return hasApiKind(value, ItdApiErrorKind.NotFound);\n}\n\n/** Сущность уже существует. */\nexport function isItdConflictError(value: unknown): value is ItdConflictError {\n return hasApiKind(value, ItdApiErrorKind.Conflict);\n}\n\n/** Превышен лимит запросов. */\nexport function isItdRateLimitError(value: unknown): value is ItdRateLimitError {\n return hasApiKind(value, ItdApiErrorKind.RateLimit);\n}\n\n/** Действие требует подтверждённого телефона. Ссылка — в `verificationUrl`. */\nexport function isItdPhoneVerificationError(value: unknown): value is ItdPhoneVerificationError {\n return hasApiKind(value, ItdApiErrorKind.PhoneVerification);\n}\n\n/** Ошибка на стороне сервера (`5xx`). */\nexport function isItdServerError(value: unknown): value is ItdServerError {\n return hasApiKind(value, ItdApiErrorKind.Server);\n}\n","/**\n * Сохранённая сессия.\n *\n * Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них\n * восстановить сессию после перезапуска процесса невозможно.\n */\nexport interface ItdSession {\n /** Токен доступа для заголовка `Authorization: Bearer`. */\n accessToken?: string | undefined;\n /**\n * Refresh-токен, если удалось получить его явным значением.\n *\n * Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется\n * пустым, а обновление пойдёт через {@link ItdSession.cookies}.\n */\n refreshToken?: string | undefined;\n /** Сырые cookie в форме `имя=значение`, привязанные к origin API. */\n cookies?: string[] | undefined;\n /**\n * Идентификатор устройства для заголовка `X-Device-Id`.\n *\n * Сервер различает по нему записи в списке сессий, поэтому значение должно пережить\n * перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека\n * заводит его сама при первом запросе и хранит здесь.\n */\n deviceId?: string | undefined;\n /** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */\n obtainedAt?: number | undefined;\n}\n\n/**\n * Создаёт независимый снимок сессии.\n *\n * Сессии пересекают границу пользовательского кода и внутреннего состояния клиента.\n * Возвращать или сохранять их по ссылке нельзя: последующая мутация объекта или массива\n * cookie меняла бы уже сохранённую сессию без вызова `set()`.\n *\n * @internal\n */\nexport function copySession(session: ItdSession): ItdSession {\n return {\n ...session,\n ...(session.cookies ? { cookies: [...session.cookies] } : {}),\n };\n}\n\n/**\n * Хранилище сессии.\n *\n * Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним\n * только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.\n *\n * @example Своё хранилище поверх AsyncStorage в React Native\n * ```ts\n * const storage = createTokenStorage({\n * get: async () => JSON.parse((await AsyncStorage.getItem('itd')) ?? 'null'),\n * set: (session) => AsyncStorage.setItem('itd', JSON.stringify(session)),\n * clear: () => AsyncStorage.removeItem('itd'),\n * });\n * ```\n */\nexport interface TokenStorage {\n /** Прочитать сессию. `null`, если её нет. */\n get(): ItdSession | null | Promise<ItdSession | null>;\n /** Сохранить сессию целиком. */\n set(session: ItdSession): void | Promise<void>;\n /** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */\n clear(): void | Promise<void>;\n}\n\n/**\n * Хранилище в памяти процесса — вариант по умолчанию.\n *\n * Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`\n * из `itd-api/node`, для браузера — `LocalStorageTokenStorage` из `itd-api/web`.\n */\nexport class MemoryTokenStorage implements TokenStorage {\n #session: ItdSession | null = null;\n\n constructor(initial?: ItdSession | null) {\n this.#session = initial ? copySession(initial) : null;\n }\n\n get(): ItdSession | null {\n return this.#session ? copySession(this.#session) : null;\n }\n\n set(session: ItdSession): void {\n this.#session = copySession(session);\n }\n\n clear(): void {\n this.#session = null;\n }\n}\n\n/**\n * Собирает {@link TokenStorage} из трёх функций — когда заводить класс избыточно.\n *\n * @example\n * ```ts\n * const storage = createTokenStorage({\n * get: () => db.getSession(userId),\n * set: (session) => db.saveSession(userId, session),\n * clear: () => db.deleteSession(userId),\n * });\n * ```\n */\nexport function createTokenStorage(handlers: TokenStorage): TokenStorage {\n return handlers;\n}\n"],"mappings":"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"}