@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.
- package/CHANGELOG.md +21 -11
- package/README.md +223 -148
- package/dist/cjs/client.d.ts +23 -42
- package/dist/cjs/client.d.ts.map +1 -1
- package/dist/cjs/client.js +44 -53
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/core/errors.d.ts +18 -18
- package/dist/cjs/core/errors.d.ts.map +1 -1
- package/dist/cjs/core/errors.js +17 -17
- package/dist/cjs/core/errors.js.map +1 -1
- package/dist/cjs/core/http.d.ts +22 -26
- package/dist/cjs/core/http.d.ts.map +1 -1
- package/dist/cjs/core/http.js +28 -36
- package/dist/cjs/core/http.js.map +1 -1
- package/dist/cjs/core/pagination.d.ts +6 -7
- package/dist/cjs/core/pagination.d.ts.map +1 -1
- package/dist/cjs/core/pagination.js +1 -1
- package/dist/cjs/core/pagination.js.map +1 -1
- package/dist/cjs/core/scope.d.ts +8 -0
- package/dist/cjs/core/scope.d.ts.map +1 -0
- package/dist/cjs/core/scope.js +3 -0
- package/dist/cjs/core/scope.js.map +1 -0
- package/dist/cjs/generated/types.d.ts +129 -117
- package/dist/cjs/generated/types.d.ts.map +1 -1
- package/dist/cjs/generated/types.js +1 -1
- package/dist/cjs/generated/types.js.map +1 -1
- package/dist/cjs/index.d.ts +6 -6
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +13 -16
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/resources/account.d.ts +12 -51
- package/dist/cjs/resources/account.d.ts.map +1 -1
- package/dist/cjs/resources/account.js +17 -61
- package/dist/cjs/resources/account.js.map +1 -1
- package/dist/cjs/resources/addresses.d.ts +49 -65
- package/dist/cjs/resources/addresses.d.ts.map +1 -1
- package/dist/cjs/resources/addresses.js +60 -69
- package/dist/cjs/resources/addresses.js.map +1 -1
- package/dist/cjs/resources/catalog.d.ts +17 -10
- package/dist/cjs/resources/catalog.d.ts.map +1 -1
- package/dist/cjs/resources/catalog.js +23 -17
- package/dist/cjs/resources/catalog.js.map +1 -1
- package/dist/cjs/resources/deliveries.d.ts +34 -23
- package/dist/cjs/resources/deliveries.d.ts.map +1 -1
- package/dist/cjs/resources/deliveries.js +27 -17
- package/dist/cjs/resources/deliveries.js.map +1 -1
- package/dist/cjs/resources/transactions.d.ts +14 -14
- package/dist/cjs/resources/transactions.d.ts.map +1 -1
- package/dist/cjs/resources/transactions.js +15 -16
- package/dist/cjs/resources/transactions.js.map +1 -1
- package/dist/cjs/resources/webhooks.d.ts +22 -0
- package/dist/cjs/resources/webhooks.d.ts.map +1 -0
- package/dist/cjs/resources/webhooks.js +35 -0
- package/dist/cjs/resources/webhooks.js.map +1 -0
- package/dist/cjs/units.d.ts +11 -11
- package/dist/cjs/units.js +14 -14
- package/dist/cjs/units.js.map +1 -1
- package/dist/cjs/version.d.ts +3 -3
- package/dist/cjs/version.d.ts.map +1 -1
- package/dist/cjs/version.js +3 -3
- package/dist/cjs/version.js.map +1 -1
- package/dist/cjs/webhooks.d.ts +33 -28
- package/dist/cjs/webhooks.d.ts.map +1 -1
- package/dist/cjs/webhooks.js +33 -28
- package/dist/cjs/webhooks.js.map +1 -1
- package/dist/esm/client.d.ts +23 -42
- package/dist/esm/client.d.ts.map +1 -1
- package/dist/esm/client.js +46 -55
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/core/errors.d.ts +18 -18
- package/dist/esm/core/errors.d.ts.map +1 -1
- package/dist/esm/core/errors.js +17 -17
- package/dist/esm/core/errors.js.map +1 -1
- package/dist/esm/core/http.d.ts +22 -26
- package/dist/esm/core/http.d.ts.map +1 -1
- package/dist/esm/core/http.js +28 -36
- package/dist/esm/core/http.js.map +1 -1
- package/dist/esm/core/pagination.d.ts +6 -7
- package/dist/esm/core/pagination.d.ts.map +1 -1
- package/dist/esm/core/pagination.js +1 -1
- package/dist/esm/core/pagination.js.map +1 -1
- package/dist/esm/core/scope.d.ts +8 -0
- package/dist/esm/core/scope.d.ts.map +1 -0
- package/dist/esm/core/scope.js +2 -0
- package/dist/esm/core/scope.js.map +1 -0
- package/dist/esm/generated/types.d.ts +129 -117
- package/dist/esm/generated/types.d.ts.map +1 -1
- package/dist/esm/generated/types.js +1 -1
- package/dist/esm/generated/types.js.map +1 -1
- package/dist/esm/index.d.ts +6 -6
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +6 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/resources/account.d.ts +12 -51
- package/dist/esm/resources/account.d.ts.map +1 -1
- package/dist/esm/resources/account.js +15 -57
- package/dist/esm/resources/account.js.map +1 -1
- package/dist/esm/resources/addresses.d.ts +49 -65
- package/dist/esm/resources/addresses.d.ts.map +1 -1
- package/dist/esm/resources/addresses.js +60 -69
- package/dist/esm/resources/addresses.js.map +1 -1
- package/dist/esm/resources/catalog.d.ts +17 -10
- package/dist/esm/resources/catalog.d.ts.map +1 -1
- package/dist/esm/resources/catalog.js +23 -17
- package/dist/esm/resources/catalog.js.map +1 -1
- package/dist/esm/resources/deliveries.d.ts +34 -23
- package/dist/esm/resources/deliveries.d.ts.map +1 -1
- package/dist/esm/resources/deliveries.js +27 -17
- package/dist/esm/resources/deliveries.js.map +1 -1
- package/dist/esm/resources/transactions.d.ts +14 -14
- package/dist/esm/resources/transactions.d.ts.map +1 -1
- package/dist/esm/resources/transactions.js +15 -16
- package/dist/esm/resources/transactions.js.map +1 -1
- package/dist/esm/resources/webhooks.d.ts +22 -0
- package/dist/esm/resources/webhooks.d.ts.map +1 -0
- package/dist/esm/resources/webhooks.js +31 -0
- package/dist/esm/resources/webhooks.js.map +1 -0
- package/dist/esm/units.d.ts +11 -11
- package/dist/esm/units.js +14 -14
- package/dist/esm/units.js.map +1 -1
- package/dist/esm/version.d.ts +3 -3
- package/dist/esm/version.d.ts.map +1 -1
- package/dist/esm/version.js +3 -3
- package/dist/esm/version.js.map +1 -1
- package/dist/esm/webhooks.d.ts +33 -28
- package/dist/esm/webhooks.d.ts.map +1 -1
- package/dist/esm/webhooks.js +33 -28
- package/dist/esm/webhooks.js.map +1 -1
- package/package.json +8 -5
- package/src/client.ts +50 -61
- package/src/core/errors.ts +18 -18
- package/src/core/http.ts +45 -55
- package/src/core/pagination.ts +7 -8
- package/src/core/scope.ts +8 -0
- package/src/generated/types.ts +139 -125
- package/src/index.ts +7 -24
- package/src/resources/account.ts +18 -72
- package/src/resources/addresses.ts +84 -109
- package/src/resources/catalog.ts +28 -19
- package/src/resources/deliveries.ts +43 -30
- package/src/resources/transactions.ts +18 -17
- package/src/resources/webhooks.ts +36 -0
- package/src/units.ts +14 -14
- package/src/version.ts +3 -3
- package/src/webhooks.ts +37 -32
- package/dist/cjs/resources/clients.d.ts +0 -84
- package/dist/cjs/resources/clients.d.ts.map +0 -1
- package/dist/cjs/resources/clients.js +0 -102
- package/dist/cjs/resources/clients.js.map +0 -1
- package/dist/esm/resources/clients.d.ts +0 -84
- package/dist/esm/resources/clients.d.ts.map +0 -1
- package/dist/esm/resources/clients.js +0 -97
- package/dist/esm/resources/clients.js.map +0 -1
- package/src/resources/clients.ts +0 -135
package/src/core/http.ts
CHANGED
|
@@ -1,111 +1,112 @@
|
|
|
1
1
|
import { SDK_VERSION } from '../version.js'
|
|
2
2
|
import { apiErrorFrom, MonitoringConnectionError, MonitoringError, MonitoringTimeoutError } from './errors.js'
|
|
3
3
|
|
|
4
|
-
/**
|
|
4
|
+
/** Per-request options, accepted as the last argument of every method. */
|
|
5
5
|
export interface RequestOptions {
|
|
6
|
-
/**
|
|
6
|
+
/** Cancels the request, including pending retries. */
|
|
7
7
|
signal?: AbortSignal
|
|
8
|
-
/**
|
|
8
|
+
/** Timeout for this request in milliseconds. Overrides {@link ClientOptions.timeoutMs}. */
|
|
9
9
|
timeoutMs?: number
|
|
10
|
-
/**
|
|
10
|
+
/** Maximum number of retries for this request. Overrides {@link ClientOptions.maxRetries}. */
|
|
11
11
|
maxRetries?: number
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
/**
|
|
14
|
+
/** Options of {@link MonitoringClient}. */
|
|
15
15
|
export interface ClientOptions {
|
|
16
|
+
/** Your API key. Sent in the `x-api-key` header. */
|
|
17
|
+
apiKey: string
|
|
16
18
|
/**
|
|
17
|
-
*
|
|
18
|
-
* (всё, что вы можете в панели, с вашими правами). Уходит в заголовке `x-api-key`.
|
|
19
|
+
* Your client ID. Optional: when omitted, it is resolved from the API key on first use and cached.
|
|
19
20
|
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
sessionToken?: string
|
|
23
|
-
/** Адрес API. По умолчанию `https://monitoring.v3.finance` */
|
|
21
|
+
clientId?: string
|
|
22
|
+
/** API base URL. Defaults to `https://monitoring.v3.finance`. */
|
|
24
23
|
baseUrl?: string
|
|
25
|
-
/**
|
|
24
|
+
/** Request timeout in milliseconds. Defaults to `30000`. */
|
|
26
25
|
timeoutMs?: number
|
|
27
26
|
/**
|
|
28
|
-
*
|
|
27
|
+
* Maximum number of retries for transient errors. Defaults to `2`.
|
|
29
28
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* `Retry-After`, иначе экспоненциальная с разбросом.
|
|
29
|
+
* `429` and `503` responses are retried for every request, honoring `Retry-After`. Network errors and timeouts are
|
|
30
|
+
* retried only for requests that are safe to repeat. Backoff is exponential with jitter.
|
|
33
31
|
*/
|
|
34
32
|
maxRetries?: number
|
|
35
|
-
/**
|
|
33
|
+
/** Custom `fetch` implementation, e.g. for proxies or instrumentation. Defaults to the global `fetch`. */
|
|
36
34
|
fetch?: typeof fetch
|
|
37
|
-
/**
|
|
35
|
+
/** Additional headers sent with every request. */
|
|
38
36
|
headers?: Record<string, string>
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
type Query = Record<string, string | number | boolean | null | undefined>
|
|
42
40
|
|
|
43
|
-
/**
|
|
41
|
+
/** @internal A request to the API. */
|
|
44
42
|
export interface Call {
|
|
45
43
|
method: 'GET' | 'POST' | 'PATCH' | 'DELETE'
|
|
46
44
|
path: string
|
|
47
45
|
query?: Query
|
|
48
46
|
body?: unknown
|
|
49
|
-
/**
|
|
47
|
+
/** The request can be repeated after a network failure without changing the outcome. */
|
|
50
48
|
idempotent: boolean
|
|
51
|
-
/**
|
|
49
|
+
/** Statuses returned as data rather than thrown. */
|
|
52
50
|
acceptStatuses?: number[]
|
|
53
|
-
/** false — запрос без учётных данных (вход) */
|
|
54
|
-
auth?: boolean
|
|
55
51
|
options?: RequestOptions | undefined
|
|
56
52
|
}
|
|
57
53
|
|
|
58
54
|
const DEFAULTS = { timeoutMs: 30_000, maxRetries: 2 }
|
|
59
55
|
const MAX_RETRY_DELAY_MS = 60_000
|
|
60
56
|
|
|
61
|
-
/**
|
|
57
|
+
/** @internal Transport: base URL, authentication, timeouts, retries and error mapping. */
|
|
62
58
|
export class HttpClient {
|
|
63
59
|
readonly baseUrl: string
|
|
64
|
-
readonly #apiKey: string
|
|
65
|
-
readonly #sessionToken: string | undefined
|
|
60
|
+
readonly #apiKey: string
|
|
66
61
|
readonly #timeoutMs: number
|
|
67
62
|
readonly #maxRetries: number
|
|
68
63
|
readonly #fetch: typeof fetch
|
|
69
64
|
readonly #headers: Record<string, string>
|
|
70
65
|
|
|
71
66
|
constructor(options: ClientOptions, defaultBaseUrl: string) {
|
|
72
|
-
if (options
|
|
67
|
+
if (!options?.apiKey) throw new MonitoringError('apiKey is required')
|
|
73
68
|
this.baseUrl = (options.baseUrl ?? defaultBaseUrl).replace(/\/+$/, '')
|
|
74
69
|
this.#apiKey = options.apiKey
|
|
75
|
-
this.#sessionToken = options.sessionToken
|
|
76
70
|
this.#timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs
|
|
77
71
|
this.#maxRetries = options.maxRetries ?? DEFAULTS.maxRetries
|
|
78
72
|
const f = options.fetch ?? globalThis.fetch
|
|
79
|
-
if (typeof f !== 'function') throw new MonitoringError('fetch is not available: use Node.js 20
|
|
73
|
+
if (typeof f !== 'function') throw new MonitoringError('fetch is not available: use Node.js 20 or later, or pass options.fetch')
|
|
80
74
|
this.#fetch = f
|
|
81
75
|
this.#headers = { ...options.headers }
|
|
82
76
|
}
|
|
83
77
|
|
|
84
|
-
/**
|
|
78
|
+
/** Sends a request and returns the parsed JSON response. */
|
|
85
79
|
async request<T>(call: Call): Promise<T> {
|
|
86
80
|
const url = this.#url(call.path, call.query)
|
|
87
|
-
const headers =
|
|
81
|
+
const headers: Record<string, string> = {
|
|
82
|
+
accept: 'application/json',
|
|
83
|
+
'user-agent': `@v3finance/monitoring-sdk/${SDK_VERSION}`,
|
|
84
|
+
...this.#headers,
|
|
85
|
+
'x-api-key': this.#apiKey,
|
|
86
|
+
}
|
|
87
|
+
if (call.body !== undefined) headers['content-type'] = 'application/json'
|
|
88
88
|
const body = call.body === undefined ? undefined : JSON.stringify(call.body)
|
|
89
89
|
const maxRetries = call.options?.maxRetries ?? this.#maxRetries
|
|
90
90
|
const timeoutMs = call.options?.timeoutMs ?? this.#timeoutMs
|
|
91
|
+
const signal = call.options?.signal
|
|
91
92
|
|
|
92
93
|
for (let attempt = 0; ; attempt++) {
|
|
93
94
|
let res: { status: number; headers: Headers; data: unknown }
|
|
94
95
|
try {
|
|
95
|
-
res = await this.#send(url, { method: call.method, headers, body }, timeoutMs,
|
|
96
|
-
} catch (
|
|
97
|
-
if (
|
|
96
|
+
res = await this.#send(url, { method: call.method, headers, body }, timeoutMs, signal)
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (signal?.aborted) throw signal.reason
|
|
98
99
|
if (call.idempotent && attempt < maxRetries) {
|
|
99
|
-
await sleep(backoff(attempt),
|
|
100
|
+
await sleep(backoff(attempt), signal)
|
|
100
101
|
continue
|
|
101
102
|
}
|
|
102
|
-
throw
|
|
103
|
+
throw error
|
|
103
104
|
}
|
|
104
105
|
if ((res.status >= 200 && res.status < 300) || call.acceptStatuses?.includes(res.status)) return res.data as T
|
|
105
106
|
const error = apiErrorFrom(res.status, res.data, res.headers.get('cf-ray') ?? undefined)
|
|
106
|
-
// 429
|
|
107
|
+
// 429 and 503 mean the request was not processed, so retrying is safe for any method
|
|
107
108
|
if (error.retryable && attempt < maxRetries) {
|
|
108
|
-
await sleep(retryAfter(res.headers) ?? backoff(attempt),
|
|
109
|
+
await sleep(retryAfter(res.headers) ?? backoff(attempt), signal)
|
|
109
110
|
continue
|
|
110
111
|
}
|
|
111
112
|
throw error
|
|
@@ -118,18 +119,7 @@ export class HttpClient {
|
|
|
118
119
|
return url.toString()
|
|
119
120
|
}
|
|
120
121
|
|
|
121
|
-
|
|
122
|
-
const headers: Record<string, string> = { accept: 'application/json', 'user-agent': `@v3finance/monitoring-sdk/${SDK_VERSION}`, ...this.#headers }
|
|
123
|
-
if (call.body !== undefined) headers['content-type'] = 'application/json'
|
|
124
|
-
if (call.auth !== false) {
|
|
125
|
-
if (this.#apiKey) headers['x-api-key'] = this.#apiKey
|
|
126
|
-
else if (this.#sessionToken) headers.authorization = `Bearer ${this.#sessionToken}`
|
|
127
|
-
else throw new MonitoringError('credentials required: pass apiKey or sessionToken to MonitoringClient')
|
|
128
|
-
}
|
|
129
|
-
return headers
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/** Один запрос с таймаутом на всё — и соединение, и чтение тела */
|
|
122
|
+
/** One attempt, with a single timeout covering both the connection and the response body. */
|
|
133
123
|
async #send(url: string, init: RequestInit, timeoutMs: number, signal: AbortSignal | undefined) {
|
|
134
124
|
const controller = new AbortController()
|
|
135
125
|
const timer = setTimeout(() => controller.abort(new MonitoringTimeoutError(timeoutMs)), timeoutMs)
|
|
@@ -140,11 +130,11 @@ export class HttpClient {
|
|
|
140
130
|
const res = await this.#fetch(url, { ...init, signal: controller.signal })
|
|
141
131
|
const text = await res.text()
|
|
142
132
|
return { status: res.status, headers: res.headers, data: text ? parseJson(text) : undefined }
|
|
143
|
-
} catch (
|
|
133
|
+
} catch (error) {
|
|
144
134
|
const reason: unknown = controller.signal.reason
|
|
145
135
|
if (reason instanceof MonitoringTimeoutError) throw reason
|
|
146
136
|
if (signal?.aborted) throw signal.reason
|
|
147
|
-
throw new MonitoringConnectionError(`request to ${new URL(url).origin} failed: ${(
|
|
137
|
+
throw new MonitoringConnectionError(`request to ${new URL(url).origin} failed: ${(error as Error).message}`, { cause: error })
|
|
148
138
|
} finally {
|
|
149
139
|
clearTimeout(timer)
|
|
150
140
|
signal?.removeEventListener('abort', onAbort)
|
|
@@ -160,12 +150,12 @@ function parseJson(text: string): unknown {
|
|
|
160
150
|
}
|
|
161
151
|
}
|
|
162
152
|
|
|
163
|
-
/**
|
|
153
|
+
/** Exponential backoff with jitter: ~0.5 s, 1 s, 2 s… capped at 8 s. */
|
|
164
154
|
function backoff(attempt: number): number {
|
|
165
155
|
return Math.min(8_000, 500 * 2 ** attempt) * (0.5 + Math.random() / 2)
|
|
166
156
|
}
|
|
167
157
|
|
|
168
|
-
/**
|
|
158
|
+
/** Delay from a `Retry-After` header: seconds or an HTTP date. */
|
|
169
159
|
function retryAfter(headers: Headers): number | undefined {
|
|
170
160
|
const raw = headers.get('retry-after')
|
|
171
161
|
if (!raw) return undefined
|
|
@@ -189,5 +179,5 @@ function sleep(ms: number, signal: AbortSignal | undefined): Promise<void> {
|
|
|
189
179
|
})
|
|
190
180
|
}
|
|
191
181
|
|
|
192
|
-
/**
|
|
182
|
+
/** @internal Encodes a path segment. */
|
|
193
183
|
export const seg = (value: string | number) => encodeURIComponent(String(value))
|
package/src/core/pagination.ts
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* A page of results. `next` is the cursor of the next page; `null` when there are no more pages.
|
|
3
3
|
*
|
|
4
|
-
* @typeParam T -
|
|
5
|
-
* @typeParam Cursor - тип курсора: строка (клиенты) или число (адреса, история)
|
|
4
|
+
* @typeParam T - Item type.
|
|
6
5
|
*/
|
|
7
|
-
export interface Page<T
|
|
6
|
+
export interface Page<T> {
|
|
8
7
|
items: T[]
|
|
9
|
-
next:
|
|
8
|
+
next: number | null
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
/**
|
|
13
|
-
export async function* paginate<T
|
|
14
|
-
let cursor:
|
|
11
|
+
/** @internal Yields every item, fetching the next page only when the current one is exhausted. */
|
|
12
|
+
export async function* paginate<T>(fetchPage: (cursor: number | undefined) => Promise<Page<T>>): AsyncGenerator<T, void, undefined> {
|
|
13
|
+
let cursor: number | undefined
|
|
15
14
|
for (;;) {
|
|
16
15
|
const page = await fetchPage(cursor)
|
|
17
16
|
yield* page.items
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HttpClient } from './http.js'
|
|
2
|
+
|
|
3
|
+
/** @internal What resources share: the transport and the client ID of the API key. */
|
|
4
|
+
export interface Scope {
|
|
5
|
+
http: HttpClient
|
|
6
|
+
/** Path segment of the client: resolved from the API key once, then cached. */
|
|
7
|
+
clientPath: () => Promise<string>
|
|
8
|
+
}
|