@olympio/payment-gateway 0.1.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,1071 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ AsaasApiError: () => AsaasApiError,
34
+ AsaasGateway: () => AsaasGateway,
35
+ AuthenticationError: () => AuthenticationError,
36
+ Capability: () => Capability,
37
+ CardDeclinedError: () => CardDeclinedError,
38
+ GatewayError: () => GatewayError,
39
+ GatewayUnavailableError: () => GatewayUnavailableError,
40
+ Money: () => Money,
41
+ RateLimitError: () => RateLimitError,
42
+ StripeGateway: () => StripeGateway,
43
+ UnknownGatewayError: () => UnknownGatewayError,
44
+ UnsupportedCapabilityError: () => UnsupportedCapabilityError,
45
+ ValidationError: () => ValidationError,
46
+ createAsaasHttpClient: () => createAsaasHttpClient,
47
+ createGateway: () => createGateway,
48
+ hasCapability: () => hasCapability
49
+ });
50
+ module.exports = __toCommonJS(index_exports);
51
+
52
+ // src/adapters/stripe/StripeGateway.ts
53
+ var import_stripe = __toESM(require("stripe"), 1);
54
+
55
+ // src/domain/capabilities/Capability.ts
56
+ var Capability = {
57
+ PIX: "pix",
58
+ BOLETO: "boleto",
59
+ CARD: "card",
60
+ REFUND: "refund",
61
+ SUBSCRIPTIONS: "subscriptions"
62
+ };
63
+ function hasCapability(caps, capability) {
64
+ return caps.has(capability);
65
+ }
66
+
67
+ // src/domain/errors/index.ts
68
+ var GatewayError = class extends Error {
69
+ constructor(provider, message, options = {}) {
70
+ super(message, { cause: options.cause });
71
+ this.provider = provider;
72
+ this.name = new.target.name;
73
+ this.raw = options.raw;
74
+ }
75
+ provider;
76
+ raw;
77
+ };
78
+ var CardDeclinedError = class extends GatewayError {
79
+ code = "card_declined";
80
+ constructor(provider, options) {
81
+ super(provider, "Cart\xE3o recusado.", options);
82
+ }
83
+ };
84
+ var AuthenticationError = class extends GatewayError {
85
+ code = "authentication";
86
+ constructor(provider, options) {
87
+ super(provider, "Falha de autentica\xE7\xE3o com o gateway.", options);
88
+ }
89
+ };
90
+ var RateLimitError = class extends GatewayError {
91
+ code = "rate_limit";
92
+ constructor(provider, options) {
93
+ super(provider, "Limite de requisi\xE7\xF5es do gateway excedido.", options);
94
+ }
95
+ };
96
+ var ValidationError = class extends GatewayError {
97
+ code = "validation";
98
+ constructor(provider, message, options) {
99
+ super(provider, message, options);
100
+ }
101
+ };
102
+ var GatewayUnavailableError = class extends GatewayError {
103
+ code = "gateway_unavailable";
104
+ constructor(provider, options) {
105
+ super(provider, "Gateway indispon\xEDvel.", options);
106
+ }
107
+ };
108
+ var UnknownGatewayError = class extends GatewayError {
109
+ code = "unknown";
110
+ constructor(provider, message, options) {
111
+ super(provider, message, options);
112
+ }
113
+ };
114
+ var UnsupportedCapabilityError = class extends GatewayError {
115
+ constructor(provider, capability, options) {
116
+ super(
117
+ provider,
118
+ `O gateway "${provider}" n\xE3o suporta a capability "${capability}".`,
119
+ options
120
+ );
121
+ this.capability = capability;
122
+ }
123
+ capability;
124
+ code = "unsupported_capability";
125
+ };
126
+
127
+ // src/domain/models/Money.ts
128
+ var Money = class _Money {
129
+ constructor(cents, currency) {
130
+ this.cents = cents;
131
+ this.currency = currency;
132
+ }
133
+ cents;
134
+ currency;
135
+ static fromCents(cents, currency) {
136
+ if (!Number.isInteger(cents)) {
137
+ throw new RangeError(`Money.cents deve ser inteiro, recebido: ${cents}`);
138
+ }
139
+ return new _Money(cents, currency.toUpperCase());
140
+ }
141
+ static fromDecimal(amount, currency) {
142
+ return _Money.fromCents(Math.round(amount * 100), currency);
143
+ }
144
+ toDecimal() {
145
+ return this.cents / 100;
146
+ }
147
+ equals(other) {
148
+ return this.cents === other.cents && this.currency === other.currency;
149
+ }
150
+ };
151
+
152
+ // src/adapters/stripe/mappers.ts
153
+ var PROVIDER = "stripe";
154
+ function toChargeStatus(pi) {
155
+ switch (pi.status) {
156
+ case "succeeded":
157
+ return "paid";
158
+ case "canceled":
159
+ return "canceled";
160
+ case "requires_payment_method":
161
+ return pi.last_payment_error ? "failed" : "pending";
162
+ default:
163
+ return "pending";
164
+ }
165
+ }
166
+ function toPaymentMethod(types) {
167
+ if (types?.includes("pix")) return "pix";
168
+ if (types?.includes("boleto")) return "boleto";
169
+ return "card";
170
+ }
171
+ function customerId(customer) {
172
+ if (!customer) return void 0;
173
+ return typeof customer === "string" ? customer : customer.id;
174
+ }
175
+ function toCharge(pi) {
176
+ return {
177
+ id: pi.id,
178
+ status: toChargeStatus(pi),
179
+ amount: Money.fromCents(pi.amount, pi.currency),
180
+ paymentMethod: toPaymentMethod(pi.payment_method_types),
181
+ customerId: customerId(pi.customer),
182
+ description: pi.description ?? void 0,
183
+ createdAt: new Date(pi.created * 1e3),
184
+ metadata: pi.metadata ?? void 0
185
+ };
186
+ }
187
+ function toCustomer(c) {
188
+ return {
189
+ id: c.id,
190
+ name: c.name ?? "",
191
+ email: c.email ?? void 0,
192
+ phone: c.phone ?? void 0,
193
+ metadata: c.metadata ?? void 0
194
+ };
195
+ }
196
+ function toSubscriptionStatus(status) {
197
+ switch (status) {
198
+ case "active":
199
+ case "trialing":
200
+ return "active";
201
+ case "canceled":
202
+ return "canceled";
203
+ default:
204
+ return "past_due";
205
+ }
206
+ }
207
+ function toInterval(interval) {
208
+ switch (interval) {
209
+ case "week":
210
+ return "weekly";
211
+ case "year":
212
+ return "yearly";
213
+ default:
214
+ return "monthly";
215
+ }
216
+ }
217
+ function toSubscription(sub) {
218
+ const price = sub.items.data[0]?.price;
219
+ return {
220
+ id: sub.id,
221
+ status: toSubscriptionStatus(sub.status),
222
+ customerId: customerId(sub.customer) ?? "",
223
+ amount: Money.fromCents(price?.unit_amount ?? 0, price?.currency ?? "brl"),
224
+ interval: toInterval(price?.recurring?.interval),
225
+ createdAt: new Date(sub.created * 1e3),
226
+ metadata: sub.metadata ?? void 0
227
+ };
228
+ }
229
+ function mapStripeError(err) {
230
+ const e = err;
231
+ const opts = { cause: err, raw: err };
232
+ switch (e.type) {
233
+ case "StripeCardError":
234
+ return new CardDeclinedError(PROVIDER, opts);
235
+ case "StripeAuthenticationError":
236
+ return new AuthenticationError(PROVIDER, opts);
237
+ case "StripeRateLimitError":
238
+ return new RateLimitError(PROVIDER, opts);
239
+ case "StripeInvalidRequestError":
240
+ return new ValidationError(PROVIDER, e.message ?? "Requisi\xE7\xE3o inv\xE1lida.", opts);
241
+ default:
242
+ return new UnknownGatewayError(PROVIDER, e.message ?? "Erro do Stripe.", opts);
243
+ }
244
+ }
245
+ function toWebhookEvent(event) {
246
+ switch (event.type) {
247
+ case "payment_intent.succeeded":
248
+ return {
249
+ type: "charge.paid",
250
+ data: toCharge(event.data.object),
251
+ raw: event
252
+ };
253
+ case "payment_intent.payment_failed":
254
+ return {
255
+ type: "charge.failed",
256
+ data: toCharge(event.data.object),
257
+ raw: event
258
+ };
259
+ case "customer.subscription.deleted":
260
+ return {
261
+ type: "subscription.canceled",
262
+ data: toSubscription(event.data.object),
263
+ raw: event
264
+ };
265
+ default:
266
+ return { type: "unknown", data: null, raw: event };
267
+ }
268
+ }
269
+
270
+ // src/adapters/stripe/StripeGateway.ts
271
+ var PROVIDER2 = "stripe";
272
+ var CAPABILITY_BY_METHOD = {
273
+ card: Capability.CARD,
274
+ pix: Capability.PIX,
275
+ boleto: Capability.BOLETO
276
+ };
277
+ var STRIPE_INTERVAL = {
278
+ weekly: "week",
279
+ monthly: "month",
280
+ yearly: "year"
281
+ };
282
+ async function normalizeErrors(fn) {
283
+ try {
284
+ return await fn();
285
+ } catch (err) {
286
+ throw mapStripeError(err);
287
+ }
288
+ }
289
+ function isResourceMissing(err) {
290
+ return err.code === "resource_missing";
291
+ }
292
+ var StripeGateway = class {
293
+ constructor(config, client) {
294
+ this.config = config;
295
+ this.client = client ?? new import_stripe.default(config.apiKey);
296
+ this.customers = this.buildCustomerPort();
297
+ this.charges = this.buildChargePort();
298
+ this.subscriptions = this.buildSubscriptionPort();
299
+ this.webhooks = this.buildWebhookPort();
300
+ }
301
+ config;
302
+ provider = PROVIDER2;
303
+ capabilities = /* @__PURE__ */ new Set([
304
+ Capability.CARD,
305
+ Capability.REFUND,
306
+ Capability.SUBSCRIPTIONS
307
+ ]);
308
+ client;
309
+ customers;
310
+ charges;
311
+ subscriptions;
312
+ webhooks;
313
+ supports(capability) {
314
+ return this.capabilities.has(capability);
315
+ }
316
+ raw() {
317
+ return this.client;
318
+ }
319
+ requireMethod(method) {
320
+ const cap = CAPABILITY_BY_METHOD[method];
321
+ if (!this.capabilities.has(cap)) {
322
+ throw new UnsupportedCapabilityError(PROVIDER2, cap);
323
+ }
324
+ }
325
+ buildCustomerPort() {
326
+ const client = this.client;
327
+ return {
328
+ create: (input) => normalizeErrors(
329
+ async () => toCustomer(
330
+ await client.customers.create(
331
+ {
332
+ name: input.name,
333
+ email: input.email,
334
+ phone: input.phone,
335
+ metadata: input.metadata
336
+ },
337
+ input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : void 0
338
+ )
339
+ )
340
+ ),
341
+ get: async (id) => {
342
+ try {
343
+ const c = await client.customers.retrieve(id);
344
+ if (c.deleted) return null;
345
+ return toCustomer(c);
346
+ } catch (err) {
347
+ if (isResourceMissing(err)) return null;
348
+ throw mapStripeError(err);
349
+ }
350
+ },
351
+ update: (id, input) => normalizeErrors(
352
+ async () => toCustomer(
353
+ await client.customers.update(id, {
354
+ name: input.name,
355
+ email: input.email,
356
+ phone: input.phone,
357
+ metadata: input.metadata
358
+ })
359
+ )
360
+ ),
361
+ delete: (id) => normalizeErrors(async () => {
362
+ await client.customers.del(id);
363
+ })
364
+ };
365
+ }
366
+ buildChargePort() {
367
+ const client = this.client;
368
+ return {
369
+ create: async (input) => {
370
+ this.requireMethod(input.paymentMethod);
371
+ return normalizeErrors(
372
+ async () => toCharge(
373
+ await client.paymentIntents.create(
374
+ {
375
+ amount: input.amount.cents,
376
+ currency: input.amount.currency.toLowerCase(),
377
+ customer: input.customerId,
378
+ description: input.description,
379
+ payment_method: input.cardToken,
380
+ payment_method_types: ["card"],
381
+ confirm: input.cardToken !== void 0,
382
+ metadata: input.metadata
383
+ },
384
+ input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : void 0
385
+ )
386
+ )
387
+ );
388
+ },
389
+ get: async (id) => {
390
+ try {
391
+ return toCharge(await client.paymentIntents.retrieve(id));
392
+ } catch (err) {
393
+ if (isResourceMissing(err)) return null;
394
+ throw mapStripeError(err);
395
+ }
396
+ },
397
+ cancel: (id) => normalizeErrors(async () => toCharge(await client.paymentIntents.cancel(id))),
398
+ refund: (input) => normalizeErrors(async () => {
399
+ await client.refunds.create({
400
+ payment_intent: input.chargeId,
401
+ amount: input.amount?.cents
402
+ });
403
+ const pi = await client.paymentIntents.retrieve(input.chargeId);
404
+ return { ...toCharge(pi), status: "refunded" };
405
+ })
406
+ };
407
+ }
408
+ buildSubscriptionPort() {
409
+ const client = this.client;
410
+ return {
411
+ create: (input) => normalizeErrors(async () => {
412
+ const price = await client.prices.create({
413
+ unit_amount: input.amount.cents,
414
+ currency: input.amount.currency.toLowerCase(),
415
+ recurring: { interval: STRIPE_INTERVAL[input.interval] },
416
+ product_data: { name: `subscription-${input.customerId}` }
417
+ });
418
+ const sub = await client.subscriptions.create(
419
+ {
420
+ customer: input.customerId,
421
+ items: [{ price: price.id }],
422
+ metadata: input.metadata
423
+ },
424
+ input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : void 0
425
+ );
426
+ return toSubscription(sub);
427
+ }),
428
+ get: async (id) => {
429
+ try {
430
+ return toSubscription(await client.subscriptions.retrieve(id));
431
+ } catch (err) {
432
+ if (isResourceMissing(err)) return null;
433
+ throw mapStripeError(err);
434
+ }
435
+ },
436
+ cancel: (id) => normalizeErrors(async () => toSubscription(await client.subscriptions.cancel(id)))
437
+ };
438
+ }
439
+ buildWebhookPort() {
440
+ const client = this.client;
441
+ const secret = this.config.webhookSecret;
442
+ return {
443
+ verifyAndParse: (input) => {
444
+ if (!secret) {
445
+ throw new ValidationError(PROVIDER2, "webhookSecret n\xE3o configurado.");
446
+ }
447
+ const signature = input.headers["stripe-signature"];
448
+ try {
449
+ const event = client.webhooks.constructEvent(input.payload, signature ?? "", secret);
450
+ return toWebhookEvent(event);
451
+ } catch (err) {
452
+ throw new ValidationError(PROVIDER2, "Assinatura de webhook inv\xE1lida.", {
453
+ cause: err
454
+ });
455
+ }
456
+ }
457
+ };
458
+ }
459
+ };
460
+
461
+ // src/adapters/asaas/AsaasHttpClient.ts
462
+ var AsaasApiError = class extends Error {
463
+ constructor(status, body) {
464
+ super(`Asaas API respondeu ${status}`);
465
+ this.status = status;
466
+ this.body = body;
467
+ this.name = "AsaasApiError";
468
+ }
469
+ status;
470
+ body;
471
+ };
472
+ var DEFAULT_BASE_URL = "https://api.asaas.com/v3";
473
+ function createAsaasHttpClient(config) {
474
+ const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
475
+ async function request(method, path, body) {
476
+ const res = await fetch(`${baseUrl}${path}`, {
477
+ method,
478
+ headers: {
479
+ access_token: config.apiKey,
480
+ "Content-Type": "application/json"
481
+ },
482
+ body: body === void 0 ? void 0 : JSON.stringify(body)
483
+ });
484
+ const text = await res.text();
485
+ const json = text ? JSON.parse(text) : {};
486
+ if (!res.ok) {
487
+ throw new AsaasApiError(res.status, json);
488
+ }
489
+ return json;
490
+ }
491
+ return {
492
+ get: (path) => request("GET", path),
493
+ post: (path, body) => request("POST", path, body),
494
+ delete: (path) => request("DELETE", path)
495
+ };
496
+ }
497
+
498
+ // src/adapters/asaas/mappers.ts
499
+ var PROVIDER3 = "asaas";
500
+ var CURRENCY = "BRL";
501
+ function toChargeStatus2(status) {
502
+ switch (status) {
503
+ case "RECEIVED":
504
+ case "CONFIRMED":
505
+ case "RECEIVED_IN_CASH":
506
+ return "paid";
507
+ case "OVERDUE":
508
+ return "failed";
509
+ case "REFUNDED":
510
+ case "REFUND_REQUESTED":
511
+ return "refunded";
512
+ default:
513
+ return "pending";
514
+ }
515
+ }
516
+ function toPaymentMethod2(billingType) {
517
+ switch (billingType) {
518
+ case "PIX":
519
+ return "pix";
520
+ case "BOLETO":
521
+ return "boleto";
522
+ default:
523
+ return "card";
524
+ }
525
+ }
526
+ function toCharge2(p) {
527
+ return {
528
+ id: p.id,
529
+ status: toChargeStatus2(p.status),
530
+ amount: Money.fromDecimal(p.value, CURRENCY),
531
+ paymentMethod: toPaymentMethod2(p.billingType),
532
+ customerId: p.customer,
533
+ description: p.description ?? void 0,
534
+ boleto: p.bankSlipUrl ? { url: p.bankSlipUrl } : void 0,
535
+ createdAt: new Date(p.dateCreated)
536
+ };
537
+ }
538
+ function toCustomer2(c) {
539
+ return {
540
+ id: c.id,
541
+ name: c.name,
542
+ email: c.email ?? void 0,
543
+ taxId: c.cpfCnpj ?? void 0,
544
+ phone: c.phone ?? c.mobilePhone ?? void 0
545
+ };
546
+ }
547
+ function toSubscriptionStatus2(status) {
548
+ switch (status) {
549
+ case "ACTIVE":
550
+ return "active";
551
+ case "EXPIRED":
552
+ return "past_due";
553
+ default:
554
+ return "canceled";
555
+ }
556
+ }
557
+ function toInterval2(cycle) {
558
+ switch (cycle) {
559
+ case "WEEKLY":
560
+ return "weekly";
561
+ case "YEARLY":
562
+ return "yearly";
563
+ default:
564
+ return "monthly";
565
+ }
566
+ }
567
+ function toSubscription2(s) {
568
+ return {
569
+ id: s.id,
570
+ status: toSubscriptionStatus2(s.status),
571
+ customerId: s.customer,
572
+ amount: Money.fromDecimal(s.value, CURRENCY),
573
+ interval: toInterval2(s.cycle),
574
+ createdAt: new Date(s.dateCreated)
575
+ };
576
+ }
577
+ function mapAsaasError(status, body) {
578
+ const description = body.errors?.[0]?.description;
579
+ const opts = { raw: body };
580
+ if (status === 401 || status === 403) return new AuthenticationError(PROVIDER3, opts);
581
+ if (status === 429) return new RateLimitError(PROVIDER3, opts);
582
+ if (status >= 500) return new GatewayUnavailableError(PROVIDER3, opts);
583
+ if (status === 400) {
584
+ return new ValidationError(PROVIDER3, description ?? "Requisi\xE7\xE3o inv\xE1lida.", opts);
585
+ }
586
+ return new UnknownGatewayError(PROVIDER3, description ?? "Erro do Asaas.", opts);
587
+ }
588
+ function toWebhookEvent2(body) {
589
+ const payment = body.payment;
590
+ switch (body.event) {
591
+ case "PAYMENT_RECEIVED":
592
+ case "PAYMENT_CONFIRMED":
593
+ return { type: "charge.paid", data: toCharge2(payment), raw: body };
594
+ case "PAYMENT_OVERDUE":
595
+ return { type: "charge.failed", data: toCharge2(payment), raw: body };
596
+ case "PAYMENT_REFUNDED":
597
+ return { type: "charge.refunded", data: toCharge2(payment), raw: body };
598
+ default:
599
+ return { type: "unknown", data: null, raw: body };
600
+ }
601
+ }
602
+
603
+ // src/adapters/asaas/AsaasGateway.ts
604
+ var PROVIDER4 = "asaas";
605
+ var BILLING_TYPE = {
606
+ pix: "PIX",
607
+ boleto: "BOLETO",
608
+ card: "CREDIT_CARD"
609
+ };
610
+ var ASAAS_CYCLE = {
611
+ weekly: "WEEKLY",
612
+ monthly: "MONTHLY",
613
+ yearly: "YEARLY"
614
+ };
615
+ function today() {
616
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
617
+ }
618
+ async function normalizeErrors2(fn) {
619
+ try {
620
+ return await fn();
621
+ } catch (err) {
622
+ if (err instanceof GatewayError) throw err;
623
+ if (err instanceof AsaasApiError) throw mapAsaasError(err.status, err.body);
624
+ throw new UnknownGatewayError(PROVIDER4, "Erro inesperado no Asaas.", { cause: err });
625
+ }
626
+ }
627
+ function isNotFound(err) {
628
+ return err instanceof AsaasApiError && err.status === 404;
629
+ }
630
+ var AsaasGateway = class {
631
+ constructor(config, http) {
632
+ this.config = config;
633
+ this.http = http ?? createAsaasHttpClient(config);
634
+ this.customers = this.buildCustomerPort();
635
+ this.charges = this.buildChargePort();
636
+ this.subscriptions = this.buildSubscriptionPort();
637
+ this.webhooks = this.buildWebhookPort();
638
+ }
639
+ config;
640
+ provider = PROVIDER4;
641
+ capabilities = /* @__PURE__ */ new Set([
642
+ Capability.PIX,
643
+ Capability.BOLETO,
644
+ Capability.CARD,
645
+ Capability.REFUND,
646
+ Capability.SUBSCRIPTIONS
647
+ ]);
648
+ http;
649
+ customers;
650
+ charges;
651
+ subscriptions;
652
+ webhooks;
653
+ supports(capability) {
654
+ return this.capabilities.has(capability);
655
+ }
656
+ raw() {
657
+ return this.http;
658
+ }
659
+ buildCustomerPort() {
660
+ const http = this.http;
661
+ return {
662
+ create: (input) => normalizeErrors2(
663
+ async () => toCustomer2(
664
+ await http.post("/customers", {
665
+ name: input.name,
666
+ email: input.email,
667
+ cpfCnpj: input.taxId,
668
+ mobilePhone: input.phone,
669
+ externalReference: input.idempotencyKey
670
+ })
671
+ )
672
+ ),
673
+ get: async (id) => {
674
+ try {
675
+ return toCustomer2(await http.get(`/customers/${id}`));
676
+ } catch (err) {
677
+ if (isNotFound(err)) return null;
678
+ throw mapAsaasError(err.status, err.body);
679
+ }
680
+ },
681
+ update: (id, input) => normalizeErrors2(
682
+ async () => toCustomer2(
683
+ await http.post(`/customers/${id}`, {
684
+ name: input.name,
685
+ email: input.email,
686
+ cpfCnpj: input.taxId,
687
+ mobilePhone: input.phone
688
+ })
689
+ )
690
+ ),
691
+ delete: (id) => normalizeErrors2(async () => {
692
+ await http.delete(`/customers/${id}`);
693
+ })
694
+ };
695
+ }
696
+ buildChargePort() {
697
+ const http = this.http;
698
+ return {
699
+ create: (input) => normalizeErrors2(
700
+ async () => toCharge2(
701
+ await http.post("/payments", {
702
+ customer: input.customerId,
703
+ billingType: BILLING_TYPE[input.paymentMethod],
704
+ value: input.amount.toDecimal(),
705
+ dueDate: (input.dueDate ?? /* @__PURE__ */ new Date()).toISOString().slice(0, 10),
706
+ description: input.description,
707
+ creditCardToken: input.cardToken,
708
+ remoteIp: input.remoteIp,
709
+ externalReference: input.idempotencyKey
710
+ })
711
+ )
712
+ ),
713
+ get: async (id) => {
714
+ try {
715
+ return toCharge2(await http.get(`/payments/${id}`));
716
+ } catch (err) {
717
+ if (isNotFound(err)) return null;
718
+ throw mapAsaasError(err.status, err.body);
719
+ }
720
+ },
721
+ cancel: (id) => normalizeErrors2(async () => {
722
+ const payment = await http.get(`/payments/${id}`);
723
+ await http.delete(`/payments/${id}`);
724
+ return { ...toCharge2(payment), status: "canceled" };
725
+ }),
726
+ refund: (input) => normalizeErrors2(
727
+ async () => toCharge2(
728
+ await http.post(`/payments/${input.chargeId}/refund`, {
729
+ value: input.amount?.toDecimal()
730
+ })
731
+ )
732
+ )
733
+ };
734
+ }
735
+ buildSubscriptionPort() {
736
+ const http = this.http;
737
+ return {
738
+ create: (input) => normalizeErrors2(
739
+ async () => toSubscription2(
740
+ await http.post("/subscriptions", {
741
+ customer: input.customerId,
742
+ billingType: BILLING_TYPE[input.paymentMethod],
743
+ value: input.amount.toDecimal(),
744
+ cycle: ASAAS_CYCLE[input.interval],
745
+ nextDueDate: today(),
746
+ creditCardToken: input.cardToken,
747
+ externalReference: input.idempotencyKey
748
+ })
749
+ )
750
+ ),
751
+ get: async (id) => {
752
+ try {
753
+ return toSubscription2(await http.get(`/subscriptions/${id}`));
754
+ } catch (err) {
755
+ if (isNotFound(err)) return null;
756
+ throw mapAsaasError(err.status, err.body);
757
+ }
758
+ },
759
+ cancel: (id) => normalizeErrors2(async () => {
760
+ const sub = await http.get(`/subscriptions/${id}`);
761
+ await http.delete(`/subscriptions/${id}`);
762
+ return { ...toSubscription2(sub), status: "canceled" };
763
+ })
764
+ };
765
+ }
766
+ buildWebhookPort() {
767
+ const expectedToken = this.config.webhookToken;
768
+ return {
769
+ verifyAndParse: (input) => {
770
+ const received = input.headers["asaas-access-token"];
771
+ if (!expectedToken || received !== expectedToken) {
772
+ throw new ValidationError(PROVIDER4, "Token de webhook do Asaas inv\xE1lido.");
773
+ }
774
+ const body = JSON.parse(input.payload.toString());
775
+ return toWebhookEvent2(body);
776
+ }
777
+ };
778
+ }
779
+ };
780
+
781
+ // src/adapters/dom/DomHttpClient.ts
782
+ var DomHttpClient = class {
783
+ baseUrl;
784
+ apiKey;
785
+ constructor(config) {
786
+ this.baseUrl = config.baseUrl ?? "https://apiv3.dompagamentos.com.br/checkout/production";
787
+ this.apiKey = config.apiKey;
788
+ }
789
+ async request(path, options) {
790
+ const url = `${this.baseUrl}${path}`;
791
+ const response = await fetch(url, {
792
+ ...options,
793
+ headers: {
794
+ "Content-Type": "application/json",
795
+ Authorization: `Bearer ${this.apiKey}`,
796
+ ...options.headers
797
+ }
798
+ });
799
+ if (!response.ok) {
800
+ const body = await response.text();
801
+ throw new Error(`DOM API Error: ${response.status} ${response.statusText} - ${body}`);
802
+ }
803
+ if (response.status === 204) {
804
+ return {};
805
+ }
806
+ return await response.json();
807
+ }
808
+ async get(path) {
809
+ return this.request(path, { method: "GET" });
810
+ }
811
+ async post(path, body) {
812
+ return this.request(path, {
813
+ method: "POST",
814
+ body: body ? JSON.stringify(body) : void 0
815
+ });
816
+ }
817
+ async put(path, body) {
818
+ return this.request(path, {
819
+ method: "PUT",
820
+ body: body ? JSON.stringify(body) : void 0
821
+ });
822
+ }
823
+ async delete(path) {
824
+ return this.request(path, { method: "DELETE" });
825
+ }
826
+ };
827
+
828
+ // src/adapters/dom/mappers.ts
829
+ function toDomCustomer(input) {
830
+ const data = {
831
+ name: input.name,
832
+ email: input.email,
833
+ mobile_phone: input.phone || "00000000000",
834
+ code_external: input.metadata?.code_external
835
+ };
836
+ if (input.taxId) {
837
+ data.document = input.taxId;
838
+ data.document_type = input.taxId.length === 11 ? "CPF" : "CNPJ";
839
+ }
840
+ return data;
841
+ }
842
+ function toDomainCustomer(domCustomer) {
843
+ return {
844
+ id: domCustomer.id,
845
+ name: domCustomer.name,
846
+ email: domCustomer.email,
847
+ taxId: domCustomer.document,
848
+ phone: domCustomer.mobile_phone,
849
+ metadata: domCustomer.code_external ? { code_external: domCustomer.code_external } : void 0
850
+ };
851
+ }
852
+ function mapDomStatus(domStatus) {
853
+ switch (domStatus) {
854
+ case "pending":
855
+ return "pending";
856
+ case "paid":
857
+ return "paid";
858
+ case "canceled":
859
+ return "canceled";
860
+ case "failed":
861
+ return "failed";
862
+ case "refunded":
863
+ return "refunded";
864
+ default:
865
+ return "pending";
866
+ }
867
+ }
868
+ function toDomainCharge(domTransaction) {
869
+ return {
870
+ id: domTransaction.id,
871
+ status: mapDomStatus(domTransaction.status),
872
+ amount: Money.fromCents(domTransaction.amount, domTransaction.currency || "BRL"),
873
+ paymentMethod: domTransaction.payment_method === "credit_card" ? "card" : domTransaction.payment_method,
874
+ customerId: domTransaction.customer?.id,
875
+ description: domTransaction.items?.[0]?.description,
876
+ createdAt: new Date(domTransaction.created_at),
877
+ boleto: domTransaction.payment_method === "boleto" ? {
878
+ url: domTransaction.boleto_url,
879
+ barcode: domTransaction.boleto_digitable_line
880
+ } : void 0,
881
+ pix: domTransaction.payment_method === "pix" ? {
882
+ copyPaste: domTransaction.pix_content,
883
+ qrCode: domTransaction.pix_qrcode
884
+ } : void 0
885
+ };
886
+ }
887
+ function toWebhookEvent3(payload) {
888
+ const transaction = payload.data?.transaction;
889
+ if (!transaction) return { type: "unknown", data: null, raw: payload };
890
+ const charge = toDomainCharge(transaction);
891
+ switch (payload.event) {
892
+ case "transaction.paid":
893
+ return { type: "charge.paid", data: charge, raw: payload };
894
+ case "transaction.failed":
895
+ return { type: "charge.failed", data: charge, raw: payload };
896
+ case "transaction.refunded":
897
+ return { type: "charge.refunded", data: charge, raw: payload };
898
+ default:
899
+ return { type: "unknown", data: null, raw: payload };
900
+ }
901
+ }
902
+
903
+ // src/adapters/dom/ports.ts
904
+ var PROVIDER5 = "dom";
905
+ function buildDomCustomerPort(http) {
906
+ return {
907
+ create: async (input) => {
908
+ const response = await http.post("/customers", toDomCustomer(input));
909
+ return toDomainCustomer(response);
910
+ },
911
+ get: async (id) => {
912
+ try {
913
+ const response = await http.get(`/customers/${id}`);
914
+ return toDomainCustomer(response);
915
+ } catch (err) {
916
+ if (err.message.includes("404")) return null;
917
+ throw err;
918
+ }
919
+ },
920
+ update: async (id, input) => {
921
+ const response = await http.post(`/customers/${id}`, toDomCustomer(input));
922
+ return toDomainCustomer(response);
923
+ },
924
+ delete: async (id) => {
925
+ await http.delete(`/customers/${id}`);
926
+ }
927
+ };
928
+ }
929
+ function buildDomChargePort(http, customerPort) {
930
+ return {
931
+ create: async (input) => {
932
+ let customerData;
933
+ if (!input.cardToken) {
934
+ const c = await customerPort.get(input.customerId);
935
+ if (!c) throw new Error("Cliente n\xE3o encontrado para criar transa\xE7\xE3o (DOM Pagamentos exige customer para Pix/Boleto)");
936
+ customerData = toDomCustomer({ ...c, phone: c.phone || "00000000000", taxId: c.taxId });
937
+ }
938
+ const isBoleto = input.paymentMethod === "boleto";
939
+ const isPix = input.paymentMethod === "pix";
940
+ const isCard = input.paymentMethod === "card";
941
+ const payload = {
942
+ cod_external: input.metadata?.cod_external || input.idempotencyKey,
943
+ items: [{ description: input.description || "Cobran\xE7a", price: input.amount.toDecimal(), quantity: 1 }],
944
+ payment: {
945
+ total: input.amount.toDecimal(),
946
+ payment_method: isCard ? "credit_card" : input.paymentMethod
947
+ }
948
+ };
949
+ if (customerData) payload.customer = customerData;
950
+ if (isCard && input.cardToken) payload.payment.credit_card = { token: input.cardToken, installments: 1 };
951
+ if (isBoleto) payload.payment.boleto = { boleto_due_days: 3 };
952
+ if (isPix) payload.payment.pix = {};
953
+ const response = await http.post("/transactions", payload);
954
+ return toDomainCharge(response);
955
+ },
956
+ get: async (id) => {
957
+ try {
958
+ const response = await http.get(`/transactions/${id}`);
959
+ return toDomainCharge(response);
960
+ } catch (err) {
961
+ if (err.message.includes("404")) return null;
962
+ throw err;
963
+ }
964
+ },
965
+ cancel: async (id) => {
966
+ const response = await http.post(`/transactions/${id}/cancel`);
967
+ return toDomainCharge(response);
968
+ },
969
+ refund: async (input) => {
970
+ const payload = {};
971
+ if (input.amount) {
972
+ payload.amount = input.amount.toDecimal();
973
+ }
974
+ const response = await http.post(`/transactions/${input.chargeId}/refund`, payload);
975
+ return toDomainCharge(response);
976
+ }
977
+ };
978
+ }
979
+ function buildDomSubscriptionPort(http) {
980
+ return {
981
+ create: async (input) => {
982
+ throw new UnknownGatewayError(PROVIDER5, "DOM SubscriptionPort.create n\xE3o implementado.", { cause: null });
983
+ },
984
+ get: async (id) => {
985
+ throw new UnknownGatewayError(PROVIDER5, "DOM SubscriptionPort.get n\xE3o implementado.", { cause: null });
986
+ },
987
+ cancel: async (id) => {
988
+ throw new UnknownGatewayError(PROVIDER5, "DOM SubscriptionPort.cancel n\xE3o implementado.", { cause: null });
989
+ }
990
+ };
991
+ }
992
+ function buildDomWebhookPort(webhookSecret) {
993
+ return {
994
+ verifyAndParse: (input) => {
995
+ const receivedToken = input.headers["authorization"] || input.headers["x-dom-token"];
996
+ if (webhookSecret && receivedToken !== webhookSecret) {
997
+ throw new ValidationError(PROVIDER5, "Token de webhook inv\xE1lido.");
998
+ }
999
+ const payload = typeof input.payload === "string" ? JSON.parse(input.payload) : JSON.parse(input.payload.toString());
1000
+ return toWebhookEvent3(payload);
1001
+ }
1002
+ };
1003
+ }
1004
+
1005
+ // src/adapters/dom/DomGateway.ts
1006
+ var PROVIDER6 = "dom";
1007
+ var DomGateway = class {
1008
+ constructor(config, http) {
1009
+ this.config = config;
1010
+ this.http = http ?? new DomHttpClient(config);
1011
+ this.customers = buildDomCustomerPort(this.http);
1012
+ this.charges = buildDomChargePort(this.http, this.customers);
1013
+ this.subscriptions = buildDomSubscriptionPort(this.http);
1014
+ this.webhooks = buildDomWebhookPort(config.webhookToken);
1015
+ }
1016
+ config;
1017
+ provider = PROVIDER6;
1018
+ capabilities = /* @__PURE__ */ new Set([
1019
+ Capability.PIX,
1020
+ Capability.CARD,
1021
+ Capability.BOLETO,
1022
+ Capability.REFUND
1023
+ ]);
1024
+ http;
1025
+ customers;
1026
+ charges;
1027
+ subscriptions;
1028
+ webhooks;
1029
+ supports(capability) {
1030
+ return this.capabilities.has(capability);
1031
+ }
1032
+ raw() {
1033
+ return this.http;
1034
+ }
1035
+ };
1036
+
1037
+ // src/createGateway.ts
1038
+ function createGateway(config) {
1039
+ switch (config.provider) {
1040
+ case "stripe":
1041
+ return new StripeGateway(config);
1042
+ case "asaas":
1043
+ return new AsaasGateway(config);
1044
+ case "dom":
1045
+ return new DomGateway(config);
1046
+ default: {
1047
+ const exhaustive = config;
1048
+ throw new Error(`Provider n\xE3o suportado: ${JSON.stringify(exhaustive)}`);
1049
+ }
1050
+ }
1051
+ }
1052
+ // Annotate the CommonJS export names for ESM import in node:
1053
+ 0 && (module.exports = {
1054
+ AsaasApiError,
1055
+ AsaasGateway,
1056
+ AuthenticationError,
1057
+ Capability,
1058
+ CardDeclinedError,
1059
+ GatewayError,
1060
+ GatewayUnavailableError,
1061
+ Money,
1062
+ RateLimitError,
1063
+ StripeGateway,
1064
+ UnknownGatewayError,
1065
+ UnsupportedCapabilityError,
1066
+ ValidationError,
1067
+ createAsaasHttpClient,
1068
+ createGateway,
1069
+ hasCapability
1070
+ });
1071
+ //# sourceMappingURL=index.cjs.map