@sinnu-dev/sdk 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,895 @@
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
+ Checkout: () => Checkout,
24
+ DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
25
+ DEFAULT_CHECKOUT_BASE_URL: () => DEFAULT_CHECKOUT_BASE_URL,
26
+ SINNU_SIGNATURE_HEADER: () => SINNU_SIGNATURE_HEADER,
27
+ Sinnu: () => Sinnu,
28
+ SinnuAuthError: () => SinnuAuthError,
29
+ SinnuError: () => SinnuError,
30
+ SinnuNotFoundError: () => SinnuNotFoundError,
31
+ SinnuRateLimitError: () => SinnuRateLimitError,
32
+ SinnuValidationError: () => SinnuValidationError,
33
+ SinnuWebhookSignatureError: () => SinnuWebhookSignatureError,
34
+ collectAll: () => collectAll,
35
+ computeSignature: () => computeSignature,
36
+ constructEvent: () => constructEvent,
37
+ createTypedClient: () => createTypedClient,
38
+ default: () => index_default,
39
+ paginate: () => paginate,
40
+ unwrap: () => unwrap,
41
+ verifySignature: () => verifySignature,
42
+ webhooks: () => webhooks
43
+ });
44
+ module.exports = __toCommonJS(index_exports);
45
+
46
+ // node_modules/openapi-fetch/dist/index.js
47
+ var PATH_PARAM_RE = /\{[^{}]+\}/g;
48
+ var supportsRequestInitExt = () => {
49
+ return typeof process === "object" && Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 && process.versions.undici;
50
+ };
51
+ function randomID() {
52
+ return Math.random().toString(36).slice(2, 11);
53
+ }
54
+ function createClient(clientOptions) {
55
+ let {
56
+ baseUrl = "",
57
+ Request: CustomRequest = globalThis.Request,
58
+ fetch: baseFetch = globalThis.fetch,
59
+ querySerializer: globalQuerySerializer,
60
+ bodySerializer: globalBodySerializer,
61
+ headers: baseHeaders,
62
+ requestInitExt = void 0,
63
+ ...baseOptions
64
+ } = { ...clientOptions };
65
+ requestInitExt = supportsRequestInitExt() ? requestInitExt : void 0;
66
+ baseUrl = removeTrailingSlash(baseUrl);
67
+ const middlewares = [];
68
+ async function coreFetch(schemaPath, fetchOptions) {
69
+ const {
70
+ baseUrl: localBaseUrl,
71
+ fetch: fetch2 = baseFetch,
72
+ Request = CustomRequest,
73
+ headers,
74
+ params = {},
75
+ parseAs = "json",
76
+ querySerializer: requestQuerySerializer,
77
+ bodySerializer = globalBodySerializer ?? defaultBodySerializer,
78
+ body,
79
+ ...init
80
+ } = fetchOptions || {};
81
+ let finalBaseUrl = baseUrl;
82
+ if (localBaseUrl) {
83
+ finalBaseUrl = removeTrailingSlash(localBaseUrl) ?? baseUrl;
84
+ }
85
+ let querySerializer = typeof globalQuerySerializer === "function" ? globalQuerySerializer : createQuerySerializer(globalQuerySerializer);
86
+ if (requestQuerySerializer) {
87
+ querySerializer = typeof requestQuerySerializer === "function" ? requestQuerySerializer : createQuerySerializer({
88
+ ...typeof globalQuerySerializer === "object" ? globalQuerySerializer : {},
89
+ ...requestQuerySerializer
90
+ });
91
+ }
92
+ const serializedBody = body === void 0 ? void 0 : bodySerializer(
93
+ body,
94
+ // Note: we declare mergeHeaders() both here and below because it’s a bit of a chicken-or-egg situation:
95
+ // bodySerializer() needs all headers so we aren’t dropping ones set by the user, however,
96
+ // the result of this ALSO sets the lowest-priority content-type header. So we re-merge below,
97
+ // setting the content-type at the very beginning to be overwritten.
98
+ // Lastly, based on the way headers work, it’s not a simple “present-or-not” check becauase null intentionally un-sets headers.
99
+ mergeHeaders(baseHeaders, headers, params.header)
100
+ );
101
+ const finalHeaders = mergeHeaders(
102
+ // with no body, we should not to set Content-Type
103
+ serializedBody === void 0 || // if serialized body is FormData; browser will correctly set Content-Type & boundary expression
104
+ serializedBody instanceof FormData ? {} : {
105
+ "Content-Type": "application/json"
106
+ },
107
+ baseHeaders,
108
+ headers,
109
+ params.header
110
+ );
111
+ const requestInit = {
112
+ redirect: "follow",
113
+ ...baseOptions,
114
+ ...init,
115
+ body: serializedBody,
116
+ headers: finalHeaders
117
+ };
118
+ let id;
119
+ let options;
120
+ let request = new CustomRequest(
121
+ createFinalURL(schemaPath, { baseUrl: finalBaseUrl, params, querySerializer }),
122
+ requestInit
123
+ );
124
+ let response;
125
+ for (const key in init) {
126
+ if (!(key in request)) {
127
+ request[key] = init[key];
128
+ }
129
+ }
130
+ if (middlewares.length) {
131
+ id = randomID();
132
+ options = Object.freeze({
133
+ baseUrl: finalBaseUrl,
134
+ fetch: fetch2,
135
+ parseAs,
136
+ querySerializer,
137
+ bodySerializer
138
+ });
139
+ for (const m of middlewares) {
140
+ if (m && typeof m === "object" && typeof m.onRequest === "function") {
141
+ const result = await m.onRequest({
142
+ request,
143
+ schemaPath,
144
+ params,
145
+ options,
146
+ id
147
+ });
148
+ if (result) {
149
+ if (result instanceof CustomRequest) {
150
+ request = result;
151
+ } else if (result instanceof Response) {
152
+ response = result;
153
+ break;
154
+ } else {
155
+ throw new Error("onRequest: must return new Request() or Response() when modifying the request");
156
+ }
157
+ }
158
+ }
159
+ }
160
+ }
161
+ if (!response) {
162
+ try {
163
+ response = await fetch2(request, requestInitExt);
164
+ } catch (error2) {
165
+ let errorAfterMiddleware = error2;
166
+ if (middlewares.length) {
167
+ for (let i = middlewares.length - 1; i >= 0; i--) {
168
+ const m = middlewares[i];
169
+ if (m && typeof m === "object" && typeof m.onError === "function") {
170
+ const result = await m.onError({
171
+ request,
172
+ error: errorAfterMiddleware,
173
+ schemaPath,
174
+ params,
175
+ options,
176
+ id
177
+ });
178
+ if (result) {
179
+ if (result instanceof Response) {
180
+ errorAfterMiddleware = void 0;
181
+ response = result;
182
+ break;
183
+ }
184
+ if (result instanceof Error) {
185
+ errorAfterMiddleware = result;
186
+ continue;
187
+ }
188
+ throw new Error("onError: must return new Response() or instance of Error");
189
+ }
190
+ }
191
+ }
192
+ }
193
+ if (errorAfterMiddleware) {
194
+ throw errorAfterMiddleware;
195
+ }
196
+ }
197
+ if (middlewares.length) {
198
+ for (let i = middlewares.length - 1; i >= 0; i--) {
199
+ const m = middlewares[i];
200
+ if (m && typeof m === "object" && typeof m.onResponse === "function") {
201
+ const result = await m.onResponse({
202
+ request,
203
+ response,
204
+ schemaPath,
205
+ params,
206
+ options,
207
+ id
208
+ });
209
+ if (result) {
210
+ if (!(result instanceof Response)) {
211
+ throw new Error("onResponse: must return new Response() when modifying the response");
212
+ }
213
+ response = result;
214
+ }
215
+ }
216
+ }
217
+ }
218
+ }
219
+ if (response.status === 204 || request.method === "HEAD" || response.headers.get("Content-Length") === "0") {
220
+ return response.ok ? { data: void 0, response } : { error: void 0, response };
221
+ }
222
+ if (response.ok) {
223
+ if (parseAs === "stream") {
224
+ return { data: response.body, response };
225
+ }
226
+ return { data: await response[parseAs](), response };
227
+ }
228
+ let error = await response.text();
229
+ try {
230
+ error = JSON.parse(error);
231
+ } catch {
232
+ }
233
+ return { error, response };
234
+ }
235
+ return {
236
+ request(method, url, init) {
237
+ return coreFetch(url, { ...init, method: method.toUpperCase() });
238
+ },
239
+ /** Call a GET endpoint */
240
+ GET(url, init) {
241
+ return coreFetch(url, { ...init, method: "GET" });
242
+ },
243
+ /** Call a PUT endpoint */
244
+ PUT(url, init) {
245
+ return coreFetch(url, { ...init, method: "PUT" });
246
+ },
247
+ /** Call a POST endpoint */
248
+ POST(url, init) {
249
+ return coreFetch(url, { ...init, method: "POST" });
250
+ },
251
+ /** Call a DELETE endpoint */
252
+ DELETE(url, init) {
253
+ return coreFetch(url, { ...init, method: "DELETE" });
254
+ },
255
+ /** Call a OPTIONS endpoint */
256
+ OPTIONS(url, init) {
257
+ return coreFetch(url, { ...init, method: "OPTIONS" });
258
+ },
259
+ /** Call a HEAD endpoint */
260
+ HEAD(url, init) {
261
+ return coreFetch(url, { ...init, method: "HEAD" });
262
+ },
263
+ /** Call a PATCH endpoint */
264
+ PATCH(url, init) {
265
+ return coreFetch(url, { ...init, method: "PATCH" });
266
+ },
267
+ /** Call a TRACE endpoint */
268
+ TRACE(url, init) {
269
+ return coreFetch(url, { ...init, method: "TRACE" });
270
+ },
271
+ /** Register middleware */
272
+ use(...middleware) {
273
+ for (const m of middleware) {
274
+ if (!m) {
275
+ continue;
276
+ }
277
+ if (typeof m !== "object" || !("onRequest" in m || "onResponse" in m || "onError" in m)) {
278
+ throw new Error("Middleware must be an object with one of `onRequest()`, `onResponse() or `onError()`");
279
+ }
280
+ middlewares.push(m);
281
+ }
282
+ },
283
+ /** Unregister middleware */
284
+ eject(...middleware) {
285
+ for (const m of middleware) {
286
+ const i = middlewares.indexOf(m);
287
+ if (i !== -1) {
288
+ middlewares.splice(i, 1);
289
+ }
290
+ }
291
+ }
292
+ };
293
+ }
294
+ function serializePrimitiveParam(name, value, options) {
295
+ if (value === void 0 || value === null) {
296
+ return "";
297
+ }
298
+ if (typeof value === "object") {
299
+ throw new Error(
300
+ "Deeply-nested arrays/objects aren\u2019t supported. Provide your own `querySerializer()` to handle these."
301
+ );
302
+ }
303
+ return `${name}=${options?.allowReserved === true ? value : encodeURIComponent(value)}`;
304
+ }
305
+ function serializeObjectParam(name, value, options) {
306
+ if (!value || typeof value !== "object") {
307
+ return "";
308
+ }
309
+ const values = [];
310
+ const joiner = {
311
+ simple: ",",
312
+ label: ".",
313
+ matrix: ";"
314
+ }[options.style] || "&";
315
+ if (options.style !== "deepObject" && options.explode === false) {
316
+ for (const k in value) {
317
+ values.push(k, options.allowReserved === true ? value[k] : encodeURIComponent(value[k]));
318
+ }
319
+ const final2 = values.join(",");
320
+ switch (options.style) {
321
+ case "form": {
322
+ return `${name}=${final2}`;
323
+ }
324
+ case "label": {
325
+ return `.${final2}`;
326
+ }
327
+ case "matrix": {
328
+ return `;${name}=${final2}`;
329
+ }
330
+ default: {
331
+ return final2;
332
+ }
333
+ }
334
+ }
335
+ for (const k in value) {
336
+ const finalName = options.style === "deepObject" ? `${name}[${k}]` : k;
337
+ values.push(serializePrimitiveParam(finalName, value[k], options));
338
+ }
339
+ const final = values.join(joiner);
340
+ return options.style === "label" || options.style === "matrix" ? `${joiner}${final}` : final;
341
+ }
342
+ function serializeArrayParam(name, value, options) {
343
+ if (!Array.isArray(value)) {
344
+ return "";
345
+ }
346
+ if (options.explode === false) {
347
+ const joiner2 = { form: ",", spaceDelimited: "%20", pipeDelimited: "|" }[options.style] || ",";
348
+ const final = (options.allowReserved === true ? value : value.map((v) => encodeURIComponent(v))).join(joiner2);
349
+ switch (options.style) {
350
+ case "simple": {
351
+ return final;
352
+ }
353
+ case "label": {
354
+ return `.${final}`;
355
+ }
356
+ case "matrix": {
357
+ return `;${name}=${final}`;
358
+ }
359
+ // case "spaceDelimited":
360
+ // case "pipeDelimited":
361
+ default: {
362
+ return `${name}=${final}`;
363
+ }
364
+ }
365
+ }
366
+ const joiner = { simple: ",", label: ".", matrix: ";" }[options.style] || "&";
367
+ const values = [];
368
+ for (const v of value) {
369
+ if (options.style === "simple" || options.style === "label") {
370
+ values.push(options.allowReserved === true ? v : encodeURIComponent(v));
371
+ } else {
372
+ values.push(serializePrimitiveParam(name, v, options));
373
+ }
374
+ }
375
+ return options.style === "label" || options.style === "matrix" ? `${joiner}${values.join(joiner)}` : values.join(joiner);
376
+ }
377
+ function createQuerySerializer(options) {
378
+ return function querySerializer(queryParams) {
379
+ const search = [];
380
+ if (queryParams && typeof queryParams === "object") {
381
+ for (const name in queryParams) {
382
+ const value = queryParams[name];
383
+ if (value === void 0 || value === null) {
384
+ continue;
385
+ }
386
+ if (Array.isArray(value)) {
387
+ if (value.length === 0) {
388
+ continue;
389
+ }
390
+ search.push(
391
+ serializeArrayParam(name, value, {
392
+ style: "form",
393
+ explode: true,
394
+ ...options?.array,
395
+ allowReserved: options?.allowReserved || false
396
+ })
397
+ );
398
+ continue;
399
+ }
400
+ if (typeof value === "object") {
401
+ search.push(
402
+ serializeObjectParam(name, value, {
403
+ style: "deepObject",
404
+ explode: true,
405
+ ...options?.object,
406
+ allowReserved: options?.allowReserved || false
407
+ })
408
+ );
409
+ continue;
410
+ }
411
+ search.push(serializePrimitiveParam(name, value, options));
412
+ }
413
+ }
414
+ return search.join("&");
415
+ };
416
+ }
417
+ function defaultPathSerializer(pathname, pathParams) {
418
+ let nextURL = pathname;
419
+ for (const match of pathname.match(PATH_PARAM_RE) ?? []) {
420
+ let name = match.substring(1, match.length - 1);
421
+ let explode = false;
422
+ let style = "simple";
423
+ if (name.endsWith("*")) {
424
+ explode = true;
425
+ name = name.substring(0, name.length - 1);
426
+ }
427
+ if (name.startsWith(".")) {
428
+ style = "label";
429
+ name = name.substring(1);
430
+ } else if (name.startsWith(";")) {
431
+ style = "matrix";
432
+ name = name.substring(1);
433
+ }
434
+ if (!pathParams || pathParams[name] === void 0 || pathParams[name] === null) {
435
+ continue;
436
+ }
437
+ const value = pathParams[name];
438
+ if (Array.isArray(value)) {
439
+ nextURL = nextURL.replace(match, serializeArrayParam(name, value, { style, explode }));
440
+ continue;
441
+ }
442
+ if (typeof value === "object") {
443
+ nextURL = nextURL.replace(match, serializeObjectParam(name, value, { style, explode }));
444
+ continue;
445
+ }
446
+ if (style === "matrix") {
447
+ nextURL = nextURL.replace(match, `;${serializePrimitiveParam(name, value)}`);
448
+ continue;
449
+ }
450
+ nextURL = nextURL.replace(match, style === "label" ? `.${encodeURIComponent(value)}` : encodeURIComponent(value));
451
+ }
452
+ return nextURL;
453
+ }
454
+ function defaultBodySerializer(body, headers) {
455
+ if (body instanceof FormData) {
456
+ return body;
457
+ }
458
+ if (headers) {
459
+ const contentType = headers.get instanceof Function ? headers.get("Content-Type") ?? headers.get("content-type") : headers["Content-Type"] ?? headers["content-type"];
460
+ if (contentType === "application/x-www-form-urlencoded") {
461
+ return new URLSearchParams(body).toString();
462
+ }
463
+ }
464
+ return JSON.stringify(body);
465
+ }
466
+ function createFinalURL(pathname, options) {
467
+ let finalURL = `${options.baseUrl}${pathname}`;
468
+ if (options.params?.path) {
469
+ finalURL = defaultPathSerializer(finalURL, options.params.path);
470
+ }
471
+ let search = options.querySerializer(options.params.query ?? {});
472
+ if (search.startsWith("?")) {
473
+ search = search.substring(1);
474
+ }
475
+ if (search) {
476
+ finalURL += `?${search}`;
477
+ }
478
+ return finalURL;
479
+ }
480
+ function mergeHeaders(...allHeaders) {
481
+ const finalHeaders = new Headers();
482
+ for (const h of allHeaders) {
483
+ if (!h || typeof h !== "object") {
484
+ continue;
485
+ }
486
+ const iterator = h instanceof Headers ? h.entries() : Object.entries(h);
487
+ for (const [k, v] of iterator) {
488
+ if (v === null) {
489
+ finalHeaders.delete(k);
490
+ } else if (Array.isArray(v)) {
491
+ for (const v2 of v) {
492
+ finalHeaders.append(k, v2);
493
+ }
494
+ } else if (v !== void 0) {
495
+ finalHeaders.set(k, v);
496
+ }
497
+ }
498
+ }
499
+ return finalHeaders;
500
+ }
501
+ function removeTrailingSlash(url) {
502
+ if (url.endsWith("/")) {
503
+ return url.substring(0, url.length - 1);
504
+ }
505
+ return url;
506
+ }
507
+
508
+ // src/errors.ts
509
+ var SinnuError = class extends Error {
510
+ constructor(message, statusCode, body, response) {
511
+ super(message);
512
+ this.name = "SinnuError";
513
+ this.statusCode = statusCode;
514
+ this.body = body;
515
+ this.response = response;
516
+ }
517
+ };
518
+ var SinnuAuthError = class extends SinnuError {
519
+ constructor(message, statusCode = 401, body, response) {
520
+ super(message, statusCode, body, response);
521
+ this.name = "SinnuAuthError";
522
+ }
523
+ };
524
+ var SinnuNotFoundError = class extends SinnuError {
525
+ constructor(message, body, response) {
526
+ super(message, 404, body, response);
527
+ this.name = "SinnuNotFoundError";
528
+ }
529
+ };
530
+ var SinnuValidationError = class extends SinnuError {
531
+ constructor(message, statusCode, body, response) {
532
+ super(message, statusCode, body, response);
533
+ this.name = "SinnuValidationError";
534
+ }
535
+ };
536
+ var SinnuRateLimitError = class extends SinnuError {
537
+ constructor(message, body, response) {
538
+ super(message, 429, body, response);
539
+ this.name = "SinnuRateLimitError";
540
+ }
541
+ };
542
+ function toSinnuError(statusCode, body, response) {
543
+ const message = body?.message ?? `Requisi\xE7\xE3o falhou com status ${statusCode}`;
544
+ switch (statusCode) {
545
+ case 401:
546
+ case 403:
547
+ return new SinnuAuthError(message, statusCode, body, response);
548
+ case 404:
549
+ return new SinnuNotFoundError(message, body, response);
550
+ case 400:
551
+ case 422:
552
+ return new SinnuValidationError(message, statusCode, body, response);
553
+ case 429:
554
+ return new SinnuRateLimitError(message, body, response);
555
+ default:
556
+ return new SinnuError(message, statusCode, body, response);
557
+ }
558
+ }
559
+
560
+ // src/client.ts
561
+ var DEFAULT_BASE_URL = "https://api.sinnu.com.br";
562
+ var API_KEY_PREFIXES = ["sk_live_"];
563
+ function assertApiKey(apiKey) {
564
+ if (!apiKey || typeof apiKey !== "string") {
565
+ throw new Error(
566
+ "[@sinnu-dev/sdk] apiKey \xE9 obrigat\xF3ria. Gere uma chave secreta no painel sinnu (Integra\xE7\xF5es)."
567
+ );
568
+ }
569
+ if (!API_KEY_PREFIXES.some((p) => apiKey.startsWith(p))) {
570
+ console.warn(
571
+ "[@sinnu-dev/sdk] apiKey n\xE3o come\xE7a com 'sk_live_'. Use a chave secreta no backend, nunca uma chave no cliente."
572
+ );
573
+ }
574
+ }
575
+ function createTypedClient(options) {
576
+ assertApiKey(options.apiKey);
577
+ return createClient({
578
+ baseUrl: options.baseUrl ?? DEFAULT_BASE_URL,
579
+ fetch: options.fetch,
580
+ headers: {
581
+ Authorization: `Bearer ${options.apiKey}`,
582
+ "Content-Type": "application/json",
583
+ ...options.headers
584
+ }
585
+ });
586
+ }
587
+ async function unwrap(p) {
588
+ const { data, error, response } = await p;
589
+ if (error || !response.ok) {
590
+ throw toSinnuError(
591
+ response.status,
592
+ error ?? void 0,
593
+ response
594
+ );
595
+ }
596
+ if (data === void 0 || data === null) {
597
+ throw toSinnuError(response.status, { message: "Resposta sem corpo" }, response);
598
+ }
599
+ return data;
600
+ }
601
+ var RawHttp = class {
602
+ constructor(baseUrl, apiKey, extraHeaders, fetchImpl) {
603
+ this.baseUrl = baseUrl;
604
+ this.apiKey = apiKey;
605
+ this.extraHeaders = extraHeaders;
606
+ this.fetchImpl = fetchImpl;
607
+ }
608
+ async request(path, options = {}) {
609
+ const url = new URL(path.replace(/^\//, ""), ensureTrailingSlash(this.baseUrl));
610
+ if (options.query) {
611
+ for (const [key, value] of Object.entries(options.query)) {
612
+ if (value !== void 0) {
613
+ url.searchParams.set(key, String(value));
614
+ }
615
+ }
616
+ }
617
+ const response = await this.fetchImpl(url.toString(), {
618
+ method: options.method ?? "GET",
619
+ headers: {
620
+ Authorization: `Bearer ${this.apiKey}`,
621
+ "Content-Type": "application/json",
622
+ Accept: "application/json",
623
+ ...this.extraHeaders
624
+ },
625
+ body: options.body !== void 0 ? JSON.stringify(options.body) : void 0
626
+ });
627
+ const text = await response.text();
628
+ const parsed = text ? safeJsonParse(text) : void 0;
629
+ if (!response.ok) {
630
+ throw toSinnuError(response.status, parsed, response);
631
+ }
632
+ return parsed;
633
+ }
634
+ };
635
+ function ensureTrailingSlash(url) {
636
+ return url.endsWith("/") ? url : `${url}/`;
637
+ }
638
+ function safeJsonParse(text) {
639
+ try {
640
+ return JSON.parse(text);
641
+ } catch {
642
+ return text;
643
+ }
644
+ }
645
+
646
+ // src/resources/checkout.ts
647
+ var DEFAULT_CHECKOUT_BASE_URL = "https://pay.sinnu.com.br";
648
+ var Checkout = class {
649
+ constructor(options = {}) {
650
+ this.options = options;
651
+ }
652
+ /**
653
+ * Monta a URL pública do checkout hosted para um `slug` (8 chars) gerado
654
+ * ao criar um link (`sinnu.links.create(...).url` já vem pronto; este
655
+ * helper é útil quando você só tem o slug).
656
+ *
657
+ * @example
658
+ * const url = sinnu.checkout.url("abcd1234", { reference: "pedido-123" });
659
+ * // => "https://pay.sinnu.com.br/abcd1234?ref=pedido-123"
660
+ */
661
+ url(slug, options = {}) {
662
+ if (!slug || typeof slug !== "string") {
663
+ throw new Error("[@sinnu-dev/sdk] slug do checkout \xE9 obrigat\xF3rio.");
664
+ }
665
+ const base = options.checkoutBaseUrl ?? this.options.checkoutBaseUrl ?? DEFAULT_CHECKOUT_BASE_URL;
666
+ const url = new URL(encodeURIComponent(slug), ensureTrailingSlash2(base));
667
+ const query = { ...this.options.query, ...options.query };
668
+ for (const [key, value] of Object.entries(query)) {
669
+ if (value !== void 0) {
670
+ url.searchParams.set(key, String(value));
671
+ }
672
+ }
673
+ if (options.reference !== void 0) {
674
+ if (options.reference.length > 255) {
675
+ throw new Error("[@sinnu-dev/sdk] reference tem no m\xE1ximo 255 caracteres.");
676
+ }
677
+ url.searchParams.set("ref", options.reference);
678
+ }
679
+ return url.toString();
680
+ }
681
+ };
682
+ function ensureTrailingSlash2(url) {
683
+ return url.endsWith("/") ? url : `${url}/`;
684
+ }
685
+
686
+ // src/pagination.ts
687
+ async function* paginate(fetchPage) {
688
+ let page = 1;
689
+ let seen = 0;
690
+ while (true) {
691
+ const result = await fetchPage(page);
692
+ for (const item of result.data) {
693
+ yield item;
694
+ }
695
+ seen += result.data.length;
696
+ const pageSize = result.pageSize || result.data.length;
697
+ if (result.data.length === 0 || seen >= result.total || pageSize === 0) {
698
+ return;
699
+ }
700
+ page += 1;
701
+ }
702
+ }
703
+ async function collectAll(fetchPage) {
704
+ const out = [];
705
+ for await (const item of paginate(fetchPage)) {
706
+ out.push(item);
707
+ }
708
+ return out;
709
+ }
710
+
711
+ // src/resources/links.ts
712
+ var Links = class {
713
+ constructor(http) {
714
+ this.http = http;
715
+ }
716
+ /** Cria um link de pagamento (valor em centavos). */
717
+ async create(body) {
718
+ return this.http.request("/api/payment-links", {
719
+ method: "POST",
720
+ body
721
+ });
722
+ }
723
+ /** Busca um link de pagamento pelo id. */
724
+ async get(id) {
725
+ return this.http.request(`/api/payment-links/${encodeURIComponent(id)}`);
726
+ }
727
+ /** Atualiza parcialmente um link de pagamento. */
728
+ async update(id, body) {
729
+ return this.http.request(`/api/payment-links/${encodeURIComponent(id)}`, {
730
+ method: "PATCH",
731
+ body
732
+ });
733
+ }
734
+ /** Arquiva um link de pagamento. */
735
+ async archive(id) {
736
+ await this.http.request(`/api/payment-links/${encodeURIComponent(id)}`, {
737
+ method: "DELETE"
738
+ });
739
+ }
740
+ /** Lista links de pagamento (paginado). */
741
+ async list(params = {}) {
742
+ return this.http.request("/api/payment-links", {
743
+ query: { page: params.page, pageSize: params.pageSize }
744
+ });
745
+ }
746
+ /** Lista transações de um link de pagamento (paginado). */
747
+ async transactions(id, params = {}) {
748
+ return this.http.request(
749
+ `/api/payment-links/${encodeURIComponent(id)}/transactions`,
750
+ { query: { page: params.page, pageSize: params.pageSize } }
751
+ );
752
+ }
753
+ /** Itera todos os links de pagamento, página a página. */
754
+ listAll(params = {}) {
755
+ return paginate((page) => this.list({ ...params, page }));
756
+ }
757
+ };
758
+
759
+ // src/resources/transactions.ts
760
+ var Transactions = class {
761
+ constructor(http) {
762
+ this.http = http;
763
+ }
764
+ /** Lista transações (paginado, com filtro opcional por status). */
765
+ async list(params = {}) {
766
+ return this.http.request("/api/transactions/", {
767
+ query: {
768
+ status: params.status,
769
+ search: params.search,
770
+ customer: params.customer,
771
+ page: params.page,
772
+ pageSize: params.pageSize
773
+ }
774
+ });
775
+ }
776
+ /** Busca uma transação pelo id. */
777
+ async get(id) {
778
+ return this.http.request(`/api/transactions/${encodeURIComponent(id)}/`);
779
+ }
780
+ /** Estorna (refund) uma transação, sempre pelo valor total. Exige o escopo `transactions:refund` na chave. */
781
+ async refund(id, body = {}) {
782
+ return this.http.request(
783
+ `/api/transactions/${encodeURIComponent(id)}/refund/`,
784
+ { method: "POST", body }
785
+ );
786
+ }
787
+ /** Itera todas as transações, página a página. */
788
+ listAll(params = {}) {
789
+ return paginate((page) => this.list({ ...params, page }));
790
+ }
791
+ };
792
+
793
+ // src/webhooks.ts
794
+ var import_node_crypto = require("crypto");
795
+ var SINNU_SIGNATURE_HEADER = "x-sinnu-signature";
796
+ var SinnuWebhookSignatureError = class extends SinnuError {
797
+ constructor(message) {
798
+ super(message, 0);
799
+ this.name = "SinnuWebhookSignatureError";
800
+ }
801
+ };
802
+ function normalizeSignature(signature) {
803
+ if (signature === void 0) {
804
+ throw new SinnuWebhookSignatureError(
805
+ "[@sinnu-dev/sdk] header de assinatura ausente. Esperado 'X-Sinnu-Signature'."
806
+ );
807
+ }
808
+ const value = Array.isArray(signature) ? signature[0] : signature;
809
+ if (!value) {
810
+ throw new SinnuWebhookSignatureError("[@sinnu-dev/sdk] header de assinatura vazio.");
811
+ }
812
+ return value.startsWith("sha256=") ? value.slice("sha256=".length) : value;
813
+ }
814
+ function toBuffer(payload) {
815
+ return typeof payload === "string" ? Buffer.from(payload, "utf8") : payload;
816
+ }
817
+ function computeSignature(payload, secret) {
818
+ return (0, import_node_crypto.createHmac)("sha256", secret).update(toBuffer(payload)).digest("hex");
819
+ }
820
+ function verifySignature(options) {
821
+ const { payload, signature, secret } = options;
822
+ if (!secret) {
823
+ throw new SinnuWebhookSignatureError(
824
+ "[@sinnu-dev/sdk] webhook secret \xE9 obrigat\xF3rio para verificar a assinatura."
825
+ );
826
+ }
827
+ const provided = normalizeSignature(signature);
828
+ const expected = computeSignature(payload, secret);
829
+ const providedBuf = Buffer.from(provided, "hex");
830
+ const expectedBuf = Buffer.from(expected, "hex");
831
+ if (providedBuf.length !== expectedBuf.length) {
832
+ return false;
833
+ }
834
+ return (0, import_node_crypto.timingSafeEqual)(providedBuf, expectedBuf);
835
+ }
836
+ function constructEvent(options) {
837
+ if (!verifySignature(options)) {
838
+ throw new SinnuWebhookSignatureError(
839
+ "[@sinnu-dev/sdk] assinatura de webhook inv\xE1lida. Requisi\xE7\xE3o rejeitada."
840
+ );
841
+ }
842
+ const text = typeof options.payload === "string" ? options.payload : options.payload.toString("utf8");
843
+ try {
844
+ return JSON.parse(text);
845
+ } catch {
846
+ throw new SinnuWebhookSignatureError("[@sinnu-dev/sdk] corpo do webhook n\xE3o \xE9 um JSON v\xE1lido.");
847
+ }
848
+ }
849
+ var webhooks = {
850
+ signatureHeader: SINNU_SIGNATURE_HEADER,
851
+ computeSignature,
852
+ verifySignature,
853
+ constructEvent
854
+ };
855
+
856
+ // src/index.ts
857
+ var Sinnu = class {
858
+ constructor(options) {
859
+ /** Verificação de webhooks (HMAC SHA-256): não faz requisições. */
860
+ this.webhooks = webhooks;
861
+ this.http = createTypedClient(options);
862
+ const raw = new RawHttp(
863
+ options.baseUrl ?? DEFAULT_BASE_URL,
864
+ options.apiKey,
865
+ options.headers ?? {},
866
+ options.fetch ?? fetch
867
+ );
868
+ this.links = new Links(raw);
869
+ this.transactions = new Transactions(raw);
870
+ this.checkout = new Checkout({ checkoutBaseUrl: options.checkoutBaseUrl });
871
+ }
872
+ };
873
+ var index_default = Sinnu;
874
+ // Annotate the CommonJS export names for ESM import in node:
875
+ 0 && (module.exports = {
876
+ Checkout,
877
+ DEFAULT_BASE_URL,
878
+ DEFAULT_CHECKOUT_BASE_URL,
879
+ SINNU_SIGNATURE_HEADER,
880
+ Sinnu,
881
+ SinnuAuthError,
882
+ SinnuError,
883
+ SinnuNotFoundError,
884
+ SinnuRateLimitError,
885
+ SinnuValidationError,
886
+ SinnuWebhookSignatureError,
887
+ collectAll,
888
+ computeSignature,
889
+ constructEvent,
890
+ createTypedClient,
891
+ paginate,
892
+ unwrap,
893
+ verifySignature,
894
+ webhooks
895
+ });