@windmc/js 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WindMC
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # wind-js-client
2
+ Официальная клиентская библиотека для работы с API Wind. Поддерживает Node.js и TypeScript.
3
+
4
+ ## Установка
5
+
6
+ ```bash
7
+ npm install @windmc/js
8
+ ```
9
+
10
+ ## Конфигурация
11
+
12
+ ```ts
13
+ import { WindClient } from "@windmc/js";
14
+
15
+ const client = new WindClient({
16
+ clientId: "ВАШ_CLIENT_ID",
17
+ clientSecret: "ВАШ_CLIENT_SECRET", // для OAuth
18
+ redirectUri: "https://yoursite.example/callback",
19
+ appToken: "ВАШ_APP_TOKEN", // для Billing
20
+ webhookSecret: "ВАШ_WEBHOOK_SECRET", // для проверки вебхуков
21
+ });
22
+ ```
23
+
24
+ ## OAuth авторизация
25
+
26
+ ```ts
27
+ // 1. Получить ссылку для входа
28
+ const url = client.getAuthorizeUrl(["identify", "bank"]);
29
+ // → https://windmc.su/oauth2/authorize?...
30
+
31
+ // 2. Обменять code на токены
32
+ const tokens = await client.exchangeCode(code);
33
+
34
+ // 3. Получить данные пользователя
35
+ const user = await client.getUser(tokens.access_token);
36
+ console.log(user.nickname, user.avatar);
37
+ ```
38
+
39
+ ### PKCE (для SPA и мобильных приложений)
40
+
41
+ Если ваше приложение не может безопасно хранить `clientSecret` (браузер, мобильное
42
+ приложение), используйте PKCE вместо секрета — `clientSecret` в конфиге при этом
43
+ можно не указывать:
44
+
45
+ ```ts
46
+ import { WindClient, generatePKCE } from "@windmc/js";
47
+
48
+ const client = new WindClient({
49
+ clientId: "ВАШ_CLIENT_ID",
50
+ redirectUri: "https://yourapp.example/callback",
51
+ });
52
+
53
+ // 1. Сгенерировать пару и сохранить codeVerifier (например, в сессии/cookie)
54
+ const { codeVerifier, codeChallenge } = generatePKCE();
55
+ const url = client.getAuthorizeUrl(["identify"], undefined, codeChallenge);
56
+
57
+ // 2. После редиректа обменять code на токены с помощью сохранённого codeVerifier
58
+ const tokens = await client.exchangeCode(code, codeVerifier);
59
+
60
+ // 3. refreshToken() и revokeToken() для PKCE-токенов работают без clientSecret
61
+ const refreshed = await client.refreshToken(tokens.refresh_token);
62
+ ```
63
+
64
+ ## Доступные scopes
65
+
66
+ | Scope | Описание |
67
+ |--------------|-----------------------------------------|
68
+ | `identify` | Никнейм, UUID, роли |
69
+ | `bank` | Счета и транзакции |
70
+ | `bank:charge`| Списание средств (требует подтверждения)|
71
+ | `communities`| Список сообществ пользователя |
72
+ | `friends` | Список друзей |
73
+
74
+ ## Методы
75
+
76
+ ### OAuth / пользователь
77
+
78
+ ```ts
79
+ client.getAuthorizeUrl(scopes, state?) // URL авторизации
80
+ client.exchangeCode(code) // code → tokens
81
+ client.refreshToken(refreshToken) // обновить токен
82
+ client.revokeToken(token) // отозвать токен
83
+ client.getUser(accessToken) // scope: identify
84
+ client.getBank(accessToken) // scope: bank
85
+ client.getBankTransactions(accessToken, limit?)// scope: bank
86
+ client.getCommunities(accessToken) // scope: communities
87
+ client.getFriends(accessToken) // scope: friends
88
+ client.createCharge(accessToken, payload) // scope: bank:charge
89
+ client.getCharge(accessToken, chargeId) // scope: bank:charge
90
+ ```
91
+
92
+ ### Billing (App Token)
93
+
94
+ ```ts
95
+ // Создать счёт — вернёт payUrl для редиректа пользователя
96
+ const bill = await client.createBill({
97
+ toAccountId: 1001,
98
+ amount: 500,
99
+ comment: "Оплата",
100
+ webhookUrl: "https://yoursite.example/webhooks/wind",
101
+ returnUrl: "https://yoursite.example/success",
102
+ });
103
+ // → { billId, payUrl, expiresAt }
104
+
105
+ // Проверить статус счёта
106
+ const status = await client.getBill(bill.billId);
107
+ // → { status: "pending" | "paid" | "expired", ... }
108
+ ```
109
+
110
+ ### Вебхуки
111
+
112
+ Счёт действует 10 минут. После оплаты Wind отправляет POST-запрос на `webhookUrl` с заголовком `X-Signature: sha256=<hmac>`.
113
+
114
+ ```ts
115
+ // Express: читать тело как raw buffer
116
+ app.use("/webhooks/wind", express.raw({ type: "application/json" }));
117
+
118
+ app.post("/webhooks/wind", (req, res) => {
119
+ const signature = req.headers["x-signature"];
120
+
121
+ let payload;
122
+ try {
123
+ payload = client.parseWebhook(req.body.toString(), signature);
124
+ } catch {
125
+ return res.status(401).json({ error: "Неверная подпись" });
126
+ }
127
+
128
+ if (payload.event === "bill.paid") {
129
+ console.log(`Оплачен счёт ${payload.billId} на сумму ${payload.amount}`);
130
+ }
131
+
132
+ res.status(200).json({ ok: true });
133
+ });
134
+ ```
135
+
136
+ ## Примеры
137
+
138
+ Готовые примеры в директории [`example/`](./example):
139
+ - `oauth-login` — OAuth авторизация с Express
140
+ - `create-bill` — Создание счёта на оплату
141
+ - `webhook` — Обработка вебхуков
142
+
143
+ ## Сборка
144
+
145
+ ```bash
146
+ npm run build
147
+ ```
@@ -0,0 +1,5 @@
1
+ export declare class WindError extends Error {
2
+ statusCode?: number;
3
+ details?: object;
4
+ constructor(message: string, statusCode?: number, details?: object);
5
+ }
package/dist/error.js ADDED
@@ -0,0 +1,9 @@
1
+ // WindError © Винд 2026
2
+ export class WindError extends Error {
3
+ constructor(message, statusCode, details) {
4
+ super(message);
5
+ this.name = "WindError";
6
+ this.statusCode = statusCode;
7
+ this.details = details;
8
+ }
9
+ }
@@ -0,0 +1,98 @@
1
+ import type { Config, WindScope, AccessTokenResponse, User, BankResponse, TransactionsResponse, CommunitiesResponse, FriendsResponse, ChargeRequest, CreateChargePayload, CreateBillPayload, CreateBillResponse, BillStatusResponse, WebhookPayload } from "./types.js";
2
+ export * from "./types.js";
3
+ export { WindError } from "./error.js";
4
+ /**
5
+ * Генерирует пару PKCE (code_verifier + code_challenge, метод S256).
6
+ * Используйте для публичных клиентов (SPA, мобильные приложения), у которых
7
+ * нет безопасного места для хранения clientSecret: code_verifier храните
8
+ * у себя (например, в сессии) до обмена кода на токен, code_challenge —
9
+ * передайте в {@link WindClient.getAuthorizeUrl}.
10
+ */
11
+ export declare function generatePKCE(): {
12
+ codeVerifier: string;
13
+ codeChallenge: string;
14
+ };
15
+ export declare class WindClient {
16
+ private readonly config;
17
+ constructor(config: Config);
18
+ /**
19
+ * Возвращает URL для авторизации пользователя.
20
+ * @param scopes - массив запрашиваемых scopes
21
+ * @param state - произвольная строка для защиты от CSRF
22
+ * @param codeChallenge - PKCE code_challenge (см. {@link generatePKCE}); нужен для публичных
23
+ * клиентов (SPA, мобильные приложения), у которых нет clientSecret
24
+ */
25
+ getAuthorizeUrl(scopes: WindScope[], state?: string, codeChallenge?: string): string;
26
+ /**
27
+ * Обменивает authorization code на токены.
28
+ * @param code - код из redirect_uri
29
+ * @param codeVerifier - PKCE code_verifier, если авторизация запускалась с codeChallenge
30
+ */
31
+ exchangeCode(code: string, codeVerifier?: string): Promise<AccessTokenResponse>;
32
+ /**
33
+ * Обновляет access token с помощью refresh token.
34
+ * Для PKCE-токенов (публичный клиент без clientSecret) секрет не требуется.
35
+ */
36
+ refreshToken(refreshToken: string): Promise<AccessTokenResponse>;
37
+ /**
38
+ * Отзывает токен.
39
+ * Для PKCE-токенов (публичный клиент без clientSecret) секрет не требуется.
40
+ */
41
+ revokeToken(token: string): Promise<void>;
42
+ /**
43
+ * Возвращает информацию о текущем пользователе.
44
+ * Требует scope: identify
45
+ */
46
+ getUser(accessToken: string): Promise<User>;
47
+ /**
48
+ * Возвращает банковские счета пользователя.
49
+ * Требует scope: bank
50
+ */
51
+ getBank(accessToken: string): Promise<BankResponse>;
52
+ /**
53
+ * Возвращает транзакции пользователя.
54
+ * Требует scope: bank
55
+ */
56
+ getBankTransactions(accessToken: string, limit?: number): Promise<TransactionsResponse>;
57
+ /**
58
+ * Возвращает сообщества пользователя.
59
+ * Требует scope: communities
60
+ */
61
+ getCommunities(accessToken: string): Promise<CommunitiesResponse>;
62
+ /**
63
+ * Возвращает список друзей пользователя.
64
+ * Требует scope: friends
65
+ */
66
+ getFriends(accessToken: string): Promise<FriendsResponse>;
67
+ /**
68
+ * Создаёт запрос на списание средств.
69
+ * Требует scope: bank:charge
70
+ */
71
+ createCharge(accessToken: string, payload: CreateChargePayload): Promise<ChargeRequest>;
72
+ /**
73
+ * Возвращает статус запроса на списание.
74
+ * Требует scope: bank:charge
75
+ */
76
+ getCharge(accessToken: string, chargeId: string): Promise<ChargeRequest>;
77
+ /**
78
+ * Создаёт счёт на оплату. Использует App Token (X-Client-Id + Bearer).
79
+ * После создания пользователь перейдёт по payUrl для оплаты.
80
+ */
81
+ createBill(payload: CreateBillPayload): Promise<CreateBillResponse>;
82
+ /**
83
+ * Возвращает информацию о счёте по его ID.
84
+ */
85
+ getBill(billId: string): Promise<BillStatusResponse>;
86
+ /**
87
+ * Проверяет подпись входящего вебхука.
88
+ * @param rawBody - тело запроса как строка (до JSON.parse)
89
+ * @param signature - значение заголовка X-Signature
90
+ */
91
+ verifyWebhookSignature(rawBody: string, signature: string): boolean;
92
+ /**
93
+ * Парсит тело вебхука с проверкой подписи.
94
+ * Бросает WindError если подпись неверна.
95
+ */
96
+ parseWebhook(rawBody: string, signature: string): WebhookPayload;
97
+ private request;
98
+ }
package/dist/index.js ADDED
@@ -0,0 +1,265 @@
1
+ // WindClient © Винд 2026
2
+ import crypto from "node:crypto";
3
+ import { WindError } from "./error.js";
4
+ export * from "./types.js";
5
+ export { WindError } from "./error.js";
6
+ const DEFAULT_API_URL = "https://api.windmc.su";
7
+ const DEFAULT_SITE_URL = "https://windmc.su";
8
+ /**
9
+ * Генерирует пару PKCE (code_verifier + code_challenge, метод S256).
10
+ * Используйте для публичных клиентов (SPA, мобильные приложения), у которых
11
+ * нет безопасного места для хранения clientSecret: code_verifier храните
12
+ * у себя (например, в сессии) до обмена кода на токен, code_challenge —
13
+ * передайте в {@link WindClient.getAuthorizeUrl}.
14
+ */
15
+ export function generatePKCE() {
16
+ const codeVerifier = crypto.randomBytes(32).toString("base64url");
17
+ const codeChallenge = crypto.createHash("sha256").update(codeVerifier).digest("base64url");
18
+ return { codeVerifier, codeChallenge };
19
+ }
20
+ export class WindClient {
21
+ constructor(config) {
22
+ this.config = {
23
+ clientId: config.clientId,
24
+ clientSecret: config.clientSecret ?? "",
25
+ redirectUri: config.redirectUri ?? "",
26
+ appToken: config.appToken ?? "",
27
+ webhookSecret: config.webhookSecret ?? "",
28
+ apiUrl: config.apiUrl ?? DEFAULT_API_URL,
29
+ siteUrl: config.siteUrl ?? DEFAULT_SITE_URL,
30
+ };
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // OAuth
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Возвращает URL для авторизации пользователя.
37
+ * @param scopes - массив запрашиваемых scopes
38
+ * @param state - произвольная строка для защиты от CSRF
39
+ * @param codeChallenge - PKCE code_challenge (см. {@link generatePKCE}); нужен для публичных
40
+ * клиентов (SPA, мобильные приложения), у которых нет clientSecret
41
+ */
42
+ getAuthorizeUrl(scopes, state, codeChallenge) {
43
+ const params = new URLSearchParams({
44
+ client_id: this.config.clientId,
45
+ redirect_uri: this.config.redirectUri,
46
+ response_type: "code",
47
+ scope: scopes.join(" "),
48
+ });
49
+ if (state)
50
+ params.set("state", state);
51
+ if (codeChallenge) {
52
+ params.set("code_challenge", codeChallenge);
53
+ params.set("code_challenge_method", "S256");
54
+ }
55
+ return `${this.config.siteUrl}/oauth2/authorize?${params.toString()}`;
56
+ }
57
+ /**
58
+ * Обменивает authorization code на токены.
59
+ * @param code - код из redirect_uri
60
+ * @param codeVerifier - PKCE code_verifier, если авторизация запускалась с codeChallenge
61
+ */
62
+ async exchangeCode(code, codeVerifier) {
63
+ const params = {
64
+ grant_type: "authorization_code",
65
+ code,
66
+ client_id: this.config.clientId,
67
+ redirect_uri: this.config.redirectUri,
68
+ };
69
+ if (this.config.clientSecret)
70
+ params.client_secret = this.config.clientSecret;
71
+ if (codeVerifier)
72
+ params.code_verifier = codeVerifier;
73
+ return this.request("/api/oauth2/token", {
74
+ method: "POST",
75
+ body: new URLSearchParams(params),
76
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
77
+ });
78
+ }
79
+ /**
80
+ * Обновляет access token с помощью refresh token.
81
+ * Для PKCE-токенов (публичный клиент без clientSecret) секрет не требуется.
82
+ */
83
+ async refreshToken(refreshToken) {
84
+ const params = {
85
+ grant_type: "refresh_token",
86
+ refresh_token: refreshToken,
87
+ client_id: this.config.clientId,
88
+ };
89
+ if (this.config.clientSecret)
90
+ params.client_secret = this.config.clientSecret;
91
+ return this.request("/api/oauth2/token", {
92
+ method: "POST",
93
+ body: new URLSearchParams(params),
94
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
95
+ });
96
+ }
97
+ /**
98
+ * Отзывает токен.
99
+ * Для PKCE-токенов (публичный клиент без clientSecret) секрет не требуется.
100
+ */
101
+ async revokeToken(token) {
102
+ const params = {
103
+ token,
104
+ client_id: this.config.clientId,
105
+ };
106
+ if (this.config.clientSecret)
107
+ params.client_secret = this.config.clientSecret;
108
+ await this.request("/api/oauth2/revoke", {
109
+ method: "POST",
110
+ body: new URLSearchParams(params),
111
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
112
+ });
113
+ }
114
+ // ---------------------------------------------------------------------------
115
+ // @me (OAuth user endpoints)
116
+ // ---------------------------------------------------------------------------
117
+ /**
118
+ * Возвращает информацию о текущем пользователе.
119
+ * Требует scope: identify
120
+ */
121
+ async getUser(accessToken) {
122
+ return this.request("/api/oauth2/@me", {
123
+ headers: { Authorization: `Bearer ${accessToken}` },
124
+ });
125
+ }
126
+ /**
127
+ * Возвращает банковские счета пользователя.
128
+ * Требует scope: bank
129
+ */
130
+ async getBank(accessToken) {
131
+ return this.request("/api/oauth2/@me/bank", {
132
+ headers: { Authorization: `Bearer ${accessToken}` },
133
+ });
134
+ }
135
+ /**
136
+ * Возвращает транзакции пользователя.
137
+ * Требует scope: bank
138
+ */
139
+ async getBankTransactions(accessToken, limit) {
140
+ const query = limit ? `?limit=${limit}` : "";
141
+ return this.request(`/api/oauth2/@me/bank/transactions${query}`, { headers: { Authorization: `Bearer ${accessToken}` } });
142
+ }
143
+ /**
144
+ * Возвращает сообщества пользователя.
145
+ * Требует scope: communities
146
+ */
147
+ async getCommunities(accessToken) {
148
+ return this.request("/api/oauth2/@me/communities", {
149
+ headers: { Authorization: `Bearer ${accessToken}` },
150
+ });
151
+ }
152
+ /**
153
+ * Возвращает список друзей пользователя.
154
+ * Требует scope: friends
155
+ */
156
+ async getFriends(accessToken) {
157
+ return this.request("/api/oauth2/@me/friends", {
158
+ headers: { Authorization: `Bearer ${accessToken}` },
159
+ });
160
+ }
161
+ /**
162
+ * Создаёт запрос на списание средств.
163
+ * Требует scope: bank:charge
164
+ */
165
+ async createCharge(accessToken, payload) {
166
+ return this.request("/api/oauth2/@me/bank/charge", {
167
+ method: "POST",
168
+ headers: {
169
+ Authorization: `Bearer ${accessToken}`,
170
+ "Content-Type": "application/json",
171
+ },
172
+ body: JSON.stringify(payload),
173
+ });
174
+ }
175
+ /**
176
+ * Возвращает статус запроса на списание.
177
+ * Требует scope: bank:charge
178
+ */
179
+ async getCharge(accessToken, chargeId) {
180
+ return this.request(`/api/oauth2/@me/bank/charge/${chargeId}`, { headers: { Authorization: `Bearer ${accessToken}` } });
181
+ }
182
+ // ---------------------------------------------------------------------------
183
+ // Billing (app token auth)
184
+ // ---------------------------------------------------------------------------
185
+ /**
186
+ * Создаёт счёт на оплату. Использует App Token (X-Client-Id + Bearer).
187
+ * После создания пользователь перейдёт по payUrl для оплаты.
188
+ */
189
+ async createBill(payload) {
190
+ if (!this.config.appToken) {
191
+ throw new WindError("appToken не указан в конфигурации");
192
+ }
193
+ return this.request("/api/oauth2/billing/create", {
194
+ method: "POST",
195
+ headers: {
196
+ "Content-Type": "application/json",
197
+ "X-Client-Id": this.config.clientId,
198
+ Authorization: `Bearer ${this.config.appToken}`,
199
+ },
200
+ body: JSON.stringify(payload),
201
+ });
202
+ }
203
+ /**
204
+ * Возвращает информацию о счёте по его ID.
205
+ */
206
+ async getBill(billId) {
207
+ return this.request(`/api/oauth2/billing/${billId}`);
208
+ }
209
+ // ---------------------------------------------------------------------------
210
+ // Webhooks
211
+ // ---------------------------------------------------------------------------
212
+ /**
213
+ * Проверяет подпись входящего вебхука.
214
+ * @param rawBody - тело запроса как строка (до JSON.parse)
215
+ * @param signature - значение заголовка X-Signature
216
+ */
217
+ verifyWebhookSignature(rawBody, signature) {
218
+ if (!this.config.webhookSecret) {
219
+ throw new WindError("webhookSecret не указан в конфигурации");
220
+ }
221
+ const expected = "sha256=" +
222
+ crypto
223
+ .createHmac("sha256", this.config.webhookSecret)
224
+ .update(rawBody)
225
+ .digest("hex");
226
+ if (expected.length !== signature.length)
227
+ return false;
228
+ return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
229
+ }
230
+ /**
231
+ * Парсит тело вебхука с проверкой подписи.
232
+ * Бросает WindError если подпись неверна.
233
+ */
234
+ parseWebhook(rawBody, signature) {
235
+ if (!this.verifyWebhookSignature(rawBody, signature)) {
236
+ throw new WindError("Неверная подпись вебхука", 401);
237
+ }
238
+ return JSON.parse(rawBody);
239
+ }
240
+ // ---------------------------------------------------------------------------
241
+ // Internal
242
+ // ---------------------------------------------------------------------------
243
+ async request(path, init = {}) {
244
+ const url = `${this.config.apiUrl}${path}`;
245
+ const res = await fetch(url, init);
246
+ let data;
247
+ const contentType = res.headers.get("content-type") ?? "";
248
+ if (contentType.includes("application/json")) {
249
+ data = await res.json();
250
+ }
251
+ else {
252
+ data = await res.text();
253
+ }
254
+ if (!res.ok) {
255
+ const message = typeof data === "object" &&
256
+ data !== null &&
257
+ "error" in data &&
258
+ typeof data.error === "string"
259
+ ? data.error
260
+ : `HTTP ${res.status}`;
261
+ throw new WindError(message, res.status, typeof data === "object" ? data : undefined);
262
+ }
263
+ return data;
264
+ }
265
+ }
@@ -0,0 +1,125 @@
1
+ export interface Config {
2
+ clientId: string;
3
+ clientSecret?: string;
4
+ redirectUri?: string;
5
+ appToken?: string;
6
+ webhookSecret?: string;
7
+ apiUrl?: string;
8
+ siteUrl?: string;
9
+ }
10
+ export interface AccessTokenResponse {
11
+ access_token: string;
12
+ refresh_token: string;
13
+ token_type: "Bearer";
14
+ expires_in: number;
15
+ scope: string;
16
+ }
17
+ export type WindScope = "identify" | "bank" | "bank:charge" | "communities" | "friends";
18
+ export interface User {
19
+ discordId: string;
20
+ nickname: string | null;
21
+ uuid: string | null;
22
+ discordUsername: string | null;
23
+ roles: string[];
24
+ online: boolean;
25
+ avatar: string | null;
26
+ }
27
+ export interface BankAccount {
28
+ id: number;
29
+ name: string;
30
+ balance: number;
31
+ frozen: boolean;
32
+ design: string | null;
33
+ }
34
+ export interface BankResponse {
35
+ accounts: BankAccount[];
36
+ totalBalance: number;
37
+ }
38
+ export interface Transaction {
39
+ id: string | number;
40
+ fromAccountId: number;
41
+ toAccountId: number;
42
+ amount: number;
43
+ type: string;
44
+ comment: string | null;
45
+ timestamp: string;
46
+ }
47
+ export interface TransactionsResponse {
48
+ transactions: Transaction[];
49
+ count: number;
50
+ }
51
+ export interface Community {
52
+ id: string;
53
+ name: string;
54
+ slug: string;
55
+ banner: string | null;
56
+ description: string | null;
57
+ memberCount: number;
58
+ verified: boolean;
59
+ role: "owner" | "co_owner" | "member";
60
+ }
61
+ export interface CommunitiesResponse {
62
+ communities: Community[];
63
+ }
64
+ export interface FriendUser {
65
+ id: string;
66
+ nickname: string | null;
67
+ uuid: string | null;
68
+ discordUsername: string | null;
69
+ }
70
+ export interface Friend {
71
+ friendshipId: string;
72
+ user: FriendUser;
73
+ since: string;
74
+ }
75
+ export interface FriendsResponse {
76
+ friends: Friend[];
77
+ }
78
+ export interface ChargeRequest {
79
+ chargeId: string;
80
+ status: "pending" | "paid" | "expired";
81
+ amount?: number;
82
+ fromAccountId?: number;
83
+ toAccountId?: number;
84
+ }
85
+ export interface CreateChargePayload {
86
+ amount: number;
87
+ toAccountId: number;
88
+ fromAccountId?: number;
89
+ comment?: string;
90
+ }
91
+ export interface CreateBillPayload {
92
+ toAccountId: number;
93
+ amount: number;
94
+ comment?: string;
95
+ webhookUrl?: string;
96
+ returnUrl?: string;
97
+ }
98
+ export interface CreateBillResponse {
99
+ billId: string;
100
+ payUrl: string;
101
+ expiresAt: string;
102
+ }
103
+ export interface BillApp {
104
+ name: string;
105
+ iconUrl: string | null;
106
+ }
107
+ export interface BillStatusResponse {
108
+ billId: string;
109
+ status: "pending" | "paid" | "expired";
110
+ amount: number;
111
+ comment: string | null;
112
+ toAccountId: number;
113
+ returnUrl: string | null;
114
+ expiresAt: string;
115
+ app: BillApp;
116
+ }
117
+ export interface WebhookPayload {
118
+ event: "bill.paid";
119
+ billId: string;
120
+ amount: number;
121
+ fromAccountId: number;
122
+ toAccountId: number;
123
+ payerId: string;
124
+ timestamp: number;
125
+ }
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ // WindClient types © Винд 2026
2
+ export {};
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@windmc/js",
3
+ "version": "1.0.0",
4
+ "description": "Wind API client",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "prepublishOnly": "npm run build"
20
+ },
21
+ "devDependencies": {
22
+ "@types/express": "^5.0.6",
23
+ "@types/node": "^25.6.0",
24
+ "express": "^5.2.1",
25
+ "typescript": "^5.9.3"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "license": "MIT"
31
+ }