@v3finance/monitoring-sdk 0.0.0-stage → 0.2.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 (149) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +322 -2
  4. package/dist/cjs/client.d.ts +46 -0
  5. package/dist/cjs/client.d.ts.map +1 -0
  6. package/dist/cjs/client.js +80 -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 +58 -0
  13. package/dist/cjs/core/http.d.ts.map +1 -0
  14. package/dist/cjs/core/http.js +143 -0
  15. package/dist/cjs/core/http.js.map +1 -0
  16. package/dist/cjs/core/pagination.d.ts +12 -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/core/scope.d.ts +8 -0
  21. package/dist/cjs/core/scope.d.ts.map +1 -0
  22. package/dist/cjs/core/scope.js +3 -0
  23. package/dist/cjs/core/scope.js.map +1 -0
  24. package/dist/cjs/generated/types.d.ts +336 -0
  25. package/dist/cjs/generated/types.d.ts.map +1 -0
  26. package/dist/cjs/generated/types.js +5 -0
  27. package/dist/cjs/generated/types.js.map +1 -0
  28. package/dist/cjs/index.d.ts +23 -0
  29. package/dist/cjs/index.d.ts.map +1 -0
  30. package/dist/cjs/index.js +47 -0
  31. package/dist/cjs/index.js.map +1 -0
  32. package/dist/cjs/package.json +1 -0
  33. package/dist/cjs/resources/account.d.ts +22 -0
  34. package/dist/cjs/resources/account.d.ts.map +1 -0
  35. package/dist/cjs/resources/account.js +31 -0
  36. package/dist/cjs/resources/account.js.map +1 -0
  37. package/dist/cjs/resources/addresses.d.ts +93 -0
  38. package/dist/cjs/resources/addresses.d.ts.map +1 -0
  39. package/dist/cjs/resources/addresses.js +128 -0
  40. package/dist/cjs/resources/addresses.js.map +1 -0
  41. package/dist/cjs/resources/catalog.d.ts +37 -0
  42. package/dist/cjs/resources/catalog.d.ts.map +1 -0
  43. package/dist/cjs/resources/catalog.js +52 -0
  44. package/dist/cjs/resources/catalog.js.map +1 -0
  45. package/dist/cjs/resources/deliveries.d.ts +61 -0
  46. package/dist/cjs/resources/deliveries.d.ts.map +1 -0
  47. package/dist/cjs/resources/deliveries.js +53 -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 +34 -0
  52. package/dist/cjs/resources/transactions.js.map +1 -0
  53. package/dist/cjs/resources/webhooks.d.ts +22 -0
  54. package/dist/cjs/resources/webhooks.d.ts.map +1 -0
  55. package/dist/cjs/resources/webhooks.js +35 -0
  56. package/dist/cjs/resources/webhooks.js.map +1 -0
  57. package/dist/cjs/units.d.ts +29 -0
  58. package/dist/cjs/units.d.ts.map +1 -0
  59. package/dist/cjs/units.js +62 -0
  60. package/dist/cjs/units.js.map +1 -0
  61. package/dist/cjs/version.d.ts +5 -0
  62. package/dist/cjs/version.d.ts.map +1 -0
  63. package/dist/cjs/version.js +8 -0
  64. package/dist/cjs/version.js.map +1 -0
  65. package/dist/cjs/webhooks.d.ts +82 -0
  66. package/dist/cjs/webhooks.d.ts.map +1 -0
  67. package/dist/cjs/webhooks.js +133 -0
  68. package/dist/cjs/webhooks.js.map +1 -0
  69. package/dist/esm/client.d.ts +46 -0
  70. package/dist/esm/client.d.ts.map +1 -0
  71. package/dist/esm/client.js +76 -0
  72. package/dist/esm/client.js.map +1 -0
  73. package/dist/esm/core/errors.d.ts +64 -0
  74. package/dist/esm/core/errors.d.ts.map +1 -0
  75. package/dist/esm/core/errors.js +86 -0
  76. package/dist/esm/core/errors.js.map +1 -0
  77. package/dist/esm/core/http.d.ts +58 -0
  78. package/dist/esm/core/http.d.ts.map +1 -0
  79. package/dist/esm/core/http.js +138 -0
  80. package/dist/esm/core/http.js.map +1 -0
  81. package/dist/esm/core/pagination.d.ts +12 -0
  82. package/dist/esm/core/pagination.d.ts.map +1 -0
  83. package/dist/esm/core/pagination.js +12 -0
  84. package/dist/esm/core/pagination.js.map +1 -0
  85. package/dist/esm/core/scope.d.ts +8 -0
  86. package/dist/esm/core/scope.d.ts.map +1 -0
  87. package/dist/esm/core/scope.js +2 -0
  88. package/dist/esm/core/scope.js.map +1 -0
  89. package/dist/esm/generated/types.d.ts +336 -0
  90. package/dist/esm/generated/types.d.ts.map +1 -0
  91. package/dist/esm/generated/types.js +4 -0
  92. package/dist/esm/generated/types.js.map +1 -0
  93. package/dist/esm/index.d.ts +23 -0
  94. package/dist/esm/index.d.ts.map +1 -0
  95. package/dist/esm/index.js +20 -0
  96. package/dist/esm/index.js.map +1 -0
  97. package/dist/esm/resources/account.d.ts +22 -0
  98. package/dist/esm/resources/account.d.ts.map +1 -0
  99. package/dist/esm/resources/account.js +27 -0
  100. package/dist/esm/resources/account.js.map +1 -0
  101. package/dist/esm/resources/addresses.d.ts +93 -0
  102. package/dist/esm/resources/addresses.d.ts.map +1 -0
  103. package/dist/esm/resources/addresses.js +124 -0
  104. package/dist/esm/resources/addresses.js.map +1 -0
  105. package/dist/esm/resources/catalog.d.ts +37 -0
  106. package/dist/esm/resources/catalog.d.ts.map +1 -0
  107. package/dist/esm/resources/catalog.js +47 -0
  108. package/dist/esm/resources/catalog.js.map +1 -0
  109. package/dist/esm/resources/deliveries.d.ts +61 -0
  110. package/dist/esm/resources/deliveries.d.ts.map +1 -0
  111. package/dist/esm/resources/deliveries.js +49 -0
  112. package/dist/esm/resources/deliveries.js.map +1 -0
  113. package/dist/esm/resources/transactions.d.ts +28 -0
  114. package/dist/esm/resources/transactions.d.ts.map +1 -0
  115. package/dist/esm/resources/transactions.js +30 -0
  116. package/dist/esm/resources/transactions.js.map +1 -0
  117. package/dist/esm/resources/webhooks.d.ts +22 -0
  118. package/dist/esm/resources/webhooks.d.ts.map +1 -0
  119. package/dist/esm/resources/webhooks.js +31 -0
  120. package/dist/esm/resources/webhooks.js.map +1 -0
  121. package/dist/esm/units.d.ts +29 -0
  122. package/dist/esm/units.d.ts.map +1 -0
  123. package/dist/esm/units.js +58 -0
  124. package/dist/esm/units.js.map +1 -0
  125. package/dist/esm/version.d.ts +5 -0
  126. package/dist/esm/version.d.ts.map +1 -0
  127. package/dist/esm/version.js +5 -0
  128. package/dist/esm/version.js.map +1 -0
  129. package/dist/esm/webhooks.d.ts +82 -0
  130. package/dist/esm/webhooks.d.ts.map +1 -0
  131. package/dist/esm/webhooks.js +125 -0
  132. package/dist/esm/webhooks.js.map +1 -0
  133. package/package.json +69 -4
  134. package/src/client.ts +83 -0
  135. package/src/core/errors.ts +99 -0
  136. package/src/core/http.ts +183 -0
  137. package/src/core/pagination.ts +20 -0
  138. package/src/core/scope.ts +8 -0
  139. package/src/generated/types.ts +369 -0
  140. package/src/index.ts +43 -0
  141. package/src/resources/account.ts +33 -0
  142. package/src/resources/addresses.ts +165 -0
  143. package/src/resources/catalog.ts +56 -0
  144. package/src/resources/deliveries.ts +82 -0
  145. package/src/resources/transactions.ts +34 -0
  146. package/src/resources/webhooks.ts +36 -0
  147. package/src/units.ts +56 -0
  148. package/src/version.ts +5 -0
  149. package/src/webhooks.ts +138 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,26 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented in this file. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org).
