@v3finance/monitoring-sdk 0.1.0 → 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 (154) hide show
  1. package/CHANGELOG.md +21 -11
  2. package/README.md +223 -148
  3. package/dist/cjs/client.d.ts +23 -42
  4. package/dist/cjs/client.d.ts.map +1 -1
  5. package/dist/cjs/client.js +44 -53
  6. package/dist/cjs/client.js.map +1 -1
  7. package/dist/cjs/core/errors.d.ts +18 -18
  8. package/dist/cjs/core/errors.d.ts.map +1 -1
  9. package/dist/cjs/core/errors.js +17 -17
  10. package/dist/cjs/core/errors.js.map +1 -1
  11. package/dist/cjs/core/http.d.ts +22 -26
  12. package/dist/cjs/core/http.d.ts.map +1 -1
  13. package/dist/cjs/core/http.js +28 -36
  14. package/dist/cjs/core/http.js.map +1 -1
  15. package/dist/cjs/core/pagination.d.ts +6 -7
  16. package/dist/cjs/core/pagination.d.ts.map +1 -1
  17. package/dist/cjs/core/pagination.js +1 -1
  18. package/dist/cjs/core/pagination.js.map +1 -1
  19. package/dist/cjs/core/scope.d.ts +8 -0
  20. package/dist/cjs/core/scope.d.ts.map +1 -0
  21. package/dist/cjs/core/scope.js +3 -0
  22. package/dist/cjs/core/scope.js.map +1 -0
  23. package/dist/cjs/generated/types.d.ts +129 -117
  24. package/dist/cjs/generated/types.d.ts.map +1 -1
  25. package/dist/cjs/generated/types.js +1 -1
  26. package/dist/cjs/generated/types.js.map +1 -1
  27. package/dist/cjs/index.d.ts +6 -6
  28. package/dist/cjs/index.d.ts.map +1 -1
  29. package/dist/cjs/index.js +13 -16
  30. package/dist/cjs/index.js.map +1 -1
  31. package/dist/cjs/resources/account.d.ts +12 -51
  32. package/dist/cjs/resources/account.d.ts.map +1 -1
  33. package/dist/cjs/resources/account.js +17 -61
  34. package/dist/cjs/resources/account.js.map +1 -1
  35. package/dist/cjs/resources/addresses.d.ts +49 -65
  36. package/dist/cjs/resources/addresses.d.ts.map +1 -1
  37. package/dist/cjs/resources/addresses.js +60 -69
  38. package/dist/cjs/resources/addresses.js.map +1 -1
  39. package/dist/cjs/resources/catalog.d.ts +17 -10
  40. package/dist/cjs/resources/catalog.d.ts.map +1 -1
  41. package/dist/cjs/resources/catalog.js +23 -17
  42. package/dist/cjs/resources/catalog.js.map +1 -1
  43. package/dist/cjs/resources/deliveries.d.ts +34 -23
  44. package/dist/cjs/resources/deliveries.d.ts.map +1 -1
  45. package/dist/cjs/resources/deliveries.js +27 -17
  46. package/dist/cjs/resources/deliveries.js.map +1 -1
  47. package/dist/cjs/resources/transactions.d.ts +14 -14
  48. package/dist/cjs/resources/transactions.d.ts.map +1 -1
  49. package/dist/cjs/resources/transactions.js +15 -16
  50. package/dist/cjs/resources/transactions.js.map +1 -1
  51. package/dist/cjs/resources/webhooks.d.ts +22 -0
  52. package/dist/cjs/resources/webhooks.d.ts.map +1 -0
  53. package/dist/cjs/resources/webhooks.js +35 -0
  54. package/dist/cjs/resources/webhooks.js.map +1 -0
  55. package/dist/cjs/units.d.ts +11 -11
  56. package/dist/cjs/units.js +14 -14
  57. package/dist/cjs/units.js.map +1 -1
  58. package/dist/cjs/version.d.ts +3 -3
  59. package/dist/cjs/version.d.ts.map +1 -1
  60. package/dist/cjs/version.js +3 -3
  61. package/dist/cjs/version.js.map +1 -1
  62. package/dist/cjs/webhooks.d.ts +33 -28
  63. package/dist/cjs/webhooks.d.ts.map +1 -1
  64. package/dist/cjs/webhooks.js +33 -28
  65. package/dist/cjs/webhooks.js.map +1 -1
  66. package/dist/esm/client.d.ts +23 -42
  67. package/dist/esm/client.d.ts.map +1 -1
  68. package/dist/esm/client.js +46 -55
  69. package/dist/esm/client.js.map +1 -1
  70. package/dist/esm/core/errors.d.ts +18 -18
  71. package/dist/esm/core/errors.d.ts.map +1 -1
  72. package/dist/esm/core/errors.js +17 -17
  73. package/dist/esm/core/errors.js.map +1 -1
  74. package/dist/esm/core/http.d.ts +22 -26
  75. package/dist/esm/core/http.d.ts.map +1 -1
  76. package/dist/esm/core/http.js +28 -36
  77. package/dist/esm/core/http.js.map +1 -1
  78. package/dist/esm/core/pagination.d.ts +6 -7
  79. package/dist/esm/core/pagination.d.ts.map +1 -1
  80. package/dist/esm/core/pagination.js +1 -1
  81. package/dist/esm/core/pagination.js.map +1 -1
  82. package/dist/esm/core/scope.d.ts +8 -0
  83. package/dist/esm/core/scope.d.ts.map +1 -0
  84. package/dist/esm/core/scope.js +2 -0
  85. package/dist/esm/core/scope.js.map +1 -0
  86. package/dist/esm/generated/types.d.ts +129 -117
  87. package/dist/esm/generated/types.d.ts.map +1 -1
  88. package/dist/esm/generated/types.js +1 -1
  89. package/dist/esm/generated/types.js.map +1 -1
  90. package/dist/esm/index.d.ts +6 -6
  91. package/dist/esm/index.d.ts.map +1 -1
  92. package/dist/esm/index.js +6 -6
  93. package/dist/esm/index.js.map +1 -1
  94. package/dist/esm/resources/account.d.ts +12 -51
  95. package/dist/esm/resources/account.d.ts.map +1 -1
  96. package/dist/esm/resources/account.js +15 -57
  97. package/dist/esm/resources/account.js.map +1 -1
  98. package/dist/esm/resources/addresses.d.ts +49 -65
  99. package/dist/esm/resources/addresses.d.ts.map +1 -1
  100. package/dist/esm/resources/addresses.js +60 -69
  101. package/dist/esm/resources/addresses.js.map +1 -1
  102. package/dist/esm/resources/catalog.d.ts +17 -10
  103. package/dist/esm/resources/catalog.d.ts.map +1 -1
  104. package/dist/esm/resources/catalog.js +23 -17
  105. package/dist/esm/resources/catalog.js.map +1 -1
  106. package/dist/esm/resources/deliveries.d.ts +34 -23
  107. package/dist/esm/resources/deliveries.d.ts.map +1 -1
  108. package/dist/esm/resources/deliveries.js +27 -17
  109. package/dist/esm/resources/deliveries.js.map +1 -1
  110. package/dist/esm/resources/transactions.d.ts +14 -14
  111. package/dist/esm/resources/transactions.d.ts.map +1 -1
  112. package/dist/esm/resources/transactions.js +15 -16
  113. package/dist/esm/resources/transactions.js.map +1 -1
  114. package/dist/esm/resources/webhooks.d.ts +22 -0
  115. package/dist/esm/resources/webhooks.d.ts.map +1 -0
  116. package/dist/esm/resources/webhooks.js +31 -0
  117. package/dist/esm/resources/webhooks.js.map +1 -0
  118. package/dist/esm/units.d.ts +11 -11
  119. package/dist/esm/units.js +14 -14
  120. package/dist/esm/units.js.map +1 -1
  121. package/dist/esm/version.d.ts +3 -3
  122. package/dist/esm/version.d.ts.map +1 -1
  123. package/dist/esm/version.js +3 -3
  124. package/dist/esm/version.js.map +1 -1
  125. package/dist/esm/webhooks.d.ts +33 -28
  126. package/dist/esm/webhooks.d.ts.map +1 -1
  127. package/dist/esm/webhooks.js +33 -28
  128. package/dist/esm/webhooks.js.map +1 -1
  129. package/package.json +8 -5
  130. package/src/client.ts +50 -61
  131. package/src/core/errors.ts +18 -18
  132. package/src/core/http.ts +45 -55
  133. package/src/core/pagination.ts +7 -8
  134. package/src/core/scope.ts +8 -0
  135. package/src/generated/types.ts +139 -125
  136. package/src/index.ts +7 -24
  137. package/src/resources/account.ts +18 -72
  138. package/src/resources/addresses.ts +84 -109
  139. package/src/resources/catalog.ts +28 -19
  140. package/src/resources/deliveries.ts +43 -30
  141. package/src/resources/transactions.ts +18 -17
  142. package/src/resources/webhooks.ts +36 -0
  143. package/src/units.ts +14 -14
  144. package/src/version.ts +3 -3
  145. package/src/webhooks.ts +37 -32
  146. package/dist/cjs/resources/clients.d.ts +0 -84
  147. package/dist/cjs/resources/clients.d.ts.map +0 -1
  148. package/dist/cjs/resources/clients.js +0 -102
  149. package/dist/cjs/resources/clients.js.map +0 -1
  150. package/dist/esm/resources/clients.d.ts +0 -84
  151. package/dist/esm/resources/clients.d.ts.map +0 -1
  152. package/dist/esm/resources/clients.js +0 -97
  153. package/dist/esm/resources/clients.js.map +0 -1
  154. package/src/resources/clients.ts +0 -135
