rustore 1.0.1

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 (51) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +225 -0
  3. package/dist/api/apps.d.ts +32 -0
  4. package/dist/api/apps.d.ts.map +1 -0
  5. package/dist/api/apps.js +56 -0
  6. package/dist/api/apps.js.map +1 -0
  7. package/dist/api/auth.d.ts +29 -0
  8. package/dist/api/auth.d.ts.map +1 -0
  9. package/dist/api/auth.js +139 -0
  10. package/dist/api/auth.js.map +1 -0
  11. package/dist/api/catalog.d.ts +15 -0
  12. package/dist/api/catalog.d.ts.map +1 -0
  13. package/dist/api/catalog.js +15 -0
  14. package/dist/api/catalog.js.map +1 -0
  15. package/dist/api/client.d.ts +35 -0
  16. package/dist/api/client.d.ts.map +1 -0
  17. package/dist/api/client.js +80 -0
  18. package/dist/api/client.js.map +1 -0
  19. package/dist/api/payments-app.d.ts +15 -0
  20. package/dist/api/payments-app.d.ts.map +1 -0
  21. package/dist/api/payments-app.js +15 -0
  22. package/dist/api/payments-app.js.map +1 -0
  23. package/dist/api/payments.d.ts +15 -0
  24. package/dist/api/payments.d.ts.map +1 -0
  25. package/dist/api/payments.js +15 -0
  26. package/dist/api/payments.js.map +1 -0
  27. package/dist/bin.d.ts +6 -0
  28. package/dist/bin.d.ts.map +1 -0
  29. package/dist/bin.js +83 -0
  30. package/dist/bin.js.map +1 -0
  31. package/dist/commands/apps.d.ts +11 -0
  32. package/dist/commands/apps.d.ts.map +1 -0
  33. package/dist/commands/apps.js +52 -0
  34. package/dist/commands/apps.js.map +1 -0
  35. package/dist/commands/auth.d.ts +16 -0
  36. package/dist/commands/auth.d.ts.map +1 -0
  37. package/dist/commands/auth.js +46 -0
  38. package/dist/commands/auth.js.map +1 -0
  39. package/dist/config.d.ts +22 -0
  40. package/dist/config.d.ts.map +1 -0
  41. package/dist/config.js +53 -0
  42. package/dist/config.js.map +1 -0
  43. package/dist/index.d.ts +12 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +12 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/types.d.ts +56 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +5 -0
  50. package/dist/types.js.map +1 -0
  51. package/package.json +85 -0
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,225 @@
1
+ <h1 align="center">rustore<br>CLI для работы с RuStore API</h1>
2
+
3
+ <p align="center">
4
+ Командная строка для взаимодействия с RuStore API, похожая на Expo CLI
5
+ </p>
6
+
7
+ [![NPM version][npm-image]][npm-url]
8
+ ![npm-typescript]
9
+ [![License][github-license]][github-license-url]
10
+
11
+ ## 🌟 Возможности
12
+
13
+ - 🔐 Авторизация через приватный ключ из RuStore Консоль
14
+ - 🔑 Автоматическое управление токенами доступа
15
+ - 📦 Работа с API RuStore (платежи, подписки, приложения)
16
+ - ⚙️ Сохранение конфигурации в `~/.rustore/config.json`
17
+ - 🧪 Полное покрытие тестами
18
+
19
+ ## 🛠️ Установка
20
+
21
+ ```sh
22
+ npm install -g rustore
23
+ ```
24
+
25
+ или локально:
26
+
27
+ ```sh
28
+ npm install rustore
29
+ ```
30
+
31
+ ## 📖 Использование
32
+
33
+ ### Первоначальная настройка
34
+
35
+ Перед использованием CLI необходимо получить приватный ключ в [RuStore Консоль](https://console.rustore.ru/sign-in).
36
+
37
+ ### Авторизация
38
+
39
+ ```sh
40
+ # Авторизация с указанием keyId и приватного ключа
41
+ rustore login --key-id <keyId> --key <base64-ключ>
42
+
43
+ # Или короткая форма
44
+ rustore login -i <keyId> -k <base64-ключ>
45
+ ```
46
+
47
+ **Пример:**
48
+
49
+ ```sh
50
+ rustore login --key-id 123456 --key MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC...
51
+ ```
52
+
53
+ ### Проверка статуса
54
+
55
+ ```sh
56
+ # Показать информацию о текущей авторизации
57
+ rustore whoami
58
+ ```
59
+
60
+ ### Выход из системы
61
+
62
+ ```sh
63
+ # Удалить токен (ключи остаются в конфиге)
64
+ rustore logout
65
+ ```
66
+
67
+ ### Работа с приложениями
68
+
69
+ ```sh
70
+ # Получить список приложений
71
+ rustore apps list
72
+
73
+ # Получить все приложения (с пагинацией)
74
+ rustore apps list --all
75
+
76
+ # Вывести результат в формате JSON
77
+ rustore apps list --json
78
+ ```
79
+
80
+ ## 📁 Конфигурация
81
+
82
+ CLI сохраняет конфигурацию в `~/.rustore/config.json`:
83
+
84
+ ```json
85
+ {
86
+ "keyId": "ваш-key-id",
87
+ "privateKey": "ваш-приватный-ключ-base64",
88
+ "token": "jwe-токен",
89
+ "tokenExpiresAt": 1234567890
90
+ }
91
+ ```
92
+
93
+ **Важно:** Приватный ключ хранится в открытом виде. Защитите доступ к файлу конфигурации.
94
+
95
+ ## 🔧 Разработка
96
+
97
+ ### Установка зависимостей
98
+
99
+ ```sh
100
+ npm install
101
+ ```
102
+
103
+ ### Сборка
104
+
105
+ ```sh
106
+ npm run build
107
+ ```
108
+
109
+ ### Запуск в режиме разработки
110
+
111
+ ```sh
112
+ npm start
113
+ ```
114
+
115
+ ### Тестирование
116
+
117
+ ```sh
118
+ # Запустить все тесты
119
+ npm test
120
+
121
+ # Тесты в watch режиме
122
+ npm run test:watch
123
+
124
+ # С покрытием
125
+ npm run test:coverage
126
+ ```
127
+
128
+ #### Как протестировать текущие изменения
129
+
130
+ 1. **Сборка проекта:**
131
+
132
+ ```sh
133
+ npm run build
134
+ ```
135
+
136
+ 2. **Проверка типов:**
137
+
138
+ ```sh
139
+ npm run type-check
140
+ # или
141
+ ./node_modules/.bin/tsc --noEmit
142
+ ```
143
+
144
+ 3. **Запуск тестов:**
145
+
146
+ ```sh
147
+ npm test
148
+ ```
149
+
150
+ 4. **Тестирование CLI локально:**
151
+
152
+ ```sh
153
+ # Запуск без установки (через tsx)
154
+ npm start -- login <keyId> --key <key>
155
+
156
+ # Или после сборки
157
+ node dist/bin.js whoami
158
+ ```
159
+
160
+ 5. **Линтинг:**
161
+ ```sh
162
+ npm run lint
163
+ npm run lint:fix
164
+ ```
165
+
166
+ ### Проверка типов
167
+
168
+ ```sh
169
+ npm run type-check
170
+ ```
171
+
172
+ ### Линтинг
173
+
174
+ ```sh
175
+ npm run lint
176
+ npm run lint:fix
177
+ ```
178
+
179
+ ## 📚 API
180
+
181
+ ### Структура API
182
+
183
+ API организовано по категориям, как в документации RuStore:
184
+
185
+ - **Apps API** (`appsApi`) - Загрузка и публикация приложений (общие методы)
186
+ - **Payments API** (`paymentsApi`) - Работа с платежами и подписками (общие методы)
187
+ - **Payments App API** (`paymentsAppApi`) - Работа с платежами и подписками (методы приложений)
188
+ - **Catalog API** (`catalogApi`) - API для работы с продуктовым каталогом
189
+
190
+ ### Программный доступ
191
+
192
+ ```typescript
193
+ import {login, appsApi, paymentsApi, catalogApi} from 'rustore';
194
+
195
+ // Авторизация
196
+ await login('keyId', 'privateKey');
197
+
198
+ // Получить список приложений
199
+ const appsResponse = await appsApi.getAppList();
200
+ console.log(appsResponse.body.content);
201
+
202
+ // Получить все приложения (с автоматической пагинацией)
203
+ const allApps = await appsApi.getAllApps();
204
+
205
+ // Использование других API категорий
206
+ // await paymentsApi.refund(...);
207
+ // await catalogApi.getProducts(...);
208
+ ```
209
+
210
+ ## 🔗 Полезные ссылки
211
+
212
+ - [Документация RuStore API](https://www.rustore.ru/help/en/work-with-rustore-api)
213
+ - [Процесс авторизации](https://www.rustore.ru/help/work-with-rustore-api/api-authorization-token)
214
+ - [RuStore Консоль](https://console.rustore.ru/sign-in)
215
+
216
+ ## 📝 Лицензия
217
+
218
+ MIT
219
+
220
+ [package-name]: rustore
221
+ [npm-url]: https://www.npmjs.com/package/rustore
222
+ [npm-image]: https://img.shields.io/npm/v/rustore
223
+ [github-license]: https://img.shields.io/github/license/romankurnovskii/rustore
224
+ [github-license-url]: https://github.com/romankurnovskii/rustore/blob/main/LICENSE
225
+ [npm-typescript]: https://img.shields.io/npm/types/rustore
@@ -0,0 +1,32 @@
1
+ /**
2
+ * API для работы с приложениями
3
+ * Категория: Загрузка и публикация приложений (общие методы)
4
+ */
5
+ import { RustoreApiClient } from './client.js';
6
+ import type { GetAppListResponse, App } from '../types.js';
7
+ /**
8
+ * Клиент для работы с приложениями
9
+ */
10
+ export declare class AppsApi extends RustoreApiClient {
11
+ /**
12
+ * Получить список приложений
13
+ * GET /public/v1/application
14
+ *
15
+ * Метод позволяет получить приложения, доступные владельцу аккаунта,
16
+ * для которого создан приватный ключ.
17
+ *
18
+ * @param continuationToken - Токен для пагинации (опционально)
19
+ * @returns Список приложений
20
+ */
21
+ getAppList(continuationToken?: string): Promise<GetAppListResponse>;
22
+ /**
23
+ * Получить все приложения (с автоматической пагинацией)
24
+ * @returns Массив всех приложений
25
+ */
26
+ getAllApps(): Promise<App[]>;
27
+ }
28
+ /**
29
+ * Экспортируемый экземпляр клиента для работы с приложениями
30
+ */
31
+ export declare const appsApi: AppsApi;
32
+ //# sourceMappingURL=apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/api/apps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAC,kBAAkB,EAAE,GAAG,EAAC,MAAM,aAAa,CAAC;AAEzD;;GAEG;AACH,qBAAa,OAAQ,SAAQ,gBAAgB;IAC3C;;;;;;;;;OASG;IACG,UAAU,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoBzE;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;CAanC;AAED;;GAEG;AACH,eAAO,MAAM,OAAO,SAAgB,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * API для работы с приложениями
3
+ * Категория: Загрузка и публикация приложений (общие методы)
4
+ */
5
+ import { RustoreApiClient } from './client.js';
6
+ /**
7
+ * Клиент для работы с приложениями
8
+ */
9
+ export class AppsApi extends RustoreApiClient {
10
+ /**
11
+ * Получить список приложений
12
+ * GET /public/v1/application
13
+ *
14
+ * Метод позволяет получить приложения, доступные владельцу аккаунта,
15
+ * для которого создан приватный ключ.
16
+ *
17
+ * @param continuationToken - Токен для пагинации (опционально)
18
+ * @returns Список приложений
19
+ */
20
+ async getAppList(continuationToken) {
21
+ // Проверяем, не указан ли endpoint вручную через переменную окружения
22
+ const customEndpoint = process.env.RUSTORE_APPLICATIONS_ENDPOINT;
23
+ if (customEndpoint) {
24
+ const endpoint = continuationToken
25
+ ? `${customEndpoint}?continuationToken=${encodeURIComponent(continuationToken)}`
26
+ : customEndpoint;
27
+ return this.get(endpoint);
28
+ }
29
+ // Правильный endpoint согласно документации RuStore: /public/v1/application
30
+ // Используем единственное число "application", а не "applications"
31
+ const baseEndpoint = '/public/v1/application';
32
+ const endpoint = continuationToken
33
+ ? `${baseEndpoint}?continuationToken=${encodeURIComponent(continuationToken)}`
34
+ : baseEndpoint;
35
+ return this.get(endpoint);
36
+ }
37
+ /**
38
+ * Получить все приложения (с автоматической пагинацией)
39
+ * @returns Массив всех приложений
40
+ */
41
+ async getAllApps() {
42
+ const allApps = [];
43
+ let continuationToken;
44
+ do {
45
+ const response = await this.getAppList(continuationToken);
46
+ allApps.push(...response.body.content);
47
+ continuationToken = response.body.continuationToken;
48
+ } while (continuationToken);
49
+ return allApps;
50
+ }
51
+ }
52
+ /**
53
+ * Экспортируемый экземпляр клиента для работы с приложениями
54
+ */
55
+ export const appsApi = new AppsApi();
56
+ //# sourceMappingURL=apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.js","sourceRoot":"","sources":["../../src/api/apps.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAG7C;;GAEG;AACH,MAAM,OAAO,OAAQ,SAAQ,gBAAgB;IAC3C;;;;;;;;;OASG;IACH,KAAK,CAAC,UAAU,CAAC,iBAA0B;QACzC,sEAAsE;QACtE,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC;QACjE,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,iBAAiB;gBAChC,CAAC,CAAC,GAAG,cAAc,sBAAsB,kBAAkB,CAAC,iBAAiB,CAAC,EAAE;gBAChF,CAAC,CAAC,cAAc,CAAC;YACnB,OAAO,IAAI,CAAC,GAAG,CAAqB,QAAQ,CAAC,CAAC;QAChD,CAAC;QAED,4EAA4E;QAC5E,mEAAmE;QACnE,MAAM,YAAY,GAAG,wBAAwB,CAAC;QAC9C,MAAM,QAAQ,GAAG,iBAAiB;YAChC,CAAC,CAAC,GAAG,YAAY,sBAAsB,kBAAkB,CAAC,iBAAiB,CAAC,EAAE;YAC9E,CAAC,CAAC,YAAY,CAAC;QAEjB,OAAO,IAAI,CAAC,GAAG,CAAqB,QAAQ,CAAC,CAAC;IAChD,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU;QACd,MAAM,OAAO,GAAU,EAAE,CAAC;QAC1B,IAAI,iBAAqC,CAAC;QAE1C,GAAG,CAAC;YACF,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YAC1D,OAAO,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAEvC,iBAAiB,GAAG,QAAQ,CAAC,IAAI,CAAC,iBAAiB,CAAC;QACtD,CAAC,QAAQ,iBAAiB,EAAE;QAE5B,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Модуль для работы с авторизацией RuStore API
3
+ */
4
+ import type { AuthRequest, AuthTokenResponse } from '../types.js';
5
+ /**
6
+ * Генерирует RSA-SHA512 подпись для запроса авторизации
7
+ */
8
+ export declare function generateSignature(keyId: string, timestamp: string, privateKey: string): string;
9
+ /**
10
+ * Формирует запрос для получения токена авторизации
11
+ */
12
+ export declare function createAuthRequest(keyId: string, privateKey: string): AuthRequest;
13
+ /**
14
+ * Получает токен авторизации от RuStore API
15
+ */
16
+ export declare function getAuthToken(keyId: string, privateKey: string): Promise<AuthTokenResponse>;
17
+ /**
18
+ * Сохраняет токен в конфигурацию
19
+ */
20
+ export declare function login(keyId: string, privateKey: string): Promise<void>;
21
+ /**
22
+ * Проверяет, действителен ли сохранённый токен
23
+ */
24
+ export declare function isTokenValid(): boolean;
25
+ /**
26
+ * Получает токен из конфигурации или обновляет его
27
+ */
28
+ export declare function getToken(): Promise<string>;
29
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAC,WAAW,EAAE,iBAAiB,EAAS,MAAM,aAAa,CAAC;AAKxE;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CA4CR;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,WAAW,CAYhF;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,iBAAiB,CAAC,CAyB5B;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAe5E;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAQtC;AAED;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CA8BhD"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Модуль для работы с авторизацией RuStore API
3
+ */
4
+ import { createSign } from 'node:crypto';
5
+ import { loadConfig, saveConfig } from '../config.js';
6
+ const API_BASE_URL = 'https://public-api.rustore.ru';
7
+ /**
8
+ * Генерирует RSA-SHA512 подпись для запроса авторизации
9
+ */
10
+ export function generateSignature(keyId, timestamp, privateKey) {
11
+ try {
12
+ // Приватный ключ может быть в Base64 или уже в PEM формате
13
+ // Пытаемся определить формат
14
+ let privateKeyPEM;
15
+ // Если ключ не содержит заголовков PEM, значит это Base64
16
+ if (!privateKey.includes('-----BEGIN')) {
17
+ // Декодируем приватный ключ из Base64
18
+ const privateKeyBuffer = Buffer.from(privateKey, 'base64');
19
+ privateKeyPEM = privateKeyBuffer.toString('utf-8');
20
+ // Если после декодирования всё ещё нет заголовков, возможно это DER формат
21
+ // В Node.js crypto может работать с DER, но попробуем сначала как PEM
22
+ if (!privateKeyPEM.includes('-----BEGIN')) {
23
+ // Пытаемся использовать как DER (raw binary)
24
+ privateKeyPEM = privateKey;
25
+ }
26
+ }
27
+ else {
28
+ // Ключ уже в PEM формате
29
+ privateKeyPEM = privateKey;
30
+ }
31
+ // Создаём сообщение для подписи: keyId + timestamp
32
+ const message = keyId + timestamp;
33
+ // Создаём подпись
34
+ const sign = createSign('RSA-SHA512');
35
+ sign.update(message, 'utf-8');
36
+ sign.end();
37
+ // Пытаемся использовать ключ как PEM, если не получится - как DER
38
+ try {
39
+ return sign.sign(privateKeyPEM, 'base64');
40
+ }
41
+ catch {
42
+ // Если не получилось с PEM, пробуем с raw buffer в DER формате
43
+ const keyBuffer = Buffer.from(privateKey, 'base64');
44
+ return sign.sign({ key: keyBuffer, format: 'der', type: 'pkcs1' }, 'base64');
45
+ }
46
+ }
47
+ catch (error) {
48
+ throw new Error(`Ошибка генерации подписи: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ }
51
+ /**
52
+ * Формирует запрос для получения токена авторизации
53
+ */
54
+ export function createAuthRequest(keyId, privateKey) {
55
+ // Генерируем timestamp в формате ISO 8601 с миллисекундами
56
+ const now = new Date();
57
+ const timestamp = now.toISOString().replace('Z', '+00:00');
58
+ const signature = generateSignature(keyId, timestamp, privateKey);
59
+ return {
60
+ keyId,
61
+ timestamp,
62
+ signature,
63
+ };
64
+ }
65
+ /**
66
+ * Получает токен авторизации от RuStore API
67
+ */
68
+ export async function getAuthToken(keyId, privateKey) {
69
+ const authRequest = createAuthRequest(keyId, privateKey);
70
+ const response = await fetch(`${API_BASE_URL}/public/auth/`, {
71
+ method: 'POST',
72
+ headers: {
73
+ 'Content-Type': 'application/json',
74
+ },
75
+ body: JSON.stringify(authRequest),
76
+ });
77
+ if (!response.ok) {
78
+ const errorText = await response.text();
79
+ throw new Error(`Ошибка получения токена: ${response.status} ${response.statusText} - ${errorText}`);
80
+ }
81
+ const data = (await response.json());
82
+ if (data.code !== 'OK' && data.code !== 'ok') {
83
+ throw new Error(`Ошибка API: ${data.message ?? 'Неизвестная ошибка'}`);
84
+ }
85
+ return data;
86
+ }
87
+ /**
88
+ * Сохраняет токен в конфигурацию
89
+ */
90
+ export async function login(keyId, privateKey) {
91
+ const tokenResponse = await getAuthToken(keyId, privateKey);
92
+ if (!tokenResponse.body?.jwe) {
93
+ throw new Error('Токен не получен в ответе API');
94
+ }
95
+ const config = {
96
+ keyId,
97
+ privateKey,
98
+ token: tokenResponse.body.jwe,
99
+ tokenExpiresAt: Date.now() + tokenResponse.body.ttl * 1000,
100
+ };
101
+ saveConfig(config);
102
+ }
103
+ /**
104
+ * Проверяет, действителен ли сохранённый токен
105
+ */
106
+ export function isTokenValid() {
107
+ const config = loadConfig();
108
+ if (!config.token || !config.tokenExpiresAt) {
109
+ return false;
110
+ }
111
+ // Проверяем, не истёк ли токен (с запасом в 60 секунд)
112
+ return config.tokenExpiresAt > Date.now() + 60000;
113
+ }
114
+ /**
115
+ * Получает токен из конфигурации или обновляет его
116
+ */
117
+ export async function getToken() {
118
+ const config = loadConfig();
119
+ if (!config.keyId || !config.privateKey) {
120
+ throw new Error('Ключи не настроены. Используйте команду "rustore login" для настройки.');
121
+ }
122
+ // Если токен валиден, возвращаем его
123
+ if (isTokenValid() && config.token) {
124
+ return config.token;
125
+ }
126
+ // Иначе обновляем токен
127
+ const tokenResponse = await getAuthToken(config.keyId, config.privateKey);
128
+ if (!tokenResponse.body?.jwe) {
129
+ throw new Error('Токен не получен в ответе API');
130
+ }
131
+ const updatedConfig = {
132
+ ...config,
133
+ token: tokenResponse.body.jwe,
134
+ tokenExpiresAt: Date.now() + tokenResponse.body.ttl * 1000,
135
+ };
136
+ saveConfig(updatedConfig);
137
+ return tokenResponse.body.jwe;
138
+ }
139
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAC,UAAU,EAAC,MAAM,aAAa,CAAC;AAEvC,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAEpD,MAAM,YAAY,GAAG,+BAA+B,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,SAAiB,EACjB,UAAkB;IAElB,IAAI,CAAC;QACH,2DAA2D;QAC3D,6BAA6B;QAC7B,IAAI,aAAqB,CAAC;QAE1B,0DAA0D;QAC1D,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACvC,sCAAsC;YACtC,MAAM,gBAAgB,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAC3D,aAAa,GAAG,gBAAgB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAEnD,2EAA2E;YAC3E,sEAAsE;YACtE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC1C,6CAA6C;gBAC7C,aAAa,GAAG,UAAU,CAAC;YAC7B,CAAC;QACH,CAAC;aAAM,CAAC;YACN,yBAAyB;YACzB,aAAa,GAAG,UAAU,CAAC;QAC7B,CAAC;QAED,mDAAmD;QACnD,MAAM,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC;QAElC,kBAAkB;QAClB,MAAM,IAAI,GAAG,UAAU,CAAC,YAAY,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,GAAG,EAAE,CAAC;QAEX,kEAAkE;QAClE,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;QAC5C,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;YAC/D,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACpD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAC,EAAE,QAAQ,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,UAAkB;IACjE,2DAA2D;IAC3D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE3D,MAAM,SAAS,GAAG,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;IAElE,OAAO;QACL,KAAK;QACL,SAAS;QACT,SAAS;KACV,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAa,EACb,UAAkB;IAElB,MAAM,WAAW,GAAG,iBAAiB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAEzD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,eAAe,EAAE;QAC3D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;KAClC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,4BAA4B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,MAAM,SAAS,EAAE,CACpF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB,CAAC;IAE1D,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,eAAe,IAAI,CAAC,OAAO,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACzE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,KAAa,EAAE,UAAkB;IAC3D,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IAE5D,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,MAAM,GAAW;QACrB,KAAK;QACL,UAAU;QACV,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG;QAC7B,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI;KAC3D,CAAC;IAEF,UAAU,CAAC,MAAM,CAAC,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uDAAuD;IACvD,OAAO,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,wEAAwE,CACzE,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,IAAI,YAAY,EAAE,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACnC,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,wBAAwB;IACxB,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAE1E,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,MAAM,aAAa,GAAW;QAC5B,GAAG,MAAM;QACT,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,GAAG;QAC7B,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI;KAC3D,CAAC;IAEF,UAAU,CAAC,aAAa,CAAC,CAAC;IAE1B,OAAO,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;AAChC,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * API для работы с продуктовым каталогом
3
+ * Категория: API для работы с продуктовым каталогом
4
+ */
5
+ import { RustoreApiClient } from './client.js';
6
+ /**
7
+ * Клиент для работы с продуктовым каталогом
8
+ */
9
+ export declare class CatalogApi extends RustoreApiClient {
10
+ }
11
+ /**
12
+ * Экспортируемый экземпляр клиента для работы с каталогом
13
+ */
14
+ export declare const catalogApi: CatalogApi;
15
+ //# sourceMappingURL=catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../src/api/catalog.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,qBAAa,UAAW,SAAQ,gBAAgB;CAG/C;AAED;;GAEG;AACH,eAAO,MAAM,UAAU,YAAmB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * API для работы с продуктовым каталогом
3
+ * Категория: API для работы с продуктовым каталогом
4
+ */
5
+ import { RustoreApiClient } from './client.js';
6
+ /**
7
+ * Клиент для работы с продуктовым каталогом
8
+ */
9
+ export class CatalogApi extends RustoreApiClient {
10
+ }
11
+ /**
12
+ * Экспортируемый экземпляр клиента для работы с каталогом
13
+ */
14
+ export const catalogApi = new CatalogApi();
15
+ //# sourceMappingURL=catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../src/api/catalog.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,aAAa,CAAC;AAE7C;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,gBAAgB;CAG/C;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,UAAU,EAAE,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Клиент для работы с RuStore API
3
+ */
4
+ /**
5
+ * Базовый класс для работы с API
6
+ */
7
+ export declare class RustoreApiClient {
8
+ private baseUrl;
9
+ constructor(baseUrl?: string);
10
+ /**
11
+ * Выполняет авторизованный запрос к API
12
+ */
13
+ protected request<T>(endpoint: string, options?: RequestInit): Promise<T>;
14
+ /**
15
+ * GET запрос
16
+ */
17
+ get<T>(endpoint: string): Promise<T>;
18
+ /**
19
+ * POST запрос
20
+ */
21
+ post<T>(endpoint: string, body?: unknown): Promise<T>;
22
+ /**
23
+ * PUT запрос
24
+ */
25
+ put<T>(endpoint: string, body?: unknown): Promise<T>;
26
+ /**
27
+ * DELETE запрос
28
+ */
29
+ delete<T>(endpoint: string): Promise<T>;
30
+ }
31
+ /**
32
+ * Экспортируемый экземпляр клиента
33
+ */
34
+ export declare const apiClient: RustoreApiClient;
35
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,MAAqB;IAI1C;;OAEG;cACa,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,CAAC,CAAC;IAiCnF;;OAEG;IACG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAI1C;;OAEG;IACG,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAO3D;;OAEG;IACG,GAAG,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAO1D;;OAEG;IACG,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CAG9C;AAED;;GAEG;AACH,eAAO,MAAM,SAAS,kBAAyB,CAAC"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Клиент для работы с RuStore API
3
+ */
4
+ import { getToken } from './auth.js';
5
+ const API_BASE_URL = 'https://public-api.rustore.ru';
6
+ /**
7
+ * Базовый класс для работы с API
8
+ */
9
+ export class RustoreApiClient {
10
+ baseUrl;
11
+ constructor(baseUrl = API_BASE_URL) {
12
+ this.baseUrl = baseUrl;
13
+ }
14
+ /**
15
+ * Выполняет авторизованный запрос к API
16
+ */
17
+ async request(endpoint, options = {}) {
18
+ const token = await getToken();
19
+ const url = `${this.baseUrl}${endpoint}`;
20
+ // RuStore API использует JWE токен в заголовке Public-Token
21
+ // Токен получается через login и передаётся в заголовке Public-Token
22
+ const response = await fetch(url, {
23
+ ...options,
24
+ headers: {
25
+ 'Content-Type': 'application/json',
26
+ 'Public-Token': token, // JWE токен из login передаётся в заголовке Public-Token
27
+ ...options.headers,
28
+ },
29
+ });
30
+ if (!response.ok) {
31
+ const errorText = await response.text();
32
+ let errorData;
33
+ try {
34
+ errorData = JSON.parse(errorText);
35
+ }
36
+ catch {
37
+ // Игнорируем ошибку парсинга
38
+ }
39
+ // Более информативное сообщение об ошибке
40
+ const errorMessage = errorData?.message ?? errorText;
41
+ throw new Error(`Ошибка API (${response.status}): ${errorMessage}`);
42
+ }
43
+ return (await response.json());
44
+ }
45
+ /**
46
+ * GET запрос
47
+ */
48
+ async get(endpoint) {
49
+ return this.request(endpoint, { method: 'GET' });
50
+ }
51
+ /**
52
+ * POST запрос
53
+ */
54
+ async post(endpoint, body) {
55
+ return this.request(endpoint, {
56
+ method: 'POST',
57
+ body: body ? JSON.stringify(body) : undefined,
58
+ });
59
+ }
60
+ /**
61
+ * PUT запрос
62
+ */
63
+ async put(endpoint, body) {
64
+ return this.request(endpoint, {
65
+ method: 'PUT',
66
+ body: body ? JSON.stringify(body) : undefined,
67
+ });
68
+ }
69
+ /**
70
+ * DELETE запрос
71
+ */
72
+ async delete(endpoint) {
73
+ return this.request(endpoint, { method: 'DELETE' });
74
+ }
75
+ }
76
+ /**
77
+ * Экспортируемый экземпляр клиента
78
+ */
79
+ export const apiClient = new RustoreApiClient();
80
+ //# sourceMappingURL=client.js.map