5
+
6
+ ## 0.2.0 — 2026-10-28
7
+
8
+ ### Breaking changes
9
+
10
+ - `MonitoringClient` authenticates with an API key only. Your client ID is resolved from the key, so methods no
11
+ longer take it as a parameter.
12
+ - Removed account management APIs: `MonitoringClient.signIn`, `auth`, `account.keys` and `clients`.
13
+ - `clients.sendTestWebhook()` is now `webhooks.sendTest()`.
14
+ - `AddressDefaults` is renamed to `SubscriptionDefaults`, and `AddressSubscriptionUpdate` to `AddressUpdate`.
15
+
16
+ ### Added
17
+
18
+ - `account.get()` and `account.id()`.
19
+
20
+ ### Changed
21
+
22
+ - Documentation and type descriptions are now in English.
23
+
24
+ ## 0.1.0 — 2026-10-28
25
+
26
+ - Initial release.
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,323 @@
1
- # Temporary Holding Version
1
+ # V3 Finance Monitoring SDK
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm version](https://img.shields.io/npm/v/@v3finance/monitoring-sdk.svg)](https://www.npmjs.com/package/@v3finance/monitoring-sdk)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@v3finance/monitoring-sdk.svg)](https://www.npmjs.com/package/@v3finance/monitoring-sdk)
5
+ [![types](https://img.shields.io/npm/types/@v3finance/monitoring-sdk.svg)](https://www.npmjs.com/package/@v3finance/monitoring-sdk)
6
+ [![license](https://img.shields.io/npm/l/@v3finance/monitoring-sdk.svg)](./LICENSE)
7
+
8
+ The official TypeScript SDK for the [V3 Finance Monitoring API](https://monitoring.v3.finance/docs).
9
+ Monitor addresses on TRON and EVM networks and receive a signed webhook for every incoming and outgoing transfer.
10
+
11
+ - **Address monitoring** with per-address subscriptions: choose the assets and the direction you are notified about.
12
+ - **Webhooks** with signature verification and fully typed payloads.
13
+ - **Transaction lookup** with confirmations and finality, for any transaction on a supported network.
14
+ - **Delivery history** of every webhook sent to you.
15
+ - **Production-ready**: automatic retries, timeouts, cancellation, pagination and batching.
16
+ - **Fully typed**, zero dependencies, ESM and CommonJS. Runs on Node.js, Bun, Deno and Cloudflare Workers.
17
+
18
+ ## Contents
19
+
20
+ - [Installation](#installation)
21
+ - [Quick start](#quick-start)
22
+ - [Configuration](#configuration)
23
+ - [Addresses](#addresses)
24
+ - [Receiving webhooks](#receiving-webhooks)
25
+ - [Transactions and finality](#transactions-and-finality)
26
+ - [Delivery history](#delivery-history)
27
+ - [Networks and assets](#networks-and-assets)
28
+ - [Amounts](#amounts)
29
+ - [Error handling](#error-handling)
30
+ - [Retries, timeouts and cancellation](#retries-timeouts-and-cancellation)
31
+ - [TypeScript](#typescript)
32
+ - [Requirements](#requirements)
33
+ - [Security](#security)
34
+ - [Versioning](#versioning)
35
+ - [Support](#support)
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ npm install @v3finance/monitoring-sdk
41
+ ```
42
+
43
+ ```bash
44
+ pnpm add @v3finance/monitoring-sdk
45
+ yarn add @v3finance/monitoring-sdk
46
+ bun add @v3finance/monitoring-sdk
47
+ ```
48
+
49
+ ## Quick start
50
+
51
+ ```ts
52
+ import { MonitoringClient } from '@v3finance/monitoring-sdk'
53
+
54
+ const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY! })
55
+
56
+ // Notify about incoming USDT on a deposit address
57
+ await monitoring.addresses.add(
58
+ [{ network: 'tron', address: 'TA8HgQbFjuMLWCaJeGyfrv8FErWSHz82vr', label: 'user-42' }],
59
+ { assets: ['USDT'], direction: 'in' },
60
+ )
61
+ ```
62
+
63
+ Every transfer on the address now triggers a signed webhook to your endpoint — see
64
+ [Receiving webhooks](#receiving-webhooks).
65
+
66
+ ## Configuration
67
+
68
+ ```ts
69
+ const monitoring = new MonitoringClient({
70
+ apiKey: process.env.MONITORING_API_KEY!,
71
+ timeoutMs: 10_000,
72
+ maxRetries: 3,
73
+ })
74
+ ```
75
+
76
+ | Option | Type | Default | Description |
77
+ |---|---|---|---|
78
+ | `apiKey` | `string` | — | Your API key. **Required.** |
79
+ | `clientId` | `string` | resolved from the API key | Your client ID. |
80
+ | `baseUrl` | `string` | `https://monitoring.v3.finance` | API base URL. |
81
+ | `timeoutMs` | `number` | `30000` | Request timeout in milliseconds. |
82
+ | `maxRetries` | `number` | `2` | Retries for rate limits and transient errors. |
83
+ | `fetch` | `typeof fetch` | global `fetch` | Custom `fetch` implementation. |
84
+ | `headers` | `Record<string, string>` | — | Additional headers sent with every request. |
85
+
86
+ ## Addresses
87
+
88
+ An address is monitored on a single network; to watch an EVM address on several networks, add it once per network.
89
+ Each address has a **subscription** — which assets (`assets`) and which direction (`direction`: `in`, `out` or
90
+ `both`) you are notified about. By default it covers all assets of the network in both directions.
91
+
92
+ ```ts
93
+ // Add — lists larger than 1,000 addresses are sent in batches automatically
94
+ await monitoring.addresses.add(
95
+ [
96
+ { network: 'tron', address: 'TA8HgQbFjuMLWCaJeGyfrv8FErWSHz82vr', label: 'user-42' },
97
+ { network: 'ethereum', address: '0x533bcdd534fc3f9651471d7b4469a0d01ca45a2a', assets: ['USDT', 'USDC'] },
98
+ ],
99
+ { direction: 'in' },
100
+ )
101
+
102
+ // Change the subscription
103
+ await monitoring.addresses.update([{ network: 'tron', address: 'TA8HgQbFjuMLWCaJeGyfrv8FErWSHz82vr' }], { direction: 'both' })
104
+
105
+ // Iterate over all monitored addresses
106
+ for await (const address of monitoring.addresses.iterate({ network: 'tron' })) {
107
+ console.log(address.address, address.assets ?? 'all assets', address.direction)
108
+ }
109
+
110
+ // Stop monitoring
111
+ await monitoring.addresses.remove([{ network: 'tron', address: 'TA8HgQbFjuMLWCaJeGyfrv8FErWSHz82vr' }])
112
+ ```
113
+
114
+ Requests are validated as a whole: if any address is invalid for its network, nothing is changed and
115
+ `error.details` lists the problems by index.
116
+
117
+ ## Receiving webhooks
118
+
119
+ Every webhook is a `POST` request with a JSON body and an `x-signature` header — an HMAC-SHA256 of the raw body keyed
120
+ with your webhook secret. `parseWebhook` verifies the signature and returns a typed payload.
121
+
122
+ **Express**
123
+
124
+ ```ts
125
+ import express from 'express'
126
+ import { isTestWebhook, parseWebhook, webhookIdempotencyKey, WebhookSignatureError } from '@v3finance/monitoring-sdk'
127
+
128
+ const app = express()
129
+
130
+ app.post('/webhooks/monitoring', express.raw({ type: 'application/json' }), async (req, res) => {
131
+ try {
132
+ const event = await parseWebhook(req.body, req.headers, process.env.MONITORING_WEBHOOK_SECRET!)
133
+ if (!isTestWebhook(event)) {
134
+ await creditOnce(webhookIdempotencyKey(event), event.tx)
135
+ }
136
+ res.sendStatus(200)
137
+ } catch (error) {
138
+ if (error instanceof WebhookSignatureError) return res.sendStatus(401)
139
+ throw error
140
+ }
141
+ })
142
+ ```
143
+
144
+ **Next.js (App Router)** — and any runtime built on the Fetch API: Cloudflare Workers, Bun, Deno
145
+
146
+ ```ts
147
+ export async function POST(request: Request) {
148
+ const event = await parseWebhook(await request.text(), request.headers, process.env.MONITORING_WEBHOOK_SECRET!)
149
+ // …
150
+ return new Response(null, { status: 200 })
151
+ }
152
+ ```
153
+
154
+ **Hono**
155
+
156
+ ```ts
157
+ app.post('/webhooks/monitoring', async (c) => {
158
+ const event = await parseWebhook(await c.req.text(), c.req.raw.headers, c.env.MONITORING_WEBHOOK_SECRET)
159
+ // …
160
+ return c.body(null, 200)
161
+ })
162
+ ```
163
+
164
+ The payload:
165
+
166
+ ```json
167
+ {
168
+ "tx": {
169
+ "network": "TRON",
170
+ "asset": "USDT",
171
+ "contract": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
172
+ "type": "TOPUP",
173
+ "id": "1249cb7b7edd42072684b1db37ad495d4a5b7eefd1aff83e595e9bdb63a5fc45",
174
+ "block": 87445412,
175
+ "timestamp": 1793009472000,
176
+ "from": "TW9goADYcUxskhQQRifvwoRBUMHnmTh9MA",
177
+ "to": "TA8HgQbFjuMLWCaJeGyfrv8FErWSHz82vr",
178
+ "value": "100000000"
179
+ }
180
+ }
181
+ ```
182
+
183
+ Best practices:
184
+
185
+ - **Verify against the raw body.** Parsing and re-serializing the JSON changes the bytes and breaks the signature.
186
+ - **Respond quickly.** Return a 2xx status within 15 seconds; otherwise the webhook is retried after 10 seconds,
187
+ 1 minute and 5 minutes.
188
+ - **Process idempotently.** A webhook may be delivered more than once — deduplicate with `webhookIdempotencyKey(event)`.
189
+ - **Check the direction.** `type` is `TOPUP` for both directions; compare `from` and `to` with your addresses.
190
+ - **Wait for finality on large amounts.** Webhooks are sent as soon as a transfer is included in a block — see
191
+ [Transactions and finality](#transactions-and-finality).
192
+ - **Ignore test webhooks** — `isTestWebhook(event)` is `true` for them.
193
+
194
+ Send a test webhook to check your endpoint:
195
+
196
+ ```ts
197
+ const { delivery, signature, body } = await monitoring.webhooks.sendTest({ asset: 'USDT' })
198
+ console.log(delivery.ok ? 'Delivered' : `Endpoint responded with ${delivery.status ?? delivery.error}`)
199
+ ```
200
+
201
+ ## Transactions and finality
202
+
203
+ Look up any transaction on a supported network — not only the ones you were notified about.
204
+
205
+ ```ts
206
+ const tx = await monitoring.transactions.get('tron', event.tx.id)
207
+
208
+ tx.status // 'success' | 'failed' | 'pending'
209
+ tx.confirmations // blocks since inclusion
210
+ tx.final // the transaction can no longer be reverted
211
+ tx.fee // { asset: 'TRX', value: '6773500' }
212
+ tx.transfers // every transfer inside the transaction
213
+ tx.watched // your monitored addresses involved
214
+ tx.webhooks // webhooks sent to you for this transaction
215
+ ```
216
+
217
+ A transaction is final once its block is solidified on TRON (about 1 minute) or finalized on EVM networks (about
218
+ 13 minutes on Ethereum). Credit large amounts once `final` is `true`.
219
+
220
+ ## Delivery history
221
+
222
+ Every webhook sent to you is recorded with its status, attempts and your endpoint's response, and kept for 90 days.
223
+
224
+ ```ts
225
+ for await (const delivery of monitoring.deliveries.iterate({ status: 'failed', since: new Date(Date.now() - 86_400_000) })) {
226
+ console.log(delivery.txId, delivery.attempts, delivery.lastHttpStatus ?? delivery.lastError)
227
+ }
228
+
229
+ const detail = await monitoring.deliveries.get(deliveryId) // includes the exact request body
230
+ ```
231
+
232
+ Filter by `status` (`delivered`, `retrying`, `failed`), `network`, `asset`, `tx`, `address`, `since` and `until`.
233
+
234
+ ## Networks and assets
235
+
236
+ ```ts
237
+ const networks = await monitoring.networks.list()
238
+ const assets = await monitoring.assets.list({ network: 'tron' })
239
+ ```
240
+
241
+ You are notified about transfers of enabled assets of at least the asset's `minAmount`.
242
+
243
+ ## Amounts
244
+
245
+ Amounts are strings in the asset's smallest unit (sun, wei; USDT has 6 decimals). Convert them without losing
246
+ precision:
247
+
248
+ ```ts
249
+ import { formatUnits, parseUnits } from '@v3finance/monitoring-sdk'
250
+
251
+ formatUnits('100000000', 6) // '100'
252
+ parseUnits('1.5', 6) // '1500000'
253
+ ```
254
+
255
+ ## Error handling
256
+
257
+ All errors extend `MonitoringError`.
258
+
259
+ | Error | When |
260
+ |---|---|
261
+ | `MonitoringApiError` | The API responded with an error. Has `status`, `code`, `details` and `requestId`. |
262
+ | `MonitoringConnectionError` | The request failed to reach the API. |
263
+ | `MonitoringTimeoutError` | The request exceeded `timeoutMs`. |
264
+ | `WebhookSignatureError` | A webhook signature does not match. |
265
+
266
+ ```ts
267
+ import { MonitoringApiError } from '@v3finance/monitoring-sdk'
268
+
269
+ try {
270
+ await monitoring.addresses.add(items)
271
+ } catch (error) {
272
+ if (error instanceof MonitoringApiError && error.status === 400) {
273
+ for (const { index, message } of error.details) console.error(`Item ${index}: ${message}`)
274
+ } else {
275
+ throw error
276
+ }
277
+ }
278
+ ```
279
+
280
+ ## Retries, timeouts and cancellation
281
+
282
+ Rate-limited (`429`) and temporarily unavailable (`503`) requests are retried automatically with exponential backoff,
283
+ honoring `Retry-After`. Network errors are retried only for requests that are safe to repeat. Configure this with
284
+ `maxRetries` and `timeoutMs`, globally or per request:
285
+
286
+ ```ts
287
+ const controller = new AbortController()
288
+
289
+ await monitoring.addresses.list({ network: 'tron' }, { timeoutMs: 5_000, maxRetries: 0, signal: controller.signal })
290
+ ```
291
+
292
+ ## TypeScript
293
+
294
+ The SDK is written in TypeScript and ships its own type declarations. All request and response types are exported:
295
+
296
+ ```ts
297
+ import type { Address, Delivery, Transaction, WebhookPayload } from '@v3finance/monitoring-sdk'
298
+ ```
299
+
300
+ ## Requirements
301
+
302
+ - Node.js 20 or later, Bun, Deno or Cloudflare Workers.
303
+ - ESM (`import`) and CommonJS (`require`) are both supported.
304
+
305
+ ## Security
306
+
307
+ - Use the SDK on your servers only. Never expose your API key or webhook secret to browsers or mobile apps.
308
+ - Keep credentials in environment variables or a secrets manager, not in source code.
309
+ - Always verify webhook signatures before processing a webhook.
310
+
311
+ ## Versioning
312
+
313
+ This package follows [Semantic Versioning](https://semver.org). Changes are listed in [CHANGELOG.md](./CHANGELOG.md).
314
+
315
+ ## Support
316
+
317
+ - API reference: [monitoring.v3.finance/docs](https://monitoring.v3.finance/docs)
318
+ - OpenAPI specification: [monitoring.v3.finance/openapi.json](https://monitoring.v3.finance/openapi.json)
319
+ - For access and support, contact your V3 Finance account manager.
320
+
321
+ ## License
322
+
323
+ [MIT](./LICENSE) © V3 Finance
@@ -0,0 +1,46 @@
1
+ import { type ClientOptions } from './core/http.js';
2
+ import { AccountResource } from './resources/account.js';
3
+ import { AddressesResource } from './resources/addresses.js';
4
+ import { AssetsResource, NetworksResource } from './resources/catalog.js';
5
+ import { DeliveriesResource } from './resources/deliveries.js';
6
+ import { TransactionsResource } from './resources/transactions.js';
7
+ import { WebhooksResource } from './resources/webhooks.js';
8
+ /**
9
+ * Client for the V3 Finance Monitoring API.
10
+ *
11
+ * Use it on the server only: an API key in a browser is visible to anyone.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { MonitoringClient } from '@v3finance/monitoring-sdk'
16
+ *
17
+ * const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY! })
18
+ *
19
+ * await monitoring.addresses.add([{ network: 'tron', address: 'TA8Hg…' }], { assets: ['USDT'], direction: 'in' })
20
+ * ```
21
+ */
22
+ export declare class MonitoringClient {
23
+ #private;
24
+ /** Your client: the account your API key belongs to. */
25
+ readonly account: AccountResource;
26
+ /** Addresses you monitor and their subscriptions. */
27
+ readonly addresses: AddressesResource;
28
+ /** Test your webhook endpoint. */
29
+ readonly webhooks: WebhooksResource;
30
+ /** History of webhooks sent to you. */
31
+ readonly deliveries: DeliveriesResource;
32
+ /** Any transaction by hash, with confirmations and finality. */
33
+ readonly transactions: TransactionsResource;
34
+ /** Supported networks. */
35
+ readonly networks: NetworksResource;
36
+ /** Supported native coins and tokens. */
37
+ readonly assets: AssetsResource;
38
+ /**
39
+ * @param options - API key and optional settings.
40
+ * @throws {@link MonitoringError} when `apiKey` is missing or `fetch` is not available.
41
+ */
42
+ constructor(options: ClientOptions);
43
+ /** API base URL this client sends requests to. */
44
+ get baseUrl(): string;
45
+ }
46
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGpE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAG1D;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB;;IAC3B,wDAAwD;IACxD,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAA;IACjC,qDAAqD;IACrD,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAA;IACrC,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,uCAAuC;IACvC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAA;IACvC,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,oBAAoB,CAAA;IAC3C,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAA;IACnC,yCAAyC;IACzC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;IAK/B;;;OAGG;IACH,YAAY,OAAO,EAAE,aAAa,EAWjC;IAED,kDAAkD;IAClD,IAAI,OAAO,IAAI,MAAM,CAEpB;CAiBF"}
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MonitoringClient = void 0;
4
+ const errors_js_1 = require("./core/errors.js");
5
+ const http_js_1 = require("./core/http.js");
6
+ const account_js_1 = require("./resources/account.js");
7
+ const addresses_js_1 = require("./resources/addresses.js");
8
+ const catalog_js_1 = require("./resources/catalog.js");
9
+ const deliveries_js_1 = require("./resources/deliveries.js");
10
+ const transactions_js_1 = require("./resources/transactions.js");
11
+ const webhooks_js_1 = require("./resources/webhooks.js");
12
+ const version_js_1 = require("./version.js");
13
+ /**
14
+ * Client for the V3 Finance Monitoring API.
15
+ *
16
+ * Use it on the server only: an API key in a browser is visible to anyone.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { MonitoringClient } from '@v3finance/monitoring-sdk'
21
+ *
22
+ * const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY! })
23
+ *
24
+ * await monitoring.addresses.add([{ network: 'tron', address: 'TA8Hg…' }], { assets: ['USDT'], direction: 'in' })
25
+ * ```
26
+ */
27
+ class MonitoringClient {
28
+ /** Your client: the account your API key belongs to. */
29
+ account;
30
+ /** Addresses you monitor and their subscriptions. */
31
+ addresses;
32
+ /** Test your webhook endpoint. */
33
+ webhooks;
34
+ /** History of webhooks sent to you. */
35
+ deliveries;
36
+ /** Any transaction by hash, with confirmations and finality. */
37
+ transactions;
38
+ /** Supported networks. */
39
+ networks;
40
+ /** Supported native coins and tokens. */
41
+ assets;
42
+ #http;
43
+ #clientId;
44
+ /**
45
+ * @param options - API key and optional settings.
46
+ * @throws {@link MonitoringError} when `apiKey` is missing or `fetch` is not available.
47
+ */
48
+ constructor(options) {
49
+ this.#http = new http_js_1.HttpClient(options, version_js_1.DEFAULT_BASE_URL);
50
+ if (options.clientId)
51
+ this.#clientId = Promise.resolve(options.clientId);
52
+ const scope = { http: this.#http, clientPath: async () => `/v1/clients/${(0, http_js_1.seg)(await this.#resolveClientId())}` };
53
+ this.account = new account_js_1.AccountResource(scope, () => this.#resolveClientId());
54
+ this.addresses = new addresses_js_1.AddressesResource(scope);
55
+ this.webhooks = new webhooks_js_1.WebhooksResource(scope);
56
+ this.deliveries = new deliveries_js_1.DeliveriesResource(scope);
57
+ this.transactions = new transactions_js_1.TransactionsResource(scope);
58
+ this.networks = new catalog_js_1.NetworksResource(scope);
59
+ this.assets = new catalog_js_1.AssetsResource(scope);
60
+ }
61
+ /** API base URL this client sends requests to. */
62
+ get baseUrl() {
63
+ return this.#http.baseUrl;
64
+ }
65
+ /** Client ID of the API key: from the options, or resolved once from the API and cached. */
66
+ #resolveClientId() {
67
+ this.#clientId ??= this.#http.request({ method: 'GET', path: '/v1/me', idempotent: true }).then((identity) => {
68
+ if (!identity.actor.clientId)
69
+ throw new errors_js_1.MonitoringError('this API key is not bound to a client: pass clientId in the options');
70
+ return identity.actor.clientId;
71
+ }, (error) => {
72
+ // a failed lookup is not cached: the next call tries again
73
+ this.#clientId = undefined;
74
+ throw error;
75
+ });
76
+ return this.#clientId;
77
+ }
78
+ }
79
+ exports.MonitoringClient = MonitoringClient;
80
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;AAAA,gDAAkD;AAClD,4CAAoE;AAGpE,uDAAwD;AACxD,2DAA4D;AAC5D,uDAAyE;AACzE,6DAA8D;AAC9D,iEAAkE;AAClE,yDAA0D;AAC1D,6CAA+C;AAE/C;;;;;;;;;;;;;GAaG;AACH;IACE,wDAAwD;IAC/C,OAAO,CAAiB;IACjC,qDAAqD;IAC5C,SAAS,CAAmB;IACrC,kCAAkC;IACzB,QAAQ,CAAkB;IACnC,uCAAuC;IAC9B,UAAU,CAAoB;IACvC,gEAAgE;IACvD,YAAY,CAAsB;IAC3C,0BAA0B;IACjB,QAAQ,CAAkB;IACnC,yCAAyC;IAChC,MAAM,CAAgB;IAEtB,KAAK,CAAY;IAC1B,SAAS,CAA6B;IAEtC;;;OAGG;IACH,YAAY,OAAsB;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,oBAAU,CAAC,OAAO,EAAE,6BAAgB,CAAC,CAAA;QACtD,IAAI,OAAO,CAAC,QAAQ;YAAE,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACxE,MAAM,KAAK,GAAU,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,IAAI,EAAE,CAAC,eAAe,IAAA,aAAG,EAAC,MAAM,IAAI,CAAC,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAA;QACtH,IAAI,CAAC,OAAO,GAAG,IAAI,4BAAe,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,CAAA;QACxE,IAAI,CAAC,SAAS,GAAG,IAAI,gCAAiB,CAAC,KAAK,CAAC,CAAA;QAC7C,IAAI,CAAC,QAAQ,GAAG,IAAI,8BAAgB,CAAC,KAAK,CAAC,CAAA;QAC3C,IAAI,CAAC,UAAU,GAAG,IAAI,kCAAkB,CAAC,KAAK,CAAC,CAAA;QAC/C,IAAI,CAAC,YAAY,GAAG,IAAI,sCAAoB,CAAC,KAAK,CAAC,CAAA;QACnD,IAAI,CAAC,QAAQ,GAAG,IAAI,6BAAgB,CAAC,KAAK,CAAC,CAAA;QAC3C,IAAI,CAAC,MAAM,GAAG,IAAI,2BAAc,CAAC,KAAK,CAAC,CAAA;IACzC,CAAC;IAED,kDAAkD;IAClD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAA;IAC3B,CAAC;IAED,4FAA4F;IAC5F,gBAAgB;QACd,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAW,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACvG,CAAC,QAAQ,EAAE,EAAE;YACX,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ;gBAAE,MAAM,IAAI,2BAAe,CAAC,qEAAqE,CAAC,CAAA;YAC9H,OAAO,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAA;QAChC,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,2DAA2D;YAC3D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAA;YAC1B,MAAM,KAAK,CAAA;QACb,CAAC,CACF,CAAA;QACD,OAAO,IAAI,CAAC,SAAS,CAAA;IACvB,CAAC;CACF"}
@@ -0,0 +1,64 @@
1
+ import type { ApiErrorBody } from '../generated/types.js';
2
+ /** A per-item problem of a batch request: the item's index in your request and the reason. */
3
+ export type ErrorDetail = NonNullable<ApiErrorBody['error']['details']>[number];
4
+ /**
5
+ * Base class of every error thrown by the SDK.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * try {
10
+ * await monitoring.addresses.add(items)
11
+ * } catch (error) {
12
+ * if (error instanceof MonitoringApiError && error.status === 400) console.log(error.details)
13
+ * else throw error
14
+ * }
15
+ * ```
16
+ */
17
+ export declare class MonitoringError extends Error {
18
+ constructor(message: string, options?: {
19
+ cause?: unknown;
20
+ });
21
+ }
22
+ /** The API responded with an error status (4xx or 5xx). */
23
+ export declare class MonitoringApiError extends MonitoringError {
24
+ /** HTTP status code. */
25
+ readonly status: number;
26
+ /**
27
+ * Machine-readable error code, e.g. `invalid_request`, `unauthorized`, `forbidden`, `not_found`,
28
+ * `rate_limited`, `upstream_error`, `upstream_rate_limited`.
29
+ */
30
+ readonly code: string;
31
+ /** Per-item problems of a batch request, such as invalid addresses. Empty when there are none. */
32
+ readonly details: ErrorDetail[];
33
+ /** Request ID. Include it when contacting support. */
34
+ readonly requestId: string | undefined;
35
+ /** Raw response body. */
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
+ /** `true` for transient errors — rate limits and unavailable upstream providers — that can be retried later. */
46
+ get retryable(): boolean;
47
+ }
48
+ /** The request did not get a response because of a network or connection failure. */
49
+ export declare class MonitoringConnectionError extends MonitoringError {
50
+ constructor(message: string, options?: {
51
+ cause?: unknown;
52
+ });
53
+ }
54
+ /** The request did not complete within `timeoutMs`. */
55
+ export declare class MonitoringTimeoutError extends MonitoringConnectionError {
56
+ constructor(timeoutMs: number);
57
+ }
58
+ /** The webhook signature does not match: the body was altered or is verified with the wrong secret. */
59
+ export declare class WebhookSignatureError extends MonitoringError {
60
+ constructor(message?: string);
61
+ }
62
+ /** Builds an error from any error body the API returns. */
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,8FAA8F;AAC9F,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,2DAA2D;AAC3D,qBAAa,kBAAmB,SAAQ,eAAe;IACrD,wBAAwB;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,kGAAkG;IAClG,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAA;IAC/B,sDAAsD;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;IACtC,yBAAyB;IACzB,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,gHAAgH;IAChH,IAAI,SAAS,IAAI,OAAO,CAEvB;CACF;AAED,qFAAqF;AACrF,qBAAa,yBAA0B,SAAQ,eAAe;IAC5D,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAGzD;CACF;AAED,uDAAuD;AACvD,qBAAa,sBAAuB,SAAQ,yBAAyB;IACnE,YAAY,SAAS,EAAE,MAAM,EAG5B;CACF;AAED,uGAAuG;AACvG,qBAAa,qBAAsB,SAAQ,eAAe;IACxD,YAAY,OAAO,SAA+B,EAGjD;CACF;AAED,2DAA2D;AAC3D,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
+ * Base class of every error thrown by the SDK.
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * try {
11
+ * await monitoring.addresses.add(items)
12
+ * } catch (error) {
13
+ * if (error instanceof MonitoringApiError && error.status === 400) console.log(error.details)
14
+ * else throw error
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
+ /** The API responded with an error status (4xx or 5xx). */
26
+ class MonitoringApiError extends MonitoringError {
27
+ /** HTTP status code. */
28
+ status;
29
+ /**
30
+ * Machine-readable error code, e.g. `invalid_request`, `unauthorized`, `forbidden`, `not_found`,
31
+ * `rate_limited`, `upstream_error`, `upstream_rate_limited`.
32
+ */
33
+ code;
34
+ /** Per-item problems of a batch request, such as invalid addresses. Empty when there are none. */
35
+ details;
36
+ /** Request ID. Include it when contacting support. */
37
+ requestId;
38
+ /** Raw response body. */
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
+ /** `true` for transient errors — rate limits and unavailable upstream providers — that can be retried later. */
50
+ get retryable() {
51
+ return this.status === 429 || this.status === 503;
52
+ }
53
+ }
54
+ exports.MonitoringApiError = MonitoringApiError;
55
+ /** The request did not get a response because of a network or connection failure. */
56
+ class MonitoringConnectionError extends MonitoringError {
57
+ constructor(message, options) {
58
+ super(message, options);
59
+ this.name = 'MonitoringConnectionError';
60
+ }
61
+ }
62
+ exports.MonitoringConnectionError = MonitoringConnectionError;
63
+ /** The request did not complete within `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
+ /** The webhook signature does not match: the body was altered or is verified with the wrong secret. */
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
+ /** Builds an error from any error body the API returns. */
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