mupag-sdk 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,225 @@
1
+ type Environment = 'test' | 'prd';
2
+ type JsonPrimitive = string | number | boolean | null;
3
+ type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
4
+ type JsonObject = {
5
+ [key: string]: JsonValue;
6
+ };
7
+ type FetchLike = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
8
+ type RetryConfig = {
9
+ maxRetries: number;
10
+ initialDelayMs: number;
11
+ maxDelayMs: number;
12
+ };
13
+ type MuPagConfig = {
14
+ apiKey: string;
15
+ env: Environment;
16
+ baseUrl?: string | undefined;
17
+ fetch?: FetchLike | undefined;
18
+ timeoutMs?: number | undefined;
19
+ maxResponseBytes?: number | undefined;
20
+ retry?: Partial<RetryConfig> | undefined;
21
+ };
22
+ type RequestOptions = {
23
+ idempotencyKey?: string | undefined;
24
+ };
25
+ type CheckoutSessionItem = {
26
+ name: string;
27
+ quantity: number;
28
+ unit_amount_cents: number;
29
+ };
30
+ type CheckoutSessionCustomerData = {
31
+ name?: string | undefined;
32
+ email?: string | undefined;
33
+ document?: string | undefined;
34
+ phone?: string | undefined;
35
+ };
36
+ type CreateCheckoutSessionParams = {
37
+ items: CheckoutSessionItem[];
38
+ success_url: string;
39
+ cancel_url: string;
40
+ customer_id?: string | undefined;
41
+ customer_data?: CheckoutSessionCustomerData | undefined;
42
+ allowed_payment_methods?: Array<'pix' | 'credit_card'> | readonly ['pix', 'credit_card'] | undefined;
43
+ affiliate_code?: string | undefined;
44
+ coupon_id?: string | undefined;
45
+ utm_params?: JsonObject | undefined;
46
+ expires_in_minutes?: number | undefined;
47
+ metadata?: JsonObject | undefined;
48
+ collect_shipping_address?: boolean | undefined;
49
+ delivery_type?: string | undefined;
50
+ allow_coupons?: boolean | undefined;
51
+ };
52
+ type CheckoutSession = JsonObject & {
53
+ id: string;
54
+ url: string;
55
+ expires_at: string;
56
+ };
57
+ type Page<TItem extends JsonValue = JsonObject> = {
58
+ data: TItem[];
59
+ next_cursor?: string | null | undefined;
60
+ };
61
+ type Charge = JsonObject & {
62
+ charge_id: string;
63
+ amount_cents: number;
64
+ status: string;
65
+ psp_charge_id?: string | null | undefined;
66
+ card_token_id?: string | null | undefined;
67
+ card_brand?: string | null | undefined;
68
+ card_last4?: string | null | undefined;
69
+ three_ds_acs_url?: string | null | undefined;
70
+ failure_classification?: string | null | undefined;
71
+ pix_qr_code_base64?: string | null | undefined;
72
+ pix_emv_code?: string | null | undefined;
73
+ pix_qr_code?: string | undefined;
74
+ pix_copy_paste?: string | undefined;
75
+ expires_at?: string | null | undefined;
76
+ created_at?: string | undefined;
77
+ };
78
+ type ChargeCancellation = JsonObject & {
79
+ charge_id: string;
80
+ status: 'cancelled' | 'cancellation_pending';
81
+ reason: 'payment_attempt_cancelled';
82
+ cancelled_at: string | null;
83
+ };
84
+ type CancelChargeOptions = {
85
+ idempotencyKey: string;
86
+ reason?: 'payment_attempt_cancelled' | undefined;
87
+ };
88
+ type ChargeCustomer = {
89
+ id: string;
90
+ name: string;
91
+ email: string;
92
+ tax_id: string;
93
+ } | {
94
+ id?: never;
95
+ name: string;
96
+ email: string;
97
+ tax_id: string;
98
+ };
99
+ type ChargeSplitRule = {
100
+ recipient_id: string;
101
+ value_type: 'fixed_amount';
102
+ value_cents: number;
103
+ value_bps?: never;
104
+ } | {
105
+ recipient_id: string;
106
+ value_type: 'percentage_of_gross';
107
+ value_bps: number;
108
+ value_cents?: never;
109
+ };
110
+ type CreateChargeParams = {
111
+ amount_cents: number;
112
+ payment_method: 'pix' | 'credit_card';
113
+ customer: ChargeCustomer;
114
+ installments?: 1 | undefined;
115
+ card_token?: string | undefined;
116
+ card_token_id?: string | undefined;
117
+ save_card?: boolean | undefined;
118
+ description?: string | undefined;
119
+ /** @deprecated O PSP Asaas nao oferece este campo; qualquer valor nao vazio e rejeitado. */
120
+ soft_descriptor?: string | undefined;
121
+ /** IP literal do pagador atestado pelo merchant; obrigatorio para credit_card. */
122
+ payer_ip?: string | undefined;
123
+ auth_only?: boolean | undefined;
124
+ product_max_installments?: 1 | undefined;
125
+ external_reference?: string | undefined;
126
+ expires_in_seconds?: number | undefined;
127
+ metadata?: JsonObject | undefined;
128
+ affiliate_code?: string | undefined;
129
+ coupon_code?: string | undefined;
130
+ split_rules?: ChargeSplitRule[] | undefined;
131
+ is_mit?: boolean | undefined;
132
+ initial_mit_reference_id?: string | undefined;
133
+ };
134
+ type ListChargesParams = {
135
+ status?: string | undefined;
136
+ customer_id?: string | undefined;
137
+ payment_method?: string | undefined;
138
+ created_at_from?: string | undefined;
139
+ created_at_to?: string | undefined;
140
+ limit?: number | undefined;
141
+ cursor?: string | undefined;
142
+ };
143
+ type Subscription = JsonObject & {
144
+ id: string;
145
+ customer_id: string;
146
+ plan_id: string;
147
+ payment_method: string;
148
+ status: string;
149
+ cancel_at_period_end: boolean;
150
+ metadata: JsonObject;
151
+ };
152
+ type CreateSubscriptionParams = {
153
+ customer_id: string;
154
+ plan_id: string;
155
+ payment_method: 'pix' | 'credit_card';
156
+ trial_days?: number | undefined;
157
+ card_token_id?: string | undefined;
158
+ coupon_id?: string | undefined;
159
+ affiliate_code?: string | undefined;
160
+ metadata?: JsonObject | undefined;
161
+ external_reference?: string | undefined;
162
+ };
163
+ type CancelSubscriptionParams = {
164
+ mode: 'immediate' | 'end_of_period';
165
+ reason?: string | undefined;
166
+ };
167
+ type Refund = JsonObject & {
168
+ refund_id: string;
169
+ charge_id: string;
170
+ amount_cents: number;
171
+ status: string;
172
+ psp_refund_id?: string | null | undefined;
173
+ reason?: string | null | undefined;
174
+ requested_at?: string | undefined;
175
+ completed_at?: string | null | undefined;
176
+ failure_reason?: string | null | undefined;
177
+ };
178
+ type CreateRefundParams = {
179
+ amount_cents: number;
180
+ full?: never;
181
+ reason?: string | undefined;
182
+ } | {
183
+ full: true;
184
+ amount_cents?: never;
185
+ reason?: string | undefined;
186
+ };
187
+ type RefundList = {
188
+ refunds: Refund[];
189
+ next_cursor?: string | null | undefined;
190
+ };
191
+ type ListRefundsParams = {
192
+ limit?: number | undefined;
193
+ cursor?: string | undefined;
194
+ };
195
+ type Customer = JsonObject & {
196
+ id: string;
197
+ merchant_id?: string | undefined;
198
+ environment?: string | undefined;
199
+ name?: string | undefined;
200
+ email?: string | undefined;
201
+ tax_id?: string | undefined;
202
+ phone?: string | undefined;
203
+ birth_date?: string | undefined;
204
+ external_reference?: string | undefined;
205
+ marketing_consent?: boolean | undefined;
206
+ created_at?: string | undefined;
207
+ updated_at?: string | undefined;
208
+ };
209
+ type UpdateCustomerParams = {
210
+ name: string;
211
+ email: string;
212
+ tax_id?: string | undefined;
213
+ phone?: string | undefined;
214
+ birth_date?: string | undefined;
215
+ external_reference?: string | undefined;
216
+ marketing_consent?: boolean | undefined;
217
+ };
218
+ type MuPagEvent<TData extends JsonValue = JsonValue> = {
219
+ id: string;
220
+ type: string;
221
+ data: TData;
222
+ created_at?: string;
223
+ };
224
+
225
+ export type { CancelChargeOptions as C, Environment as E, FetchLike as F, JsonObject as J, ListChargesParams as L, MuPagConfig as M, Page as P, Refund as R, Subscription as S, UpdateCustomerParams as U, CancelSubscriptionParams as a, Charge as b, ChargeCancellation as c, ChargeCustomer as d, ChargeSplitRule as e, CheckoutSession as f, CheckoutSessionCustomerData as g, CheckoutSessionItem as h, CreateChargeParams as i, CreateCheckoutSessionParams as j, CreateRefundParams as k, CreateSubscriptionParams as l, Customer as m, JsonPrimitive as n, JsonValue as o, ListRefundsParams as p, MuPagEvent as q, RefundList as r, RequestOptions as s, RetryConfig as t };
@@ -0,0 +1,2 @@
1
+ 'use strict';var l=class extends Error{status;code;requestId;suggestion;documentationUrl;constructor(e){super(e.message,e.cause===void 0?void 0:{cause:e.cause}),this.name="MuPagError",this.status=e.status,this.code=e.code,this.requestId=e.requestId,this.suggestion=e.suggestion,this.documentationUrl=e.documentationUrl;}};var a=class extends l{constructor(e){super(e),this.name="WebhookSignatureError";}};var p=300,h=1024*1024;async function y(t,e,n,r={}){let o=typeof t=="string"?t:new TextDecoder().decode(t);if((typeof t=="string"?new TextEncoder().encode(t).byteLength:t.byteLength)>h)throw new a({message:"Payload de webhook excede o limite seguro.",code:"webhook_payload_too_large",suggestion:"Rejeite o request com HTTP 413 antes de processar o evento."});let i=r.toleranceSeconds??p;if(n.length<1||n.length>512||n.trim()!==n)throw new a({message:"Webhook secret invalido.",code:"webhook_secret_invalid",suggestion:"Configure o webhook secret exato e nao use valor vazio ou com espacos externos."});if(!Number.isSafeInteger(i)||i<1||i>1440*60)throw new a({message:"Tolerancia de webhook invalida.",code:"webhook_tolerance_invalid",suggestion:"Use uma tolerancia inteira entre 1 segundo e 24 horas."});let d=w(e);if(Math.abs(Math.floor(Date.now()/1e3)-d.timestamp)>i)throw new a({message:"Assinatura de webhook fora da janela de tolerancia.",code:"webhook_timestamp_outside_tolerance",suggestion:"Confira relogio do servidor e rejeite replays antigos."});let c=await b(n,`${d.timestamp}.${o}`);if(!x(c,d.value))throw new a({message:"Assinatura de webhook invalida.",code:"webhook_signature_mismatch",suggestion:"Use o webhook secret correto e o payload bruto, sem parse antes da validacao."});let s;try{s=JSON.parse(o);}catch{throw new a({message:"Payload de webhook nao e JSON valido.",code:"webhook_payload_invalid",suggestion:"Use o payload bruto recebido no endpoint da MuPag."})}if(typeof s.id!="string"||s.id.length===0||s.id.length>256||typeof s.type!="string"||s.type.length===0||s.type.length>128||s.data===null||typeof s.data!="object"||Array.isArray(s.data))throw new a({message:"Payload de webhook valido, mas sem campos obrigatorios.",code:"webhook_payload_invalid",suggestion:"Verifique se voce esta usando o endpoint de webhook da MuPag."});return s}var f=class{constructEvent=y};function w(t){if(t.length>4096)throw u();let e=t.split(",");if(e.length>16)throw u();let n,r;for(let m of e){let i=m.trim(),d=i.indexOf("=");if(d<=0)throw u();let g=i.slice(0,d),c=i.slice(d+1);if(g==="t"){if(n!==void 0)throw u();n=c;}else if(g==="v1"){if(r!==void 0)throw u();r=c;}}if(n===void 0||!/^(?:0|[1-9]\d*)$/.test(n))throw u();let o=Number(n);if(!Number.isSafeInteger(o)||o<=0||r===void 0||!/^[a-f0-9]{64}$/i.test(r))throw u();return {timestamp:o,value:r}}function u(){return new a({message:"Header de assinatura de webhook malformado.",code:"webhook_signature_malformed",suggestion:"Envie o header no formato t=<unix>,v1=<assinatura_hex>."})}async function b(t,e){let n=await crypto.subtle.importKey("raw",new TextEncoder().encode(t),{name:"HMAC",hash:"SHA-256"},false,["sign"]),r=await crypto.subtle.sign("HMAC",n,new TextEncoder().encode(e));return [...new Uint8Array(r)].map(o=>o.toString(16).padStart(2,"0")).join("")}function x(t,e){let n=Math.max(t.length,e.length),r=t.length^e.length;for(let o=0;o<n;o+=1)r|=(t.charCodeAt(o)||0)^(e.charCodeAt(o)||0);return r===0}exports.WebhooksResource=f;exports.constructWebhookEvent=y;//# sourceMappingURL=webhooks.cjs.map
2
+ //# sourceMappingURL=webhooks.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/webhooks.ts"],"names":["MuPagError","options","WebhookSignatureError","DEFAULT_TOLERANCE_SECONDS","MAX_WEBHOOK_BYTES","constructWebhookEvent","rawPayload","signatureHeader","secret","payload","toleranceSeconds","signature","parseSignatureHeader","expected","hmacSha256Hex","constantTimeEqual","event","WebhooksResource","malformedSignatureHeader","parts","timestampText","value","rawPart","part","separator","key","candidate","timestamp","byte","left","right","maxLength","diff","index"],"mappings":"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","file":"webhooks.cjs","sourcesContent":["import type { JsonObject, JsonValue } from './types.js';\n\nexport type ProblemDetails = JsonObject & {\n title?: string | undefined;\n detail?: string | undefined;\n status?: number | undefined;\n code?: string | undefined;\n suggestion?: string | undefined;\n documentation_url?: string | undefined;\n request_id?: string | undefined;\n};\n\nexport type MuPagErrorOptions = {\n message: string;\n status?: number | undefined;\n code?: string | undefined;\n requestId?: string | undefined;\n suggestion?: string | undefined;\n documentationUrl?: string | undefined;\n cause?: unknown | undefined;\n};\n\nexport class MuPagError extends Error {\n readonly status: number | undefined;\n readonly code: string | undefined;\n readonly requestId: string | undefined;\n readonly suggestion: string | undefined;\n readonly documentationUrl: string | undefined;\n\n /**\n * Mantem os campos de erro da API acessiveis no SDK sem expor payload bruto.\n *\n * A API publica envia Problem Details com extensoes DX-first. O SDK preserva\n * codigo, sugestao, link e request_id para o integrador resolver o problema\n * sem abrir suporte, mas evita guardar headers ou corpo inteiro com dados sensiveis.\n */\n constructor(options: MuPagErrorOptions) {\n super(options.message, options.cause === undefined ? undefined : { cause: options.cause });\n this.name = 'MuPagError';\n this.status = options.status;\n this.code = options.code;\n this.requestId = options.requestId;\n this.suggestion = options.suggestion;\n this.documentationUrl = options.documentationUrl;\n }\n}\n\nexport class APIError extends MuPagError {\n constructor(options: MuPagErrorOptions) {\n super(options);\n this.name = 'APIError';\n }\n}\n\nexport class RateLimitError extends APIError {\n readonly retryAfter: number | undefined;\n\n constructor(options: MuPagErrorOptions & { retryAfter?: number | undefined }) {\n super(options);\n this.name = 'RateLimitError';\n this.retryAfter = options.retryAfter;\n }\n}\n\nexport class ValidationError extends APIError {\n constructor(options: MuPagErrorOptions) {\n super(options);\n this.name = 'ValidationError';\n }\n}\n\nexport class AuthError extends APIError {\n constructor(options: MuPagErrorOptions) {\n super(options);\n this.name = 'AuthError';\n }\n}\n\nexport class IdempotencyError extends APIError {\n constructor(options: MuPagErrorOptions) {\n super(options);\n this.name = 'IdempotencyError';\n }\n}\n\nexport class OutcomeUnknownError extends APIError {\n readonly idempotencyKey: string;\n readonly outcomeUnknown = true;\n\n /**\n * Indica que uma mutacao pode ter sido aceita, mas nao houve confirmacao confiavel.\n *\n * A chave fica disponivel apenas no campo estruturado para evitar vazamento acidental\n * em logs. O integrador deve reutiliza-la com exatamente o mesmo payload.\n */\n constructor(idempotencyKey: string, cause: unknown) {\n const apiCause = cause instanceof APIError ? cause : undefined;\n super({\n message:\n 'O resultado da mutacao e desconhecido; reutilize a Idempotency-Key exposta com o mesmo payload.',\n status: apiCause?.status,\n code: 'outcome_unknown',\n requestId: apiCause?.requestId,\n suggestion:\n 'Reutilize a mesma Idempotency-Key e o mesmo payload para reconciliar a operacao.',\n documentationUrl: apiCause?.documentationUrl,\n cause\n });\n this.name = 'OutcomeUnknownError';\n this.idempotencyKey = idempotencyKey;\n }\n}\n\nexport class WebhookSignatureError extends MuPagError {\n constructor(options: MuPagErrorOptions) {\n super(options);\n this.name = 'WebhookSignatureError';\n }\n}\n\nexport function createApiError(\n status: number,\n payload: JsonValue | undefined,\n headers: Headers\n): APIError {\n const problem = isProblemDetails(payload) ? payload : {};\n const message = problem.detail ?? problem.title ?? `A API retornou HTTP ${status}.`;\n const options: MuPagErrorOptions = {\n message,\n status,\n code: problem.code,\n requestId: problem.request_id ?? headers.get('request-id') ?? undefined,\n suggestion: problem.suggestion,\n documentationUrl: problem.documentation_url\n };\n\n if (status === 401 || status === 403) {\n return new AuthError(options);\n }\n\n if (status === 409 && problem.code === 'idempotency_key_reused') {\n return new IdempotencyError(options);\n }\n\n if (status === 400 || status === 422) {\n return new ValidationError(options);\n }\n\n if (status === 429) {\n return new RateLimitError({\n ...options,\n retryAfter: parseRetryAfter(headers.get('retry-after'))\n });\n }\n\n return new APIError(options);\n}\n\nfunction parseRetryAfter(value: string | null): number | undefined {\n if (value === null) return undefined;\n if (/^\\d+$/.test(value)) return Number(value);\n const retryAt = Date.parse(value);\n if (Number.isNaN(retryAt)) return undefined;\n return Math.max(0, Math.ceil((retryAt - Date.now()) / 1_000));\n}\n\nfunction isProblemDetails(value: JsonValue | undefined): value is ProblemDetails {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n","import { WebhookSignatureError } from './errors.js';\nimport type { JsonValue, MuPagEvent } from './types.js';\n\nexport type WebhookOptions = {\n toleranceSeconds?: number;\n};\n\nconst DEFAULT_TOLERANCE_SECONDS = 300;\nconst MAX_WEBHOOK_BYTES = 1024 * 1024;\n\n/**\n * Valida assinatura HMAC-SHA256 de webhook e retorna evento tipado.\n *\n * A verificacao usa Web Crypto para funcionar tambem em Deno, Bun e edge\n * runtimes. O formato de assinatura e `t=<unix>,v1=<hex>`, sempre sobre\n * `timestamp.payload`, evitando replay com tolerancia curta.\n */\nexport async function constructWebhookEvent<TData extends JsonValue = JsonValue>(\n rawPayload: string | Uint8Array,\n signatureHeader: string,\n secret: string,\n options: WebhookOptions = {}\n): Promise<MuPagEvent<TData>> {\n const payload = typeof rawPayload === 'string' ? rawPayload : new TextDecoder().decode(rawPayload);\n const payloadBytes = typeof rawPayload === 'string' ? new TextEncoder().encode(rawPayload).byteLength : rawPayload.byteLength;\n if (payloadBytes > MAX_WEBHOOK_BYTES) {\n throw new WebhookSignatureError({\n message: 'Payload de webhook excede o limite seguro.',\n code: 'webhook_payload_too_large',\n suggestion: 'Rejeite o request com HTTP 413 antes de processar o evento.'\n });\n }\n const toleranceSeconds = options.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;\n if (secret.length < 1 || secret.length > 512 || secret.trim() !== secret) {\n throw new WebhookSignatureError({\n message: 'Webhook secret invalido.',\n code: 'webhook_secret_invalid',\n suggestion: 'Configure o webhook secret exato e nao use valor vazio ou com espacos externos.'\n });\n }\n if (\n !Number.isSafeInteger(toleranceSeconds)\n || toleranceSeconds < 1\n || toleranceSeconds > 24 * 60 * 60\n ) {\n throw new WebhookSignatureError({\n message: 'Tolerancia de webhook invalida.',\n code: 'webhook_tolerance_invalid',\n suggestion: 'Use uma tolerancia inteira entre 1 segundo e 24 horas.'\n });\n }\n const signature = parseSignatureHeader(signatureHeader);\n const ageSeconds = Math.abs(Math.floor(Date.now() / 1000) - signature.timestamp);\n\n if (ageSeconds > toleranceSeconds) {\n throw new WebhookSignatureError({\n message: 'Assinatura de webhook fora da janela de tolerancia.',\n code: 'webhook_timestamp_outside_tolerance',\n suggestion: 'Confira relogio do servidor e rejeite replays antigos.'\n });\n }\n\n const expected = await hmacSha256Hex(secret, `${signature.timestamp}.${payload}`);\n if (!constantTimeEqual(expected, signature.value)) {\n throw new WebhookSignatureError({\n message: 'Assinatura de webhook invalida.',\n code: 'webhook_signature_mismatch',\n suggestion: 'Use o webhook secret correto e o payload bruto, sem parse antes da validacao.'\n });\n }\n\n let event: MuPagEvent<TData>;\n try {\n event = JSON.parse(payload) as MuPagEvent<TData>;\n } catch {\n throw new WebhookSignatureError({\n message: 'Payload de webhook nao e JSON valido.',\n code: 'webhook_payload_invalid',\n suggestion: 'Use o payload bruto recebido no endpoint da MuPag.'\n });\n }\n if (typeof event.id !== 'string' || event.id.length === 0 || event.id.length > 256\n || typeof event.type !== 'string' || event.type.length === 0 || event.type.length > 128\n || event.data === null || typeof event.data !== 'object' || Array.isArray(event.data)) {\n throw new WebhookSignatureError({\n message: 'Payload de webhook valido, mas sem campos obrigatorios.',\n code: 'webhook_payload_invalid',\n suggestion: 'Verifique se voce esta usando o endpoint de webhook da MuPag.'\n });\n }\n\n return event;\n}\n\nexport class WebhooksResource {\n constructEvent = constructWebhookEvent;\n}\n\nfunction parseSignatureHeader(signatureHeader: string) {\n if (signatureHeader.length > 4096) throw malformedSignatureHeader();\n const parts = signatureHeader.split(',');\n if (parts.length > 16) throw malformedSignatureHeader();\n\n let timestampText: string | undefined;\n let value: string | undefined;\n for (const rawPart of parts) {\n const part = rawPart.trim();\n const separator = part.indexOf('=');\n if (separator <= 0) throw malformedSignatureHeader();\n const key = part.slice(0, separator);\n const candidate = part.slice(separator + 1);\n if (key === 't') {\n if (timestampText !== undefined) throw malformedSignatureHeader();\n timestampText = candidate;\n } else if (key === 'v1') {\n if (value !== undefined) throw malformedSignatureHeader();\n value = candidate;\n }\n }\n\n if (timestampText === undefined || !/^(?:0|[1-9]\\d*)$/.test(timestampText)) {\n throw malformedSignatureHeader();\n }\n const timestamp = Number(timestampText);\n if (!Number.isSafeInteger(timestamp) || timestamp <= 0 || value === undefined || !/^[a-f0-9]{64}$/i.test(value)) {\n throw malformedSignatureHeader();\n }\n\n return { timestamp, value };\n}\n\nfunction malformedSignatureHeader() {\n return new WebhookSignatureError({\n message: 'Header de assinatura de webhook malformado.',\n code: 'webhook_signature_malformed',\n suggestion: 'Envie o header no formato t=<unix>,v1=<assinatura_hex>.'\n });\n}\n\nasync function hmacSha256Hex(secret: string, value: string) {\n const key = await crypto.subtle.importKey(\n 'raw',\n new TextEncoder().encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n );\n const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(value));\n return [...new Uint8Array(signature)]\n .map((byte) => byte.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction constantTimeEqual(left: string, right: string) {\n const maxLength = Math.max(left.length, right.length);\n let diff = left.length ^ right.length;\n\n for (let index = 0; index < maxLength; index += 1) {\n diff |= (left.charCodeAt(index) || 0) ^ (right.charCodeAt(index) || 0);\n }\n\n return diff === 0;\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import { o as JsonValue, q as MuPagEvent } from './types-C1s3-E1E.cjs';
2
+
3
+ type WebhookOptions = {
4
+ toleranceSeconds?: number;
5
+ };
6
+ /**
7
+ * Valida assinatura HMAC-SHA256 de webhook e retorna evento tipado.
8
+ *
9
+ * A verificacao usa Web Crypto para funcionar tambem em Deno, Bun e edge
10
+ * runtimes. O formato de assinatura e `t=<unix>,v1=<hex>`, sempre sobre
11
+ * `timestamp.payload`, evitando replay com tolerancia curta.
12
+ */
13
+ declare function constructWebhookEvent<TData extends JsonValue = JsonValue>(rawPayload: string | Uint8Array, signatureHeader: string, secret: string, options?: WebhookOptions): Promise<MuPagEvent<TData>>;
14
+ declare class WebhooksResource {
15
+ constructEvent: typeof constructWebhookEvent;
16
+ }
17
+
18
+ export { type WebhookOptions, WebhooksResource, constructWebhookEvent };
@@ -0,0 +1,18 @@
1
+ import { o as JsonValue, q as MuPagEvent } from './types-C1s3-E1E.js';
2
+
3
+ type WebhookOptions = {
4
+ toleranceSeconds?: number;
5
+ };
6
+ /**
7
+ * Valida assinatura HMAC-SHA256 de webhook e retorna evento tipado.
8
+ *
9
+ * A verificacao usa Web Crypto para funcionar tambem em Deno, Bun e edge
10
+ * runtimes. O formato de assinatura e `t=<unix>,v1=<hex>`, sempre sobre
11
+ * `timestamp.payload`, evitando replay com tolerancia curta.
12
+ */
13
+ declare function constructWebhookEvent<TData extends JsonValue = JsonValue>(rawPayload: string | Uint8Array, signatureHeader: string, secret: string, options?: WebhookOptions): Promise<MuPagEvent<TData>>;
14
+ declare class WebhooksResource {
15
+ constructEvent: typeof constructWebhookEvent;
16
+ }
17
+
18
+ export { type WebhookOptions, WebhooksResource, constructWebhookEvent };
@@ -0,0 +1,2 @@
1
+ export{b as WebhooksResource,a as constructWebhookEvent}from'./chunk-FQHYME3I.js';import'./chunk-M4RQIIHN.js';//# sourceMappingURL=webhooks.js.map
2
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"webhooks.js"}
@@ -0,0 +1,23 @@
1
+ import { MuPag } from 'mupag-sdk';
2
+
3
+ const mupag = new MuPag({
4
+ apiKey: process.env.MUPAG_API_KEY!,
5
+ env: 'test'
6
+ });
7
+
8
+ const charge = await mupag.charges.create({
9
+ amount_cents: 14990,
10
+ payment_method: 'credit_card',
11
+ customer: {
12
+ id: 'cus_123',
13
+ name: 'Ana Silva',
14
+ email: 'ana@example.com',
15
+ tax_id: '12345678901'
16
+ },
17
+ card_token_id: '11111111-1111-1111-1111-111111111111',
18
+ payer_ip: '203.0.113.10',
19
+ installments: 1,
20
+ metadata: { checkout_id: 'chk_123' }
21
+ });
22
+
23
+ console.log(charge.status);
@@ -0,0 +1,20 @@
1
+ import { MuPag } from 'mupag-sdk';
2
+
3
+ const mupag = new MuPag({
4
+ apiKey: process.env.MUPAG_API_KEY!,
5
+ env: 'test'
6
+ });
7
+
8
+ const charge = await mupag.charges.create({
9
+ amount_cents: 9990,
10
+ payment_method: 'pix',
11
+ customer: {
12
+ id: 'cus_123',
13
+ name: 'Ana Silva',
14
+ email: 'ana@example.com',
15
+ tax_id: '12345678901'
16
+ },
17
+ description: 'Plano Pro mensal'
18
+ });
19
+
20
+ console.log(charge.charge_id);
@@ -0,0 +1,13 @@
1
+ import { MuPag } from 'mupag-sdk';
2
+
3
+ const mupag = new MuPag({
4
+ apiKey: process.env.MUPAG_API_KEY!,
5
+ env: 'test'
6
+ });
7
+
8
+ const refund = await mupag.refunds.create('ch_123', {
9
+ amount_cents: 9990,
10
+ reason: 'requested_by_customer'
11
+ });
12
+
13
+ console.log(refund.refund_id);
@@ -0,0 +1,13 @@
1
+ import { MuPag } from 'mupag-sdk';
2
+
3
+ const mupag = new MuPag({
4
+ apiKey: process.env.MUPAG_API_KEY!,
5
+ env: 'test'
6
+ });
7
+
8
+ const subscription = await mupag.subscriptions.cancel('sub_123', {
9
+ mode: 'immediate',
10
+ reason: 'customer_request'
11
+ });
12
+
13
+ console.log(subscription.status);
@@ -0,0 +1,20 @@
1
+ import { MuPag } from 'mupag-sdk';
2
+
3
+ const mupag = new MuPag({
4
+ apiKey: process.env.MUPAG_API_KEY!,
5
+ env: 'test'
6
+ });
7
+
8
+ export async function handleWebhook(rawPayload: string, signature: string) {
9
+ const event = await mupag.webhooks.constructEvent(
10
+ rawPayload,
11
+ signature,
12
+ process.env.MUPAG_WEBHOOK_SECRET!
13
+ );
14
+
15
+ if (event.type === 'charge.paid') {
16
+ console.log(event.data);
17
+ }
18
+
19
+ return event;
20
+ }
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "mupag-sdk",
3
+ "version": "0.2.0",
4
+ "description": "SDK TypeScript/Node.js oficial da MuPag para integrar pagamentos em minutos.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ },
16
+ "./errors": {
17
+ "types": "./dist/errors.d.ts",
18
+ "import": "./dist/errors.js",
19
+ "require": "./dist/errors.cjs"
20
+ },
21
+ "./webhooks": {
22
+ "types": "./dist/webhooks.d.ts",
23
+ "import": "./dist/webhooks.js",
24
+ "require": "./dist/webhooks.cjs"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist",
29
+ "README.md",
30
+ "examples"
31
+ ],
32
+ "scripts": {
33
+ "build": "tsup",
34
+ "test": "vitest run",
35
+ "coverage": "vitest run --coverage",
36
+ "typecheck": "tsc --noEmit",
37
+ "lint": "tsc --noEmit",
38
+ "docs": "typedoc src/index.ts",
39
+ "size": "npm run build && node scripts/check-bundle-size.mjs",
40
+ "check": "npm run typecheck && npm run coverage && npm run build && npm run size && npm run docs"
41
+ },
42
+ "keywords": [
43
+ "mupag",
44
+ "payments",
45
+ "payments",
46
+ "pix",
47
+ "typescript"
48
+ ],
49
+ "author": "MuPag",
50
+ "license": "UNLICENSED",
51
+ "homepage": "https://docs.mupag.com.br",
52
+ "engines": {
53
+ "node": ">=18"
54
+ },
55
+ "devDependencies": {
56
+ "@types/node": "^22.15.21",
57
+ "@vitest/coverage-v8": "4.1.8",
58
+ "nock": "^14.0.10",
59
+ "tsup": "^8.5.0",
60
+ "typedoc": "^0.28.14",
61
+ "typescript": "^5.8.3",
62
+ "vitest": "4.1.8"
63
+ },
64
+ "overrides": {
65
+ "esbuild": "0.28.2"
66
+ }
67
+ }