@v3finance/monitoring-sdk 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +247 -2
  4. package/dist/cjs/client.d.ts +65 -0
  5. package/dist/cjs/client.d.ts.map +1 -0
  6. package/dist/cjs/client.js +89 -0
  7. package/dist/cjs/client.js.map +1 -0
  8. package/dist/cjs/core/errors.d.ts +64 -0
  9. package/dist/cjs/core/errors.d.ts.map +1 -0
  10. package/dist/cjs/core/errors.js +95 -0
  11. package/dist/cjs/core/errors.js.map +1 -0
  12. package/dist/cjs/core/http.d.ts +62 -0
  13. package/dist/cjs/core/http.d.ts.map +1 -0
  14. package/dist/cjs/core/http.js +151 -0
  15. package/dist/cjs/core/http.js.map +1 -0
  16. package/dist/cjs/core/pagination.d.ts +13 -0
  17. package/dist/cjs/core/pagination.d.ts.map +1 -0
  18. package/dist/cjs/core/pagination.js +15 -0
  19. package/dist/cjs/core/pagination.js.map +1 -0
  20. package/dist/cjs/generated/types.d.ts +324 -0
  21. package/dist/cjs/generated/types.d.ts.map +1 -0
  22. package/dist/cjs/generated/types.js +5 -0
  23. package/dist/cjs/generated/types.js.map +1 -0
  24. package/dist/cjs/index.d.ts +23 -0
  25. package/dist/cjs/index.d.ts.map +1 -0
  26. package/dist/cjs/index.js +50 -0
  27. package/dist/cjs/index.js.map +1 -0
  28. package/dist/cjs/package.json +1 -0
  29. package/dist/cjs/resources/account.d.ts +61 -0
  30. package/dist/cjs/resources/account.d.ts.map +1 -0
  31. package/dist/cjs/resources/account.js +75 -0
  32. package/dist/cjs/resources/account.js.map +1 -0
  33. package/dist/cjs/resources/addresses.d.ts +109 -0
  34. package/dist/cjs/resources/addresses.d.ts.map +1 -0
  35. package/dist/cjs/resources/addresses.js +137 -0
  36. package/dist/cjs/resources/addresses.js.map +1 -0
  37. package/dist/cjs/resources/catalog.d.ts +30 -0
  38. package/dist/cjs/resources/catalog.d.ts.map +1 -0
  39. package/dist/cjs/resources/catalog.js +46 -0
  40. package/dist/cjs/resources/catalog.js.map +1 -0
  41. package/dist/cjs/resources/clients.d.ts +84 -0
  42. package/dist/cjs/resources/clients.d.ts.map +1 -0
  43. package/dist/cjs/resources/clients.js +102 -0
  44. package/dist/cjs/resources/clients.js.map +1 -0
  45. package/dist/cjs/resources/deliveries.d.ts +50 -0
  46. package/dist/cjs/resources/deliveries.d.ts.map +1 -0
  47. package/dist/cjs/resources/deliveries.js +43 -0
  48. package/dist/cjs/resources/deliveries.js.map +1 -0
  49. package/dist/cjs/resources/transactions.d.ts +28 -0
  50. package/dist/cjs/resources/transactions.d.ts.map +1 -0
  51. package/dist/cjs/resources/transactions.js +35 -0
  52. package/dist/cjs/resources/transactions.js.map +1 -0
  53. package/dist/cjs/units.d.ts +29 -0
  54. package/dist/cjs/units.d.ts.map +1 -0
  55. package/dist/cjs/units.js +62 -0
  56. package/dist/cjs/units.js.map +1 -0
  57. package/dist/cjs/version.d.ts +5 -0
  58. package/dist/cjs/version.d.ts.map +1 -0
  59. package/dist/cjs/version.js +8 -0
  60. package/dist/cjs/version.js.map +1 -0
  61. package/dist/cjs/webhooks.d.ts +77 -0
  62. package/dist/cjs/webhooks.d.ts.map +1 -0
  63. package/dist/cjs/webhooks.js +128 -0
  64. package/dist/cjs/webhooks.js.map +1 -0
  65. package/dist/esm/client.d.ts +65 -0
  66. package/dist/esm/client.d.ts.map +1 -0
  67. package/dist/esm/client.js +85 -0
  68. package/dist/esm/client.js.map +1 -0
  69. package/dist/esm/core/errors.d.ts +64 -0
  70. package/dist/esm/core/errors.d.ts.map +1 -0
  71. package/dist/esm/core/errors.js +86 -0
  72. package/dist/esm/core/errors.js.map +1 -0
  73. package/dist/esm/core/http.d.ts +62 -0
  74. package/dist/esm/core/http.d.ts.map +1 -0
  75. package/dist/esm/core/http.js +146 -0
  76. package/dist/esm/core/http.js.map +1 -0
  77. package/dist/esm/core/pagination.d.ts +13 -0
  78. package/dist/esm/core/pagination.d.ts.map +1 -0
  79. package/dist/esm/core/pagination.js +12 -0
  80. package/dist/esm/core/pagination.js.map +1 -0
  81. package/dist/esm/generated/types.d.ts +324 -0
  82. package/dist/esm/generated/types.d.ts.map +1 -0
  83. package/dist/esm/generated/types.js +4 -0
  84. package/dist/esm/generated/types.js.map +1 -0
  85. package/dist/esm/index.d.ts +23 -0
  86. package/dist/esm/index.d.ts.map +1 -0
  87. package/dist/esm/index.js +20 -0
  88. package/dist/esm/index.js.map +1 -0
  89. package/dist/esm/resources/account.d.ts +61 -0
  90. package/dist/esm/resources/account.d.ts.map +1 -0
  91. package/dist/esm/resources/account.js +69 -0
  92. package/dist/esm/resources/account.js.map +1 -0
  93. package/dist/esm/resources/addresses.d.ts +109 -0
  94. package/dist/esm/resources/addresses.d.ts.map +1 -0
  95. package/dist/esm/resources/addresses.js +133 -0
  96. package/dist/esm/resources/addresses.js.map +1 -0
  97. package/dist/esm/resources/catalog.d.ts +30 -0
  98. package/dist/esm/resources/catalog.d.ts.map +1 -0
  99. package/dist/esm/resources/catalog.js +41 -0
  100. package/dist/esm/resources/catalog.js.map +1 -0
  101. package/dist/esm/resources/clients.d.ts +84 -0
  102. package/dist/esm/resources/clients.d.ts.map +1 -0
  103. package/dist/esm/resources/clients.js +97 -0
  104. package/dist/esm/resources/clients.js.map +1 -0
  105. package/dist/esm/resources/deliveries.d.ts +50 -0
  106. package/dist/esm/resources/deliveries.d.ts.map +1 -0
  107. package/dist/esm/resources/deliveries.js +39 -0
  108. package/dist/esm/resources/deliveries.js.map +1 -0
  109. package/dist/esm/resources/transactions.d.ts +28 -0
  110. package/dist/esm/resources/transactions.d.ts.map +1 -0
  111. package/dist/esm/resources/transactions.js +31 -0
  112. package/dist/esm/resources/transactions.js.map +1 -0
  113. package/dist/esm/units.d.ts +29 -0
  114. package/dist/esm/units.d.ts.map +1 -0
  115. package/dist/esm/units.js +58 -0
  116. package/dist/esm/units.js.map +1 -0
  117. package/dist/esm/version.d.ts +5 -0
  118. package/dist/esm/version.d.ts.map +1 -0
  119. package/dist/esm/version.js +5 -0
  120. package/dist/esm/version.js.map +1 -0
  121. package/dist/esm/webhooks.d.ts +77 -0
  122. package/dist/esm/webhooks.d.ts.map +1 -0
  123. package/dist/esm/webhooks.js +120 -0
  124. package/dist/esm/webhooks.js.map +1 -0
  125. package/package.json +66 -4
  126. package/src/client.ts +94 -0
  127. package/src/core/errors.ts +99 -0
  128. package/src/core/http.ts +193 -0
  129. package/src/core/pagination.ts +21 -0
  130. package/src/generated/types.ts +355 -0
  131. package/src/index.ts +60 -0
  132. package/src/resources/account.ts +87 -0
  133. package/src/resources/addresses.ts +190 -0
  134. package/src/resources/catalog.ts +47 -0
  135. package/src/resources/clients.ts +135 -0
  136. package/src/resources/deliveries.ts +69 -0
  137. package/src/resources/transactions.ts +33 -0
  138. package/src/units.ts +56 -0
  139. package/src/version.ts +5 -0
  140. package/src/webhooks.ts +133 -0