@@ -1,56 +1,60 @@
1
1
  /**
2
- * Приём вебхуков: проверка подписи и разбор тела. Работает без клиента API и без сети — нужен только секрет
3
- * подписи клиента. Использует WebCrypto: Node.js 20+, Bun, Deno, Cloudflare Workers.
2
+ * Receiving webhooks: signature verification and parsing. No API key or network access is needed — only your
3
+ * webhook secret. Uses Web Crypto, so it runs on Node.js 20+, Bun, Deno and Cloudflare Workers.
4
4
  */
5
5
  import type { WebhookPayload } from './generated/types.js';
6
- /** Заголовки вебхука */
6
+ /** Headers sent with every webhook. */
7
7
  export declare const WEBHOOK_HEADERS: {
8
- /** HMAC-SHA256 сырого тела секретом клиента, hex в нижнем регистре */
8
+ /** HMAC-SHA256 of the raw body keyed with your webhook secret, hex-encoded. */
9
9
  readonly signature: 'x-signature';
10
- /** id клиента */
10
+ /** Your client ID. */
11
11
  readonly clientId: 'x-client-id';
12
- /** `1` у тестового вебхука — такой не зачислять */
12
+ /** `1` for test webhooks. */
13
13
  readonly test: 'x-webhook-test';
14
14
  };
