itd-api 0.4.0 → 0.5.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.
- package/dist/index.cjs +2888 -1552
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +922 -416
- package/dist/index.d.ts +922 -416
- package/dist/index.js +2815 -1494
- package/dist/index.js.map +1 -1
- package/dist/{multi-storage-D4h6QA-w.js → multi-storage-B0r0AInH.js} +127 -83
- package/dist/multi-storage-B0r0AInH.js.map +1 -0
- package/dist/{multi-storage-DwaIh24p.d.ts → multi-storage-CLqmzq07.d.ts} +13 -39
- package/dist/{multi-storage-C8R5Crwo.cjs → multi-storage-mBuCOVZY.cjs} +164 -84
- package/dist/multi-storage-mBuCOVZY.cjs.map +1 -0
- package/dist/{multi-storage-DP_ujJw1.d.cts → multi-storage-s_PcWPGH.d.cts} +13 -39
- package/dist/node.cjs +62 -53
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +19 -5
- package/dist/node.d.ts +19 -5
- package/dist/node.js +62 -54
- package/dist/node.js.map +1 -1
- package/dist/{storage-D9tfHx7Z.js → storage-DWrK3Z4M.js} +201 -18
- package/dist/storage-DWrK3Z4M.js.map +1 -0
- package/dist/storage-Doe3lpFQ.d.cts +152 -0
- package/dist/storage-Doe3lpFQ.d.ts +152 -0
- package/dist/{storage-ycBqLBRB.cjs → storage-dF8Tio5y.cjs} +254 -17
- package/dist/storage-dF8Tio5y.cjs.map +1 -0
- package/dist/web.cjs +143 -40
- package/dist/web.cjs.map +1 -1
- package/dist/web.d.cts +40 -3
- package/dist/web.d.ts +40 -3
- package/dist/web.js +141 -41
- package/dist/web.js.map +1 -1
- package/package.json +3 -3
- package/dist/multi-storage-C8R5Crwo.cjs.map +0 -1
- package/dist/multi-storage-D4h6QA-w.js.map +0 -1
- package/dist/runtime-CFEsf-jD.cjs +0 -185
- package/dist/runtime-CFEsf-jD.cjs.map +0 -1
- package/dist/runtime-DHxDn8gf.js +0 -126
- package/dist/runtime-DHxDn8gf.js.map +0 -1
- package/dist/storage-BjNRlkbE.d.cts +0 -82
- package/dist/storage-BjNRlkbE.d.ts +0 -82
- package/dist/storage-D9tfHx7Z.js.map +0 -1
- package/dist/storage-ycBqLBRB.cjs.map +0 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//#region src/core/key-value-store.d.ts
|
|
2
|
+
/** Синхронный или асинхронный результат операции хранилища. */
|
|
3
|
+
type KeyValueStoreResult<T> = T | Promise<T>;
|
|
4
|
+
/** Синхронный или асинхронный источник ключей. */
|
|
5
|
+
type KeyValueStoreKeys = Iterable<string> | AsyncIterable<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Минимальный backend именованных значений.
|
|
8
|
+
*
|
|
9
|
+
* Контракт ничего не знает о сессиях, сериализации или конкретной базе данных. Значение
|
|
10
|
+
* `undefined` означает отсутствие ключа; хранить `undefined` как самостоятельное значение нельзя.
|
|
11
|
+
*/
|
|
12
|
+
interface KeyValueStore<T> {
|
|
13
|
+
/** Читает значение либо возвращает `undefined`, если ключ отсутствует. */
|
|
14
|
+
get(key: string): KeyValueStoreResult<T | undefined>;
|
|
15
|
+
/** Полностью заменяет значение ключа. */
|
|
16
|
+
set(key: string, value: T): KeyValueStoreResult<void>;
|
|
17
|
+
/** Удаляет ключ. Отсутствующий ключ не должен считаться ошибкой. */
|
|
18
|
+
delete(key: string): KeyValueStoreResult<void>;
|
|
19
|
+
/** Перечисляет ключи, при возможности ограничивая их префиксом. */
|
|
20
|
+
keys?(prefix?: string): KeyValueStoreResult<KeyValueStoreKeys>;
|
|
21
|
+
}
|
|
22
|
+
/** Backend, который гарантированно умеет перечислять ключи. */
|
|
23
|
+
interface EnumerableKeyValueStore<T> extends KeyValueStore<T> {
|
|
24
|
+
keys(prefix?: string): KeyValueStoreResult<KeyValueStoreKeys>;
|
|
25
|
+
}
|
|
26
|
+
/** Кодирует значения для хранения в backend другого типа. */
|
|
27
|
+
interface KeyValueCodec<T, Stored> {
|
|
28
|
+
/** Преобразует доменное значение перед записью. */
|
|
29
|
+
encode(value: T): KeyValueStoreResult<Stored>;
|
|
30
|
+
/** Восстанавливает доменное значение после чтения. */
|
|
31
|
+
decode(value: Stored): KeyValueStoreResult<T>;
|
|
32
|
+
}
|
|
33
|
+
/** Источник одной записи, содержащей всю карту key-value. */
|
|
34
|
+
interface RecordKeyValueStoreSource<T> {
|
|
35
|
+
/** Читает всю карту. `undefined` означает отсутствие записи. */
|
|
36
|
+
read(): KeyValueStoreResult<Readonly<Record<string, T>> | undefined>;
|
|
37
|
+
/** Записывает стабильный снимок всей карты. */
|
|
38
|
+
write(record: Readonly<Record<string, T>>): KeyValueStoreResult<void>;
|
|
39
|
+
/** Удаляет запись, когда карта становится пустой. */
|
|
40
|
+
delete?(): KeyValueStoreResult<void>;
|
|
41
|
+
}
|
|
42
|
+
declare function createKeyValueStore<T>(handlers: EnumerableKeyValueStore<T>): EnumerableKeyValueStore<T>;
|
|
43
|
+
declare function createKeyValueStore<T>(handlers: KeyValueStore<T>): KeyValueStore<T>;
|
|
44
|
+
/** Проверяет доступность перечисления ключей. */
|
|
45
|
+
declare function isEnumerableKeyValueStore<T>(store: KeyValueStore<T>): store is EnumerableKeyValueStore<T>;
|
|
46
|
+
/** Key-value backend в памяти процесса. Значения сохраняются по ссылке. */
|
|
47
|
+
declare class MemoryKeyValueStore<T> implements EnumerableKeyValueStore<T> {
|
|
48
|
+
#private;
|
|
49
|
+
constructor(initial?: Iterable<readonly [string, T]>);
|
|
50
|
+
get(key: string): T | undefined;
|
|
51
|
+
set(key: string, value: T): void;
|
|
52
|
+
delete(key: string): void;
|
|
53
|
+
keys(prefix?: string): string[];
|
|
54
|
+
}
|
|
55
|
+
declare function withNamespace<T>(store: EnumerableKeyValueStore<T>, namespace: string, separator?: string): EnumerableKeyValueStore<T>;
|
|
56
|
+
declare function withNamespace<T>(store: KeyValueStore<T>, namespace: string, separator?: string): KeyValueStore<T>;
|
|
57
|
+
declare function withCodec<T, Stored>(store: EnumerableKeyValueStore<Stored>, codec: KeyValueCodec<T, Stored>): EnumerableKeyValueStore<T>;
|
|
58
|
+
declare function withCodec<T, Stored>(store: KeyValueStore<Stored>, codec: KeyValueCodec<T, Stored>): KeyValueStore<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Создаёт key-value backend поверх одной общей записи.
|
|
61
|
+
*
|
|
62
|
+
* Чтение выполняется один раз, изменения сразу попадают в локальный снимок, а записи
|
|
63
|
+
* выстраиваются последовательно. Несколько экземпляров или процессов требуют внешней
|
|
64
|
+
* синхронизации со стороны source.
|
|
65
|
+
*/
|
|
66
|
+
declare function createRecordKeyValueStore<T>(source: RecordKeyValueStoreSource<T>): EnumerableKeyValueStore<T>;
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/core/storage.d.ts
|
|
69
|
+
/**
|
|
70
|
+
* Сохранённая сессия.
|
|
71
|
+
*
|
|
72
|
+
* Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них
|
|
73
|
+
* восстановить сессию после перезапуска процесса невозможно.
|
|
74
|
+
*/
|
|
75
|
+
interface ItdSession {
|
|
76
|
+
/** Токен доступа для заголовка `Authorization: Bearer`. */
|
|
77
|
+
accessToken?: string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Refresh-токен, если удалось получить его явным значением.
|
|
80
|
+
*
|
|
81
|
+
* Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется
|
|
82
|
+
* пустым, а обновление пойдёт через {@link ItdSession.cookies}.
|
|
83
|
+
*/
|
|
84
|
+
refreshToken?: string | undefined;
|
|
85
|
+
/** Сырые cookie в форме `имя=значение`, привязанные к origin API. */
|
|
86
|
+
cookies?: string[] | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Идентификатор устройства для заголовка `X-Device-Id`.
|
|
89
|
+
*
|
|
90
|
+
* Сервер различает по нему записи в списке сессий, поэтому значение должно пережить
|
|
91
|
+
* перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека
|
|
92
|
+
* заводит его сама при первом запросе и хранит здесь.
|
|
93
|
+
*/
|
|
94
|
+
deviceId?: string | undefined;
|
|
95
|
+
/** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */
|
|
96
|
+
obtainedAt?: number | undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Хранилище сессии.
|
|
100
|
+
*
|
|
101
|
+
* Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним
|
|
102
|
+
* только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.
|
|
103
|
+
*
|
|
104
|
+
* @example Своё хранилище поверх AsyncStorage в React Native
|
|
105
|
+
* ```ts
|
|
106
|
+
* const backend = withCodec(createKeyValueStore({
|
|
107
|
+
* get: (key) => AsyncStorage.getItem(key).then((value) => value ?? undefined),
|
|
108
|
+
* set: (key, value) => AsyncStorage.setItem(key, value),
|
|
109
|
+
* delete: (key) => AsyncStorage.removeItem(key),
|
|
110
|
+
* }), { encode: JSON.stringify, decode: JSON.parse });
|
|
111
|
+
* const storage = createTokenStorage(withNamespace(backend, 'my-app'));
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
interface TokenStorage {
|
|
115
|
+
/** Прочитать сессию. `null`, если её нет. */
|
|
116
|
+
get(): ItdSession | null | Promise<ItdSession | null>;
|
|
117
|
+
/** Сохранить сессию целиком. */
|
|
118
|
+
set(session: ItdSession): void | Promise<void>;
|
|
119
|
+
/** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */
|
|
120
|
+
clear(): void | Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Хранилище в памяти процесса — вариант по умолчанию.
|
|
124
|
+
*
|
|
125
|
+
* Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`
|
|
126
|
+
* из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или
|
|
127
|
+
* `SessionStorageTokenStorage` из `itd-api/web`.
|
|
128
|
+
*/
|
|
129
|
+
declare class MemoryTokenStorage implements TokenStorage {
|
|
130
|
+
#private;
|
|
131
|
+
constructor(initial?: ItdSession | null);
|
|
132
|
+
get(): ItdSession | null;
|
|
133
|
+
set(session: ItdSession): void;
|
|
134
|
+
clear(): void;
|
|
135
|
+
}
|
|
136
|
+
/** Настройки доменного адаптера одной сессии. */
|
|
137
|
+
interface TokenStorageAdapterOptions {
|
|
138
|
+
/** Ключ сессии в backend. По умолчанию `session`. */
|
|
139
|
+
key?: string | undefined;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* const storage = createTokenStorage(withNamespace(redisStore, 'itd'));
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function createTokenStorage(store: KeyValueStore<ItdSession>, options?: TokenStorageAdapterOptions): TokenStorage;
|
|
150
|
+
//#endregion
|
|
151
|
+
export { withNamespace as _, createTokenStorage as a, KeyValueStore as c, MemoryKeyValueStore as d, RecordKeyValueStoreSource as f, withCodec as g, isEnumerableKeyValueStore as h, TokenStorageAdapterOptions as i, KeyValueStoreKeys as l, createRecordKeyValueStore as m, MemoryTokenStorage as n, EnumerableKeyValueStore as o, createKeyValueStore as p, TokenStorage as r, KeyValueCodec as s, ItdSession as t, KeyValueStoreResult as u };
|
|
152
|
+
//# sourceMappingURL=storage-Doe3lpFQ.d.cts.map
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//#region src/core/key-value-store.d.ts
|
|
2
|
+
/** Синхронный или асинхронный результат операции хранилища. */
|
|
3
|
+
type KeyValueStoreResult<T> = T | Promise<T>;
|
|
4
|
+
/** Синхронный или асинхронный источник ключей. */
|
|
5
|
+
type KeyValueStoreKeys = Iterable<string> | AsyncIterable<string>;
|
|
6
|
+
/**
|
|
7
|
+
* Минимальный backend именованных значений.
|
|
8
|
+
*
|
|
9
|
+
* Контракт ничего не знает о сессиях, сериализации или конкретной базе данных. Значение
|
|
10
|
+
* `undefined` означает отсутствие ключа; хранить `undefined` как самостоятельное значение нельзя.
|
|
11
|
+
*/
|
|
12
|
+
interface KeyValueStore<T> {
|
|
13
|
+
/** Читает значение либо возвращает `undefined`, если ключ отсутствует. */
|
|
14
|
+
get(key: string): KeyValueStoreResult<T | undefined>;
|
|
15
|
+
/** Полностью заменяет значение ключа. */
|
|
16
|
+
set(key: string, value: T): KeyValueStoreResult<void>;
|
|
17
|
+
/** Удаляет ключ. Отсутствующий ключ не должен считаться ошибкой. */
|
|
18
|
+
delete(key: string): KeyValueStoreResult<void>;
|
|
19
|
+
/** Перечисляет ключи, при возможности ограничивая их префиксом. */
|
|
20
|
+
keys?(prefix?: string): KeyValueStoreResult<KeyValueStoreKeys>;
|
|
21
|
+
}
|
|
22
|
+
/** Backend, который гарантированно умеет перечислять ключи. */
|
|
23
|
+
interface EnumerableKeyValueStore<T> extends KeyValueStore<T> {
|
|
24
|
+
keys(prefix?: string): KeyValueStoreResult<KeyValueStoreKeys>;
|
|
25
|
+
}
|
|
26
|
+
/** Кодирует значения для хранения в backend другого типа. */
|
|
27
|
+
interface KeyValueCodec<T, Stored> {
|
|
28
|
+
/** Преобразует доменное значение перед записью. */
|
|
29
|
+
encode(value: T): KeyValueStoreResult<Stored>;
|
|
30
|
+
/** Восстанавливает доменное значение после чтения. */
|
|
31
|
+
decode(value: Stored): KeyValueStoreResult<T>;
|
|
32
|
+
}
|
|
33
|
+
/** Источник одной записи, содержащей всю карту key-value. */
|
|
34
|
+
interface RecordKeyValueStoreSource<T> {
|
|
35
|
+
/** Читает всю карту. `undefined` означает отсутствие записи. */
|
|
36
|
+
read(): KeyValueStoreResult<Readonly<Record<string, T>> | undefined>;
|
|
37
|
+
/** Записывает стабильный снимок всей карты. */
|
|
38
|
+
write(record: Readonly<Record<string, T>>): KeyValueStoreResult<void>;
|
|
39
|
+
/** Удаляет запись, когда карта становится пустой. */
|
|
40
|
+
delete?(): KeyValueStoreResult<void>;
|
|
41
|
+
}
|
|
42
|
+
declare function createKeyValueStore<T>(handlers: EnumerableKeyValueStore<T>): EnumerableKeyValueStore<T>;
|
|
43
|
+
declare function createKeyValueStore<T>(handlers: KeyValueStore<T>): KeyValueStore<T>;
|
|
44
|
+
/** Проверяет доступность перечисления ключей. */
|
|
45
|
+
declare function isEnumerableKeyValueStore<T>(store: KeyValueStore<T>): store is EnumerableKeyValueStore<T>;
|
|
46
|
+
/** Key-value backend в памяти процесса. Значения сохраняются по ссылке. */
|
|
47
|
+
declare class MemoryKeyValueStore<T> implements EnumerableKeyValueStore<T> {
|
|
48
|
+
#private;
|
|
49
|
+
constructor(initial?: Iterable<readonly [string, T]>);
|
|
50
|
+
get(key: string): T | undefined;
|
|
51
|
+
set(key: string, value: T): void;
|
|
52
|
+
delete(key: string): void;
|
|
53
|
+
keys(prefix?: string): string[];
|
|
54
|
+
}
|
|
55
|
+
declare function withNamespace<T>(store: EnumerableKeyValueStore<T>, namespace: string, separator?: string): EnumerableKeyValueStore<T>;
|
|
56
|
+
declare function withNamespace<T>(store: KeyValueStore<T>, namespace: string, separator?: string): KeyValueStore<T>;
|
|
57
|
+
declare function withCodec<T, Stored>(store: EnumerableKeyValueStore<Stored>, codec: KeyValueCodec<T, Stored>): EnumerableKeyValueStore<T>;
|
|
58
|
+
declare function withCodec<T, Stored>(store: KeyValueStore<Stored>, codec: KeyValueCodec<T, Stored>): KeyValueStore<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Создаёт key-value backend поверх одной общей записи.
|
|
61
|
+
*
|
|
62
|
+
* Чтение выполняется один раз, изменения сразу попадают в локальный снимок, а записи
|
|
63
|
+
* выстраиваются последовательно. Несколько экземпляров или процессов требуют внешней
|
|
64
|
+
* синхронизации со стороны source.
|
|
65
|
+
*/
|
|
66
|
+
declare function createRecordKeyValueStore<T>(source: RecordKeyValueStoreSource<T>): EnumerableKeyValueStore<T>;
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/core/storage.d.ts
|
|
69
|
+
/**
|
|
70
|
+
* Сохранённая сессия.
|
|
71
|
+
*
|
|
72
|
+
* Кроме токенов сюда попадают cookie: refresh-токен итд.com живёт именно в cookie, и без них
|
|
73
|
+
* восстановить сессию после перезапуска процесса невозможно.
|
|
74
|
+
*/
|
|
75
|
+
interface ItdSession {
|
|
76
|
+
/** Токен доступа для заголовка `Authorization: Bearer`. */
|
|
77
|
+
accessToken?: string | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Refresh-токен, если удалось получить его явным значением.
|
|
80
|
+
*
|
|
81
|
+
* Обычно сервер держит его в httpOnly-cookie и наружу не отдаёт — тогда поле останется
|
|
82
|
+
* пустым, а обновление пойдёт через {@link ItdSession.cookies}.
|
|
83
|
+
*/
|
|
84
|
+
refreshToken?: string | undefined;
|
|
85
|
+
/** Сырые cookie в форме `имя=значение`, привязанные к origin API. */
|
|
86
|
+
cookies?: string[] | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Идентификатор устройства для заголовка `X-Device-Id`.
|
|
89
|
+
*
|
|
90
|
+
* Сервер различает по нему записи в списке сессий, поэтому значение должно пережить
|
|
91
|
+
* перезапуск процесса — иначе каждый старт бота порождает новую сессию. Библиотека
|
|
92
|
+
* заводит его сама при первом запросе и хранит здесь.
|
|
93
|
+
*/
|
|
94
|
+
deviceId?: string | undefined;
|
|
95
|
+
/** Когда сессия получена, мс с начала эпохи. Нужно для диагностики. */
|
|
96
|
+
obtainedAt?: number | undefined;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Хранилище сессии.
|
|
100
|
+
*
|
|
101
|
+
* Подключаемый компонент: библиотека не знает, где вы держите токены, и обращается к ним
|
|
102
|
+
* только через этот интерфейс. Все методы могут быть как синхронными, так и асинхронными.
|
|
103
|
+
*
|
|
104
|
+
* @example Своё хранилище поверх AsyncStorage в React Native
|
|
105
|
+
* ```ts
|
|
106
|
+
* const backend = withCodec(createKeyValueStore({
|
|
107
|
+
* get: (key) => AsyncStorage.getItem(key).then((value) => value ?? undefined),
|
|
108
|
+
* set: (key, value) => AsyncStorage.setItem(key, value),
|
|
109
|
+
* delete: (key) => AsyncStorage.removeItem(key),
|
|
110
|
+
* }), { encode: JSON.stringify, decode: JSON.parse });
|
|
111
|
+
* const storage = createTokenStorage(withNamespace(backend, 'my-app'));
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
interface TokenStorage {
|
|
115
|
+
/** Прочитать сессию. `null`, если её нет. */
|
|
116
|
+
get(): ItdSession | null | Promise<ItdSession | null>;
|
|
117
|
+
/** Сохранить сессию целиком. */
|
|
118
|
+
set(session: ItdSession): void | Promise<void>;
|
|
119
|
+
/** Удалить сессию. Вызывается при выходе и при неудачном обновлении токена. */
|
|
120
|
+
clear(): void | Promise<void>;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Хранилище в памяти процесса — вариант по умолчанию.
|
|
124
|
+
*
|
|
125
|
+
* Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`
|
|
126
|
+
* из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или
|
|
127
|
+
* `SessionStorageTokenStorage` из `itd-api/web`.
|
|
128
|
+
*/
|
|
129
|
+
declare class MemoryTokenStorage implements TokenStorage {
|
|
130
|
+
#private;
|
|
131
|
+
constructor(initial?: ItdSession | null);
|
|
132
|
+
get(): ItdSession | null;
|
|
133
|
+
set(session: ItdSession): void;
|
|
134
|
+
clear(): void;
|
|
135
|
+
}
|
|
136
|
+
/** Настройки доменного адаптера одной сессии. */
|
|
137
|
+
interface TokenStorageAdapterOptions {
|
|
138
|
+
/** Ключ сессии в backend. По умолчанию `session`. */
|
|
139
|
+
key?: string | undefined;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* const storage = createTokenStorage(withNamespace(redisStore, 'itd'));
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
declare function createTokenStorage(store: KeyValueStore<ItdSession>, options?: TokenStorageAdapterOptions): TokenStorage;
|
|
150
|
+
//#endregion
|
|
151
|
+
export { withNamespace as _, createTokenStorage as a, KeyValueStore as c, MemoryKeyValueStore as d, RecordKeyValueStoreSource as f, withCodec as g, isEnumerableKeyValueStore as h, TokenStorageAdapterOptions as i, KeyValueStoreKeys as l, createRecordKeyValueStore as m, MemoryTokenStorage as n, EnumerableKeyValueStore as o, createKeyValueStore as p, TokenStorage as r, KeyValueCodec as s, ItdSession as t, KeyValueStoreResult as u };
|
|
152
|
+
//# sourceMappingURL=storage-Doe3lpFQ.d.ts.map
|
|
@@ -15,6 +15,8 @@ const ItdErrorKind = Object.freeze({
|
|
|
15
15
|
Timeout: "timeout",
|
|
16
16
|
/** Запрос отменён через `AbortSignal`. */
|
|
17
17
|
Abort: "abort",
|
|
18
|
+
/** Операция невозможна в текущем состоянии объекта. */
|
|
19
|
+
State: "state",
|
|
18
20
|
/** Не удалось получить или подготовить содержимое вложения. */
|
|
19
21
|
File: "file",
|
|
20
22
|
/** Некорректная конфигурация или аргументы — обнаружено до обращения к сети. */
|
|
@@ -300,14 +302,26 @@ var ItdAbortError = class extends ItdError {
|
|
|
300
302
|
}
|
|
301
303
|
};
|
|
302
304
|
/**
|
|
305
|
+
* Операция невозможна в текущем состоянии объекта.
|
|
306
|
+
*
|
|
307
|
+
* Например, клиент уже окончательно освобождён через `dispose()` и не может выполнять
|
|
308
|
+
* новые запросы или создавать realtime-потоки.
|
|
309
|
+
*/
|
|
310
|
+
var ItdStateError = class extends ItdError {
|
|
311
|
+
constructor(message, options) {
|
|
312
|
+
super(ItdErrorKind.State, message, options);
|
|
313
|
+
this.name = "ItdStateError";
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
/**
|
|
303
317
|
* Некорректная конфигурация или аргументы — обнаружено до обращения к сети.
|
|
304
318
|
*
|
|
305
319
|
* Этим же классом сообщают о нарушенных инвариантах билдеры: например, опрос
|
|
306
320
|
* с одним вариантом ответа.
|
|
307
321
|
*/
|
|
308
322
|
var ItdConfigError = class extends ItdError {
|
|
309
|
-
constructor(message) {
|
|
310
|
-
super(ItdErrorKind.Config, message);
|
|
323
|
+
constructor(message, options) {
|
|
324
|
+
super(ItdErrorKind.Config, message, options);
|
|
311
325
|
this.name = "ItdConfigError";
|
|
312
326
|
}
|
|
313
327
|
};
|
|
@@ -323,6 +337,10 @@ function isItdApiError(value) {
|
|
|
323
337
|
function isItdFileError(value) {
|
|
324
338
|
return isItdError(value) && value.kind === ItdErrorKind.File;
|
|
325
339
|
}
|
|
340
|
+
/** Операция невозможна в текущем состоянии объекта. */
|
|
341
|
+
function isItdStateError(value) {
|
|
342
|
+
return isItdError(value) && value.kind === ItdErrorKind.State;
|
|
343
|
+
}
|
|
326
344
|
/**
|
|
327
345
|
* Проверяет разновидность ошибки API.
|
|
328
346
|
*
|
|
@@ -366,6 +384,158 @@ function isItdServerError(value) {
|
|
|
366
384
|
return hasApiKind(value, ItdApiErrorKind.Server);
|
|
367
385
|
}
|
|
368
386
|
//#endregion
|
|
387
|
+
//#region src/core/key-value-store.ts
|
|
388
|
+
function isRecord(value) {
|
|
389
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
390
|
+
}
|
|
391
|
+
function requireStore(value) {
|
|
392
|
+
const store = value;
|
|
393
|
+
if (!isRecord(store)) throw new ItdConfigError("KeyValueStore должен быть объектом");
|
|
394
|
+
for (const method of [
|
|
395
|
+
"get",
|
|
396
|
+
"set",
|
|
397
|
+
"delete"
|
|
398
|
+
]) if (typeof store[method] !== "function") throw new ItdConfigError(`KeyValueStore.${method} должен быть функцией`);
|
|
399
|
+
if (store.keys !== void 0 && typeof store.keys !== "function") throw new ItdConfigError("KeyValueStore.keys должен быть функцией");
|
|
400
|
+
}
|
|
401
|
+
/** Собирает {@link KeyValueStore} из функций конкретного backend. */
|
|
402
|
+
function createKeyValueStore(handlers) {
|
|
403
|
+
requireStore(handlers);
|
|
404
|
+
return handlers;
|
|
405
|
+
}
|
|
406
|
+
/** Проверяет доступность перечисления ключей. */
|
|
407
|
+
function isEnumerableKeyValueStore(store) {
|
|
408
|
+
return typeof store.keys === "function";
|
|
409
|
+
}
|
|
410
|
+
/** @internal */
|
|
411
|
+
async function collectKeyValueStoreKeys(store, prefix) {
|
|
412
|
+
const source = await store.keys(prefix);
|
|
413
|
+
const result = [];
|
|
414
|
+
for await (const key of source) {
|
|
415
|
+
if (typeof key !== "string") throw new ItdConfigError("KeyValueStore.keys() должен возвращать только строки");
|
|
416
|
+
if (prefix === void 0 || key.startsWith(prefix)) result.push(key);
|
|
417
|
+
}
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
/** Key-value backend в памяти процесса. Значения сохраняются по ссылке. */
|
|
421
|
+
var MemoryKeyValueStore = class {
|
|
422
|
+
#values = /* @__PURE__ */ new Map();
|
|
423
|
+
constructor(initial) {
|
|
424
|
+
for (const [key, value] of initial ?? []) this.#values.set(key, value);
|
|
425
|
+
}
|
|
426
|
+
get(key) {
|
|
427
|
+
return this.#values.get(key);
|
|
428
|
+
}
|
|
429
|
+
set(key, value) {
|
|
430
|
+
this.#values.set(key, value);
|
|
431
|
+
}
|
|
432
|
+
delete(key) {
|
|
433
|
+
this.#values.delete(key);
|
|
434
|
+
}
|
|
435
|
+
keys(prefix = "") {
|
|
436
|
+
return [...this.#values.keys()].filter((key) => key.startsWith(prefix));
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
/** Добавляет namespace ко всем ключам, не меняя исходный backend. */
|
|
440
|
+
function withNamespace(store, namespace, separator = ":") {
|
|
441
|
+
requireStore(store);
|
|
442
|
+
if (typeof namespace !== "string" || typeof separator !== "string") throw new ItdConfigError("namespace и separator KeyValueStore должны быть строками");
|
|
443
|
+
const base = namespace.length === 0 ? "" : `${namespace}${separator}`;
|
|
444
|
+
const key = (value) => `${base}${value}`;
|
|
445
|
+
const namespaced = {
|
|
446
|
+
get: (value) => store.get(key(value)),
|
|
447
|
+
set: (value, data) => store.set(key(value), data),
|
|
448
|
+
delete: (value) => store.delete(key(value))
|
|
449
|
+
};
|
|
450
|
+
if (isEnumerableKeyValueStore(store)) namespaced.keys = async (prefix = "") => {
|
|
451
|
+
return (await collectKeyValueStoreKeys(store, key(prefix))).map((value) => value.slice(base.length));
|
|
452
|
+
};
|
|
453
|
+
return namespaced;
|
|
454
|
+
}
|
|
455
|
+
/** Преобразует значения на границе backend, сохраняя его пространство ключей. */
|
|
456
|
+
function withCodec(store, codec) {
|
|
457
|
+
requireStore(store);
|
|
458
|
+
if (!isRecord(codec) || typeof codec.encode !== "function" || typeof codec.decode !== "function") throw new ItdConfigError("codec должен содержать функции encode и decode");
|
|
459
|
+
const encoded = {
|
|
460
|
+
async get(key) {
|
|
461
|
+
const value = await store.get(key);
|
|
462
|
+
return value === void 0 ? void 0 : codec.decode(value);
|
|
463
|
+
},
|
|
464
|
+
async set(key, value) {
|
|
465
|
+
await store.set(key, await codec.encode(value));
|
|
466
|
+
},
|
|
467
|
+
delete: (key) => store.delete(key)
|
|
468
|
+
};
|
|
469
|
+
if (isEnumerableKeyValueStore(store)) encoded.keys = (prefix) => store.keys(prefix);
|
|
470
|
+
return encoded;
|
|
471
|
+
}
|
|
472
|
+
/** Создаёт запись без прототипа, чтобы любые пользовательские ключи оставались данными. */
|
|
473
|
+
function emptyRecord() {
|
|
474
|
+
return Object.create(null);
|
|
475
|
+
}
|
|
476
|
+
function copyRecord(record) {
|
|
477
|
+
const copy = emptyRecord();
|
|
478
|
+
for (const [key, value] of Object.entries(record ?? {})) copy[key] = value;
|
|
479
|
+
return copy;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Создаёт key-value backend поверх одной общей записи.
|
|
483
|
+
*
|
|
484
|
+
* Чтение выполняется один раз, изменения сразу попадают в локальный снимок, а записи
|
|
485
|
+
* выстраиваются последовательно. Несколько экземпляров или процессов требуют внешней
|
|
486
|
+
* синхронизации со стороны source.
|
|
487
|
+
*/
|
|
488
|
+
function createRecordKeyValueStore(source) {
|
|
489
|
+
if (!isRecord(source) || typeof source.read !== "function" || typeof source.write !== "function") throw new ItdConfigError("RecordKeyValueStoreSource должен содержать read и write");
|
|
490
|
+
if (source.delete !== void 0 && typeof source.delete !== "function") throw new ItdConfigError("RecordKeyValueStoreSource.delete должен быть функцией");
|
|
491
|
+
let snapshot;
|
|
492
|
+
let loading;
|
|
493
|
+
let writing = Promise.resolve();
|
|
494
|
+
const load = async () => {
|
|
495
|
+
if (snapshot !== void 0) return snapshot;
|
|
496
|
+
loading ??= Promise.resolve(source.read()).then((value) => {
|
|
497
|
+
if (value !== void 0 && !isRecord(value)) throw new ItdConfigError("RecordKeyValueStoreSource.read() должен вернуть объект");
|
|
498
|
+
snapshot = copyRecord(value);
|
|
499
|
+
return snapshot;
|
|
500
|
+
}).finally(() => {
|
|
501
|
+
loading = void 0;
|
|
502
|
+
});
|
|
503
|
+
return loading;
|
|
504
|
+
};
|
|
505
|
+
const flush = () => {
|
|
506
|
+
const current = copyRecord(snapshot);
|
|
507
|
+
const operation = async () => {
|
|
508
|
+
if (source.delete && Object.keys(current).length === 0) await source.delete();
|
|
509
|
+
else await source.write(current);
|
|
510
|
+
};
|
|
511
|
+
writing = writing.then(operation, operation);
|
|
512
|
+
return writing;
|
|
513
|
+
};
|
|
514
|
+
return {
|
|
515
|
+
async get(key) {
|
|
516
|
+
const current = await load();
|
|
517
|
+
await writing;
|
|
518
|
+
return Object.hasOwn(current, key) ? current[key] : void 0;
|
|
519
|
+
},
|
|
520
|
+
async set(key, value) {
|
|
521
|
+
const current = await load();
|
|
522
|
+
current[key] = value;
|
|
523
|
+
await flush();
|
|
524
|
+
},
|
|
525
|
+
async delete(key) {
|
|
526
|
+
const current = await load();
|
|
527
|
+
if (!Object.hasOwn(current, key)) return;
|
|
528
|
+
delete current[key];
|
|
529
|
+
await flush();
|
|
530
|
+
},
|
|
531
|
+
async keys(prefix = "") {
|
|
532
|
+
const current = await load();
|
|
533
|
+
await writing;
|
|
534
|
+
return Object.keys(current).filter((key) => key.startsWith(prefix));
|
|
535
|
+
}
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
//#endregion
|
|
369
539
|
//#region src/core/storage.ts
|
|
370
540
|
/**
|
|
371
541
|
* Создаёт независимый снимок сессии.
|
|
@@ -386,37 +556,50 @@ function copySession(session) {
|
|
|
386
556
|
* Хранилище в памяти процесса — вариант по умолчанию.
|
|
387
557
|
*
|
|
388
558
|
* Сессия теряется при перезапуске. Для долгоживущих ботов возьмите `FileTokenStorage`
|
|
389
|
-
* из `itd-api/node`, для браузера — `LocalStorageTokenStorage`
|
|
559
|
+
* из `itd-api/node`, для браузера — `LocalStorageTokenStorage` или
|
|
560
|
+
* `SessionStorageTokenStorage` из `itd-api/web`.
|
|
390
561
|
*/
|
|
391
562
|
var MemoryTokenStorage = class {
|
|
392
|
-
#
|
|
563
|
+
#store = new MemoryKeyValueStore();
|
|
393
564
|
constructor(initial) {
|
|
394
|
-
|
|
565
|
+
if (initial) this.#store.set(TOKEN_STORAGE_KEY, copySession(initial));
|
|
395
566
|
}
|
|
396
567
|
get() {
|
|
397
|
-
|
|
568
|
+
const session = this.#store.get(TOKEN_STORAGE_KEY);
|
|
569
|
+
return session ? copySession(session) : null;
|
|
398
570
|
}
|
|
399
571
|
set(session) {
|
|
400
|
-
this.#
|
|
572
|
+
this.#store.set(TOKEN_STORAGE_KEY, copySession(session));
|
|
401
573
|
}
|
|
402
574
|
clear() {
|
|
403
|
-
this.#
|
|
575
|
+
this.#store.delete(TOKEN_STORAGE_KEY);
|
|
404
576
|
}
|
|
405
577
|
};
|
|
578
|
+
const TOKEN_STORAGE_KEY = "session";
|
|
579
|
+
function isPromise(value) {
|
|
580
|
+
return typeof value === "object" && value !== null && typeof value.then === "function";
|
|
581
|
+
}
|
|
406
582
|
/**
|
|
407
|
-
*
|
|
583
|
+
* Создаёт доменное хранилище сессии поверх общего {@link KeyValueStore}.
|
|
408
584
|
*
|
|
409
585
|
* @example
|
|
410
586
|
* ```ts
|
|
411
|
-
* const storage = createTokenStorage(
|
|
412
|
-
* get: () => db.getSession(userId),
|
|
413
|
-
* set: (session) => db.saveSession(userId, session),
|
|
414
|
-
* clear: () => db.deleteSession(userId),
|
|
415
|
-
* });
|
|
587
|
+
* const storage = createTokenStorage(withNamespace(redisStore, 'itd'));
|
|
416
588
|
* ```
|
|
417
589
|
*/
|
|
418
|
-
function createTokenStorage(
|
|
419
|
-
|
|
590
|
+
function createTokenStorage(store, options = {}) {
|
|
591
|
+
const key = options.key ?? TOKEN_STORAGE_KEY;
|
|
592
|
+
if (typeof key !== "string") throw new ItdConfigError("key TokenStorage должен быть строкой");
|
|
593
|
+
const backend = createKeyValueStore(store);
|
|
594
|
+
return {
|
|
595
|
+
get() {
|
|
596
|
+
const value = backend.get(key);
|
|
597
|
+
if (isPromise(value)) return value.then((session) => session ? copySession(session) : null);
|
|
598
|
+
return value ? copySession(value) : null;
|
|
599
|
+
},
|
|
600
|
+
set: (session) => backend.set(key, copySession(session)),
|
|
601
|
+
clear: () => backend.delete(key)
|
|
602
|
+
};
|
|
420
603
|
}
|
|
421
604
|
//#endregion
|
|
422
605
|
Object.defineProperty(exports, "ItdAbortError", {
|
|
@@ -515,6 +698,12 @@ Object.defineProperty(exports, "ItdServerError", {
|
|
|
515
698
|
return ItdServerError;
|
|
516
699
|
}
|
|
517
700
|
});
|
|
701
|
+
Object.defineProperty(exports, "ItdStateError", {
|
|
702
|
+
enumerable: true,
|
|
703
|
+
get: function() {
|
|
704
|
+
return ItdStateError;
|
|
705
|
+
}
|
|
706
|
+
});
|
|
518
707
|
Object.defineProperty(exports, "ItdTimeoutError", {
|
|
519
708
|
enumerable: true,
|
|
520
709
|
get: function() {
|
|
@@ -527,24 +716,54 @@ Object.defineProperty(exports, "ItdValidationError", {
|
|
|
527
716
|
return ItdValidationError;
|
|
528
717
|
}
|
|
529
718
|
});
|
|
719
|
+
Object.defineProperty(exports, "MemoryKeyValueStore", {
|
|
720
|
+
enumerable: true,
|
|
721
|
+
get: function() {
|
|
722
|
+
return MemoryKeyValueStore;
|
|
723
|
+
}
|
|
724
|
+
});
|
|
530
725
|
Object.defineProperty(exports, "MemoryTokenStorage", {
|
|
531
726
|
enumerable: true,
|
|
532
727
|
get: function() {
|
|
533
728
|
return MemoryTokenStorage;
|
|
534
729
|
}
|
|
535
730
|
});
|
|
731
|
+
Object.defineProperty(exports, "collectKeyValueStoreKeys", {
|
|
732
|
+
enumerable: true,
|
|
733
|
+
get: function() {
|
|
734
|
+
return collectKeyValueStoreKeys;
|
|
735
|
+
}
|
|
736
|
+
});
|
|
536
737
|
Object.defineProperty(exports, "copySession", {
|
|
537
738
|
enumerable: true,
|
|
538
739
|
get: function() {
|
|
539
740
|
return copySession;
|
|
540
741
|
}
|
|
541
742
|
});
|
|
743
|
+
Object.defineProperty(exports, "createKeyValueStore", {
|
|
744
|
+
enumerable: true,
|
|
745
|
+
get: function() {
|
|
746
|
+
return createKeyValueStore;
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
Object.defineProperty(exports, "createRecordKeyValueStore", {
|
|
750
|
+
enumerable: true,
|
|
751
|
+
get: function() {
|
|
752
|
+
return createRecordKeyValueStore;
|
|
753
|
+
}
|
|
754
|
+
});
|
|
542
755
|
Object.defineProperty(exports, "createTokenStorage", {
|
|
543
756
|
enumerable: true,
|
|
544
757
|
get: function() {
|
|
545
758
|
return createTokenStorage;
|
|
546
759
|
}
|
|
547
760
|
});
|
|
761
|
+
Object.defineProperty(exports, "isEnumerableKeyValueStore", {
|
|
762
|
+
enumerable: true,
|
|
763
|
+
get: function() {
|
|
764
|
+
return isEnumerableKeyValueStore;
|
|
765
|
+
}
|
|
766
|
+
});
|
|
548
767
|
Object.defineProperty(exports, "isItdApiError", {
|
|
549
768
|
enumerable: true,
|
|
550
769
|
get: function() {
|
|
@@ -605,11 +824,29 @@ Object.defineProperty(exports, "isItdServerError", {
|
|
|
605
824
|
return isItdServerError;
|
|
606
825
|
}
|
|
607
826
|
});
|
|
827
|
+
Object.defineProperty(exports, "isItdStateError", {
|
|
828
|
+
enumerable: true,
|
|
829
|
+
get: function() {
|
|
830
|
+
return isItdStateError;
|
|
831
|
+
}
|
|
832
|
+
});
|
|
608
833
|
Object.defineProperty(exports, "isItdValidationError", {
|
|
609
834
|
enumerable: true,
|
|
610
835
|
get: function() {
|
|
611
836
|
return isItdValidationError;
|
|
612
837
|
}
|
|
613
838
|
});
|
|
839
|
+
Object.defineProperty(exports, "withCodec", {
|
|
840
|
+
enumerable: true,
|
|
841
|
+
get: function() {
|
|
842
|
+
return withCodec;
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
Object.defineProperty(exports, "withNamespace", {
|
|
846
|
+
enumerable: true,
|
|
847
|
+
get: function() {
|
|
848
|
+
return withNamespace;
|
|
849
|
+
}
|
|
850
|
+
});
|
|
614
851
|
|
|
615
|
-
//# sourceMappingURL=storage-
|
|
852
|
+
//# sourceMappingURL=storage-dF8Tio5y.cjs.map
|