@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.
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +247 -2
- package/dist/cjs/client.d.ts +65 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +89 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/core/errors.d.ts +64 -0
- package/dist/cjs/core/errors.d.ts.map +1 -0
- package/dist/cjs/core/errors.js +95 -0
- package/dist/cjs/core/errors.js.map +1 -0
- package/dist/cjs/core/http.d.ts +62 -0
- package/dist/cjs/core/http.d.ts.map +1 -0
- package/dist/cjs/core/http.js +151 -0
- package/dist/cjs/core/http.js.map +1 -0
- package/dist/cjs/core/pagination.d.ts +13 -0
- package/dist/cjs/core/pagination.d.ts.map +1 -0
- package/dist/cjs/core/pagination.js +15 -0
- package/dist/cjs/core/pagination.js.map +1 -0
- package/dist/cjs/generated/types.d.ts +324 -0
- package/dist/cjs/generated/types.d.ts.map +1 -0
- package/dist/cjs/generated/types.js +5 -0
- package/dist/cjs/generated/types.js.map +1 -0
- package/dist/cjs/index.d.ts +23 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +50 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/resources/account.d.ts +61 -0
- package/dist/cjs/resources/account.d.ts.map +1 -0
- package/dist/cjs/resources/account.js +75 -0
- package/dist/cjs/resources/account.js.map +1 -0
- package/dist/cjs/resources/addresses.d.ts +109 -0
- package/dist/cjs/resources/addresses.d.ts.map +1 -0
- package/dist/cjs/resources/addresses.js +137 -0
- package/dist/cjs/resources/addresses.js.map +1 -0
- package/dist/cjs/resources/catalog.d.ts +30 -0
- package/dist/cjs/resources/catalog.d.ts.map +1 -0
- package/dist/cjs/resources/catalog.js +46 -0
- package/dist/cjs/resources/catalog.js.map +1 -0
- package/dist/cjs/resources/clients.d.ts +84 -0
- package/dist/cjs/resources/clients.d.ts.map +1 -0
- package/dist/cjs/resources/clients.js +102 -0
- package/dist/cjs/resources/clients.js.map +1 -0
- package/dist/cjs/resources/deliveries.d.ts +50 -0
- package/dist/cjs/resources/deliveries.d.ts.map +1 -0
- package/dist/cjs/resources/deliveries.js +43 -0
- package/dist/cjs/resources/deliveries.js.map +1 -0
- package/dist/cjs/resources/transactions.d.ts +28 -0
- package/dist/cjs/resources/transactions.d.ts.map +1 -0
- package/dist/cjs/resources/transactions.js +35 -0
- package/dist/cjs/resources/transactions.js.map +1 -0
- package/dist/cjs/units.d.ts +29 -0
- package/dist/cjs/units.d.ts.map +1 -0
- package/dist/cjs/units.js +62 -0
- package/dist/cjs/units.js.map +1 -0
- package/dist/cjs/version.d.ts +5 -0
- package/dist/cjs/version.d.ts.map +1 -0
- package/dist/cjs/version.js +8 -0
- package/dist/cjs/version.js.map +1 -0
- package/dist/cjs/webhooks.d.ts +77 -0
- package/dist/cjs/webhooks.d.ts.map +1 -0
- package/dist/cjs/webhooks.js +128 -0
- package/dist/cjs/webhooks.js.map +1 -0
- package/dist/esm/client.d.ts +65 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +85 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/core/errors.d.ts +64 -0
- package/dist/esm/core/errors.d.ts.map +1 -0
- package/dist/esm/core/errors.js +86 -0
- package/dist/esm/core/errors.js.map +1 -0
- package/dist/esm/core/http.d.ts +62 -0
- package/dist/esm/core/http.d.ts.map +1 -0
- package/dist/esm/core/http.js +146 -0
- package/dist/esm/core/http.js.map +1 -0
- package/dist/esm/core/pagination.d.ts +13 -0
- package/dist/esm/core/pagination.d.ts.map +1 -0
- package/dist/esm/core/pagination.js +12 -0
- package/dist/esm/core/pagination.js.map +1 -0
- package/dist/esm/generated/types.d.ts +324 -0
- package/dist/esm/generated/types.d.ts.map +1 -0
- package/dist/esm/generated/types.js +4 -0
- package/dist/esm/generated/types.js.map +1 -0
- package/dist/esm/index.d.ts +23 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/resources/account.d.ts +61 -0
- package/dist/esm/resources/account.d.ts.map +1 -0
- package/dist/esm/resources/account.js +69 -0
- package/dist/esm/resources/account.js.map +1 -0
- package/dist/esm/resources/addresses.d.ts +109 -0
- package/dist/esm/resources/addresses.d.ts.map +1 -0
- package/dist/esm/resources/addresses.js +133 -0
- package/dist/esm/resources/addresses.js.map +1 -0
- package/dist/esm/resources/catalog.d.ts +30 -0
- package/dist/esm/resources/catalog.d.ts.map +1 -0
- package/dist/esm/resources/catalog.js +41 -0
- package/dist/esm/resources/catalog.js.map +1 -0
- package/dist/esm/resources/clients.d.ts +84 -0
- package/dist/esm/resources/clients.d.ts.map +1 -0
- package/dist/esm/resources/clients.js +97 -0
- package/dist/esm/resources/clients.js.map +1 -0
- package/dist/esm/resources/deliveries.d.ts +50 -0
- package/dist/esm/resources/deliveries.d.ts.map +1 -0
- package/dist/esm/resources/deliveries.js +39 -0
- package/dist/esm/resources/deliveries.js.map +1 -0
- package/dist/esm/resources/transactions.d.ts +28 -0
- package/dist/esm/resources/transactions.d.ts.map +1 -0
- package/dist/esm/resources/transactions.js +31 -0
- package/dist/esm/resources/transactions.js.map +1 -0
- package/dist/esm/units.d.ts +29 -0
- package/dist/esm/units.d.ts.map +1 -0
- package/dist/esm/units.js +58 -0
- package/dist/esm/units.js.map +1 -0
- package/dist/esm/version.d.ts +5 -0
- package/dist/esm/version.d.ts.map +1 -0
- package/dist/esm/version.js +5 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/esm/webhooks.d.ts +77 -0
- package/dist/esm/webhooks.d.ts.map +1 -0
- package/dist/esm/webhooks.js +120 -0
- package/dist/esm/webhooks.js.map +1 -0
- package/package.json +66 -4
- package/src/client.ts +94 -0
- package/src/core/errors.ts +99 -0
- package/src/core/http.ts +193 -0
- package/src/core/pagination.ts +21 -0
- package/src/generated/types.ts +355 -0
- package/src/index.ts +60 -0
- package/src/resources/account.ts +87 -0
- package/src/resources/addresses.ts +190 -0
- package/src/resources/catalog.ts +47 -0
- package/src/resources/clients.ts +135 -0
- package/src/resources/deliveries.ts +69 -0
- package/src/resources/transactions.ts +33 -0
- package/src/units.ts +56 -0
- package/src/version.ts +5 -0
- package/src/webhooks.ts +133 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this package. The format follows [Keep a Changelog](https://keepachangelog.com), versions —
|
|
4
|
+
[SemVer](https://semver.org).
|
|
5
|
+
|
|
6
|
+
## 0.1.0 — 2026-10-28
|
|
7
|
+
|
|
8
|
+
First release.
|
|
9
|
+
|
|
10
|
+
- `MonitoringClient`: account and personal keys, sign-in, networks and assets, your client (webhook URL, signing
|
|
11
|
+
secret, client keys, members, test webhook), addresses and subscriptions with automatic batching, webhook history,
|
|
12
|
+
transaction lookup with confirmations and finality.
|
|
13
|
+
- Webhooks: `parseWebhook`, `verifyWebhookSignature`, `signWebhookBody`, `isTestWebhook`, `webhookIdempotencyKey`.
|
|
14
|
+
- Amounts: `formatUnits`, `parseUnits`.
|
|
15
|
+
- Timeouts, cancellation, retries on 429 and 503, typed errors with per-item details.
|
|
16
|
+
- Types generated from the OpenAPI spec of the API.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 V3 Finance
|
|
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
CHANGED
|
@@ -1,3 +1,248 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @v3finance/monitoring-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Official TypeScript SDK for the [V3 Finance address monitoring API](https://monitoring.v3.finance/docs):
|
|
4
|
+
watch addresses on TRON and EVM networks and receive a signed webhook for every incoming and outgoing transfer.
|
|
5
|
+
|
|
6
|
+
- **Typed end to end** — request and response types are generated from the API's OpenAPI spec, with docs on hover.
|
|
7
|
+
- **Webhooks** — signature verification and typed parsing with no network calls, using Web Crypto.
|
|
8
|
+
- **Built for production** — timeouts, cancellation, retries on rate limits, typed errors with per-item details,
|
|
9
|
+
automatic batching of large address lists, async iteration over pages.
|
|
10
|
+
- **Zero runtime dependencies** — Node.js 20+, Bun, Deno, Cloudflare Workers; ESM and CommonJS.
|
|
11
|
+
|
|
12
|
+
[Русская версия ниже](#по-русски).
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @v3finance/monitoring-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Server-side only: an API key in a browser is visible to anyone.
|
|
21
|
+
|
|
22
|
+
## Quick start
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { MonitoringClient } from '@v3finance/monitoring-sdk'
|
|
26
|
+
|
|
27
|
+
const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY })
|
|
28
|
+
|
|
29
|
+
// your client id: for a client key it is in the key's identity
|
|
30
|
+
const { actor } = await monitoring.account.me()
|
|
31
|
+
const clientId = actor.clientId!
|
|
32
|
+
|
|
33
|
+
// deposit addresses: incoming USDT only
|
|
34
|
+
await monitoring.addresses.add(clientId, [{ network: 'tron', address: 'TA8HgQbFjuMLWCaJeGyfrv8FErWSHz82vr', label: 'user-42' }], {
|
|
35
|
+
assets: ['USDT'],
|
|
36
|
+
direction: 'in',
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Authentication
|
|
41
|
+
|
|
42
|
+
| Credential | How to get it | What it can do |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Client key `ce_…` | panel → client → API keys, or `clients.keys.create()` | addresses, history and transactions of that client |
|
|
45
|
+
| Personal key `ce_user_…` | panel → Account, or `account.keys.create()` after signing in | everything you can do in the panel, with your role |
|
|
46
|
+
| Session | `MonitoringClient.signIn({ email, password })` | same as a personal key |
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
const monitoring = new MonitoringClient({ apiKey: 'ce_…' })
|
|
50
|
+
const { client } = await MonitoringClient.signIn({ email, password })
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Receiving webhooks
|
|
54
|
+
|
|
55
|
+
Every webhook is a `POST` with JSON `{ tx: { network, asset, contract, type, id, block, timestamp, from, to, value, logIndex? } }`
|
|
56
|
+
and an `x-signature` header — HMAC-SHA256 of the raw body with your client's secret. Verify it against the **raw**
|
|
57
|
+
body: re-serialized JSON will not match.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import express from 'express'
|
|
61
|
+
import { isTestWebhook, parseWebhook, webhookIdempotencyKey, WebhookSignatureError } from '@v3finance/monitoring-sdk'
|
|
62
|
+
|
|
63
|
+
app.post('/webhooks/monitoring', express.raw({ type: 'application/json' }), async (req, res) => {
|
|
64
|
+
try {
|
|
65
|
+
const event = await parseWebhook(req.body, req.headers, process.env.MONITORING_WEBHOOK_SECRET!)
|
|
66
|
+
if (!isTestWebhook(event)) await creditOnce(webhookIdempotencyKey(event), event.tx)
|
|
67
|
+
res.sendStatus(200)
|
|
68
|
+
} catch (e) {
|
|
69
|
+
if (e instanceof WebhookSignatureError) return res.sendStatus(401)
|
|
70
|
+
throw e
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Hono, Next.js route handlers, Cloudflare Workers:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const event = await parseWebhook(await request.text(), request.headers, env.MONITORING_WEBHOOK_SECRET)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Rules of delivery:
|
|
82
|
+
|
|
83
|
+
- Answer **2xx within 15 seconds**; otherwise the webhook is retried after 10 s, 1 min and 5 min.
|
|
84
|
+
- The same webhook can arrive more than once — process it idempotently by `webhookIdempotencyKey(event)`.
|
|
85
|
+
- `type` is always `TOPUP` for both directions: compare `from` and `to` with your addresses.
|
|
86
|
+
- A webhook is sent as soon as the transfer is in a block, before finality. For large amounts check
|
|
87
|
+
`final` first (below).
|
|
88
|
+
- Test webhooks (`isTestWebhook(event)`, header `x-webhook-test: 1`) must not be credited.
|
|
89
|
+
|
|
90
|
+
## Transactions: confirmations and finality
|
|
91
|
+
|
|
92
|
+
Any transaction by hash, not only the ones you got a webhook for:
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
const tx = await monitoring.transactions.get('tron', event.tx.id)
|
|
96
|
+
tx.status // 'success' | 'failed' | 'pending'
|
|
97
|
+
tx.confirmations // from the current head of the network
|
|
98
|
+
tx.final // cannot be reverted: TRON — solidified (~1 min), Ethereum — finalized (~13 min)
|
|
99
|
+
tx.transfers // every transfer inside: native, tokens, TRON internal TRX transfers
|
|
100
|
+
tx.watched // your watched addresses in this transaction
|
|
101
|
+
tx.webhooks // webhooks we sent you for it
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Addresses and subscriptions
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
await monitoring.addresses.add(clientId, items, { assets: ['USDT'], direction: 'in' }) // more than 1000 — batched for you
|
|
108
|
+
await monitoring.addresses.update(clientId, [{ network: 'tron', address: 'T…' }], { direction: 'both' })
|
|
109
|
+
await monitoring.addresses.remove(clientId, [{ network: 'tron', address: 'T…' }])
|
|
110
|
+
|
|
111
|
+
for await (const a of monitoring.addresses.iterate(clientId, { network: 'tron' })) {
|
|
112
|
+
console.log(a.address, a.assets ?? 'all assets', a.direction)
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
A subscription narrows what you are notified about: `assets` — symbols or contract addresses (`null` — all assets of
|
|
117
|
+
the network, including ones added later), `direction` — `in`, `out` or `both`. EVM addresses are per network: watch
|
|
118
|
+
one address on several networks with several items.
|
|
119
|
+
|
|
120
|
+
## Webhook history
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
for await (const d of monitoring.deliveries.iterate(clientId, { status: 'failed', since: new Date(Date.now() - 86_400_000) })) {
|
|
124
|
+
console.log(d.txId, d.attempts, d.lastHttpStatus ?? d.lastError)
|
|
125
|
+
}
|
|
126
|
+
const detail = await monitoring.deliveries.get(clientId, id) // exact body and URL
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Your client
|
|
130
|
+
|
|
131
|
+
Owner and admin of a client (session or personal key):
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
await monitoring.clients.update(clientId, { webhookUrl: 'https://example.com/webhooks/monitoring' })
|
|
135
|
+
const { secretKey } = await monitoring.clients.rotateSecret(clientId) // the old secret stops working at once
|
|
136
|
+
const { key } = await monitoring.clients.keys.create(clientId, { name: 'backend', expiresInDays: 365 })
|
|
137
|
+
const result = await monitoring.clients.sendTestWebhook(clientId, { asset: 'USDT' }) // result.delivery.ok
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Amounts
|
|
141
|
+
|
|
142
|
+
Amounts are strings in minimal units (sun, wei; USDT has 6 decimals). Convert without losing precision:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { formatUnits, parseUnits } from '@v3finance/monitoring-sdk'
|
|
146
|
+
|
|
147
|
+
formatUnits('100000000', 6) // '100'
|
|
148
|
+
parseUnits('1.5', 6) // '1500000'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Decimals of every asset: `monitoring.assets.list()`.
|
|
152
|
+
|
|
153
|
+
## Errors, retries, timeouts
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { MonitoringApiError, MonitoringConnectionError } from '@v3finance/monitoring-sdk'
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
await monitoring.addresses.add(clientId, items)
|
|
160
|
+
} catch (e) {
|
|
161
|
+
if (e instanceof MonitoringApiError) {
|
|
162
|
+
e.status // 400
|
|
163
|
+
e.code // 'invalid_request'
|
|
164
|
+
e.details // [{ index: 3, message: 'not a valid TRON address' }]
|
|
165
|
+
e.requestId // send it to support
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
- `429` and `503` are retried with the server's `Retry-After` or exponential backoff (`maxRetries`, default 2).
|
|
171
|
+
Network errors are retried only for requests that are safe to repeat.
|
|
172
|
+
- Every request has a timeout (`timeoutMs`, default 30 s) and accepts an `AbortSignal`:
|
|
173
|
+
`monitoring.addresses.list(clientId, {}, { signal })`.
|
|
174
|
+
- All errors extend `MonitoringError`.
|
|
175
|
+
|
|
176
|
+
## API reference
|
|
177
|
+
|
|
178
|
+
- Interactive reference: https://monitoring.v3.finance/docs
|
|
179
|
+
- OpenAPI 3.1: https://monitoring.v3.finance/openapi.json
|
|
180
|
+
- All request and response types are exported: `import type { Transaction, WebhookPayload } from '@v3finance/monitoring-sdk'`.
|
|
181
|
+
|
|
182
|
+
## Versioning
|
|
183
|
+
|
|
184
|
+
[SemVer](https://semver.org). While the version is `0.x`, minor releases may contain breaking changes; they are listed in
|
|
185
|
+
[CHANGELOG.md](./CHANGELOG.md).
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## По-русски
|
|
190
|
+
|
|
191
|
+
Официальный SDK API мониторинга адресов V3 Finance: адреса в TRON и EVM-сетях, подписанные вебхуки о переводах,
|
|
192
|
+
история доставок, транзакции с подтверждениями и финальностью. Подсказки в редакторе — по-русски.
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
npm install @v3finance/monitoring-sdk
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**Только для сервера** — ключ в браузере увидит любой. Node.js 20+, Bun, Deno, Cloudflare Workers; ESM и CommonJS.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { MonitoringClient, parseWebhook, isTestWebhook, webhookIdempotencyKey } from '@v3finance/monitoring-sdk'
|
|
202
|
+
|
|
203
|
+
const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY }) // ключ клиента ce_…
|
|
204
|
+
const clientId = (await monitoring.account.me()).actor.clientId!
|
|
205
|
+
|
|
206
|
+
// депозитные адреса: только входящие USDT
|
|
207
|
+
await monitoring.addresses.add(clientId, [{ network: 'tron', address: 'T…', label: 'user-42' }], { assets: ['USDT'], direction: 'in' })
|
|
208
|
+
|
|
209
|
+
// приём вебхука: подпись — по сырому телу
|
|
210
|
+
const event = await parseWebhook(rawBody, headers, process.env.MONITORING_WEBHOOK_SECRET!)
|
|
211
|
+
if (!isTestWebhook(event)) await creditOnce(webhookIdempotencyKey(event), event.tx)
|
|
212
|
+
|
|
213
|
+
// перед зачислением крупной суммы — финальность
|
|
214
|
+
const tx = await monitoring.transactions.get('tron', event.tx.id)
|
|
215
|
+
if (tx.status === 'success' && tx.final) { /* зачислить */ }
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Главное при приёме вебхуков:
|
|
219
|
+
|
|
220
|
+
- отвечайте **2xx за 15 секунд**, иначе повторы через 10 с, 1 мин и 5 мин;
|
|
221
|
+
- один вебхук может прийти повторно — обрабатывайте идемпотентно по `webhookIdempotencyKey(event)`;
|
|
222
|
+
- `type` всегда `TOPUP` — направление определяйте по `from` и `to`;
|
|
223
|
+
- вебхук уходит сразу, как перевод попал в блок, до финальности: крупные суммы зачисляйте после `final`;
|
|
224
|
+
- тестовые вебхуки (`isTestWebhook`, заголовок `x-webhook-test: 1`) не зачислять.
|
|
225
|
+
|
|
226
|
+
Ключи: **ключ клиента** `ce_…` — адреса, история и транзакции своего клиента; **личный ключ** `ce_user_…` — всё, что вы
|
|
227
|
+
можете в панели (URL вебхука, секрет, ключи клиента, тестовый вебхук). Ошибки — `MonitoringApiError` со статусом, кодом
|
|
228
|
+
и ошибками по элементам (`details`); повторы при 429 и 503, таймауты и отмена через `AbortSignal` — встроены.
|
|
229
|
+
Суммы — строки в минимальных единицах: `formatUnits('100000000', 6) === '100'`.
|
|
230
|
+
|
|
231
|
+
Справочник API: https://monitoring.v3.finance/docs.
|
|
232
|
+
|
|
233
|
+
## Development
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
npm install
|
|
237
|
+
npm run spec:update # snapshot of https://monitoring.v3.finance/openapi.json → openapi/openapi.json
|
|
238
|
+
npm run generate # → src/generated/types.ts
|
|
239
|
+
npm run typecheck && npm test && npm run build
|
|
240
|
+
npm run build && MONITORING_API_KEY=ce_… node scripts/smoke.ts # against the real API, with a client key
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Releases: bump `version` in `package.json` and `src/version.ts`, update `CHANGELOG.md`, publish a GitHub release
|
|
244
|
+
`vX.Y.Z` — the `publish` workflow publishes to npm with Trusted Publishing.
|
|
245
|
+
|
|
246
|
+
## License
|
|
247
|
+
|
|
248
|
+
[MIT](./LICENSE)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type ClientOptions, type RequestOptions } from './core/http.js';
|
|
2
|
+
import { AccountResource, AuthResource, type SignInResult } from './resources/account.js';
|
|
3
|
+
import { AddressesResource } from './resources/addresses.js';
|
|
4
|
+
import { AssetsResource, NetworksResource } from './resources/catalog.js';
|
|
5
|
+
import { ClientsResource } from './resources/clients.js';
|
|
6
|
+
import { DeliveriesResource } from './resources/deliveries.js';
|
|
7
|
+
import { TransactionsResource } from './resources/transactions.js';
|
|
8
|
+
/**
|
|
9
|
+
* Клиент API мониторинга адресов V3 Finance: адреса и подписки, история вебхуков, транзакции, ваш клиент и ключи.
|
|
10
|
+
* Только для сервера: ключ в браузере увидит любой.
|
|
11
|
+
*
|
|
12
|
+
* @example С ключом клиента — для бэкенда
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { MonitoringClient } from '@v3finance/monitoring-sdk'
|
|
15
|
+
*
|
|
16
|
+
* const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY })
|
|
17
|
+
* await monitoring.addresses.add(clientId, [{ network: 'tron', address: 'T…' }], { assets: ['USDT'], direction: 'in' })
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @example По паролю — для скриптов, которым нужны права пользователя
|
|
21
|
+
* ```ts
|
|
22
|
+
* const { client } = await MonitoringClient.signIn({ email, password })
|
|
23
|
+
* const { key } = await client.account.keys.create({ name: 'ci' })
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class MonitoringClient {
|
|
27
|
+
#private;
|
|
28
|
+
/** Кто вы и ваши личные ключи */
|
|
29
|
+
readonly account: AccountResource;
|
|
30
|
+
/** Выход и смена пароля (для клиента, вошедшего по паролю) */
|
|
31
|
+
readonly auth: AuthResource;
|
|
32
|
+
/** Сети */
|
|
33
|
+
readonly networks: NetworksResource;
|
|
34
|
+
/** Нативные монеты и токены */
|
|
35
|
+
readonly assets: AssetsResource;
|
|
36
|
+
/** Ваш клиент: URL вебхука, секрет, ключи, участники, тестовый вебхук */
|
|
37
|
+
readonly clients: ClientsResource;
|
|
38
|
+
/** Адреса на мониторинге и подписка */
|
|
39
|
+
readonly addresses: AddressesResource;
|
|
40
|
+
/** История вебхуков */
|
|
41
|
+
readonly deliveries: DeliveriesResource;
|
|
42
|
+
/** Транзакция по хешу: статус, подтверждения, финальность */
|
|
43
|
+
readonly transactions: TransactionsResource;
|
|
44
|
+
/**
|
|
45
|
+
* @param options - ключ (`apiKey`) или токен сессии (`sessionToken`), адрес API, таймаут, повторы
|
|
46
|
+
* @throws {@link MonitoringError} переданы и ключ, и токен; нет `fetch`
|
|
47
|
+
*/
|
|
48
|
+
constructor(options?: ClientOptions);
|
|
49
|
+
/** Адрес API, с которым работает клиент */
|
|
50
|
+
get baseUrl(): string;
|
|
51
|
+
/**
|
|
52
|
+
* Вход по email и паролю: возвращает клиента с токеном сессии. Регистрации нет — пользователей заводит
|
|
53
|
+
* администратор сервиса. Не больше 3 попыток за 10 секунд с одного IP.
|
|
54
|
+
*
|
|
55
|
+
* @param options - настройки клиента, кроме учётных данных
|
|
56
|
+
* @throws {@link MonitoringApiError} 401 — неверный email или пароль
|
|
57
|
+
*/
|
|
58
|
+
static signIn(credentials: {
|
|
59
|
+
email: string;
|
|
60
|
+
password: string;
|
|
61
|
+
}, options?: Omit<ClientOptions, 'apiKey' | 'sessionToken'>, requestOptions?: RequestOptions): Promise<SignInResult & {
|
|
62
|
+
client: MonitoringClient;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpF,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAGlE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,gBAAgB;;IAC3B,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,WAAW;IACX,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAC/B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC,uCAAuC;IACvC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAA;IACrC,uBAAuB;IACvB,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;IACvC,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAA;IAI3C;;;OAGG;IACH,YAAY,OAAO,GAAE,aAAkB,EAUtC;IAED,2CAA2C;IAC3C,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;;;;OAMG;IACH,OAAa,MAAM,CACjB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAChD,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,cAAc,CAAM,EAC5D,cAAc,CAAC,EAAE,cAAc,GAC9B,OAAO,CAAC,YAAY,GAAG;QAAE,MAAM,EAAE,gBAAgB,CAAA;KAAE,CAAC,CAYtD;CACF"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MonitoringClient = void 0;
|
|
4
|
+
const http_js_1 = require("./core/http.js");
|
|
5
|
+
const account_js_1 = require("./resources/account.js");
|
|
6
|
+
const addresses_js_1 = require("./resources/addresses.js");
|
|
7
|
+
const catalog_js_1 = require("./resources/catalog.js");
|
|
8
|
+
const clients_js_1 = require("./resources/clients.js");
|
|
9
|
+
const deliveries_js_1 = require("./resources/deliveries.js");
|
|
10
|
+
const transactions_js_1 = require("./resources/transactions.js");
|
|
11
|
+
const version_js_1 = require("./version.js");
|
|
12
|
+
/**
|
|
13
|
+
* Клиент API мониторинга адресов V3 Finance: адреса и подписки, история вебхуков, транзакции, ваш клиент и ключи.
|
|
14
|
+
* Только для сервера: ключ в браузере увидит любой.
|
|
15
|
+
*
|
|
16
|
+
* @example С ключом клиента — для бэкенда
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { MonitoringClient } from '@v3finance/monitoring-sdk'
|
|
19
|
+
*
|
|
20
|
+
* const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY })
|
|
21
|
+
* await monitoring.addresses.add(clientId, [{ network: 'tron', address: 'T…' }], { assets: ['USDT'], direction: 'in' })
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example По паролю — для скриптов, которым нужны права пользователя
|
|
25
|
+
* ```ts
|
|
26
|
+
* const { client } = await MonitoringClient.signIn({ email, password })
|
|
27
|
+
* const { key } = await client.account.keys.create({ name: 'ci' })
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class MonitoringClient {
|
|
31
|
+
/** Кто вы и ваши личные ключи */
|
|
32
|
+
account;
|
|
33
|
+
/** Выход и смена пароля (для клиента, вошедшего по паролю) */
|
|
34
|
+
auth;
|
|
35
|
+
/** Сети */
|
|
36
|
+
networks;
|
|
37
|
+
/** Нативные монеты и токены */
|
|
38
|
+
assets;
|
|
39
|
+
/** Ваш клиент: URL вебхука, секрет, ключи, участники, тестовый вебхук */
|
|
40
|
+
clients;
|
|
41
|
+
/** Адреса на мониторинге и подписка */
|
|
42
|
+
addresses;
|
|
43
|
+
/** История вебхуков */
|
|
44
|
+
deliveries;
|
|
45
|
+
/** Транзакция по хешу: статус, подтверждения, финальность */
|
|
46
|
+
transactions;
|
|
47
|
+
#http;
|
|
48
|
+
/**
|
|
49
|
+
* @param options - ключ (`apiKey`) или токен сессии (`sessionToken`), адрес API, таймаут, повторы
|
|
50
|
+
* @throws {@link MonitoringError} переданы и ключ, и токен; нет `fetch`
|
|
51
|
+
*/
|
|
52
|
+
constructor(options = {}) {
|
|
53
|
+
this.#http = new http_js_1.HttpClient(options, version_js_1.DEFAULT_BASE_URL);
|
|
54
|
+
this.account = new account_js_1.AccountResource(this.#http);
|
|
55
|
+
this.auth = new account_js_1.AuthResource(this.#http);
|
|
56
|
+
this.networks = new catalog_js_1.NetworksResource(this.#http);
|
|
57
|
+
this.assets = new catalog_js_1.AssetsResource(this.#http);
|
|
58
|
+
this.clients = new clients_js_1.ClientsResource(this.#http);
|
|
59
|
+
this.addresses = new addresses_js_1.AddressesResource(this.#http);
|
|
60
|
+
this.deliveries = new deliveries_js_1.DeliveriesResource(this.#http);
|
|
61
|
+
this.transactions = new transactions_js_1.TransactionsResource(this.#http);
|
|
62
|
+
}
|
|
63
|
+
/** Адрес API, с которым работает клиент */
|
|
64
|
+
get baseUrl() {
|
|
65
|
+
return this.#http.baseUrl;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Вход по email и паролю: возвращает клиента с токеном сессии. Регистрации нет — пользователей заводит
|
|
69
|
+
* администратор сервиса. Не больше 3 попыток за 10 секунд с одного IP.
|
|
70
|
+
*
|
|
71
|
+
* @param options - настройки клиента, кроме учётных данных
|
|
72
|
+
* @throws {@link MonitoringApiError} 401 — неверный email или пароль
|
|
73
|
+
*/
|
|
74
|
+
static async signIn(credentials, options = {}, requestOptions) {
|
|
75
|
+
const http = new http_js_1.HttpClient(options, version_js_1.DEFAULT_BASE_URL);
|
|
76
|
+
const r = await http.request({
|
|
77
|
+
method: 'POST',
|
|
78
|
+
path: '/api/auth/sign-in/email',
|
|
79
|
+
body: credentials,
|
|
80
|
+
idempotent: false,
|
|
81
|
+
auth: false,
|
|
82
|
+
// повтор при отказе 429 только сожжёт попытки входа
|
|
83
|
+
options: { maxRetries: 0, ...requestOptions },
|
|
84
|
+
});
|
|
85
|
+
return { token: r.token, user: r.user, client: new MonitoringClient({ ...options, sessionToken: r.token }) };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.MonitoringClient = MonitoringClient;
|
|
89
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;AAAA,4CAAoF;AAEpF,uDAAyF;AACzF,2DAA4D;AAC5D,uDAAyE;AACzE,uDAAwD;AACxD,6DAA8D;AAC9D,iEAAkE;AAClE,6CAA+C;AAE/C;;;;;;;;;;;;;;;;;GAiBG;AACH;IACE,iCAAiC;IACxB,OAAO,CAAiB;IACjC,8DAA8D;IACrD,IAAI,CAAc;IAC3B,WAAW;IACF,QAAQ,CAAkB;IACnC,+BAA+B;IACtB,MAAM,CAAgB;IAC/B,yEAAyE;IAChE,OAAO,CAAiB;IACjC,uCAAuC;IAC9B,SAAS,CAAmB;IACrC,uBAAuB;IACd,UAAU,CAAoB;IACvC,6DAA6D;IACpD,YAAY,CAAsB;IAElC,KAAK,CAAY;IAE1B;;;OAGG;IACH,YAAY,OAAO,GAAkB,EAAE;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,oBAAU,CAAC,OAAO,EAAE,6BAAgB,CAAC,CAAA;QACtD,IAAI,CAAC,OAAO,GAAG,IAAI,4BAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC9C,IAAI,CAAC,IAAI,GAAG,IAAI,yBAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACxC,IAAI,CAAC,QAAQ,GAAG,IAAI,6BAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAChD,IAAI,CAAC,MAAM,GAAG,IAAI,2BAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC5C,IAAI,CAAC,OAAO,GAAG,IAAI,4BAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAC9C,IAAI,CAAC,SAAS,GAAG,IAAI,gCAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QAClD,IAAI,CAAC,UAAU,GAAG,IAAI,kCAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACpD,IAAI,CAAC,YAAY,GAAG,IAAI,sCAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC1D,CAAC;IAED,2CAA2C;IAC3C,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAA;IAC3B,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CACjB,WAAgD,EAChD,OAAO,GAAmD,EAAE,EAC5D,cAA+B;QAE/B,MAAM,IAAI,GAAG,IAAI,oBAAU,CAAC,OAAO,EAAE,6BAAgB,CAAC,CAAA;QACtD,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAgC;YAC1D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,yBAAyB;YAC/B,IAAI,EAAE,WAAW;YACjB,UAAU,EAAE,KAAK;YACjB,IAAI,EAAE,KAAK;YACX,oDAAoD;YACpD,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,cAAc,EAAE;SAC9C,CAAC,CAAA;QACF,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,gBAAgB,CAAC,EAAE,GAAG,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAA;IAC9G,CAAC;CACF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ApiErrorBody } from '../generated/types.js';
|
|
2
|
+
/** Ошибка по элементу запроса: номер элемента в переданном массиве и причина */
|
|
3
|
+
export type ErrorDetail = NonNullable<ApiErrorBody['error']['details']>[number];
|
|
4
|
+
/**
|
|
5
|
+
* Базовый класс всех ошибок SDK. Ловите его, чтобы перехватить любую ошибку SDK.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* try {
|
|
10
|
+
* await monitoring.addresses.add(clientId, items)
|
|
11
|
+
* } catch (e) {
|
|
12
|
+
* if (e instanceof MonitoringApiError && e.status === 400) console.log(e.details)
|
|
13
|
+
* else throw e
|
|
14
|
+
* }
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export declare class MonitoringError extends Error {
|
|
18
|
+
constructor(message: string, options?: {
|
|
19
|
+
cause?: unknown;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** API ответил ошибкой: HTTP 4xx или 5xx */
|
|
23
|
+
export declare class MonitoringApiError extends MonitoringError {
|
|
24
|
+
/** HTTP-статус ответа */
|
|
25
|
+
readonly status: number;
|
|
26
|
+
/**
|
|
27
|
+
* Машинный код ошибки: `invalid_request`, `unauthorized`, `forbidden`, `not_found`, `conflict`,
|
|
28
|
+
* `rate_limited`, `upstream_error`, `upstream_rate_limited`, `unavailable`…
|
|
29
|
+
*/
|
|
30
|
+
readonly code: string;
|
|
31
|
+
/** Ошибки по элементам запроса (например, какой адрес из переданных не подошёл); пустой массив, если их нет */
|
|
32
|
+
readonly details: ErrorDetail[];
|
|
33
|
+
/** Идентификатор запроса (`cf-ray`) — укажите его, если обращаетесь в поддержку */
|
|
34
|
+
readonly requestId: string | undefined;
|
|
35
|
+
/** Тело ответа как есть */
|
|
36
|
+
readonly body: unknown;
|
|
37
|
+
constructor(init: {
|
|
38
|
+
status: number;
|
|
39
|
+
code: string;
|
|
40
|
+
message: string;
|
|
41
|
+
details?: ErrorDetail[];
|
|
42
|
+
requestId?: string;
|
|
43
|
+
body?: unknown;
|
|
44
|
+
});
|
|
45
|
+
/** Временная ошибка — лимит частоты или недоступный провайдер: запрос можно повторить позже */
|
|
46
|
+
get retryable(): boolean;
|
|
47
|
+
}
|
|
48
|
+
/** Ответа нет: сбой сети или соединения */
|
|
49
|
+
export declare class MonitoringConnectionError extends MonitoringError {
|
|
50
|
+
constructor(message: string, options?: {
|
|
51
|
+
cause?: unknown;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/** Запрос не уложился в таймаут (`timeoutMs`) */
|
|
55
|
+
export declare class MonitoringTimeoutError extends MonitoringConnectionError {
|
|
56
|
+
constructor(timeoutMs: number);
|
|
57
|
+
}
|
|
58
|
+
/** Подпись вебхука не прошла проверку: тело подделано, изменено по дороге или проверяется не тем секретом */
|
|
59
|
+
export declare class WebhookSignatureError extends MonitoringError {
|
|
60
|
+
constructor(message?: string);
|
|
61
|
+
}
|
|
62
|
+
/** Тело ошибки в любом из форматов API: `/v1`, старые пути (`{ok: false}`), вход (`{code, message}`) */
|
|
63
|
+
export declare function apiErrorFrom(status: number, body: unknown, requestId: string | undefined): MonitoringApiError;
|
|
64
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAEzD,gFAAgF;AAChF,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAE/E;;;;;;;;;;;;GAYG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAGzD;CACF;AAED,4CAA4C;AAC5C,qBAAa,kBAAmB,SAAQ,eAAe;IACrD,yBAAyB;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,+GAA+G;IAC/G,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAA;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,2BAA2B;IAC3B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;IAEtB,YAAY,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,EAQ/H;IAED,+FAA+F;IAC/F,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF;AAED,2CAA2C;AAC3C,qBAAa,yBAA0B,SAAQ,eAAe;IAC5D,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAGzD;CACF;AAED,iDAAiD;AACjD,qBAAa,sBAAuB,SAAQ,yBAAyB;IACnE,YAAY,SAAS,EAAE,MAAM,EAG5B;CACF;AAED,6GAA6G;AAC7G,qBAAa,qBAAsB,SAAQ,eAAe;IACxD,YAAY,OAAO,SAA+B,EAGjD;CACF;AAED,wGAAwG;AACxG,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,kBAAkB,CAW7G"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebhookSignatureError = exports.MonitoringTimeoutError = exports.MonitoringConnectionError = exports.MonitoringApiError = exports.MonitoringError = void 0;
|
|
4
|
+
exports.apiErrorFrom = apiErrorFrom;
|
|
5
|
+
/**
|
|
6
|
+
* Базовый класс всех ошибок SDK. Ловите его, чтобы перехватить любую ошибку SDK.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* try {
|
|
11
|
+
* await monitoring.addresses.add(clientId, items)
|
|
12
|
+
* } catch (e) {
|
|
13
|
+
* if (e instanceof MonitoringApiError && e.status === 400) console.log(e.details)
|
|
14
|
+
* else throw e
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
class MonitoringError extends Error {
|
|
19
|
+
constructor(message, options) {
|
|
20
|
+
super(message, options);
|
|
21
|
+
this.name = 'MonitoringError';
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.MonitoringError = MonitoringError;
|
|
25
|
+
/** API ответил ошибкой: HTTP 4xx или 5xx */
|
|
26
|
+
class MonitoringApiError extends MonitoringError {
|
|
27
|
+
/** HTTP-статус ответа */
|
|
28
|
+
status;
|
|
29
|
+
/**
|
|
30
|
+
* Машинный код ошибки: `invalid_request`, `unauthorized`, `forbidden`, `not_found`, `conflict`,
|
|
31
|
+
* `rate_limited`, `upstream_error`, `upstream_rate_limited`, `unavailable`…
|
|
32
|
+
*/
|
|
33
|
+
code;
|
|
34
|
+
/** Ошибки по элементам запроса (например, какой адрес из переданных не подошёл); пустой массив, если их нет */
|
|
35
|
+
details;
|
|
36
|
+
/** Идентификатор запроса (`cf-ray`) — укажите его, если обращаетесь в поддержку */
|
|
37
|
+
requestId;
|
|
38
|
+
/** Тело ответа как есть */
|
|
39
|
+
body;
|
|
40
|
+
constructor(init) {
|
|
41
|
+
super(`${init.message} (HTTP ${init.status}, ${init.code})`);
|
|
42
|
+
this.name = 'MonitoringApiError';
|
|
43
|
+
this.status = init.status;
|
|
44
|
+
this.code = init.code;
|
|
45
|
+
this.details = init.details ?? [];
|
|
46
|
+
this.requestId = init.requestId;
|
|
47
|
+
this.body = init.body;
|
|
48
|
+
}
|
|
49
|
+
/** Временная ошибка — лимит частоты или недоступный провайдер: запрос можно повторить позже */
|
|
50
|
+
get retryable() {
|
|
51
|
+
return this.status === 429 || this.status === 503;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.MonitoringApiError = MonitoringApiError;
|
|
55
|
+
/** Ответа нет: сбой сети или соединения */
|
|
56
|
+
class MonitoringConnectionError extends MonitoringError {
|
|
57
|
+
constructor(message, options) {
|
|
58
|
+
super(message, options);
|
|
59
|
+
this.name = 'MonitoringConnectionError';
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.MonitoringConnectionError = MonitoringConnectionError;
|
|
63
|
+
/** Запрос не уложился в таймаут (`timeoutMs`) */
|
|
64
|
+
class MonitoringTimeoutError extends MonitoringConnectionError {
|
|
65
|
+
constructor(timeoutMs) {
|
|
66
|
+
super(`request timed out after ${timeoutMs} ms`);
|
|
67
|
+
this.name = 'MonitoringTimeoutError';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.MonitoringTimeoutError = MonitoringTimeoutError;
|
|
71
|
+
/** Подпись вебхука не прошла проверку: тело подделано, изменено по дороге или проверяется не тем секретом */
|
|
72
|
+
class WebhookSignatureError extends MonitoringError {
|
|
73
|
+
constructor(message = 'webhook signature mismatch') {
|
|
74
|
+
super(message);
|
|
75
|
+
this.name = 'WebhookSignatureError';
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
exports.WebhookSignatureError = WebhookSignatureError;
|
|
79
|
+
/** Тело ошибки в любом из форматов API: `/v1`, старые пути (`{ok: false}`), вход (`{code, message}`) */
|
|
80
|
+
function apiErrorFrom(status, body, requestId) {
|
|
81
|
+
const b = (body ?? {});
|
|
82
|
+
const v1 = typeof b.error === 'object' && b.error !== null ? b.error : undefined;
|
|
83
|
+
const message = (typeof v1?.message === 'string' && v1.message) ||
|
|
84
|
+
(typeof b.error === 'string' && b.error) ||
|
|
85
|
+
(typeof b.message === 'string' && b.message) ||
|
|
86
|
+
`HTTP ${status}`;
|
|
87
|
+
const code = (typeof v1?.code === 'string' && v1.code) || (typeof b.code === 'string' && b.code.toLowerCase()) || defaultCode(status);
|
|
88
|
+
const details = (Array.isArray(v1?.details) ? v1.details : Array.isArray(b.details) ? b.details : []);
|
|
89
|
+
return new MonitoringApiError({ status, code, message, details, requestId, body });
|
|
90
|
+
}
|
|
91
|
+
function defaultCode(status) {
|
|
92
|
+
const codes = { 400: 'invalid_request', 401: 'unauthorized', 403: 'forbidden', 404: 'not_found', 409: 'conflict', 429: 'rate_limited' };
|
|
93
|
+
return codes[status] ?? (status >= 500 ? 'server_error' : 'http_error');
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/core/errors.ts"],"names":[],"mappings":"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"}
|