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.
- package/LICENSE +9 -0
- package/README.md +225 -0
- package/dist/api/apps.d.ts +32 -0
- package/dist/api/apps.d.ts.map +1 -0
- package/dist/api/apps.js +56 -0
- package/dist/api/apps.js.map +1 -0
- package/dist/api/auth.d.ts +29 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +139 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/catalog.d.ts +15 -0
- package/dist/api/catalog.d.ts.map +1 -0
- package/dist/api/catalog.js +15 -0
- package/dist/api/catalog.js.map +1 -0
- package/dist/api/client.d.ts +35 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +80 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/payments-app.d.ts +15 -0
- package/dist/api/payments-app.d.ts.map +1 -0
- package/dist/api/payments-app.js +15 -0
- package/dist/api/payments-app.js.map +1 -0
- package/dist/api/payments.d.ts +15 -0
- package/dist/api/payments.d.ts.map +1 -0
- package/dist/api/payments.js +15 -0
- package/dist/api/payments.js.map +1 -0
- package/dist/bin.d.ts +6 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +83 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/apps.d.ts +11 -0
- package/dist/commands/apps.d.ts.map +1 -0
- package/dist/commands/apps.js +52 -0
- package/dist/commands/apps.js.map +1 -0
- package/dist/commands/auth.d.ts +16 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +46 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +53 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- 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"}
|
package/dist/api/apps.js
ADDED
|
@@ -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"}
|
package/dist/api/auth.js
ADDED
|
@@ -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":"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"}
|
|
@@ -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
|