@@ -0,0 +1,355 @@
1
+ // Generated from openapi/openapi.json by scripts/generate.ts — do not edit by hand.
2
+ // chain-events API 1.0.0. Regenerate: npm run spec:update && npm run generate
3
+
4
+ export interface ApiErrorBody {
5
+ error: {
6
+ /** @example "invalid_request" */
7
+ code: string
8
+ message: string
9
+ details?: Array<{
10
+ index: number
11
+ message: string
12
+ }>
13
+ }
14
+ }
15
+
16
+ export interface User {
17
+ id: string
18
+ email: string
19
+ name: string
20
+ role?: "admin" | "user"
21
+ banned?: boolean
22
+ createdAt?: string
23
+ }
24
+
25
+ export interface Identity {
26
+ actor: {
27
+ /** user — пользователь, client-key — ключ клиента */
28
+ kind: "user" | "client-key" | "admin"
29
+ via?: "session" | "api-key" | "token"
30
+ userId?: string | null
31
+ clientId?: string
32
+ keyId?: string
33
+ }
34
+ user: User | null
35
+ memberships: Array<{
36
+ clientId: string
37
+ role: "owner" | "admin" | "member"
38
+ }>
39
+ }
40
+
41
+ export interface ApiKey {
42
+ id: string
43
+ name: string | null
44
+ /** начало ключа — чтобы узнать его */
45
+ start: string
46
+ enabled: boolean
47
+ expiresAt: string | null
48
+ lastUsedAt: string | null
49
+ createdAt: string
50
+ }
51
+
52
+ export interface IssueKeyRequest {
53
+ /** length: 0..100 */
54
+ name?: string
55
+ /**
56
+ * срок; без него — бессрочный
57
+ *
58
+ * range: 1..3650
59
+ */
60
+ expiresInDays?: number
61
+ }
62
+
63
+ export interface IssuedKey {
64
+ id: string
65
+ /** полный ключ — показывается один раз */
66
+ key: string
67
+ start: string
68
+ name: string | null
69
+ expiresAt: string | null
70
+ }
71
+
72
+ export interface Network {
73
+ id: number
74
+ /** @example "tron" */
75
+ slug: string
76
+ /** @example "tron:0x2b6653dc" */
77
+ caip2: string
78
+ chainId: number
79
+ name: string
80
+ shortName: string | null
81
+ /** 1 — L1, 2 — L2 */
82
+ layer: 1 | 2
83
+ parent: string | null
84
+ l2Type: string | null
85
+ l2Stack: string | null
86
+ isTestnet: boolean
87
+ explorerUrl: string | null
88
+ /** сервис читает сеть: если false, вебхуков по ней нет */
89
+ enabled: boolean
90
+ }
91
+
92
+ export interface Asset {
93
+ id: number
94
+ network: string
95
+ caip19: string
96
+ standard: "native" | "erc20" | "trc20"
97
+ contract: string | null
98
+ symbol: string
99
+ name: string
100
+ decimals: number
101
+ /** порог включительно, в минимальных единицах: меньшие переводы не сообщаются */
102
+ minAmount: string
103
+ /** включён: о его переводах приходят вебхуки */
104
+ enabled: boolean
105
+ }
106
+
107
+ export interface Client {
108
+ id: string
109
+ name: string | null
110
+ webhookUrl: string
111
+ /** disabled — вебхуки не отправляются */
112
+ status: "active" | "disabled"
113
+ createdAt: string
114
+ }
115
+
116
+ export interface Member {
117
+ userId: string
118
+ email: string
119
+ name: string
120
+ role: "owner" | "admin" | "member"
121
+ createdAt: string
122
+ }
123
+
124
+ /** in — адрес получатель, out — отправитель, both — любой */
125
+ export type Direction = "in" | "out" | "both"
126
+
127
+ /** символы (`USDT`) или адреса контрактов; null — все активы сети, включая добавленные позже */
128
+ export type AssetSelection = string[] | null
129
+
130
+ export interface AddressInput {
131
+ /** slug или CAIP-2 */
132
+ network: string
133
+ address: string
134
+ /**
135
+ * ваша метка: id пользователя, номер счёта
136
+ *
137
+ * length: 0..200
138
+ */
139
+ label?: string
140
+ assets?: AssetSelection
141
+ direction?: Direction
142
+ }
143
+
144
+ export interface AddAddressesRequest {
145
+ /** items: 1..1000 */
146
+ addresses: AddressInput[]
147
+ assets?: AssetSelection
148
+ direction?: Direction
149
+ }
150
+
151
+ export interface UpdateAddressesRequest {
152
+ /** items: 1..1000 */
153
+ addresses: Array<{
154
+ network: string
155
+ address: string
156
+ assets?: AssetSelection
157
+ direction?: Direction
158
+ }>
159
+ assets?: AssetSelection
160
+ direction?: Direction
161
+ }
162
+
163
+ export interface Address {
164
+ id: number
165
+ network: string
166
+ caip10: string
167
+ address: string
168
+ label: string | null
169
+ /** символы активов подписки; null — все */
170
+ assets: string[] | null
171
+ direction: Direction
172
+ createdAt: string
173
+ }
174
+
175
+ /** delivered — вы ответили 2xx; retrying — последняя попытка не удалась, будет повтор; failed — повторы исчерпаны */
176
+ export type DeliveryStatus = "delivered" | "retrying" | "failed"
177
+
178
+ export interface Delivery {
179
+ id: number
180
+ clientId: string
181
+ network: string
182
+ asset: string
183
+ contract: string
184
+ txId: string
185
+ logIndex: number | null
186
+ block: number
187
+ /** время блока, мс */
188
+ blockTime: number
189
+ from: string
190
+ to: string
191
+ value: string
192
+ status: DeliveryStatus
193
+ attempts: number
194
+ lastHttpStatus: number | null
195
+ lastError: string | null
196
+ lastDurationMs: number | null
197
+ firstAttemptAt: string
198
+ lastAttemptAt: string
199
+ deliveredAt: string | null
200
+ }
201
+
202
+ export type DeliveryDetail = Delivery & {
203
+ /** куда ушла последняя попытка */
204
+ url: string
205
+ /** точное тело запроса */
206
+ body: string
207
+ }
208
+
209
+ export interface TxTransfer {
210
+ /** native — монета самой транзакцией; token — событие Transfer; internal — TRX изнутри контракта (TRON); trc10 — токен TRC-10 */
211
+ kind: "native" | "token" | "internal" | "trc10"
212
+ asset: string | null
213
+ /** адрес контракта, native или id токена TRC-10 */
214
+ contract: string
215
+ from: string
216
+ to: string
217
+ value: string
218
+ logIndex?: number
219
+ /** актив отслеживается: о таких переводах приходят вебхуки (если сумма не меньше порога) */
220
+ tracked: boolean
221
+ }
222
+
223
+ export interface Transaction {
224
+ network: string
225
+ caip2: string
226
+ txId: string
227
+ /** pending — ещё не в блоке */
228
+ status: "success" | "failed" | "pending"
229
+ failure: string | null
230
+ block: number | null
231
+ blockTime: number | null
232
+ /** от текущей головы сети; 0 — не в блоке */
233
+ confirmations: number
234
+ /** транзакцию уже не отменить */
235
+ final: boolean
236
+ /** кто подписал */
237
+ from: string
238
+ to: string | null
239
+ /** TRON — тип контракта (TransferContract, TriggerSmartContract…); EVM — transfer, contract_call, contract_creation */
240
+ type: string
241
+ /** нативная монета самой транзакции */
242
+ value: string
243
+ fee: {
244
+ asset: string
245
+ value: string
246
+ } | null
247
+ transfers: TxTransfer[]
248
+ /** ваши адреса на мониторинге в этой транзакции */
249
+ watched: Array<{
250
+ clientId: string
251
+ address: string
252
+ direction: Direction
253
+ }>
254
+ /** наши вебхуки вам по этой транзакции */
255
+ webhooks: Array<{
256
+ id: number
257
+ clientId: string
258
+ asset: string
259
+ value: string
260
+ status: DeliveryStatus
261
+ attempts: number
262
+ deliveredAt: string | null
263
+ }>
264
+ }
265
+
266
+ export interface WebhookTx {
267
+ /**
268
+ * сеть в верхнем регистре
269
+ * @example "TRON"
270
+ * @example "ETHEREUM"
271
+ */
272
+ network: string
273
+ /** @example "USDT" */
274
+ asset: string
275
+ /** адрес контракта или native */
276
+ contract: string
277
+ /** всегда TOPUP — и для входящего, и для исходящего: направление — по from и to */
278
+ type: "TOPUP"
279
+ /** хеш транзакции */
280
+ id: string
281
+ block: number
282
+ /** время блока, мс */
283
+ timestamp: number
284
+ from: string
285
+ to: string
286
+ /** в минимальных единицах */
287
+ value: string
288
+ /** у переводов токенов EVM: в одной транзакции их бывает несколько */
289
+ logIndex?: number
290
+ }
291
+
292
+ export interface WebhookPayload {
293
+ tx: WebhookTx
294
+ /** только у тестового вебхука — не зачислять */
295
+ test?: true
296
+ }
297
+
298
+ export interface TestWebhookRequest {
299
+ /** @defaultValue "USDT" */
300
+ asset?: "USDT" | "A7A5" | "TRX"
301
+ /** адрес TRON */
302
+ from?: string
303
+ /** адрес TRON */
304
+ to?: string
305
+ /** в минимальных единицах */
306
+ value?: string
307
+ }
308
+
309
+ export interface TestDelivery {
310
+ ok: boolean
311
+ /** HTTP-код вашего ответа */
312
+ status?: number
313
+ error?: string
314
+ durationMs: number
315
+ }
316
+
317
+ export interface TestWebhookResult {
318
+ delivery: TestDelivery
319
+ /** x-signature — сверьте со своим HMAC */
320
+ signature: string
321
+ /** точное тело запроса */
322
+ body: string
323
+ }
324
+
325
+ export interface LegacyAddresses {
326
+ /** items: 0..1000 */
327
+ addresses: string[]
328
+ }
329
+
330
+ export interface LegacyClientResult {
331
+ ok: true
332
+ client: {
333
+ id: string
334
+ webhookUrl: string
335
+ addresses: string[]
336
+ }
337
+ }
338
+
339
+ export interface LegacyError {
340
+ ok: false
341
+ error: string
342
+ details?: Array<{
343
+ index: number
344
+ message: string
345
+ }>
346
+ }
347
+
348
+ export interface LegacyTestResult {
349
+ ok: boolean
350
+ clientId: string
351
+ webhookUrl: string
352
+ delivery: TestDelivery
353
+ signature: string
354
+ body: string
355
+ }
package/src/index.ts ADDED
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Официальный SDK API мониторинга адресов V3 Finance (https://monitoring.v3.finance): TRON и EVM-сети,
3
+ * подписанные вебхуки о переводах, история доставок, транзакции с подтверждениями и финальностью.
4
+ *
5
+ * Справочник API — https://monitoring.v3.finance/docs
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+
10
+ export { MonitoringClient } from './client.js'
11
+ export type { ClientOptions, RequestOptions } from './core/http.js'
12
+ export type { Page } from './core/pagination.js'
13
+ export {
14
+ MonitoringApiError,
15
+ MonitoringConnectionError,
16
+ MonitoringError,
17
+ MonitoringTimeoutError,
18
+ WebhookSignatureError,
19
+ type ErrorDetail,
20
+ } from './core/errors.js'
21
+
22
+ export { AccountResource, AuthResource, PersonalKeysResource, type SignInResult } from './resources/account.js'
23
+ export {
24
+ ADDRESS_BATCH_SIZE,
25
+ AddressesResource,
26
+ type AddAddressesResult,
27
+ type AddressDefaults,
28
+ type AddressRef,
29
+ type AddressSubscriptionUpdate,
30
+ type ListAddressesParams,
31
+ type RemoveAddressesResult,
32
+ type UpdateAddressesResult,
33
+ } from './resources/addresses.js'
34
+ export { AssetsResource, NetworksResource } from './resources/catalog.js'
35
+ export {
36
+ ClientKeysResource,
37
+ ClientsResource,
38
+ type ListClientsParams,
39
+ type RotateSecretParams,
40
+ type RotateSecretResult,
41
+ type UpdateClientParams,
42
+ } from './resources/clients.js'
43
+ export { DeliveriesResource, type DeliveryFilter, type ListDeliveriesParams } from './resources/deliveries.js'
44
+ export { TransactionsResource } from './resources/transactions.js'
45
+
46
+ export {
47
+ isTestWebhook,
48
+ parseWebhook,
49
+ signWebhookBody,
50
+ verifyWebhookSignature,
51
+ WEBHOOK_HEADERS,
52
+ webhookIdempotencyKey,
53
+ type SignatureSource,
54
+ type WebhookBody,
55
+ } from './webhooks.js'
56
+ export { formatUnits, parseUnits } from './units.js'
57
+ export { DEFAULT_BASE_URL, SDK_VERSION } from './version.js'
58
+
59
+ // Типы запросов и ответов — из спецификации OpenAPI (src/generated/types.ts)
60
+ export type * from './generated/types.js'
@@ -0,0 +1,87 @@
1
+ import { seg, type HttpClient, type RequestOptions } from '../core/http.js'
2
+ import type { ApiKey, Identity, IssueKeyRequest, IssuedKey, User } from '../generated/types.js'
3
+
4
+ /** Личные ключи: действуют от вашего имени с вашими правами — всё, что вы можете в панели */
5
+ export class PersonalKeysResource {
6
+ readonly #http: HttpClient
7
+ constructor(http: HttpClient) {
8
+ this.#http = http
9
+ }
10
+
11
+ async list(options?: RequestOptions): Promise<ApiKey[]> {
12
+ const r = await this.#http.request<{ items: ApiKey[] }>({ method: 'GET', path: '/v1/me/keys', idempotent: true, options })
13
+ return r.items
14
+ }
15
+
16
+ /**
17
+ * Выпускает личный ключ. Работает только с клиентом, вошедшим по паролю ({@link MonitoringClient.signIn}):
18
+ * ключ не может выпустить себе замену. Полный ключ — в `key`, показывается один раз.
19
+ */
20
+ create(params: IssueKeyRequest = {}, options?: RequestOptions): Promise<IssuedKey> {
21
+ return this.#http.request({ method: 'POST', path: '/v1/me/keys', body: params, idempotent: false, options })
22
+ }
23
+
24
+ async revoke(keyId: string, options?: RequestOptions): Promise<void> {
25
+ await this.#http.request({ method: 'DELETE', path: `/v1/me/keys/${seg(keyId)}`, idempotent: true, options })
26
+ }
27
+ }
28
+
29
+ /** Кто вы и ваши ключи */
30
+ export class AccountResource {
31
+ readonly #http: HttpClient
32
+ /** Личные ключи */
33
+ readonly keys: PersonalKeysResource
34
+
35
+ constructor(http: HttpClient) {
36
+ this.#http = http
37
+ this.keys = new PersonalKeysResource(http)
38
+ }
39
+
40
+ /**
41
+ * Кто сделал запрос: способ входа, пользователь и участие в клиентах с ролями. Для ключа клиента —
42
+ * `actor.kind === 'client-key'` и `actor.clientId`.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const { actor } = await monitoring.account.me()
47
+ * const clientId = actor.clientId // для ключа клиента
48
+ * ```
49
+ */
50
+ me(options?: RequestOptions): Promise<Identity> {
51
+ return this.#http.request({ method: 'GET', path: '/v1/me', idempotent: true, options })
52
+ }
53
+ }
54
+
55
+ /** Результат входа по паролю */
56
+ export interface SignInResult {
57
+ /** Токен сессии: передайте его в `sessionToken` или используйте готовый клиент из {@link MonitoringClient.signIn} */
58
+ token: string
59
+ user: User
60
+ }
61
+
62
+ /** Сессия: выход и смена пароля. Нужен клиент, вошедший по паролю */
63
+ export class AuthResource {
64
+ readonly #http: HttpClient
65
+ constructor(http: HttpClient) {
66
+ this.#http = http
67
+ }
68
+
69
+ /** Текущая сессия и пользователь; `null` — сессии нет или она истекла */
70
+ session(options?: RequestOptions): Promise<{ session: Record<string, unknown>; user: User } | null> {
71
+ return this.#http.request({ method: 'GET', path: '/api/auth/get-session', idempotent: true, options })
72
+ }
73
+
74
+ /** Завершает сессию; токен перестаёт работать */
75
+ async signOut(options?: RequestOptions): Promise<void> {
76
+ await this.#http.request({ method: 'POST', path: '/api/auth/sign-out', body: {}, idempotent: true, options })
77
+ }
78
+
79
+ /**
80
+ * Меняет пароль. Ключом пароль не сменить — только в сессии.
81
+ *
82
+ * @param params.revokeOtherSessions - завершить остальные сессии
83
+ */
84
+ async changePassword(params: { currentPassword: string; newPassword: string; revokeOtherSessions?: boolean }, options?: RequestOptions): Promise<void> {
85
+ await this.#http.request({ method: 'POST', path: '/api/auth/change-password', body: params, idempotent: false, options })
86
+ }
87
+ }
@@ -0,0 +1,190 @@
1
+ import { MonitoringApiError } from '../core/errors.js'
2
+ import { seg, type HttpClient, type RequestOptions } from '../core/http.js'
3
+ import { paginate, type Page } from '../core/pagination.js'
4
+ import type { Address, AddressInput, AssetSelection, Direction, UpdateAddressesRequest } from '../generated/types.js'
5
+
6
+ /** Столько адресов API принимает за один запрос; больше SDK разбивает на пачки сам */
7
+ export const ADDRESS_BATCH_SIZE = 1000
8
+
9
+ /**
10
+ * Подписка по умолчанию для всех адресов запроса — действует на элементы, где своей нет.
11
+ * Без неё адрес получает все активы сети в обе стороны.
12
+ */
13
+ export interface AddressDefaults {
14
+ /** Символы (`USDT`) или адреса контрактов; `null` — все активы сети, включая добавленные позже */
15
+ assets?: AssetSelection
16
+ /** `in` — только входящие, `out` — только исходящие, `both` — любые */
17
+ direction?: Direction
18
+ }
19
+
20
+ /** Адрес в сети — для снятия с мониторинга */
21
+ export interface AddressRef {
22
+ /** Сеть: slug (`tron`, `ethereum`) или CAIP-2 (`eip155:1`) */
23
+ network: string
24
+ address: string
25
+ }
26
+
27
+ /** Новая подписка одного адреса; что не передано — не меняется */
28
+ export type AddressSubscriptionUpdate = UpdateAddressesRequest['addresses'][number]
29
+
30
+ export interface AddAddressesResult {
31
+ /** Добавлено новых адресов */
32
+ added: number
33
+ /** Уже отслеживались — их подписка не менялась */
34
+ alreadyWatched: number
35
+ }
36
+
37
+ export interface UpdateAddressesResult {
38
+ /** Найдено и изменено */
39
+ updated: number
40
+ /** Не на мониторинге у этого клиента */
41
+ notWatched: number
42
+ }
43
+
44
+ export interface RemoveAddressesResult {
45
+ /** Снято с мониторинга */
46
+ removed: number
47
+ /** Не отслеживались */
48
+ notWatched: number
49
+ }
50
+
51
+ export interface ListAddressesParams {
52
+ /** Только эта сеть */
53
+ network?: string
54
+ /** Размер страницы, до 5000; по умолчанию 500 */
55
+ limit?: number
56
+ /** Курсор: `next` прошлой страницы */
57
+ after?: number
58
+ }
59
+
60
+ /**
61
+ * Адреса клиента на мониторинге и их подписка: какие активы и в каком направлении сообщать.
62
+ *
63
+ * Новый адрес начинает отслеживаться через несколько секунд после добавления.
64
+ */
65
+ export class AddressesResource {
66
+ readonly #http: HttpClient
67
+ constructor(http: HttpClient) {
68
+ this.#http = http
69
+ }
70
+
71
+ /**
72
+ * Страница адресов с подпиской каждого.
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const page = await monitoring.addresses.list(clientId, { network: 'tron' })
77
+ * ```
78
+ */
79
+ list(clientId: string, params: ListAddressesParams = {}, options?: RequestOptions): Promise<Page<Address, number>> {
80
+ return this.#http.request({ method: 'GET', path: `/v1/clients/${seg(clientId)}/addresses`, query: { ...params }, idempotent: true, options })
81
+ }
82
+
83
+ /**
84
+ * Все адреса клиента — страница за страницей.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * for await (const a of monitoring.addresses.iterate(clientId)) console.log(a.network, a.address, a.direction)
89
+ * ```
90
+ */
91
+ iterate(clientId: string, params: Omit<ListAddressesParams, 'after'> = {}, options?: RequestOptions): AsyncGenerator<Address, void, undefined> {
92
+ return paginate<Address, number>((after) => this.list(clientId, { ...params, after }, options))
93
+ }
94
+
95
+ /**
96
+ * Ставит адреса на мониторинг. Уже отслеживаемые не меняются (подписку меняет {@link update}).
97
+ *
98
+ * Каждая пачка до {@link ADDRESS_BATCH_SIZE} адресов проверяется целиком: одна ошибка — пачка не записана.
99
+ * Больше 1000 адресов SDK отправит несколькими пачками по порядку; если пачка не прошла, предыдущие уже
100
+ * записаны, а номера в `error.details` указывают на элементы исходного массива. Повтор безопасен.
101
+ *
102
+ * @param defaults - подписка для элементов без своей; по умолчанию — все активы, обе стороны
103
+ * @throws {@link MonitoringApiError} 400 — адрес не той сети, неверный регистр TRON, неизвестный актив…
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * // депозитные адреса: только входящие USDT
108
+ * await monitoring.addresses.add(clientId, [{ network: 'tron', address: 'T…', label: 'user-42' }], {
109
+ * assets: ['USDT'],
110
+ * direction: 'in',
111
+ * })
112
+ * ```
113
+ */
114
+ async add(clientId: string, addresses: AddressInput[], defaults: AddressDefaults = {}, options?: RequestOptions): Promise<AddAddressesResult> {
115
+ const total: AddAddressesResult = { added: 0, alreadyWatched: 0 }
116
+ await this.#inBatches(addresses, async (batch) => {
117
+ const r = await this.#http.request<AddAddressesResult>({
118
+ method: 'POST',
119
+ path: `/v1/clients/${seg(clientId)}/addresses`,
120
+ body: { ...defaults, addresses: batch },
121
+ idempotent: true,
122
+ options,
123
+ })
124
+ total.added += r.added
125
+ total.alreadyWatched += r.alreadyWatched
126
+ })
127
+ return total
128
+ }
129
+
130
+ /**
131
+ * Меняет подписку отслеживаемых адресов: меняется только переданное. Без `assets` активы остаются прежними,
132
+ * `assets: null` — снова все активы сети.
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * await monitoring.addresses.update(clientId, [{ network: 'tron', address: 'T…' }], { direction: 'both' })
137
+ * ```
138
+ */
139
+ async update(clientId: string, addresses: AddressSubscriptionUpdate[], defaults: AddressDefaults = {}, options?: RequestOptions): Promise<UpdateAddressesResult> {
140
+ const total: UpdateAddressesResult = { updated: 0, notWatched: 0 }
141
+ await this.#inBatches(addresses, async (batch) => {
142
+ const r = await this.#http.request<UpdateAddressesResult>({
143
+ method: 'POST',
144
+ path: `/v1/clients/${seg(clientId)}/addresses/update`,
145
+ body: { ...defaults, addresses: batch },
146
+ idempotent: true,
147
+ options,
148
+ })
149
+ total.updated += r.updated
150
+ total.notWatched += r.notWatched
151
+ })
152
+ return total
153
+ }
154
+
155
+ /** Снимает адреса с мониторинга. Больше 1000 — несколькими пачками */
156
+ async remove(clientId: string, addresses: AddressRef[], options?: RequestOptions): Promise<RemoveAddressesResult> {
157
+ const total: RemoveAddressesResult = { removed: 0, notWatched: 0 }
158
+ await this.#inBatches(addresses, async (batch) => {
159
+ const r = await this.#http.request<RemoveAddressesResult>({
160
+ method: 'POST',
161
+ path: `/v1/clients/${seg(clientId)}/addresses/remove`,
162
+ body: { addresses: batch },
163
+ idempotent: true,
164
+ options,
165
+ })
166
+ total.removed += r.removed
167
+ total.notWatched += r.notWatched
168
+ })
169
+ return total
170
+ }
171
+
172
+ /** Пачками по порядку; номера ошибок по элементам — в нумерации исходного массива */
173
+ async #inBatches<T>(items: T[], send: (batch: T[]) => Promise<void>): Promise<void> {
174
+ for (let offset = 0; offset < items.length; offset += ADDRESS_BATCH_SIZE) {
175
+ try {
176
+ await send(items.slice(offset, offset + ADDRESS_BATCH_SIZE))
177
+ } catch (e) {
178
+ if (!(e instanceof MonitoringApiError) || offset === 0) throw e
179
+ throw new MonitoringApiError({
180
+ status: e.status,
181
+ code: e.code,
182
+ message: `${e.message.replace(/ \(HTTP \d+, [\w-]+\)$/, '')}; addresses before #${offset} were already applied`,
183
+ details: e.details.map((d) => ({ ...d, index: d.index + offset })),
184
+ requestId: e.requestId,
185
+ body: e.body,
186
+ })
187
+ }
188
+ }
189
+ }
190
+ }