@pagouai/api-sdk 0.1.1

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/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # Pagou.ai TypeScript SDK (`/v2`)
2
+
3
+ Cross-runtime SDK template for Node.js 18+, Bun, and Deno.
4
+
5
+ - Resource-first API (`client.transactions.*`)
6
+ - `fetch`-based (no axios)
7
+ - Typed errors
8
+ - Retries + timeout + idempotency
9
+ - Native `/v2` page/limit pagination
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ bun add @pagouai/api-sdk
15
+ # or npm i / pnpm add
16
+ ```
17
+
18
+ ## Quick Start
19
+
20
+ ```ts
21
+ import { Client } from "@pagouai/api-sdk";
22
+
23
+ const client = new Client({
24
+ apiKey: "YOUR_API_KEY",
25
+ timeoutMs: 30_000,
26
+ maxRetries: 2,
27
+ telemetry: true,
28
+ });
29
+ ```
30
+
31
+ ## Configuration
32
+
33
+ ```ts
34
+ new Client({
35
+ apiKey: "YOUR_API_KEY",
36
+ environment: "production", // default: "production"
37
+ // environment: "sandbox",
38
+ // baseUrl: "https://api.sandbox.pagou.ai", // explicit override if needed
39
+ timeoutMs: 30_000,
40
+ maxRetries: 2,
41
+ telemetry: true,
42
+ userAgent: "PagouTS-SDK/0.1.0 (Transactions; +https://pagou.ai)",
43
+ fetch: customFetch,
44
+ auth: { scheme: "bearer" }, // default
45
+ // apiVersion: "2026-02-01",
46
+ });
47
+ ```
48
+
49
+ Auth schemes:
50
+
51
+ - `bearer` (default) -> `Authorization: Bearer <apiKey>`
52
+ - `basic` -> `Authorization: Basic <base64(apiKey:x)>`
53
+ - `api_key_header` -> `apikey: <apiKey>` (or custom `headerName`)
54
+
55
+ Default base URLs:
56
+
57
+ - production: `https://api.pagou.ai`
58
+ - sandbox/test: `https://api.sandbox.pagou.ai`
59
+
60
+ ## API Coverage (`/v2`)
61
+
62
+ - `POST /v2/transactions`
63
+ - `GET /v2/transactions`
64
+ - `GET /v2/transactions/{id}`
65
+ - `PUT /v2/transactions/{id}` (test/sandbox-only behavior)
66
+ - `PUT /v2/transactions/{id}/refund`
67
+
68
+ ## Usage Examples
69
+
70
+ ### 1) Create a transaction
71
+
72
+ ```ts
73
+ const created = await client.transactions.create({
74
+ amount: 1500,
75
+ method: "pix",
76
+ currency: "BRL",
77
+ buyer: {
78
+ name: "Jane Doe",
79
+ email: "jane@example.com",
80
+ },
81
+ products: [{ name: "Pro Plan", price: 1500, quantity: 1 }],
82
+ });
83
+
84
+ console.log(created.data.id, created.meta.requestId);
85
+ ```
86
+
87
+ ### 2) Retrieve a transaction
88
+
89
+ ```ts
90
+ const tx = await client.transactions.retrieve("tr_123");
91
+ console.log(tx.data.status);
92
+ ```
93
+
94
+ ### 3) List transactions with page/limit + filters
95
+
96
+ ```ts
97
+ const page = await client.transactions.list({
98
+ page: 1,
99
+ limit: 20,
100
+ status: ["pending", "paid"],
101
+ paymentMethods: ["pix"],
102
+ });
103
+
104
+ console.log(page.data.metadata.total);
105
+ for (const item of page.data.data) {
106
+ console.log(item.id, item.status);
107
+ }
108
+ ```
109
+
110
+ ### 4) Auto-paging iterator
111
+
112
+ ```ts
113
+ for await (const item of client.transactions.listAutoPagingIterator({ limit: 100 })) {
114
+ console.log(item.id);
115
+ }
116
+ ```
117
+
118
+ ### 5) Refund a transaction
119
+
120
+ ```ts
121
+ const refunded = await client.transactions.refund(
122
+ "tr_123",
123
+ { amount: 500, reason: "requested_by_customer" },
124
+ { idempotencyKey: "idem_refund_tr_123_1" },
125
+ );
126
+
127
+ console.log(refunded.data);
128
+ ```
129
+
130
+ ## Request Options
131
+
132
+ All resource methods accept `opts?`:
133
+
134
+ ```ts
135
+ {
136
+ idempotencyKey?: string;
137
+ requestId?: string;
138
+ timeoutMs?: number;
139
+ signal?: AbortSignal;
140
+ }
141
+ ```
142
+
143
+ ## Retries and Timeout
144
+
145
+ Retries happen for:
146
+
147
+ - Network errors
148
+ - `429`, `500`, `502`, `503`, `504`
149
+
150
+ Rules:
151
+
152
+ - Always retry for `GET`/`HEAD`
153
+ - Retry `POST`/`PUT` only when `idempotencyKey` is set
154
+ - Respect `Retry-After` header when available
155
+
156
+ Timeout uses `AbortController`.
157
+
158
+ ## Error Handling
159
+
160
+ ```ts
161
+ import {
162
+ AuthenticationError,
163
+ InvalidRequestError,
164
+ NotFoundError,
165
+ RateLimitError,
166
+ ServerError,
167
+ NetworkError,
168
+ } from "@pagouai/api-sdk";
169
+
170
+ try {
171
+ await client.transactions.retrieve("tr_404");
172
+ } catch (error) {
173
+ if (error instanceof NotFoundError) {
174
+ console.error("Missing transaction", error.requestId);
175
+ } else if (error instanceof RateLimitError) {
176
+ console.error("Back off", error.status, error.code);
177
+ } else if (error instanceof NetworkError) {
178
+ console.error("Network issue", error.message);
179
+ } else if (error instanceof InvalidRequestError || error instanceof AuthenticationError || error instanceof ServerError) {
180
+ console.error(error.message);
181
+ } else {
182
+ throw error;
183
+ }
184
+ }
185
+ ```
186
+
187
+ ## Response Shapes
188
+
189
+ Data endpoints:
190
+
191
+ ```ts
192
+ {
193
+ success: boolean;
194
+ requestId: string;
195
+ data: T;
196
+ }
197
+ ```
198
+
199
+ List endpoints:
200
+
201
+ ```ts
202
+ {
203
+ success: boolean;
204
+ requestId: string;
205
+ metadata: { page: number; limit: number; total: number };
206
+ data: T[];
207
+ }
208
+ ```
209
+
210
+ Notes:
211
+ - This SDK uses `/v2` endpoint paths.
@@ -0,0 +1,50 @@
1
+ import { TransactionsResource } from "./resources/transactions";
2
+ import type { ApiResponse, ClientOptions, PaginatedEnvelope, RequestOptions } from "./types";
3
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD";
4
+ interface RawResponse {
5
+ status: number;
6
+ headers: Headers;
7
+ body: unknown;
8
+ requestId?: string;
9
+ }
10
+ interface RequestInput {
11
+ method: HttpMethod;
12
+ path: string;
13
+ query?: Record<string, unknown>;
14
+ body?: unknown;
15
+ options?: RequestOptions;
16
+ }
17
+ /**
18
+ * Main SDK client for Pagou.ai API.
19
+ */
20
+ export declare class Client {
21
+ private readonly apiKey;
22
+ private readonly baseUrl;
23
+ private readonly timeoutMs;
24
+ private readonly maxRetries;
25
+ private readonly telemetry;
26
+ private readonly userAgent;
27
+ private readonly fetchImpl;
28
+ private readonly auth;
29
+ private readonly apiVersion?;
30
+ private readonly retryBaseDelayMs;
31
+ private readonly maxRetryDelayMs;
32
+ readonly transactions: TransactionsResource;
33
+ constructor(options: ClientOptions);
34
+ /**
35
+ * Sends a request and unwraps a data envelope.
36
+ */
37
+ requestData<T>(input: RequestInput): Promise<ApiResponse<T>>;
38
+ /**
39
+ * Sends a request and unwraps a paginated envelope.
40
+ */
41
+ requestPaginated<T>(input: RequestInput): Promise<ApiResponse<PaginatedEnvelope<T>>>;
42
+ requestRaw(input: RequestInput): Promise<RawResponse>;
43
+ private prepareRequest;
44
+ private applyAuthHeader;
45
+ private applyVersionHeader;
46
+ private applyTelemetryHeaders;
47
+ private toApiError;
48
+ }
49
+ export {};
50
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,KAAK,EACX,WAAW,EAGX,aAAa,EAGb,iBAAiB,EACjB,cAAc,EAEd,MAAM,SAAS,CAAC;AAajB,KAAK,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAUvE,UAAU,WAAW;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,UAAU,YAAY;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,cAAc,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,MAAM;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAU;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IAEzC,SAAgB,YAAY,EAAE,oBAAoB,CAAC;gBAEvC,OAAO,EAAE,aAAa;IAoBlC;;OAEG;IACU,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAiBzE;;OAEG;IACU,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;IAiBpF,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC;IAsElE,OAAO,CAAC,cAAc;IA+FtB,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,qBAAqB;IAa7B,OAAO,CAAC,UAAU;CA+BlB"}
package/dist/client.js ADDED
@@ -0,0 +1,448 @@
1
+ import { ApiError, AuthenticationError, ConflictError, InvalidRequestError, NetworkError, NotFoundError, PermissionError, parseErrorPayload, RateLimitError, ServerError, } from "./errors";
2
+ import { TransactionsResource } from "./resources/transactions";
3
+ import { SDK_VERSION } from "./version";
4
+ const PRODUCTION_BASE_URL = "https://api.pagou.ai";
5
+ const SANDBOX_BASE_URL = "https://api.sandbox.pagou.ai";
6
+ const DEFAULT_AUTH_SCHEME = "bearer";
7
+ const DEFAULT_AUTH_HEADER_NAME = "apikey";
8
+ const DEFAULT_USER_AGENT = `PagouTS-SDK/${SDK_VERSION} (Transactions; +https://pagou.ai)`;
9
+ const DEFAULT_API_VERSION_HEADER = "{{API_VERSION_HEADER}}";
10
+ const DEFAULT_API_VERSION = "{{API_VERSION}}";
11
+ const RETRY_STATUS_CODES = new Set([429, 500, 502, 503, 504]);
12
+ /**
13
+ * Main SDK client for Pagou.ai API.
14
+ */
15
+ export class Client {
16
+ apiKey;
17
+ baseUrl;
18
+ timeoutMs;
19
+ maxRetries;
20
+ telemetry;
21
+ userAgent;
22
+ fetchImpl;
23
+ auth;
24
+ apiVersion;
25
+ retryBaseDelayMs;
26
+ maxRetryDelayMs;
27
+ transactions;
28
+ constructor(options) {
29
+ if (!options.apiKey) {
30
+ throw new Error("Client requires an apiKey.");
31
+ }
32
+ this.apiKey = options.apiKey;
33
+ this.baseUrl = normalizeBaseUrl(options.baseUrl ?? resolveEnvironmentBaseUrl(options.environment));
34
+ this.timeoutMs = options.timeoutMs ?? 30_000;
35
+ this.maxRetries = options.maxRetries ?? 2;
36
+ this.telemetry = options.telemetry ?? true;
37
+ this.userAgent = options.userAgent ?? DEFAULT_USER_AGENT;
38
+ this.fetchImpl = resolveFetch(options.fetch);
39
+ this.auth = options.auth ?? resolveDefaultAuth();
40
+ this.apiVersion = options.apiVersion ?? resolvePlaceholder(DEFAULT_API_VERSION);
41
+ this.retryBaseDelayMs = options.retryBaseDelayMs ?? 200;
42
+ this.maxRetryDelayMs = options.maxRetryDelayMs ?? 2_000;
43
+ this.transactions = new TransactionsResource(this);
44
+ }
45
+ /**
46
+ * Sends a request and unwraps a data envelope.
47
+ */
48
+ async requestData(input) {
49
+ const raw = await this.requestRaw(input);
50
+ const envelope = raw.body;
51
+ if (!isDataEnvelope(envelope)) {
52
+ throw new ApiError("Unexpected response format: expected data envelope", {
53
+ status: raw.status,
54
+ requestId: raw.requestId,
55
+ raw: raw.body,
56
+ });
57
+ }
58
+ return {
59
+ data: envelope.data,
60
+ meta: toMeta(raw),
61
+ };
62
+ }
63
+ /**
64
+ * Sends a request and unwraps a paginated envelope.
65
+ */
66
+ async requestPaginated(input) {
67
+ const raw = await this.requestRaw(input);
68
+ const envelope = raw.body;
69
+ if (!isPaginatedEnvelope(envelope)) {
70
+ throw new ApiError("Unexpected response format: expected paginated envelope", {
71
+ status: raw.status,
72
+ requestId: raw.requestId,
73
+ raw: raw.body,
74
+ });
75
+ }
76
+ return {
77
+ data: envelope,
78
+ meta: toMeta(raw),
79
+ };
80
+ }
81
+ async requestRaw(input) {
82
+ const method = input.method;
83
+ const canRetry = isRetryEligible(method, input.options?.idempotencyKey);
84
+ let attempt = 0;
85
+ for (;;) {
86
+ const prepared = this.prepareRequest(input);
87
+ try {
88
+ const response = await this.fetchImpl(prepared.url, prepared.init);
89
+ const requestId = extractRequestId(response.headers);
90
+ const body = await parseBody(response);
91
+ if (!response.ok) {
92
+ const shouldRetryStatus = RETRY_STATUS_CODES.has(response.status);
93
+ const shouldRetry = canRetry && shouldRetryStatus && attempt < this.maxRetries;
94
+ if (shouldRetry) {
95
+ const delayMs = computeRetryDelayMs(attempt, response.headers.get("Retry-After"), this.retryBaseDelayMs, this.maxRetryDelayMs);
96
+ attempt += 1;
97
+ prepared.clear();
98
+ await sleep(delayMs);
99
+ continue;
100
+ }
101
+ prepared.clear();
102
+ throw this.toApiError(response.status, body, requestId);
103
+ }
104
+ prepared.clear();
105
+ return {
106
+ status: response.status,
107
+ headers: response.headers,
108
+ body,
109
+ requestId: requestId ?? extractRequestIdFromBody(body),
110
+ };
111
+ }
112
+ catch (error) {
113
+ prepared.clear();
114
+ if (error instanceof ApiError) {
115
+ throw error;
116
+ }
117
+ const aborted = isAbortError(error);
118
+ const timedOut = prepared.didTimeout();
119
+ const retryable = !aborted;
120
+ if (canRetry && retryable && attempt < this.maxRetries) {
121
+ const delayMs = computeRetryDelayMs(attempt, undefined, this.retryBaseDelayMs, this.maxRetryDelayMs);
122
+ attempt += 1;
123
+ await sleep(delayMs);
124
+ continue;
125
+ }
126
+ const message = timedOut
127
+ ? `Request timed out after ${input.options?.timeoutMs ?? this.timeoutMs}ms`
128
+ : "Network request failed";
129
+ throw new NetworkError(message, {
130
+ cause: error,
131
+ });
132
+ }
133
+ }
134
+ }
135
+ prepareRequest(input) {
136
+ const headers = new Headers();
137
+ headers.set("Accept", "application/json");
138
+ if (input.body !== undefined) {
139
+ headers.set("Content-Type", "application/json");
140
+ }
141
+ const requestId = input.options?.requestId;
142
+ if (requestId) {
143
+ headers.set("X-Request-Id", requestId);
144
+ }
145
+ if (input.options?.idempotencyKey) {
146
+ headers.set("Idempotency-Key", input.options.idempotencyKey);
147
+ }
148
+ this.applyAuthHeader(headers);
149
+ this.applyVersionHeader(headers);
150
+ this.applyTelemetryHeaders(headers);
151
+ const url = new URL(input.path, this.baseUrl);
152
+ if (input.query) {
153
+ for (const [key, value] of Object.entries(input.query)) {
154
+ if (value === undefined || value === null) {
155
+ continue;
156
+ }
157
+ if (Array.isArray(value)) {
158
+ if (value.length === 0) {
159
+ continue;
160
+ }
161
+ url.searchParams.set(key, value.map((v) => String(v)).join(","));
162
+ continue;
163
+ }
164
+ url.searchParams.set(key, String(value));
165
+ }
166
+ }
167
+ const controller = new AbortController();
168
+ const externalSignal = input.options?.signal;
169
+ const timeoutMs = input.options?.timeoutMs ?? this.timeoutMs;
170
+ let timedOut = false;
171
+ let timeoutHandle;
172
+ const onExternalAbort = () => {
173
+ if (!controller.signal.aborted) {
174
+ controller.abort();
175
+ }
176
+ };
177
+ if (externalSignal) {
178
+ if (externalSignal.aborted) {
179
+ onExternalAbort();
180
+ }
181
+ else {
182
+ externalSignal.addEventListener("abort", onExternalAbort, { once: true });
183
+ }
184
+ }
185
+ if (timeoutMs > 0) {
186
+ timeoutHandle = setTimeout(() => {
187
+ timedOut = true;
188
+ if (!controller.signal.aborted) {
189
+ controller.abort();
190
+ }
191
+ }, timeoutMs);
192
+ }
193
+ const init = {
194
+ method: input.method,
195
+ headers,
196
+ signal: controller.signal,
197
+ };
198
+ if (input.body !== undefined) {
199
+ init.body = JSON.stringify(input.body);
200
+ }
201
+ const clear = () => {
202
+ if (timeoutHandle !== undefined) {
203
+ clearTimeout(timeoutHandle);
204
+ }
205
+ if (externalSignal) {
206
+ externalSignal.removeEventListener("abort", onExternalAbort);
207
+ }
208
+ };
209
+ return {
210
+ url,
211
+ init,
212
+ timeoutHandle,
213
+ clear,
214
+ didTimeout: () => timedOut,
215
+ };
216
+ }
217
+ applyAuthHeader(headers) {
218
+ switch (this.auth.scheme) {
219
+ case "bearer":
220
+ headers.set("Authorization", `Bearer ${this.apiKey}`);
221
+ break;
222
+ case "basic":
223
+ headers.set("Authorization", `Basic ${encodeBase64(`${this.apiKey}:x`)}`);
224
+ break;
225
+ case "api_key_header": {
226
+ const fallbackHeaderName = resolvePlaceholder(DEFAULT_AUTH_HEADER_NAME) ?? "apikey";
227
+ headers.set(this.auth.headerName ?? fallbackHeaderName, this.apiKey);
228
+ break;
229
+ }
230
+ }
231
+ }
232
+ applyVersionHeader(headers) {
233
+ const versionHeaderName = resolvePlaceholder(DEFAULT_API_VERSION_HEADER);
234
+ if (!versionHeaderName || !this.apiVersion) {
235
+ return;
236
+ }
237
+ headers.set(versionHeaderName, this.apiVersion);
238
+ }
239
+ applyTelemetryHeaders(headers) {
240
+ if (!this.telemetry) {
241
+ return;
242
+ }
243
+ if (this.userAgent) {
244
+ headers.set("User-Agent", this.userAgent);
245
+ }
246
+ headers.set("X-SDK-Lang", "typescript");
247
+ headers.set("X-SDK-Runtime", detectRuntime());
248
+ }
249
+ toApiError(status, body, requestIdFromHeader) {
250
+ const parsed = parseErrorPayload(body, `Request failed with status ${status}`, requestIdFromHeader);
251
+ const common = {
252
+ status,
253
+ code: parsed.code,
254
+ requestId: parsed.requestId,
255
+ details: parsed.details,
256
+ raw: parsed.raw,
257
+ };
258
+ if (status === 401) {
259
+ return new AuthenticationError(parsed.message, common);
260
+ }
261
+ if (status === 403) {
262
+ return new PermissionError(parsed.message, common);
263
+ }
264
+ if (status === 404) {
265
+ return new NotFoundError(parsed.message, common);
266
+ }
267
+ if (status === 409) {
268
+ return new ConflictError(parsed.message, common);
269
+ }
270
+ if (status === 429) {
271
+ return new RateLimitError(parsed.message, common);
272
+ }
273
+ if (status >= 500) {
274
+ return new ServerError(parsed.message, common);
275
+ }
276
+ return new InvalidRequestError(parsed.message, common);
277
+ }
278
+ }
279
+ function resolveFetch(customFetch) {
280
+ if (customFetch) {
281
+ return customFetch;
282
+ }
283
+ if (typeof fetch !== "function") {
284
+ throw new Error("Global fetch is not available. Inject a fetch implementation via Client options.");
285
+ }
286
+ return fetch;
287
+ }
288
+ function normalizeBaseUrl(baseUrl) {
289
+ if (!baseUrl) {
290
+ throw new Error("Client baseUrl cannot be empty.");
291
+ }
292
+ return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
293
+ }
294
+ function resolveDefaultAuth() {
295
+ const scheme = resolveAuthScheme(DEFAULT_AUTH_SCHEME);
296
+ if (scheme === "api_key_header") {
297
+ const headerName = DEFAULT_AUTH_HEADER_NAME;
298
+ return { scheme, headerName };
299
+ }
300
+ return { scheme };
301
+ }
302
+ function resolveAuthScheme(value) {
303
+ if (value === "basic" || value === "api_key_header" || value === "bearer") {
304
+ return value;
305
+ }
306
+ return "bearer";
307
+ }
308
+ function resolveEnvironmentBaseUrl(environment) {
309
+ if (environment === "sandbox") {
310
+ return SANDBOX_BASE_URL;
311
+ }
312
+ return PRODUCTION_BASE_URL;
313
+ }
314
+ function resolvePlaceholder(value) {
315
+ if (!value) {
316
+ return undefined;
317
+ }
318
+ if (value.includes("{{") && value.includes("}}")) {
319
+ return undefined;
320
+ }
321
+ return value;
322
+ }
323
+ function extractRequestId(headers) {
324
+ return headers.get("x-request-id") ?? headers.get("request-id") ?? undefined;
325
+ }
326
+ function extractRequestIdFromBody(body) {
327
+ if (!body || typeof body !== "object") {
328
+ return undefined;
329
+ }
330
+ const record = body;
331
+ if (typeof record.requestId === "string") {
332
+ return record.requestId;
333
+ }
334
+ if (typeof record.request_id === "string") {
335
+ return record.request_id;
336
+ }
337
+ return undefined;
338
+ }
339
+ function toMeta(raw) {
340
+ return {
341
+ status: raw.status,
342
+ headers: raw.headers,
343
+ requestId: raw.requestId,
344
+ };
345
+ }
346
+ function isDataEnvelope(value) {
347
+ return typeof value.success === "boolean" && "data" in value;
348
+ }
349
+ function isPaginatedEnvelope(value) {
350
+ return (typeof value.success === "boolean" &&
351
+ Array.isArray(value.data) &&
352
+ Boolean(value.metadata) &&
353
+ typeof value.metadata?.page === "number" &&
354
+ typeof value.metadata?.limit === "number" &&
355
+ typeof value.metadata?.total === "number");
356
+ }
357
+ function isRetryEligible(method, idempotencyKey) {
358
+ if (method === "GET" || method === "HEAD") {
359
+ return true;
360
+ }
361
+ if ((method === "POST" || method === "PUT") && Boolean(idempotencyKey)) {
362
+ return true;
363
+ }
364
+ return false;
365
+ }
366
+ async function parseBody(response) {
367
+ const contentType = response.headers.get("content-type") ?? "";
368
+ if (contentType.includes("application/json")) {
369
+ try {
370
+ return await response.json();
371
+ }
372
+ catch {
373
+ return null;
374
+ }
375
+ }
376
+ const text = await response.text();
377
+ if (!text) {
378
+ return null;
379
+ }
380
+ try {
381
+ return JSON.parse(text);
382
+ }
383
+ catch {
384
+ return text;
385
+ }
386
+ }
387
+ function parseRetryAfterMs(retryAfterValue) {
388
+ if (!retryAfterValue) {
389
+ return undefined;
390
+ }
391
+ const numeric = Number(retryAfterValue);
392
+ if (Number.isFinite(numeric)) {
393
+ return Math.max(0, numeric * 1_000);
394
+ }
395
+ const parsedDate = Date.parse(retryAfterValue);
396
+ if (!Number.isNaN(parsedDate)) {
397
+ return Math.max(0, parsedDate - Date.now());
398
+ }
399
+ return undefined;
400
+ }
401
+ function computeRetryDelayMs(attempt, retryAfterValue, baseDelayMs, maxDelayMs) {
402
+ const retryAfterMs = parseRetryAfterMs(retryAfterValue);
403
+ if (typeof retryAfterMs === "number") {
404
+ return Math.min(retryAfterMs, maxDelayMs);
405
+ }
406
+ const backoff = baseDelayMs * 2 ** attempt;
407
+ const jitter = Math.floor(Math.random() * baseDelayMs);
408
+ return Math.min(backoff + jitter, maxDelayMs);
409
+ }
410
+ function sleep(ms) {
411
+ if (ms <= 0) {
412
+ return Promise.resolve();
413
+ }
414
+ return new Promise((resolve) => setTimeout(resolve, ms));
415
+ }
416
+ function isAbortError(error) {
417
+ if (error instanceof DOMException && error.name === "AbortError") {
418
+ return true;
419
+ }
420
+ if (!error || typeof error !== "object") {
421
+ return false;
422
+ }
423
+ return error.name === "AbortError";
424
+ }
425
+ function encodeBase64(input) {
426
+ if (typeof btoa === "function") {
427
+ return btoa(input);
428
+ }
429
+ const bytes = new TextEncoder().encode(input);
430
+ let binary = "";
431
+ for (const byte of bytes) {
432
+ binary += String.fromCharCode(byte);
433
+ }
434
+ if (typeof btoa !== "function") {
435
+ throw new Error("Base64 encoding is unavailable in this runtime.");
436
+ }
437
+ return btoa(binary);
438
+ }
439
+ function detectRuntime() {
440
+ if (typeof Deno !== "undefined") {
441
+ return "deno";
442
+ }
443
+ if (typeof Bun !== "undefined") {
444
+ return "bun";
445
+ }
446
+ return "node";
447
+ }
448
+ //# sourceMappingURL=client.js.map