15
15
  /**
16
- * Тело вебхука ровно как пришло — сырые байты или строка. Не `JSON.parse` + `JSON.stringify`: подпись считается
17
- * по исходным байтам, и любое переформатирование её ломает.
16
+ * The raw request body, exactly as received. Do not parse and re-serialize the JSON: the signature is computed over
17
+ * the original bytes.
18
18
  */
19
19
  export type WebhookBody = string | Uint8Array | ArrayBuffer;
20
20
  /**
21
- * Откуда взять подпись: значение заголовка `x-signature` или все заголовки запроса — Fetch `Headers`
22
- * (Hono, Next.js, Workers) или объект Node.js (`req.headers` в Express, Fastify).
21
+ * Where to read the signature from: the value of the `x-signature` header, or all request headers — a Fetch
22
+ * `Headers` object (Next.js, Hono, Cloudflare Workers) or a Node.js headers object (`req.headers` in Express, Fastify).
23
23
  */
24
24
  export type SignatureSource = string | null | undefined | Headers | Record<string, string | string[] | undefined>;
25
25
  /**
26
- * Подпись тела секретом клиента — как её считает сервис. Нужна в тестах вашего обработчика вебхуков.
26
+ * Computes the signature of a body the way the API does. Useful for testing your webhook handler.
27
27
  *
28
28
  * @example
29
29
  * ```ts
30
- * const body = JSON.stringify({ tx: { …, id: 'test' } })
31
- * await fetch('http://localhost:3000/webhooks', { method: 'POST', body, headers: { 'x-signature': await signWebhookBody(body, secret) } })
30
+ * const body = JSON.stringify({ tx: { network: 'TRON', asset: 'USDT', … } })
31
+ * await fetch('http://localhost:3000/webhooks/monitoring', {
32
+ * method: 'POST',
33
+ * body,
34
+ * headers: { 'content-type': 'application/json', 'x-signature': await signWebhookBody(body, secret) },
35
+ * })
32
36
  * ```
33
37
  */
34
38
  export declare function signWebhookBody(body: WebhookBody, secret: string): Promise<string>;
35
39
  /**
36
- * Проверяет подпись вебхука: `true` — тело пришло от сервиса и не изменено.
40
+ * Verifies a webhook signature. Returns `true` when the body was sent by the API and was not modified.
37
41
  *
38
- * @param body - сырое тело запроса
39
- * @param signature - заголовок `x-signature` или все заголовки запроса
40
- * @param secret - секрет подписи клиента
42
+ * @param body - Raw request body.
43
+ * @param signature - The `x-signature` header, or all request headers.
44
+ * @param secret - Your webhook secret.
41
45
  */
42
46
  export declare function verifyWebhookSignature(body: WebhookBody, signature: SignatureSource, secret: string): Promise<boolean>;
43
47
  /**
44
- * Проверяет подпись и возвращает разобранный вебхук.
48
+ * Verifies the signature and returns the parsed webhook.
45
49
  *
46
- * Дальше — по правилам приёма: тестовый вебхук ({@link isTestWebhook}) не зачислять; один и тот же вебхук может
47
- * прийти повторно — обрабатывайте идемпотентно по {@link webhookIdempotencyKey}; ответьте 2xx в течение 15 секунд.
48
- * Вебхук уходит, как только перевод попал в блок, — для крупных сумм дождитесь финальности
49
- * (`monitoring.transactions.get(...).final`).
50
+ * Respond with a 2xx status within 15 seconds. Process webhooks idempotently by {@link webhookIdempotencyKey} — the
51
+ * same webhook may arrive more than once — and do not credit test webhooks ({@link isTestWebhook}). Webhooks are sent
52
+ * as soon as a transfer is included in a block; before crediting large amounts, check that the transaction is final
53
+ * with `monitoring.transactions.get()`.
50
54
  *
51
- * @throws {@link WebhookSignatureError} подпись не совпала — ответьте 401 и ничего не зачисляйте
55
+ * @throws {@link WebhookSignatureError} when the signature does not match. Respond with `401` and do not process it.
52
56
  *
53
- * @example Express — нужен сырой body
57
+ * @example Express (use the raw body)
54
58
  * ```ts
55
59
  * app.post('/webhooks/monitoring', express.raw({ type: 'application/json' }), async (req, res) => {
56
60
  * const event = await parseWebhook(req.body, req.headers, process.env.MONITORING_WEBHOOK_SECRET!)
@@ -59,17 +63,18 @@ export declare function verifyWebhookSignature(body: WebhookBody, signature: Sig
59
63
  * })
60
64
  * ```
61
65
  *
62
- * @example Hono, Next.js route handler, Cloudflare Workers
66
+ * @example Next.js route handlers, Hono, Cloudflare Workers
63
67
  * ```ts
64
68
  * const event = await parseWebhook(await request.text(), request.headers, env.MONITORING_WEBHOOK_SECRET)
65
69
  * ```
66
70
  */
