@havenpay/server 1.0.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/LICENSE +22 -0
- package/README.md +160 -0
- package/dist/index.cjs +1083 -0
- package/dist/index.d.cts +479 -0
- package/dist/index.d.ts +479 -0
- package/dist/index.js +1054 -0
- package/package.json +63 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,1054 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var HavenpayApiError = class extends Error {
|
|
3
|
+
constructor(options) {
|
|
4
|
+
super(`Havenpay API Error: ${options.status} ${options.body}`);
|
|
5
|
+
this.name = "HavenpayApiError";
|
|
6
|
+
this.body = options.body;
|
|
7
|
+
this.status = options.status;
|
|
8
|
+
if (options.requestId)
|
|
9
|
+
this.requestId = options.requestId;
|
|
10
|
+
if (options.error) {
|
|
11
|
+
this.error = options.error;
|
|
12
|
+
if (options.error.code)
|
|
13
|
+
this.code = options.error.code;
|
|
14
|
+
if (options.error.type)
|
|
15
|
+
this.type = options.error.type;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var HavenpayTimeoutError = class extends Error {
|
|
20
|
+
constructor(timeoutMs) {
|
|
21
|
+
super(`Havenpay request timed out after ${timeoutMs}ms`);
|
|
22
|
+
this.name = "HavenpayTimeoutError";
|
|
23
|
+
this.timeoutMs = timeoutMs;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
function parseHavenpayApiErrorDetails(parsed) {
|
|
27
|
+
if (!isRecord(parsed) || !isRecord(parsed.error))
|
|
28
|
+
return void 0;
|
|
29
|
+
const result = {};
|
|
30
|
+
if (typeof parsed.error.code === "string")
|
|
31
|
+
result.code = parsed.error.code;
|
|
32
|
+
if (typeof parsed.error.message === "string")
|
|
33
|
+
result.message = parsed.error.message;
|
|
34
|
+
if (typeof parsed.error.request_id === "string")
|
|
35
|
+
result.requestId = parsed.error.request_id;
|
|
36
|
+
if (typeof parsed.error.type === "string")
|
|
37
|
+
result.type = parsed.error.type;
|
|
38
|
+
return Object.keys(result).length > 0 ? result : void 0;
|
|
39
|
+
}
|
|
40
|
+
function isRecord(value) {
|
|
41
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// src/resources/Accounts.ts
|
|
45
|
+
import { API_V1_OPERATIONS } from "@havenpay/core/api-v1";
|
|
46
|
+
|
|
47
|
+
// src/resources/http.ts
|
|
48
|
+
function baseUrl(config) {
|
|
49
|
+
const value = config.baseUrl || "https://pay.7haven.online/api";
|
|
50
|
+
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
51
|
+
}
|
|
52
|
+
function authHeaders(config) {
|
|
53
|
+
return {
|
|
54
|
+
...apiVersionHeaders(config),
|
|
55
|
+
"X-API-Key": config.secretKey
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function bearerHeaders(config) {
|
|
59
|
+
return {
|
|
60
|
+
...apiVersionHeaders(config),
|
|
61
|
+
Authorization: `Bearer ${config.secretKey}`
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function jsonHeaders(config, extraHeaders = {}) {
|
|
65
|
+
return {
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
...authHeaders(config),
|
|
68
|
+
...extraHeaders
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function pathWithParams(path, params) {
|
|
72
|
+
return path.replace(/\{([^}]+)\}/g, (_match, key) => encodeURIComponent(params[key] ?? ""));
|
|
73
|
+
}
|
|
74
|
+
function withQuery(path, params) {
|
|
75
|
+
const query = new URLSearchParams();
|
|
76
|
+
for (const [key, value] of Object.entries(params)) {
|
|
77
|
+
if (value !== void 0)
|
|
78
|
+
query.set(key, String(value));
|
|
79
|
+
}
|
|
80
|
+
const encoded = query.toString();
|
|
81
|
+
return encoded ? `${path}?${encoded}` : path;
|
|
82
|
+
}
|
|
83
|
+
async function request(config, input, init, options = {}) {
|
|
84
|
+
const retry = retryOptions(config);
|
|
85
|
+
const canRetry = canRetryRequest(init);
|
|
86
|
+
const eventBase = requestEventBase(input, init, options);
|
|
87
|
+
let attempt = 1;
|
|
88
|
+
while (true) {
|
|
89
|
+
const timeout = timeoutRequestInit(config, init);
|
|
90
|
+
emitRequestEvent(config, { ...eventBase, attempt, type: "request_start" });
|
|
91
|
+
try {
|
|
92
|
+
const response = await fetch(input, timeout.init);
|
|
93
|
+
if (shouldRetryResponse(response, retry.maxAttempts, attempt, canRetry)) {
|
|
94
|
+
emitRequestEvent(config, {
|
|
95
|
+
...eventBase,
|
|
96
|
+
attempt,
|
|
97
|
+
errorKind: "api_error",
|
|
98
|
+
requestId: response.headers.get("x-request-id") ?? void 0,
|
|
99
|
+
status: response.status,
|
|
100
|
+
type: "request_retry"
|
|
101
|
+
});
|
|
102
|
+
} else {
|
|
103
|
+
emitRequestEvent(config, finalResponseEvent(eventBase, response, attempt));
|
|
104
|
+
return response;
|
|
105
|
+
}
|
|
106
|
+
} catch (error) {
|
|
107
|
+
if (timeout.didTimeout()) {
|
|
108
|
+
emitRequestEvent(config, {
|
|
109
|
+
...eventBase,
|
|
110
|
+
attempt,
|
|
111
|
+
errorKind: "timeout",
|
|
112
|
+
type: "request_error"
|
|
113
|
+
});
|
|
114
|
+
throw new HavenpayTimeoutError(timeout.timeoutMs);
|
|
115
|
+
}
|
|
116
|
+
if (shouldRetryError(retry.maxAttempts, attempt, canRetry)) {
|
|
117
|
+
emitRequestEvent(config, {
|
|
118
|
+
...eventBase,
|
|
119
|
+
attempt,
|
|
120
|
+
errorKind: "network_error",
|
|
121
|
+
type: "request_retry"
|
|
122
|
+
});
|
|
123
|
+
} else {
|
|
124
|
+
emitRequestEvent(config, {
|
|
125
|
+
...eventBase,
|
|
126
|
+
attempt,
|
|
127
|
+
errorKind: "network_error",
|
|
128
|
+
type: "request_error"
|
|
129
|
+
});
|
|
130
|
+
throw error;
|
|
131
|
+
}
|
|
132
|
+
} finally {
|
|
133
|
+
timeout.cleanup();
|
|
134
|
+
}
|
|
135
|
+
await retry.sleep(retryDelayMs(retry, attempt));
|
|
136
|
+
attempt += 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function parseJsonObjectResponse(response) {
|
|
140
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
141
|
+
const body = await response.text();
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
const parsed2 = parseJsonBody(body);
|
|
144
|
+
const error = parseHavenpayApiErrorDetails(parsed2);
|
|
145
|
+
throw new HavenpayApiError({
|
|
146
|
+
body,
|
|
147
|
+
error,
|
|
148
|
+
requestId: requestId ?? error?.requestId,
|
|
149
|
+
status: response.status
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
const parsed = JSON.parse(body || "{}");
|
|
153
|
+
return {
|
|
154
|
+
parsed: isRecord2(parsed) ? parsed : {},
|
|
155
|
+
requestId
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async function parseJsonListResponse(response, mapItem) {
|
|
159
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
160
|
+
const data = Array.isArray(parsed.data) ? parsed.data.filter(isRecord2).map((item) => mapItem(item)) : [];
|
|
161
|
+
const result = {
|
|
162
|
+
data,
|
|
163
|
+
hasMore: Boolean(parsed.has_more),
|
|
164
|
+
requestId
|
|
165
|
+
};
|
|
166
|
+
if (typeof parsed.next_cursor === "string")
|
|
167
|
+
result.nextCursor = parsed.next_cursor;
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
function stringArray(value) {
|
|
171
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
172
|
+
}
|
|
173
|
+
function isRecord2(value) {
|
|
174
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
175
|
+
}
|
|
176
|
+
function apiVersionHeaders(config) {
|
|
177
|
+
return config.apiVersion ? { "X-Haven-API-Version": config.apiVersion } : {};
|
|
178
|
+
}
|
|
179
|
+
function retryOptions(config) {
|
|
180
|
+
return {
|
|
181
|
+
initialDelayMs: Math.max(0, config.retry?.initialDelayMs ?? 100),
|
|
182
|
+
maxAttempts: Math.max(1, Math.floor(config.retry?.maxAttempts ?? (config.retry ? 3 : 1))),
|
|
183
|
+
maxDelayMs: Math.max(0, config.retry?.maxDelayMs ?? 2e3),
|
|
184
|
+
sleep: config.retry?.sleep ?? defaultSleep
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function canRetryRequest(init) {
|
|
188
|
+
const method = String(init.method ?? "GET").toUpperCase();
|
|
189
|
+
if (method === "GET" || method === "HEAD")
|
|
190
|
+
return true;
|
|
191
|
+
return Boolean(new Headers(init.headers).get("idempotency-key"));
|
|
192
|
+
}
|
|
193
|
+
function shouldRetryResponse(response, maxAttempts, attempt, canRetry) {
|
|
194
|
+
return canRetry && attempt < maxAttempts && response.status >= 500 && response.status <= 599;
|
|
195
|
+
}
|
|
196
|
+
function shouldRetryError(maxAttempts, attempt, canRetry) {
|
|
197
|
+
return canRetry && attempt < maxAttempts;
|
|
198
|
+
}
|
|
199
|
+
function retryDelayMs(retry, attempt) {
|
|
200
|
+
const delay = retry.initialDelayMs * 2 ** Math.max(0, attempt - 1);
|
|
201
|
+
return Math.min(delay, retry.maxDelayMs);
|
|
202
|
+
}
|
|
203
|
+
async function defaultSleep(delayMs) {
|
|
204
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
205
|
+
}
|
|
206
|
+
function timeoutRequestInit(config, init) {
|
|
207
|
+
const timeoutMs = timeoutMsOrZero(config);
|
|
208
|
+
if (timeoutMs === 0) {
|
|
209
|
+
return {
|
|
210
|
+
cleanup: () => {
|
|
211
|
+
},
|
|
212
|
+
didTimeout: () => false,
|
|
213
|
+
init,
|
|
214
|
+
timeoutMs
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
const controller = new AbortController();
|
|
218
|
+
let timedOut = false;
|
|
219
|
+
let callerAbortListener;
|
|
220
|
+
const timeoutId = setTimeout(() => {
|
|
221
|
+
timedOut = true;
|
|
222
|
+
controller.abort(new HavenpayTimeoutError(timeoutMs));
|
|
223
|
+
}, timeoutMs);
|
|
224
|
+
if (init.signal) {
|
|
225
|
+
if (init.signal.aborted) {
|
|
226
|
+
clearTimeout(timeoutId);
|
|
227
|
+
controller.abort(init.signal.reason);
|
|
228
|
+
} else {
|
|
229
|
+
callerAbortListener = () => {
|
|
230
|
+
clearTimeout(timeoutId);
|
|
231
|
+
controller.abort(init.signal?.reason);
|
|
232
|
+
};
|
|
233
|
+
init.signal.addEventListener("abort", callerAbortListener, { once: true });
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
cleanup: () => {
|
|
238
|
+
clearTimeout(timeoutId);
|
|
239
|
+
if (callerAbortListener)
|
|
240
|
+
init.signal?.removeEventListener("abort", callerAbortListener);
|
|
241
|
+
},
|
|
242
|
+
didTimeout: () => timedOut,
|
|
243
|
+
init: {
|
|
244
|
+
...init,
|
|
245
|
+
signal: controller.signal
|
|
246
|
+
},
|
|
247
|
+
timeoutMs
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function timeoutMsOrZero(config) {
|
|
251
|
+
if (config.timeoutMs === void 0)
|
|
252
|
+
return 0;
|
|
253
|
+
return Math.max(0, Math.floor(config.timeoutMs));
|
|
254
|
+
}
|
|
255
|
+
function requestEventBase(input, init, options) {
|
|
256
|
+
const base = {
|
|
257
|
+
method: String(init.method ?? "GET").toUpperCase(),
|
|
258
|
+
path: requestPath(input)
|
|
259
|
+
};
|
|
260
|
+
if (options.operationName)
|
|
261
|
+
base.operationName = options.operationName;
|
|
262
|
+
return base;
|
|
263
|
+
}
|
|
264
|
+
function requestPath(input) {
|
|
265
|
+
if (typeof input === "string") {
|
|
266
|
+
try {
|
|
267
|
+
return new URL(input).pathname;
|
|
268
|
+
} catch {
|
|
269
|
+
return input.split("?")[0] ?? input;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (input instanceof URL)
|
|
273
|
+
return input.pathname;
|
|
274
|
+
return new URL(input.url).pathname;
|
|
275
|
+
}
|
|
276
|
+
function finalResponseEvent(base, response, attempt) {
|
|
277
|
+
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
278
|
+
if (response.ok) {
|
|
279
|
+
return {
|
|
280
|
+
...base,
|
|
281
|
+
attempt,
|
|
282
|
+
requestId,
|
|
283
|
+
status: response.status,
|
|
284
|
+
type: "request_success"
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
...base,
|
|
289
|
+
attempt,
|
|
290
|
+
errorKind: "api_error",
|
|
291
|
+
requestId,
|
|
292
|
+
status: response.status,
|
|
293
|
+
type: "request_error"
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function emitRequestEvent(config, event) {
|
|
297
|
+
try {
|
|
298
|
+
config.onRequestEvent?.(event);
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function parseJsonBody(body) {
|
|
303
|
+
try {
|
|
304
|
+
return JSON.parse(body || "{}");
|
|
305
|
+
} catch {
|
|
306
|
+
return void 0;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// src/resources/Accounts.ts
|
|
311
|
+
var Accounts = class {
|
|
312
|
+
constructor(config) {
|
|
313
|
+
this.config = config;
|
|
314
|
+
}
|
|
315
|
+
async create(params) {
|
|
316
|
+
const operation = API_V1_OPERATIONS.createAccount;
|
|
317
|
+
const response = await request(this.config, `${baseUrl(this.config)}${operation.path}`, {
|
|
318
|
+
method: operation.method,
|
|
319
|
+
headers: jsonHeaders(this.config),
|
|
320
|
+
body: JSON.stringify(accountPayload(params))
|
|
321
|
+
}, {
|
|
322
|
+
operationName: "createAccount"
|
|
323
|
+
});
|
|
324
|
+
return parseAccountResponse(response);
|
|
325
|
+
}
|
|
326
|
+
async list(params = {}) {
|
|
327
|
+
const operation = API_V1_OPERATIONS.listAccounts;
|
|
328
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
329
|
+
limit: params.limit,
|
|
330
|
+
starting_after: params.startingAfter
|
|
331
|
+
})}`, {
|
|
332
|
+
method: operation.method,
|
|
333
|
+
headers: authHeaders(this.config)
|
|
334
|
+
}, {
|
|
335
|
+
operationName: "listAccounts"
|
|
336
|
+
});
|
|
337
|
+
return parseAccountListResponse(response);
|
|
338
|
+
}
|
|
339
|
+
async update(id, params) {
|
|
340
|
+
const operation = API_V1_OPERATIONS.updateAccount;
|
|
341
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
342
|
+
method: operation.method,
|
|
343
|
+
headers: jsonHeaders(this.config),
|
|
344
|
+
body: JSON.stringify(accountPayload(params))
|
|
345
|
+
}, {
|
|
346
|
+
operationName: "updateAccount"
|
|
347
|
+
});
|
|
348
|
+
return parseAccountResponse(response);
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
function accountPayload(params) {
|
|
352
|
+
return {
|
|
353
|
+
...params.capabilities !== void 0 ? { capabilities: params.capabilities } : {},
|
|
354
|
+
...params.displayName !== void 0 ? { display_name: params.displayName } : {},
|
|
355
|
+
...params.email !== void 0 ? { email: params.email } : {},
|
|
356
|
+
..."livemode" in params && params.livemode !== void 0 ? { livemode: params.livemode } : {},
|
|
357
|
+
...params.metadata !== void 0 ? { metadata: params.metadata } : {},
|
|
358
|
+
..."status" in params && params.status !== void 0 ? { status: params.status } : {}
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
async function parseAccountResponse(response) {
|
|
362
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
363
|
+
return toAccountResponse(parsed, requestId);
|
|
364
|
+
}
|
|
365
|
+
async function parseAccountListResponse(response) {
|
|
366
|
+
return parseJsonListResponse(response, toAccountResponse);
|
|
367
|
+
}
|
|
368
|
+
function toAccountResponse(parsed, requestId) {
|
|
369
|
+
return {
|
|
370
|
+
accountRole: String(parsed.account_role ?? "connected"),
|
|
371
|
+
capabilities: normalizeAccountCapabilities(parsed.capabilities),
|
|
372
|
+
createdAt: String(parsed.created_at ?? ""),
|
|
373
|
+
displayName: String(parsed.display_name ?? ""),
|
|
374
|
+
email: String(parsed.email ?? ""),
|
|
375
|
+
id: String(parsed.id ?? ""),
|
|
376
|
+
livemode: Boolean(parsed.livemode),
|
|
377
|
+
metadata: isRecord2(parsed.metadata) ? parsed.metadata : {},
|
|
378
|
+
ownerAccountId: typeof parsed.owner_account_id === "string" ? parsed.owner_account_id : null,
|
|
379
|
+
requestId,
|
|
380
|
+
status: String(parsed.status ?? "draft"),
|
|
381
|
+
updatedAt: String(parsed.updated_at ?? "")
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
function normalizeAccountCapabilities(value) {
|
|
385
|
+
const fallback = {
|
|
386
|
+
card_payments: false,
|
|
387
|
+
mobile_money_payments: false,
|
|
388
|
+
payouts: false,
|
|
389
|
+
refunds: false,
|
|
390
|
+
test_mode: true,
|
|
391
|
+
webhooks: false
|
|
392
|
+
};
|
|
393
|
+
if (!isRecord2(value))
|
|
394
|
+
return fallback;
|
|
395
|
+
return {
|
|
396
|
+
card_payments: typeof value.card_payments === "boolean" ? value.card_payments : fallback.card_payments,
|
|
397
|
+
mobile_money_payments: typeof value.mobile_money_payments === "boolean" ? value.mobile_money_payments : fallback.mobile_money_payments,
|
|
398
|
+
payouts: typeof value.payouts === "boolean" ? value.payouts : fallback.payouts,
|
|
399
|
+
refunds: typeof value.refunds === "boolean" ? value.refunds : fallback.refunds,
|
|
400
|
+
test_mode: typeof value.test_mode === "boolean" ? value.test_mode : fallback.test_mode,
|
|
401
|
+
webhooks: typeof value.webhooks === "boolean" ? value.webhooks : fallback.webhooks
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// src/resources/ApiKeys.ts
|
|
406
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS2 } from "@havenpay/core/api-v1";
|
|
407
|
+
var ApiKeys = class {
|
|
408
|
+
constructor(config) {
|
|
409
|
+
this.config = config;
|
|
410
|
+
}
|
|
411
|
+
async create(params) {
|
|
412
|
+
const operation = API_V1_OPERATIONS2.createApiKey;
|
|
413
|
+
const response = await request(this.config, `${baseUrl(this.config)}${operation.path}`, {
|
|
414
|
+
method: operation.method,
|
|
415
|
+
headers: jsonHeaders(this.config),
|
|
416
|
+
body: JSON.stringify({
|
|
417
|
+
display_name: params.displayName,
|
|
418
|
+
...params.scopes ? { scopes: params.scopes } : {}
|
|
419
|
+
})
|
|
420
|
+
}, {
|
|
421
|
+
operationName: "createApiKey"
|
|
422
|
+
});
|
|
423
|
+
return parseApiKeyResponse(response);
|
|
424
|
+
}
|
|
425
|
+
async list(params = {}) {
|
|
426
|
+
const operation = API_V1_OPERATIONS2.listApiKeys;
|
|
427
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
428
|
+
account_id: params.accountId,
|
|
429
|
+
limit: params.limit,
|
|
430
|
+
starting_after: params.startingAfter
|
|
431
|
+
})}`, {
|
|
432
|
+
method: operation.method,
|
|
433
|
+
headers: authHeaders(this.config)
|
|
434
|
+
}, {
|
|
435
|
+
operationName: "listApiKeys"
|
|
436
|
+
});
|
|
437
|
+
return parseApiKeyListResponse(response);
|
|
438
|
+
}
|
|
439
|
+
async revoke(id) {
|
|
440
|
+
const operation = API_V1_OPERATIONS2.revokeApiKey;
|
|
441
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
442
|
+
method: operation.method,
|
|
443
|
+
headers: authHeaders(this.config)
|
|
444
|
+
}, {
|
|
445
|
+
operationName: "revokeApiKey"
|
|
446
|
+
});
|
|
447
|
+
return parseApiKeyResponse(response);
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
async function parseApiKeyResponse(response) {
|
|
451
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
452
|
+
return toApiKeyResponse(parsed, requestId);
|
|
453
|
+
}
|
|
454
|
+
async function parseApiKeyListResponse(response) {
|
|
455
|
+
return parseJsonListResponse(response, toApiKeyResponse);
|
|
456
|
+
}
|
|
457
|
+
function toApiKeyResponse(parsed, requestId) {
|
|
458
|
+
return {
|
|
459
|
+
accountId: String(parsed.account_id ?? ""),
|
|
460
|
+
createdAt: String(parsed.created_at ?? ""),
|
|
461
|
+
displayName: String(parsed.display_name ?? ""),
|
|
462
|
+
environment: String(parsed.environment ?? "test"),
|
|
463
|
+
expiresAt: typeof parsed.expires_at === "string" ? parsed.expires_at : null,
|
|
464
|
+
id: String(parsed.id ?? ""),
|
|
465
|
+
lastUsedAt: typeof parsed.last_used_at === "string" ? parsed.last_used_at : null,
|
|
466
|
+
prefix: String(parsed.prefix ?? ""),
|
|
467
|
+
requestId,
|
|
468
|
+
revokedAt: typeof parsed.revoked_at === "string" ? parsed.revoked_at : null,
|
|
469
|
+
scopes: Array.isArray(parsed.scopes) ? parsed.scopes.filter((scope) => typeof scope === "string") : [],
|
|
470
|
+
secretKey: typeof parsed.secret_key === "string" ? parsed.secret_key : void 0
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/resources/BalanceTransactions.ts
|
|
475
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS3 } from "@havenpay/core/api-v1";
|
|
476
|
+
var BalanceTransactions = class {
|
|
477
|
+
constructor(config) {
|
|
478
|
+
this.config = config;
|
|
479
|
+
}
|
|
480
|
+
async list(params = {}) {
|
|
481
|
+
const operation = API_V1_OPERATIONS3.listBalanceTransactions;
|
|
482
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
483
|
+
currency: params.currency,
|
|
484
|
+
limit: params.limit,
|
|
485
|
+
payment_intent_id: params.paymentIntentId,
|
|
486
|
+
project_id: params.projectId,
|
|
487
|
+
starting_after: params.startingAfter
|
|
488
|
+
})}`, {
|
|
489
|
+
method: operation.method,
|
|
490
|
+
headers: authHeaders(this.config)
|
|
491
|
+
}, {
|
|
492
|
+
operationName: "listBalanceTransactions"
|
|
493
|
+
});
|
|
494
|
+
return parseBalanceTransactionListResponse(response);
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
async function parseBalanceTransactionListResponse(response) {
|
|
498
|
+
return parseJsonListResponse(response, toBalanceTransactionResponse);
|
|
499
|
+
}
|
|
500
|
+
function toBalanceTransactionResponse(parsed) {
|
|
501
|
+
return {
|
|
502
|
+
accountId: String(parsed.account_id ?? ""),
|
|
503
|
+
amount: Number(parsed.amount ?? 0),
|
|
504
|
+
balanceAfter: Number(parsed.balance_after ?? 0),
|
|
505
|
+
balanceBefore: Number(parsed.balance_before ?? 0),
|
|
506
|
+
createdAt: String(parsed.created_at ?? ""),
|
|
507
|
+
currency: String(parsed.currency ?? "usd"),
|
|
508
|
+
description: String(parsed.description ?? ""),
|
|
509
|
+
id: String(parsed.id ?? ""),
|
|
510
|
+
metadata: isRecord2(parsed.metadata) ? parsed.metadata : {},
|
|
511
|
+
paymentIntentId: typeof parsed.payment_intent_id === "string" ? parsed.payment_intent_id : null,
|
|
512
|
+
projectId: typeof parsed.project_id === "string" ? parsed.project_id : null,
|
|
513
|
+
type: String(parsed.type ?? "payment")
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// src/resources/Events.ts
|
|
518
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS4 } from "@havenpay/core/api-v1";
|
|
519
|
+
var Events = class {
|
|
520
|
+
constructor(config) {
|
|
521
|
+
this.config = config;
|
|
522
|
+
}
|
|
523
|
+
async list(params = {}) {
|
|
524
|
+
const operation = API_V1_OPERATIONS4.listEvents;
|
|
525
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
526
|
+
project_id: params.projectId,
|
|
527
|
+
limit: params.limit,
|
|
528
|
+
starting_after: params.startingAfter
|
|
529
|
+
})}`, {
|
|
530
|
+
method: operation.method,
|
|
531
|
+
headers: authHeaders(this.config)
|
|
532
|
+
}, {
|
|
533
|
+
operationName: "listEvents"
|
|
534
|
+
});
|
|
535
|
+
return parseEventListResponse(response);
|
|
536
|
+
}
|
|
537
|
+
async replay(id) {
|
|
538
|
+
const operation = API_V1_OPERATIONS4.replayEvent;
|
|
539
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
540
|
+
method: operation.method,
|
|
541
|
+
headers: authHeaders(this.config)
|
|
542
|
+
}, {
|
|
543
|
+
operationName: "replayEvent"
|
|
544
|
+
});
|
|
545
|
+
return parseReplayEventResponse(response);
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
async function parseEventListResponse(response) {
|
|
549
|
+
return parseJsonListResponse(response, toEventResponse);
|
|
550
|
+
}
|
|
551
|
+
async function parseReplayEventResponse(response) {
|
|
552
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
553
|
+
return {
|
|
554
|
+
id: String(parsed.id ?? ""),
|
|
555
|
+
requestId,
|
|
556
|
+
status: String(parsed.status ?? "pending")
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
function toEventResponse(parsed) {
|
|
560
|
+
return {
|
|
561
|
+
accountId: String(parsed.account_id ?? ""),
|
|
562
|
+
apiVersion: String(parsed.api_version ?? ""),
|
|
563
|
+
created: String(parsed.created ?? ""),
|
|
564
|
+
data: isRecord2(parsed.data) ? parsed.data : {},
|
|
565
|
+
id: String(parsed.id ?? ""),
|
|
566
|
+
livemode: Boolean(parsed.livemode),
|
|
567
|
+
objectId: String(parsed.object_id ?? ""),
|
|
568
|
+
pendingWebhookEndpoints: stringArray(parsed.pending_webhook_endpoints),
|
|
569
|
+
projectId: String(parsed.project_id ?? ""),
|
|
570
|
+
status: String(parsed.status ?? "pending"),
|
|
571
|
+
type: String(parsed.type ?? "payment_intent.created")
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// src/resources/PaymentIntents.ts
|
|
576
|
+
import { randomUUID } from "crypto";
|
|
577
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS5 } from "@havenpay/core/api-v1";
|
|
578
|
+
var PaymentIntents = class {
|
|
579
|
+
constructor(config) {
|
|
580
|
+
this.config = config;
|
|
581
|
+
}
|
|
582
|
+
async create(params) {
|
|
583
|
+
const operation = API_V1_OPERATIONS5.createPaymentIntent;
|
|
584
|
+
const url = `${baseUrl(this.config)}${operation.path}`;
|
|
585
|
+
const idempotencyKey = params.idempotencyKey || randomUUID();
|
|
586
|
+
const headers = {
|
|
587
|
+
...bearerHeaders(this.config),
|
|
588
|
+
"Content-Type": "application/json",
|
|
589
|
+
"Idempotency-Key": idempotencyKey
|
|
590
|
+
};
|
|
591
|
+
const response = await request(this.config, url, {
|
|
592
|
+
method: operation.method,
|
|
593
|
+
headers,
|
|
594
|
+
body: JSON.stringify({
|
|
595
|
+
amount: params.amount,
|
|
596
|
+
currency: params.currency,
|
|
597
|
+
customer: params.customer,
|
|
598
|
+
idempotency_key: idempotencyKey,
|
|
599
|
+
metadata: params.metadata,
|
|
600
|
+
mobile_money: params.mobileMoney,
|
|
601
|
+
payment_method_type: "mobile_money",
|
|
602
|
+
project_id: params.projectId
|
|
603
|
+
})
|
|
604
|
+
}, {
|
|
605
|
+
operationName: "createPaymentIntent"
|
|
606
|
+
});
|
|
607
|
+
return parsePaymentIntentResponse(response);
|
|
608
|
+
}
|
|
609
|
+
async retrieve(id) {
|
|
610
|
+
const operation = API_V1_OPERATIONS5.retrievePaymentIntent;
|
|
611
|
+
const url = `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`;
|
|
612
|
+
const response = await request(this.config, url, {
|
|
613
|
+
method: operation.method,
|
|
614
|
+
headers: bearerHeaders(this.config)
|
|
615
|
+
}, {
|
|
616
|
+
operationName: "retrievePaymentIntent"
|
|
617
|
+
});
|
|
618
|
+
return parsePaymentIntentResponse(response);
|
|
619
|
+
}
|
|
620
|
+
};
|
|
621
|
+
async function parsePaymentIntentResponse(response) {
|
|
622
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
623
|
+
return {
|
|
624
|
+
amount: Number(parsed.amount ?? 0),
|
|
625
|
+
clientSecret: String(parsed.client_secret ?? parsed.clientSecret ?? ""),
|
|
626
|
+
currency: String(parsed.currency ?? "usd"),
|
|
627
|
+
customer: isRecord2(parsed.customer) ? parsed.customer : void 0,
|
|
628
|
+
id: String(parsed.id),
|
|
629
|
+
nextAction: isRecord2(parsed.next_action) ? parsed.next_action : isRecord2(parsed.nextAction) ? parsed.nextAction : void 0,
|
|
630
|
+
requestId,
|
|
631
|
+
status: String(parsed.status)
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// src/resources/Projects.ts
|
|
636
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS6 } from "@havenpay/core/api-v1";
|
|
637
|
+
var Projects = class {
|
|
638
|
+
constructor(config) {
|
|
639
|
+
this.config = config;
|
|
640
|
+
}
|
|
641
|
+
async create(params) {
|
|
642
|
+
const operation = API_V1_OPERATIONS6.createProject;
|
|
643
|
+
const response = await request(this.config, `${baseUrl(this.config)}${operation.path}`, {
|
|
644
|
+
method: operation.method,
|
|
645
|
+
headers: jsonHeaders(this.config),
|
|
646
|
+
body: JSON.stringify(projectPayload(params))
|
|
647
|
+
}, {
|
|
648
|
+
operationName: "createProject"
|
|
649
|
+
});
|
|
650
|
+
return parseProjectResponse(response);
|
|
651
|
+
}
|
|
652
|
+
async list(params = {}) {
|
|
653
|
+
const operation = API_V1_OPERATIONS6.listProjects;
|
|
654
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
655
|
+
limit: params.limit,
|
|
656
|
+
starting_after: params.startingAfter
|
|
657
|
+
})}`, {
|
|
658
|
+
method: operation.method,
|
|
659
|
+
headers: authHeaders(this.config)
|
|
660
|
+
}, {
|
|
661
|
+
operationName: "listProjects"
|
|
662
|
+
});
|
|
663
|
+
return parseProjectListResponse(response);
|
|
664
|
+
}
|
|
665
|
+
async update(id, params) {
|
|
666
|
+
const operation = API_V1_OPERATIONS6.updateProject;
|
|
667
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { project_id: id })}`, {
|
|
668
|
+
method: operation.method,
|
|
669
|
+
headers: jsonHeaders(this.config),
|
|
670
|
+
body: JSON.stringify(projectPayload(params))
|
|
671
|
+
}, {
|
|
672
|
+
operationName: "updateProject"
|
|
673
|
+
});
|
|
674
|
+
return parseProjectResponse(response);
|
|
675
|
+
}
|
|
676
|
+
async archive(id) {
|
|
677
|
+
const operation = API_V1_OPERATIONS6.archiveProject;
|
|
678
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { project_id: id })}`, {
|
|
679
|
+
method: operation.method,
|
|
680
|
+
headers: authHeaders(this.config)
|
|
681
|
+
}, {
|
|
682
|
+
operationName: "archiveProject"
|
|
683
|
+
});
|
|
684
|
+
return parseProjectResponse(response);
|
|
685
|
+
}
|
|
686
|
+
async getConfig(id) {
|
|
687
|
+
const operation = API_V1_OPERATIONS6.getProjectConfig;
|
|
688
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { project_id: id })}`, {
|
|
689
|
+
method: operation.method
|
|
690
|
+
}, {
|
|
691
|
+
operationName: "getProjectConfig"
|
|
692
|
+
});
|
|
693
|
+
return parseProjectResponse(response);
|
|
694
|
+
}
|
|
695
|
+
};
|
|
696
|
+
function projectPayload(params) {
|
|
697
|
+
return {
|
|
698
|
+
...params.allowedBundleIds !== void 0 ? { allowed_bundle_ids: params.allowedBundleIds } : {},
|
|
699
|
+
...params.allowedCurrencies !== void 0 ? { allowed_currencies: params.allowedCurrencies } : {},
|
|
700
|
+
...params.allowedOrigins !== void 0 ? { allowed_origins: params.allowedOrigins } : {},
|
|
701
|
+
...params.allowedPaymentMethods !== void 0 ? { allowed_payment_methods: params.allowedPaymentMethods } : {},
|
|
702
|
+
...params.allowedReturnUrls !== void 0 ? { allowed_return_urls: params.allowedReturnUrls } : {},
|
|
703
|
+
...params.appearance !== void 0 ? { appearance: params.appearance } : {},
|
|
704
|
+
...params.displayName !== void 0 ? { display_name: params.displayName } : {},
|
|
705
|
+
..."environment" in params && params.environment !== void 0 ? { environment: params.environment } : {},
|
|
706
|
+
...params.rateLimitProfile !== void 0 ? { rate_limit_profile: params.rateLimitProfile } : {},
|
|
707
|
+
..."status" in params && params.status !== void 0 ? { status: params.status } : {}
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
async function parseProjectResponse(response) {
|
|
711
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
712
|
+
return toProjectResponse(parsed, requestId);
|
|
713
|
+
}
|
|
714
|
+
async function parseProjectListResponse(response) {
|
|
715
|
+
return parseJsonListResponse(response, toProjectResponse);
|
|
716
|
+
}
|
|
717
|
+
function toProjectResponse(parsed, requestId) {
|
|
718
|
+
return {
|
|
719
|
+
accountId: typeof parsed.account_id === "string" ? parsed.account_id : void 0,
|
|
720
|
+
allowedBundleIds: stringArray(parsed.allowed_bundle_ids),
|
|
721
|
+
allowedCurrencies: stringArray(parsed.allowed_currencies),
|
|
722
|
+
allowedOrigins: stringArray(parsed.allowed_origins),
|
|
723
|
+
allowedPaymentMethods: stringArray(parsed.allowed_payment_methods),
|
|
724
|
+
allowedReturnUrls: stringArray(parsed.allowed_return_urls),
|
|
725
|
+
appearance: isRecord2(parsed.appearance) ? parsed.appearance : {},
|
|
726
|
+
archived: typeof parsed.archived === "boolean" ? parsed.archived : void 0,
|
|
727
|
+
createdAt: typeof parsed.created_at === "string" ? parsed.created_at : void 0,
|
|
728
|
+
deleted: typeof parsed.deleted === "boolean" ? parsed.deleted : void 0,
|
|
729
|
+
displayName: String(parsed.display_name ?? ""),
|
|
730
|
+
environment: String(parsed.environment ?? "test"),
|
|
731
|
+
id: String(parsed.project_id ?? ""),
|
|
732
|
+
paymentHistoryCount: typeof parsed.payment_history_count === "number" ? parsed.payment_history_count : void 0,
|
|
733
|
+
rateLimitProfile: typeof parsed.rate_limit_profile === "string" ? parsed.rate_limit_profile : void 0,
|
|
734
|
+
requestId,
|
|
735
|
+
status: String(parsed.status ?? "active"),
|
|
736
|
+
updatedAt: typeof parsed.updated_at === "string" ? parsed.updated_at : void 0
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// src/resources/ProviderAccounts.ts
|
|
741
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS7 } from "@havenpay/core/api-v1";
|
|
742
|
+
var ProviderAccounts = class {
|
|
743
|
+
constructor(config) {
|
|
744
|
+
this.config = config;
|
|
745
|
+
}
|
|
746
|
+
async create(params) {
|
|
747
|
+
const operation = API_V1_OPERATIONS7.createProviderAccount;
|
|
748
|
+
const response = await request(this.config, `${baseUrl(this.config)}${operation.path}`, {
|
|
749
|
+
method: operation.method,
|
|
750
|
+
headers: jsonHeaders(this.config),
|
|
751
|
+
body: JSON.stringify({
|
|
752
|
+
encrypted_credential_ref: params.encryptedCredentialRef,
|
|
753
|
+
key_fingerprint: params.keyFingerprint,
|
|
754
|
+
...params.metadata ? { metadata: params.metadata } : {},
|
|
755
|
+
project_id: params.projectId,
|
|
756
|
+
provider: params.provider
|
|
757
|
+
})
|
|
758
|
+
}, {
|
|
759
|
+
operationName: "createProviderAccount"
|
|
760
|
+
});
|
|
761
|
+
return parseProviderAccountResponse(response);
|
|
762
|
+
}
|
|
763
|
+
async list(params = {}) {
|
|
764
|
+
const operation = API_V1_OPERATIONS7.listProviderAccounts;
|
|
765
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
766
|
+
project_id: params.projectId,
|
|
767
|
+
limit: params.limit,
|
|
768
|
+
starting_after: params.startingAfter
|
|
769
|
+
})}`, {
|
|
770
|
+
method: operation.method,
|
|
771
|
+
headers: authHeaders(this.config)
|
|
772
|
+
}, {
|
|
773
|
+
operationName: "listProviderAccounts"
|
|
774
|
+
});
|
|
775
|
+
return parseProviderAccountListResponse(response);
|
|
776
|
+
}
|
|
777
|
+
async rotate(id, params) {
|
|
778
|
+
const operation = API_V1_OPERATIONS7.rotateProviderAccount;
|
|
779
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
780
|
+
method: operation.method,
|
|
781
|
+
headers: jsonHeaders(this.config),
|
|
782
|
+
body: JSON.stringify({
|
|
783
|
+
encrypted_credential_ref: params.encryptedCredentialRef,
|
|
784
|
+
key_fingerprint: params.keyFingerprint,
|
|
785
|
+
...params.metadata ? { metadata: params.metadata } : {}
|
|
786
|
+
})
|
|
787
|
+
}, {
|
|
788
|
+
operationName: "rotateProviderAccount"
|
|
789
|
+
});
|
|
790
|
+
return parseProviderAccountResponse(response);
|
|
791
|
+
}
|
|
792
|
+
async revoke(id) {
|
|
793
|
+
const operation = API_V1_OPERATIONS7.revokeProviderAccount;
|
|
794
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
795
|
+
method: operation.method,
|
|
796
|
+
headers: authHeaders(this.config)
|
|
797
|
+
}, {
|
|
798
|
+
operationName: "revokeProviderAccount"
|
|
799
|
+
});
|
|
800
|
+
return parseProviderAccountResponse(response);
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
async function parseProviderAccountResponse(response) {
|
|
804
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
805
|
+
return toProviderAccountResponse(parsed, requestId);
|
|
806
|
+
}
|
|
807
|
+
async function parseProviderAccountListResponse(response) {
|
|
808
|
+
return parseJsonListResponse(response, toProviderAccountResponse);
|
|
809
|
+
}
|
|
810
|
+
function toProviderAccountResponse(parsed, requestId) {
|
|
811
|
+
return {
|
|
812
|
+
accountId: String(parsed.account_id ?? ""),
|
|
813
|
+
createdAt: String(parsed.created_at ?? ""),
|
|
814
|
+
environment: String(parsed.environment ?? "test"),
|
|
815
|
+
id: String(parsed.id ?? ""),
|
|
816
|
+
keyFingerprint: String(parsed.key_fingerprint ?? ""),
|
|
817
|
+
metadata: isRecord2(parsed.metadata) ? parsed.metadata : {},
|
|
818
|
+
projectId: String(parsed.project_id ?? ""),
|
|
819
|
+
provider: String(parsed.provider ?? "fake"),
|
|
820
|
+
requestId,
|
|
821
|
+
revokedAt: typeof parsed.revoked_at === "string" ? parsed.revoked_at : null,
|
|
822
|
+
rotatedFrom: typeof parsed.rotated_from === "string" ? parsed.rotated_from : void 0,
|
|
823
|
+
status: String(parsed.status ?? "active"),
|
|
824
|
+
updatedAt: String(parsed.updated_at ?? "")
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// src/resources/Refunds.ts
|
|
829
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
830
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS8 } from "@havenpay/core/api-v1";
|
|
831
|
+
var Refunds = class {
|
|
832
|
+
constructor(config) {
|
|
833
|
+
this.config = config;
|
|
834
|
+
}
|
|
835
|
+
async create(params) {
|
|
836
|
+
const operation = API_V1_OPERATIONS8.createRefund;
|
|
837
|
+
const idempotencyKey = params.idempotencyKey || randomUUID2();
|
|
838
|
+
const response = await request(this.config, `${baseUrl(this.config)}${operation.path}`, {
|
|
839
|
+
method: operation.method,
|
|
840
|
+
headers: jsonHeaders(this.config, { "Idempotency-Key": idempotencyKey }),
|
|
841
|
+
body: JSON.stringify({
|
|
842
|
+
...params.amount !== void 0 ? { amount: params.amount } : {},
|
|
843
|
+
payment_intent_id: params.paymentIntentId,
|
|
844
|
+
...params.reason ? { reason: params.reason } : {}
|
|
845
|
+
})
|
|
846
|
+
}, {
|
|
847
|
+
operationName: "createRefund"
|
|
848
|
+
});
|
|
849
|
+
return parseRefundResponse(response);
|
|
850
|
+
}
|
|
851
|
+
async retrieve(id, params = {}) {
|
|
852
|
+
const operation = API_V1_OPERATIONS8.retrieveRefund;
|
|
853
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(
|
|
854
|
+
pathWithParams(operation.path, { id }),
|
|
855
|
+
{
|
|
856
|
+
project_id: params.projectId
|
|
857
|
+
}
|
|
858
|
+
)}`, {
|
|
859
|
+
method: operation.method,
|
|
860
|
+
headers: authHeaders(this.config)
|
|
861
|
+
}, {
|
|
862
|
+
operationName: "retrieveRefund"
|
|
863
|
+
});
|
|
864
|
+
return parseRefundResponse(response);
|
|
865
|
+
}
|
|
866
|
+
async list(params = {}) {
|
|
867
|
+
const operation = API_V1_OPERATIONS8.listRefunds;
|
|
868
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
869
|
+
idempotency_key: params.idempotencyKey,
|
|
870
|
+
limit: params.limit,
|
|
871
|
+
project_id: params.projectId,
|
|
872
|
+
provider_refund_reference: params.providerRefundReference,
|
|
873
|
+
starting_after: params.startingAfter
|
|
874
|
+
})}`, {
|
|
875
|
+
method: operation.method,
|
|
876
|
+
headers: authHeaders(this.config)
|
|
877
|
+
}, {
|
|
878
|
+
operationName: "listRefunds"
|
|
879
|
+
});
|
|
880
|
+
return parseRefundListResponse(response);
|
|
881
|
+
}
|
|
882
|
+
};
|
|
883
|
+
async function parseRefundResponse(response) {
|
|
884
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
885
|
+
return toRefundResponse(parsed, requestId);
|
|
886
|
+
}
|
|
887
|
+
async function parseRefundListResponse(response) {
|
|
888
|
+
return parseJsonListResponse(response, toRefundResponse);
|
|
889
|
+
}
|
|
890
|
+
function toRefundResponse(parsed, requestId) {
|
|
891
|
+
return {
|
|
892
|
+
amount: Number(parsed.amount ?? 0),
|
|
893
|
+
currency: String(parsed.currency ?? "usd"),
|
|
894
|
+
id: String(parsed.id),
|
|
895
|
+
idempotencyKey: String(parsed.idempotency_key ?? ""),
|
|
896
|
+
ledgerEntryId: typeof parsed.ledger_entry_id === "string" ? parsed.ledger_entry_id : null,
|
|
897
|
+
paymentIntentId: String(parsed.payment_intent_id ?? ""),
|
|
898
|
+
projectId: String(parsed.project_id ?? ""),
|
|
899
|
+
provider: String(parsed.provider ?? "fake"),
|
|
900
|
+
providerErrorCode: typeof parsed.provider_error_code === "string" ? parsed.provider_error_code : null,
|
|
901
|
+
providerExecution: parsed.provider_execution === "attempted" ? "attempted" : "disabled",
|
|
902
|
+
providerRefundReference: typeof parsed.provider_refund_reference === "string" ? parsed.provider_refund_reference : null,
|
|
903
|
+
reason: typeof parsed.reason === "string" ? parsed.reason : null,
|
|
904
|
+
requestId,
|
|
905
|
+
status: String(parsed.status ?? "pending_provider_execution")
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// src/resources/WebhookEndpoints.ts
|
|
910
|
+
import { API_V1_OPERATIONS as API_V1_OPERATIONS9 } from "@havenpay/core/api-v1";
|
|
911
|
+
var WebhookEndpoints = class {
|
|
912
|
+
constructor(config) {
|
|
913
|
+
this.config = config;
|
|
914
|
+
}
|
|
915
|
+
async create(params) {
|
|
916
|
+
const operation = API_V1_OPERATIONS9.createWebhookEndpoint;
|
|
917
|
+
const response = await request(this.config, `${baseUrl(this.config)}${operation.path}`, {
|
|
918
|
+
method: operation.method,
|
|
919
|
+
headers: jsonHeaders(this.config),
|
|
920
|
+
body: JSON.stringify(endpointPayload(params))
|
|
921
|
+
}, {
|
|
922
|
+
operationName: "createWebhookEndpoint"
|
|
923
|
+
});
|
|
924
|
+
return parseEndpointResponse(response);
|
|
925
|
+
}
|
|
926
|
+
async list(params = {}) {
|
|
927
|
+
const operation = API_V1_OPERATIONS9.listWebhookEndpoints;
|
|
928
|
+
const response = await request(this.config, `${baseUrl(this.config)}${withQuery(operation.path, {
|
|
929
|
+
account_id: params.accountId,
|
|
930
|
+
limit: params.limit,
|
|
931
|
+
starting_after: params.startingAfter
|
|
932
|
+
})}`, {
|
|
933
|
+
method: operation.method,
|
|
934
|
+
headers: authHeaders(this.config)
|
|
935
|
+
}, {
|
|
936
|
+
operationName: "listWebhookEndpoints"
|
|
937
|
+
});
|
|
938
|
+
return parseEndpointListResponse(response);
|
|
939
|
+
}
|
|
940
|
+
async update(id, params) {
|
|
941
|
+
const operation = API_V1_OPERATIONS9.updateWebhookEndpoint;
|
|
942
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
943
|
+
method: operation.method,
|
|
944
|
+
headers: jsonHeaders(this.config),
|
|
945
|
+
body: JSON.stringify(endpointPayload(params))
|
|
946
|
+
}, {
|
|
947
|
+
operationName: "updateWebhookEndpoint"
|
|
948
|
+
});
|
|
949
|
+
return parseEndpointResponse(response);
|
|
950
|
+
}
|
|
951
|
+
async rotateSecret(id) {
|
|
952
|
+
const operation = API_V1_OPERATIONS9.rotateWebhookEndpointSecret;
|
|
953
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
954
|
+
method: operation.method,
|
|
955
|
+
headers: authHeaders(this.config)
|
|
956
|
+
}, {
|
|
957
|
+
operationName: "rotateWebhookEndpointSecret"
|
|
958
|
+
});
|
|
959
|
+
return parseEndpointResponse(response);
|
|
960
|
+
}
|
|
961
|
+
async delete(id) {
|
|
962
|
+
const operation = API_V1_OPERATIONS9.deleteWebhookEndpoint;
|
|
963
|
+
const response = await request(this.config, `${baseUrl(this.config)}${pathWithParams(operation.path, { id })}`, {
|
|
964
|
+
method: operation.method,
|
|
965
|
+
headers: authHeaders(this.config)
|
|
966
|
+
}, {
|
|
967
|
+
operationName: "deleteWebhookEndpoint"
|
|
968
|
+
});
|
|
969
|
+
return parseEndpointResponse(response);
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
function endpointPayload(params) {
|
|
973
|
+
return {
|
|
974
|
+
...params.apiVersion !== void 0 ? { api_version: params.apiVersion } : {},
|
|
975
|
+
...params.description !== void 0 ? { description: params.description } : {},
|
|
976
|
+
...params.enabledEvents !== void 0 ? { enabled_events: params.enabledEvents } : {},
|
|
977
|
+
...params.status !== void 0 ? { status: params.status } : {},
|
|
978
|
+
...params.url !== void 0 ? { url: params.url } : {}
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
async function parseEndpointResponse(response) {
|
|
982
|
+
const { parsed, requestId } = await parseJsonObjectResponse(response);
|
|
983
|
+
return toEndpointResponse(parsed, requestId);
|
|
984
|
+
}
|
|
985
|
+
async function parseEndpointListResponse(response) {
|
|
986
|
+
return parseJsonListResponse(response, toEndpointResponse);
|
|
987
|
+
}
|
|
988
|
+
function toEndpointResponse(parsed, requestId) {
|
|
989
|
+
return {
|
|
990
|
+
accountId: String(parsed.account_id ?? ""),
|
|
991
|
+
apiVersion: String(parsed.api_version ?? ""),
|
|
992
|
+
createdAt: String(parsed.created_at ?? ""),
|
|
993
|
+
deleted: typeof parsed.deleted === "boolean" ? parsed.deleted : void 0,
|
|
994
|
+
description: typeof parsed.description === "string" ? parsed.description : void 0,
|
|
995
|
+
enabledEvents: stringArray(parsed.enabled_events),
|
|
996
|
+
id: String(parsed.id ?? ""),
|
|
997
|
+
requestId,
|
|
998
|
+
signingSecret: typeof parsed.signing_secret === "string" ? parsed.signing_secret : void 0,
|
|
999
|
+
status: String(parsed.status ?? "enabled"),
|
|
1000
|
+
updatedAt: String(parsed.updated_at ?? ""),
|
|
1001
|
+
url: String(parsed.url ?? "")
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// src/resources/Webhooks.ts
|
|
1006
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
1007
|
+
var Webhooks = class {
|
|
1008
|
+
constructEvent(params) {
|
|
1009
|
+
const parts = params.signature.split(",");
|
|
1010
|
+
const timestamp = parts.find((p) => p.startsWith("t="))?.split("=")[1];
|
|
1011
|
+
const signature = parts.find((p) => p.startsWith("v1="))?.split("=")[1];
|
|
1012
|
+
if (!timestamp || !signature)
|
|
1013
|
+
throw new Error("Invalid signature header format");
|
|
1014
|
+
const timestampSeconds = Number.parseInt(timestamp, 10);
|
|
1015
|
+
if (!Number.isFinite(timestampSeconds))
|
|
1016
|
+
throw new Error("Invalid signature timestamp");
|
|
1017
|
+
const toleranceSeconds = params.toleranceSeconds ?? 300;
|
|
1018
|
+
const timeDiff = Math.abs(Date.now() / 1e3 - timestampSeconds);
|
|
1019
|
+
if (timeDiff > toleranceSeconds)
|
|
1020
|
+
throw new Error("Webhook timestamp is too old");
|
|
1021
|
+
const signedPayload = `${timestamp}.${params.rawBody}`;
|
|
1022
|
+
const expectedSignature = createHmac("sha256", params.secret).update(signedPayload).digest("hex");
|
|
1023
|
+
const actual = Buffer.from(signature, "hex");
|
|
1024
|
+
const expected = Buffer.from(expectedSignature, "hex");
|
|
1025
|
+
if (actual.length !== expected.length || !timingSafeEqual(actual, expected))
|
|
1026
|
+
throw new Error("Invalid webhook signature");
|
|
1027
|
+
return JSON.parse(params.rawBody);
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
// src/Havenpay.ts
|
|
1032
|
+
var Havenpay = class {
|
|
1033
|
+
constructor(config) {
|
|
1034
|
+
this.config = config;
|
|
1035
|
+
if (!config.secretKey) {
|
|
1036
|
+
throw new Error("Havenpay: secretKey is required");
|
|
1037
|
+
}
|
|
1038
|
+
this.accounts = new Accounts(this.config);
|
|
1039
|
+
this.apiKeys = new ApiKeys(this.config);
|
|
1040
|
+
this.balanceTransactions = new BalanceTransactions(this.config);
|
|
1041
|
+
this.events = new Events(this.config);
|
|
1042
|
+
this.paymentIntents = new PaymentIntents(this.config);
|
|
1043
|
+
this.projects = new Projects(this.config);
|
|
1044
|
+
this.providerAccounts = new ProviderAccounts(this.config);
|
|
1045
|
+
this.refunds = new Refunds(this.config);
|
|
1046
|
+
this.webhookEndpoints = new WebhookEndpoints(this.config);
|
|
1047
|
+
this.webhooks = new Webhooks();
|
|
1048
|
+
}
|
|
1049
|
+
};
|
|
1050
|
+
export {
|
|
1051
|
+
Havenpay,
|
|
1052
|
+
HavenpayApiError,
|
|
1053
|
+
HavenpayTimeoutError
|
|
1054
|
+
};
|