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