67
71
  export declare function parseWebhook(body: WebhookBody, signature: SignatureSource, secret: string): Promise<WebhookPayload>;
68
- /** Тестовый вебхук (из панели или `clients.sendTestWebhook`) — такой не зачислять */
72
+ /** `true` for test webhooks. Do not credit them. */
69
73
  export declare function isTestWebhook(event: WebhookPayload): boolean;
70
74
  /**
71
- * Ключ идемпотентности вебхука: сеть, транзакция и номер лога. Один перевод — один ключ, даже если вебхук пришёл
72
- * несколько раз. В одной транзакции EVM может быть несколько переводов токенов — у них разный `logIndex`.
75
+ * Idempotency key of a webhook: network, transaction hash and log index. A transfer always has the same key, however
76
+ * many times its webhook is delivered. An EVM transaction can contain several token transfers; they differ by
77
+ * `logIndex`.
73
78
  *
74
79
  * @example `"TRON:1249cb…a5fc45:"`, `"ETHEREUM:0x3fbc…1d57:7"`
75
80
  */
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,wBAAwB;AACxB,eAAO,MAAM,eAAe;IAC1B,sEAAsE;aACtE,SAAS,EAAE,aAAa;IACxB,iBAAiB;aACjB,QAAQ,EAAE,aAAa;IACvB,mDAAmD;aACnD,IAAI,EAAE,gBAAgB;CACd,CAAA;AAEV;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,CAAA;AAE3D;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;AA0BjH;;;;;;;;GAQG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIxF;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAI5H;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAWzH;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAE5D;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAEnE"}
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE1D,uCAAuC;AACvC,eAAO,MAAM,eAAe;IAC1B,+EAA+E;aAC/E,SAAS,EAAE,aAAa;IACxB,sBAAsB;aACtB,QAAQ,EAAE,aAAa;IACvB,6BAA6B;aAC7B,IAAI,EAAE,gBAAgB;CACd,CAAA;AAEV;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,WAAW,CAAA;AAE3D;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAA;AA0BjH;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIxF;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAI5H;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAWzH;AAED,oDAAoD;AACpD,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAE5D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAEnE"}
@@ -1,22 +1,22 @@
1
1
  /**
2
- * Приём вебхуков: проверка подписи и разбор тела. Работает без клиента API и без сети — нужен только секрет
3
- * подписи клиента. Использует WebCrypto: Node.js 20+, Bun, Deno, Cloudflare Workers.
2
+ * Receiving webhooks: signature verification and parsing. No API key or network access is needed — only your
3
+ * webhook secret. Uses Web Crypto, so it runs on Node.js 20+, Bun, Deno and Cloudflare Workers.
4
4
  */
5
5
  import { MonitoringError, WebhookSignatureError } from './core/errors.js';
6
- /** Заголовки вебхука */
6
+ /** Headers sent with every webhook. */
7
7
  export const WEBHOOK_HEADERS = {
8
- /** HMAC-SHA256 сырого тела секретом клиента, hex в нижнем регистре */
8
+ /** HMAC-SHA256 of the raw body keyed with your webhook secret, hex-encoded. */
9
9
  signature: 'x-signature',
10
- /** id клиента */
10
+ /** Your client ID. */
11
11
  clientId: 'x-client-id',
12
- /** `1` у тестового вебхука — такой не зачислять */
12
+ /** `1` for test webhooks. */
13
13
  test: 'x-webhook-test',
14
14
  };
15
15
  const encoder = new TextEncoder();
16
16
  function bytesOf(body) {
17
17
  if (typeof body === 'string')
18
18
  return encoder.encode(body);
19
- // копия: WebCrypto не принимает view над SharedArrayBuffer (Buffer в Node.js — тоже Uint8Array)
19
+ // copy: Web Crypto does not accept views over a SharedArrayBuffer (a Node.js Buffer is a Uint8Array too)
20
20
  return body instanceof Uint8Array ? new Uint8Array(body) : new Uint8Array(body);
21
21
  }
22
22
  function signatureOf(source) {
@@ -29,7 +29,7 @@ function signatureOf(source) {
29
29
  const value = source[WEBHOOK_HEADERS.signature];
30
30
  return Array.isArray(value) ? value[0] : value;
31
31
  }
32
- /** Сравнение без утечки по времени: время не зависит от того, где строки расходятся */
32
+ /** Constant-time comparison. */
33
33
  function safeEqual(a, b) {
34
34
  if (a.length !== b.length)
35
35
  return false;
@@ -39,12 +39,16 @@ function safeEqual(a, b) {
39
39
  return diff === 0;
40
40
  }
41
41
  /**
42
- * Подпись тела секретом клиента — как её считает сервис. Нужна в тестах вашего обработчика вебхуков.
42
+ * Computes the signature of a body the way the API does. Useful for testing your webhook handler.
43
43
  *
44
44
  * @example
45
45
  * ```ts
46
- * const body = JSON.stringify({ tx: { …, id: 'test' } })
47
- * await fetch('http://localhost:3000/webhooks', { method: 'POST', body, headers: { 'x-signature': await signWebhookBody(body, secret) } })
46
+ * const body = JSON.stringify({ tx: { network: 'TRON', asset: 'USDT', … } })
47
+ * await fetch('http://localhost:3000/webhooks/monitoring', {
48
+ * method: 'POST',
49
+ * body,
50
+ * headers: { 'content-type': 'application/json', 'x-signature': await signWebhookBody(body, secret) },
51
+ * })
48
52
  * ```
49
53
  */
50
54
  export async function signWebhookBody(body, secret) {
@@ -53,11 +57,11 @@ export async function signWebhookBody(body, secret) {
53
57
  return Array.from(mac, (b) => b.toString(16).padStart(2, '0')).join('');
54
58
  }
55
59
  /**
56
- * Проверяет подпись вебхука: `true` — тело пришло от сервиса и не изменено.
60
+ * Verifies a webhook signature. Returns `true` when the body was sent by the API and was not modified.
57
61
  *
58
- * @param body - сырое тело запроса
59
- * @param signature - заголовок `x-signature` или все заголовки запроса
60
- * @param secret - секрет подписи клиента
62
+ * @param body - Raw request body.
63
+ * @param signature - The `x-signature` header, or all request headers.
64
+ * @param secret - Your webhook secret.
61
65
  */
62
66
  export async function verifyWebhookSignature(body, signature, secret) {
63
67
  const given = signatureOf(signature)?.trim().toLowerCase();
@@ -66,16 +70,16 @@ export async function verifyWebhookSignature(body, signature, secret) {
66
70
  return safeEqual(await signWebhookBody(body, secret), given);
67
71
  }
68
72
  /**
69
- * Проверяет подпись и возвращает разобранный вебхук.
73
+ * Verifies the signature and returns the parsed webhook.
70
74
  *
71
- * Дальше — по правилам приёма: тестовый вебхук ({@link isTestWebhook}) не зачислять; один и тот же вебхук может
72
- * прийти повторно — обрабатывайте идемпотентно по {@link webhookIdempotencyKey}; ответьте 2xx в течение 15 секунд.
73
- * Вебхук уходит, как только перевод попал в блок, — для крупных сумм дождитесь финальности
74
- * (`monitoring.transactions.get(...).final`).
75
+ * Respond with a 2xx status within 15 seconds. Process webhooks idempotently by {@link webhookIdempotencyKey} — the
76
+ * same webhook may arrive more than once — and do not credit test webhooks ({@link isTestWebhook}). Webhooks are sent
77
+ * as soon as a transfer is included in a block; before crediting large amounts, check that the transaction is final
78
+ * with `monitoring.transactions.get()`.
75
79
  *
76
- * @throws {@link WebhookSignatureError} подпись не совпала — ответьте 401 и ничего не зачисляйте
80
+ * @throws {@link WebhookSignatureError} when the signature does not match. Respond with `401` and do not process it.
77
81
  *
78
- * @example Express — нужен сырой body
82
+ * @example Express (use the raw body)
79
83
  * ```ts
80
84
  * app.post('/webhooks/monitoring', express.raw({ type: 'application/json' }), async (req, res) => {
81
85
  * const event = await parseWebhook(req.body, req.headers, process.env.MONITORING_WEBHOOK_SECRET!)
@@ -84,7 +88,7 @@ export async function verifyWebhookSignature(body, signature, secret) {
84
88
  * })
85
89
  * ```
86
90
  *
87
- * @example Hono, Next.js route handler, Cloudflare Workers
91
+ * @example Next.js route handlers, Hono, Cloudflare Workers
88
92
  * ```ts
89
93
  * const event = await parseWebhook(await request.text(), request.headers, env.MONITORING_WEBHOOK_SECRET)
90
94
  * ```
@@ -96,21 +100,22 @@ export async function parseWebhook(body, signature, secret) {
96
100
  try {
97
101
  payload = JSON.parse(typeof body === 'string' ? body : new TextDecoder().decode(bytesOf(body)));
98
102
  }
99
- catch (e) {
100
- throw new MonitoringError('webhook body is not valid JSON', { cause: e });
103
+ catch (error) {
104
+ throw new MonitoringError('webhook body is not valid JSON', { cause: error });
101
105
  }
102
106
  const tx = payload?.tx;
103
107
  if (typeof tx !== 'object' || tx === null || typeof tx.id !== 'string')
104
108
  throw new MonitoringError('webhook body has no tx');
105
109
  return payload;
106
110
  }
107
- /** Тестовый вебхук (из панели или `clients.sendTestWebhook`) — такой не зачислять */
111
+ /** `true` for test webhooks. Do not credit them. */
108
112
  export function isTestWebhook(event) {
109
113
  return event.test === true;
110
114
  }
111
115
  /**
112
- * Ключ идемпотентности вебхука: сеть, транзакция и номер лога. Один перевод — один ключ, даже если вебхук пришёл
113
- * несколько раз. В одной транзакции EVM может быть несколько переводов токенов — у них разный `logIndex`.
116
+ * Idempotency key of a webhook: network, transaction hash and log index. A transfer always has the same key, however
117
+ * many times its webhook is delivered. An EVM transaction can contain several token transfers; they differ by
118
+ * `logIndex`.
114
119
  *
115
120
  * @example `"TRON:1249cb…a5fc45:"`, `"ETHEREUM:0x3fbc…1d57:7"`
116
121
  */
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,20 +1,23 @@
1
1
  {
2
2
  "name": "@v3finance/monitoring-sdk",
3
- "version": "0.1.0",
4
- "description": "Official TypeScript SDK for the V3 Finance address monitoring API: TRON and EVM addresses, signed webhooks, delivery history, transaction finality",
3
+ "version": "0.2.0",
4
+ "description": "Official TypeScript SDK for the V3 Finance Monitoring API — monitor TRON and EVM addresses and receive signed webhooks for every transfer.",
5
5
  "keywords": [
6
+ "v3finance",
7
+ "monitoring",
8
+ "webhooks",
6
9
  "tron",
7
10
  "ethereum",
8
11
  "evm",
9
12
  "usdt",
13
+ "usdc",
10
14
  "trc20",
11
15
  "erc20",
12
- "webhooks",
13
16
  "blockchain",
14
- "monitoring",
15
17
  "payments",
18
+ "crypto",
16
19
  "sdk",
17
- "v3finance"
20
+ "typescript"
18
21
  ],
19
22
  "homepage": "https://monitoring.v3.finance/docs",
20
23
  "repository": {
package/src/client.ts CHANGED
@@ -1,94 +1,83 @@
1
- import { HttpClient, type ClientOptions, type RequestOptions } from './core/http.js'
2
- import type { User } from './generated/types.js'
3
- import { AccountResource, AuthResource, type SignInResult } from './resources/account.js'
1
+ import { MonitoringError } from './core/errors.js'
2
+ import { HttpClient, seg, type ClientOptions } from './core/http.js'
3
+ import type { Scope } from './core/scope.js'
4
+ import type { Identity } from './generated/types.js'
5
+ import { AccountResource } from './resources/account.js'
4
6
  import { AddressesResource } from './resources/addresses.js'
5
7
  import { AssetsResource, NetworksResource } from './resources/catalog.js'
6
- import { ClientsResource } from './resources/clients.js'
7
8
  import { DeliveriesResource } from './resources/deliveries.js'
8
9
  import { TransactionsResource } from './resources/transactions.js'
10
+ import { WebhooksResource } from './resources/webhooks.js'
9
11
  import { DEFAULT_BASE_URL } from './version.js'
10
12
 
11
13
  /**
12
- * Клиент API мониторинга адресов V3 Finance: адреса и подписки, история вебхуков, транзакции, ваш клиент и ключи.
13
- * Только для сервера: ключ в браузере увидит любой.
14
+ * Client for the V3 Finance Monitoring API.
14
15
  *
15
- * @example С ключом клиента — для бэкенда
16
+ * Use it on the server only: an API key in a browser is visible to anyone.
17
+ *
18
+ * @example
16
19
  * ```ts
17
20
  * import { MonitoringClient } from '@v3finance/monitoring-sdk'
18
21
  *
19
- * const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY })
20
- * await monitoring.addresses.add(clientId, [{ network: 'tron', address: 'T…' }], { assets: ['USDT'], direction: 'in' })
21
- * ```
22
+ * const monitoring = new MonitoringClient({ apiKey: process.env.MONITORING_API_KEY! })
22
23
  *
23
- * @example По паролю — для скриптов, которым нужны права пользователя
24
- * ```ts
25
- * const { client } = await MonitoringClient.signIn({ email, password })
26
- * const { key } = await client.account.keys.create({ name: 'ci' })
24
+ * await monitoring.addresses.add([{ network: 'tron', address: 'TA8Hg…' }], { assets: ['USDT'], direction: 'in' })
27
25
  * ```
28
26
  */
29
27
  export class MonitoringClient {
30
- /** Кто вы и ваши личные ключи */
28
+ /** Your client: the account your API key belongs to. */
31
29
  readonly account: AccountResource
32
- /** Выход и смена пароля (для клиента, вошедшего по паролю) */
33
- readonly auth: AuthResource
34
- /** Сети */
35
- readonly networks: NetworksResource
36
- /** Нативные монеты и токены */
37
- readonly assets: AssetsResource
38
- /** Ваш клиент: URL вебхука, секрет, ключи, участники, тестовый вебхук */
39
- readonly clients: ClientsResource
40
- /** Адреса на мониторинге и подписка */
30
+ /** Addresses you monitor and their subscriptions. */
41
31
  readonly addresses: AddressesResource
42
- /** История вебхуков */
32
+ /** Test your webhook endpoint. */
33
+ readonly webhooks: WebhooksResource
34
+ /** History of webhooks sent to you. */
43
35
  readonly deliveries: DeliveriesResource
44
- /** Транзакция по хешу: статус, подтверждения, финальность */
36
+ /** Any transaction by hash, with confirmations and finality. */
45
37
  readonly transactions: TransactionsResource
38
+ /** Supported networks. */
39
+ readonly networks: NetworksResource
40
+ /** Supported native coins and tokens. */
41
+ readonly assets: AssetsResource
46
42
 
47
43
  readonly #http: HttpClient
44
+ #clientId: Promise<string> | undefined
48
45
 
49
46
  /**
50
- * @param options - ключ (`apiKey`) или токен сессии (`sessionToken`), адрес API, таймаут, повторы
51
- * @throws {@link MonitoringError} переданы и ключ, и токен; нет `fetch`
47
+ * @param options - API key and optional settings.
48
+ * @throws {@link MonitoringError} when `apiKey` is missing or `fetch` is not available.
52
49
  */
53
- constructor(options: ClientOptions = {}) {
50
+ constructor(options: ClientOptions) {
54
51
  this.#http = new HttpClient(options, DEFAULT_BASE_URL)
55
- this.account = new AccountResource(this.#http)
56
- this.auth = new AuthResource(this.#http)
57
- this.networks = new NetworksResource(this.#http)
58
- this.assets = new AssetsResource(this.#http)
59
- this.clients = new ClientsResource(this.#http)
60
- this.addresses = new AddressesResource(this.#http)
61
- this.deliveries = new DeliveriesResource(this.#http)
62
- this.transactions = new TransactionsResource(this.#http)
52
+ if (options.clientId) this.#clientId = Promise.resolve(options.clientId)
53
+ const scope: Scope = { http: this.#http, clientPath: async () => `/v1/clients/${seg(await this.#resolveClientId())}` }
54
+ this.account = new AccountResource(scope, () => this.#resolveClientId())
55
+ this.addresses = new AddressesResource(scope)
56
+ this.webhooks = new WebhooksResource(scope)
57
+ this.deliveries = new DeliveriesResource(scope)
58
+ this.transactions = new TransactionsResource(scope)
59
+ this.networks = new NetworksResource(scope)
60
+ this.assets = new AssetsResource(scope)
63
61
  }
64
62
 
65
- /** Адрес API, с которым работает клиент */
63
+ /** API base URL this client sends requests to. */
66
64
  get baseUrl(): string {
67
65
  return this.#http.baseUrl
68
66
  }
69
67
 
70
- /**
71
- * Вход по email и паролю: возвращает клиента с токеном сессии. Регистрации нет — пользователей заводит
72
- * администратор сервиса. Не больше 3 попыток за 10 секунд с одного IP.
73
- *
74
- * @param options - настройки клиента, кроме учётных данных
75
- * @throws {@link MonitoringApiError} 401 — неверный email или пароль
76
- */
77
- static async signIn(
78
- credentials: { email: string; password: string },
79
- options: Omit<ClientOptions, 'apiKey' | 'sessionToken'> = {},
80
- requestOptions?: RequestOptions,
81
- ): Promise<SignInResult & { client: MonitoringClient }> {
82
- const http = new HttpClient(options, DEFAULT_BASE_URL)
83
- const r = await http.request<{ token: string; user: User }>({
84
- method: 'POST',
85
- path: '/api/auth/sign-in/email',
86
- body: credentials,
87
- idempotent: false,
88
- auth: false,
89
- // повтор при отказе 429 только сожжёт попытки входа
90
- options: { maxRetries: 0, ...requestOptions },
91
- })
92
- return { token: r.token, user: r.user, client: new MonitoringClient({ ...options, sessionToken: r.token }) }
68
+ /** Client ID of the API key: from the options, or resolved once from the API and cached. */
69
+ #resolveClientId(): Promise<string> {
70
+ this.#clientId ??= this.#http.request<Identity>({ method: 'GET', path: '/v1/me', idempotent: true }).then(
71
+ (identity) => {
72
+ if (!identity.actor.clientId) throw new MonitoringError('this API key is not bound to a client: pass clientId in the options')
73
+ return identity.actor.clientId
74
+ },
75
+ (error: unknown) => {
76
+ // a failed lookup is not cached: the next call tries again
77
+ this.#clientId = undefined
78
+ throw error
79
+ },
80
+ )
81
+ return this.#clientId
93
82
  }
94
83
  }
@@ -1,18 +1,18 @@
1
1
  import type { ApiErrorBody } from '../generated/types.js'
2
2
 
3
- /** Ошибка по элементу запроса: номер элемента в переданном массиве и причина */
3
+ /** A per-item problem of a batch request: the item's index in your request and the reason. */
4
4
  export type ErrorDetail = NonNullable<ApiErrorBody['error']['details']>[number]
5
5
 
6
6
  /**
7
- * Базовый класс всех ошибок SDK. Ловите его, чтобы перехватить любую ошибку SDK.
7
+ * Base class of every error thrown by the SDK.
8
8
  *
9
9
  * @example
10
10
  * ```ts
11
11
  * try {
12
- * await monitoring.addresses.add(clientId, items)
13
- * } catch (e) {
14
- * if (e instanceof MonitoringApiError && e.status === 400) console.log(e.details)
15
- * else throw e
12
+ * await monitoring.addresses.add(items)
13
+ * } catch (error) {
14
+ * if (error instanceof MonitoringApiError && error.status === 400) console.log(error.details)
15
+ * else throw error
16
16
  * }
17
17
  * ```
18
18
  */
@@ -23,20 +23,20 @@ export class MonitoringError extends Error {
23
23
  }
24
24
  }
25
25
 
26
- /** API ответил ошибкой: HTTP 4xx или 5xx */
26
+ /** The API responded with an error status (4xx or 5xx). */
27
27
  export class MonitoringApiError extends MonitoringError {
28
- /** HTTP-статус ответа */
28
+ /** HTTP status code. */
29
29
  readonly status: number
30
30
  /**
31
- * Машинный код ошибки: `invalid_request`, `unauthorized`, `forbidden`, `not_found`, `conflict`,
32
- * `rate_limited`, `upstream_error`, `upstream_rate_limited`, `unavailable`…
31
+ * Machine-readable error code, e.g. `invalid_request`, `unauthorized`, `forbidden`, `not_found`,
32
+ * `rate_limited`, `upstream_error`, `upstream_rate_limited`.
33
33
  */
34
34
  readonly code: string
35
- /** Ошибки по элементам запроса (например, какой адрес из переданных не подошёл); пустой массив, если их нет */
35
+ /** Per-item problems of a batch request, such as invalid addresses. Empty when there are none. */
36
36
  readonly details: ErrorDetail[]
37
- /** Идентификатор запроса (`cf-ray`) — укажите его, если обращаетесь в поддержку */
37
+ /** Request ID. Include it when contacting support. */
38
38
  readonly requestId: string | undefined
39
- /** Тело ответа как есть */
39
+ /** Raw response body. */
40
40
  readonly body: unknown
41
41
 
42
42
  constructor(init: { status: number; code: string; message: string; details?: ErrorDetail[]; requestId?: string; body?: unknown }) {
@@ -49,13 +49,13 @@ export class MonitoringApiError extends MonitoringError {
49
49
  this.body = init.body
50
50
  }
51
51
 
52
- /** Временная ошибка — лимит частоты или недоступный провайдер: запрос можно повторить позже */
52
+ /** `true` for transient errors — rate limits and unavailable upstream providers — that can be retried later. */
53
53
  get retryable(): boolean {
54
54
  return this.status === 429 || this.status === 503
55
55
  }
56
56
  }
57
57
 
58
- /** Ответа нет: сбой сети или соединения */
58
+ /** The request did not get a response because of a network or connection failure. */
59
59
  export class MonitoringConnectionError extends MonitoringError {
60
60
  constructor(message: string, options?: { cause?: unknown }) {
61
61
  super(message, options)
@@ -63,7 +63,7 @@ export class MonitoringConnectionError extends MonitoringError {
63
63
  }
64
64
  }
65
65
 
66
- /** Запрос не уложился в таймаут (`timeoutMs`) */
66
+ /** The request did not complete within `timeoutMs`. */
67
67
  export class MonitoringTimeoutError extends MonitoringConnectionError {
68
68
  constructor(timeoutMs: number) {
69
69
  super(`request timed out after ${timeoutMs} ms`)
@@ -71,7 +71,7 @@ export class MonitoringTimeoutError extends MonitoringConnectionError {
71
71
  }
72
72
  }
73
73
 
74
- /** Подпись вебхука не прошла проверку: тело подделано, изменено по дороге или проверяется не тем секретом */
74
+ /** The webhook signature does not match: the body was altered or is verified with the wrong secret. */
75
75
  export class WebhookSignatureError extends MonitoringError {
76
76
  constructor(message = 'webhook signature mismatch') {
77
77
  super(message)
@@ -79,7 +79,7 @@ export class WebhookSignatureError extends MonitoringError {
79
79
  }
80
80
  }
81
81
 
82
- /** Тело ошибки в любом из форматов API: `/v1`, старые пути (`{ok: false}`), вход (`{code, message}`) */
82
+ /** Builds an error from any error body the API returns. */
83
83
  export function apiErrorFrom(status: number, body: unknown, requestId: string | undefined): MonitoringApiError {
84
84
  const b = (body ?? {}) as Record<string, unknown>
85
85
  const v1 = typeof b.error === 'object' && b.error !== null ? (b.error as Record<string, unknown>) : undefined