@sazito/checkout 0.4.19 → 0.4.20

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.
Files changed (47) hide show
  1. package/README.md +19 -37
  2. package/dist/chunks/{labels-Cysz2BgA.js → labels-CwHBYso8.js} +9 -5
  3. package/dist/chunks/labels-CwHBYso8.js.map +1 -0
  4. package/dist/chunks/{labels-Cy05dLJx.cjs → labels-FNi3eq4p.cjs} +9 -5
  5. package/dist/chunks/labels-FNi3eq4p.cjs.map +1 -0
  6. package/dist/chunks/{use-checkout-wHkKNkbK.cjs → use-checkout-DsTtOAMs.cjs} +9 -4
  7. package/dist/chunks/use-checkout-DsTtOAMs.cjs.map +1 -0
  8. package/dist/chunks/{use-checkout-uWEi8iqK.js → use-checkout-OyHfWeAh.js} +10 -5
  9. package/dist/chunks/use-checkout-OyHfWeAh.js.map +1 -0
  10. package/dist/core/index.cjs +3 -1
  11. package/dist/core/index.cjs.map +1 -1
  12. package/dist/core/index.d.cts +18 -4
  13. package/dist/core/index.d.ts +18 -4
  14. package/dist/core/index.js +2 -2
  15. package/dist/next/index.cjs +12 -6
  16. package/dist/next/index.cjs.map +1 -1
  17. package/dist/next/index.d.cts +10 -3
  18. package/dist/next/index.d.ts +10 -3
  19. package/dist/next/index.js +14 -8
  20. package/dist/next/index.js.map +1 -1
  21. package/dist/next/payment-return.cjs +50 -0
  22. package/dist/next/payment-return.cjs.map +1 -1
  23. package/dist/next/payment-return.d.cts +16 -2
  24. package/dist/next/payment-return.d.ts +16 -2
  25. package/dist/next/payment-return.js +49 -1
  26. package/dist/next/payment-return.js.map +1 -1
  27. package/dist/next/server.cjs +10 -0
  28. package/dist/next/server.cjs.map +1 -0
  29. package/dist/next/server.d.cts +33 -0
  30. package/dist/next/server.d.ts +33 -0
  31. package/dist/next/server.js +4 -0
  32. package/dist/next/server.js.map +1 -0
  33. package/dist/react/index.cjs +2 -2
  34. package/dist/react/index.d.cts +3 -2
  35. package/dist/react/index.d.ts +3 -2
  36. package/dist/react/index.js +2 -2
  37. package/dist/server/index.cjs +182 -0
  38. package/dist/server/index.cjs.map +1 -0
  39. package/dist/server/index.d.cts +33 -0
  40. package/dist/server/index.d.ts +33 -0
  41. package/dist/server/index.js +180 -0
  42. package/dist/server/index.js.map +1 -0
  43. package/package.json +30 -2
  44. package/dist/chunks/labels-Cy05dLJx.cjs.map +0 -1
  45. package/dist/chunks/labels-Cysz2BgA.js.map +0 -1
  46. package/dist/chunks/use-checkout-uWEi8iqK.js.map +0 -1
  47. package/dist/chunks/use-checkout-wHkKNkbK.cjs.map +0 -1
@@ -1,5 +1,29 @@
1
1
  'use strict';
2
2
 
3
+ const SAZITO_PAYMENT_STATUS_QUERY = {
4
+ resolution: 'sazito_payment_return',
5
+ paymentId: 'sazito_payment_id',
6
+ paymentIdentifier: 'sazito_payment_identifier'
7
+ };
8
+ /** Remove server-return credentials from the visible URL after they are read. */
9
+ function stripPaymentStatusReturn(url) {
10
+ let parsedUrl;
11
+ try {
12
+ parsedUrl = typeof url === 'string'
13
+ ? new URL(url, 'https://checkout.sazito.invalid')
14
+ : new URL(url.toString());
15
+ }
16
+ catch {
17
+ return undefined;
18
+ }
19
+ if (parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {
20
+ return undefined;
21
+ }
22
+ parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.resolution);
23
+ parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentId);
24
+ parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier);
25
+ return `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;
26
+ }
3
27
  const SAZITO_PAYMENT_RESULT_MARKERS = [
4
28
  'mellatpaymentresult', 'pecpaymentresult', 'uppaymentresult',
5
29
  'seppaymentresult', 'vandarpaymentresult', 'yourgatepaymentresult',
@@ -57,6 +81,9 @@ function parsePaymentReturnUrl(url, options = {}) {
57
81
  catch {
58
82
  return undefined;
59
83
  }
84
+ const statusReturn = parsePaymentStatusReturn(parsedUrl);
85
+ if (statusReturn)
86
+ return statusReturn;
60
87
  const segments = parsedUrl.pathname
61
88
  .split('/')
62
89
  .filter(Boolean)
@@ -73,6 +100,27 @@ function parsePaymentReturnUrl(url, options = {}) {
73
100
  }
74
101
  return parsePaymentReturn(segments.slice(-5), searchParams, options);
75
102
  }
103
+ function parsePaymentStatusReturn(url) {
104
+ if (url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {
105
+ return undefined;
106
+ }
107
+ const rawPaymentId = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.paymentId);
108
+ const identifier = url.searchParams
109
+ .get(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier)
110
+ ?.trim();
111
+ const paymentId = Number(rawPaymentId);
112
+ if (!Number.isSafeInteger(paymentId) || paymentId <= 0 || !identifier) {
113
+ return undefined;
114
+ }
115
+ return {
116
+ payment: { id: paymentId, identifier },
117
+ params: {
118
+ id: String(paymentId),
119
+ paymentIdentifier: identifier
120
+ },
121
+ resolution: 'status'
122
+ };
123
+ }
76
124
  function decodePathSegment(segment) {
77
125
  try {
78
126
  return decodeURIComponent(segment);
@@ -93,6 +141,8 @@ function normalizeSearchParams(searchParams) {
93
141
  }
94
142
 
95
143
  exports.SAZITO_PAYMENT_RESULT_MARKERS = SAZITO_PAYMENT_RESULT_MARKERS;
144
+ exports.SAZITO_PAYMENT_STATUS_QUERY = SAZITO_PAYMENT_STATUS_QUERY;
96
145
  exports.parsePaymentReturn = parsePaymentReturn;
97
146
  exports.parsePaymentReturnUrl = parsePaymentReturnUrl;
147
+ exports.stripPaymentStatusReturn = stripPaymentStatusReturn;
98
148
  //# sourceMappingURL=payment-return.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"payment-return.cjs","sources":["../../src/core/payment-return.ts"],"sourcesContent":["import type {\n CheckoutPaymentReturn,\n PaymentReturnParserOptions,\n PaymentReturnSearchParams\n} from './types';\n\nexport const SAZITO_PAYMENT_RESULT_MARKERS = [\n 'mellatpaymentresult', 'pecpaymentresult', 'uppaymentresult',\n 'seppaymentresult', 'vandarpaymentresult', 'yourgatepaymentresult',\n 'bazarpaymentresult', 'zifypaymentresult', 'zibalpaymentresult',\n 'snapppaypaymentresult', 'torobpaypaymentresult', 'ghestapaypaymentresult',\n 'azkipaymentresult', 'digipaypaymentresult', 'greenpaypaymentresult',\n 'novapaypaymentresult', 'zarinpluspaymentresult', 'tomanpaymentresult',\n 'tarapaymentresult', 'ozonpaymentresult', 'millipaypaymentresult',\n 'ayriapaymentresult', 'sadadpaymentresult', 'freepaymentresult',\n 'paymentinplaceresult', 'cardtocardpaymentresult', 'zarinpalpaymentresult',\n 'directpayresult', 'paypingpaymentresult', 'podpaymentresult',\n 'sabinpaymentresult', 'firoozepaymentresult', 'technopaypaymentresult',\n 'buywithdigikalaresult'\n] as const;\n\n/**\n * Parse Sazito's nested payment callback path into checkout-ready data.\n * Returns undefined for ordinary checkout URLs and malformed callbacks.\n */\nexport function parsePaymentReturn(\n segments: readonly string[] | undefined,\n searchParams: PaymentReturnSearchParams = {},\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n const [resultRoute, paymentSegment, rawPaymentId, identifierSegment, rawIdentifier] =\n segments ?? [];\n const paymentId = Number(rawPaymentId);\n const identifier = rawIdentifier?.trim();\n const allowedMarkers = new Set(\n (options.gatewayResultMarkers ?? SAZITO_PAYMENT_RESULT_MARKERS)\n .map((marker) => marker.toLowerCase())\n );\n\n if (\n segments?.length !== 5 ||\n !resultRoute ||\n !allowedMarkers.has(resultRoute.toLowerCase()) ||\n paymentSegment?.toLowerCase() !== 'payment' ||\n identifierSegment?.toLowerCase() !== 'identifier' ||\n !Number.isSafeInteger(paymentId) ||\n paymentId <= 0 ||\n !identifier\n ) {\n return undefined;\n }\n\n const params = normalizeSearchParams(searchParams);\n params.id = String(paymentId);\n params.paymentIdentifier = identifier;\n\n return {\n payment: { id: paymentId, identifier },\n params\n };\n}\n\n/**\n * Parse a complete checkout URL containing Sazito's nested payment callback.\n * The callback may be mounted below any checkout base path; only its final\n * five path segments are significant.\n */\nexport function parsePaymentReturnUrl(\n url: string | URL,\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n let parsedUrl: URL;\n\n try {\n parsedUrl = typeof url === 'string'\n ? new URL(url, 'https://checkout.sazito.invalid')\n : url;\n } catch {\n return undefined;\n }\n\n const segments = parsedUrl.pathname\n .split('/')\n .filter(Boolean)\n .map(decodePathSegment);\n\n if (segments.length < 5) {\n return undefined;\n }\n\n const searchParams: Record<string, string> = {};\n for (const [key, value] of parsedUrl.searchParams) {\n // Match Next.js search-param normalization: preserve the first value.\n if (searchParams[key] === undefined) {\n searchParams[key] = value;\n }\n }\n\n return parsePaymentReturn(segments.slice(-5), searchParams, options);\n}\n\nfunction decodePathSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\nfunction normalizeSearchParams(\n searchParams: PaymentReturnSearchParams\n): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(searchParams)) {\n const firstValue = Array.isArray(value) ? value[0] : value;\n if (firstValue !== undefined) {\n normalized[key] = firstValue;\n }\n }\n\n return normalized;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"payment-return.cjs","sources":["../../src/core/payment-return.ts"],"sourcesContent":["import type {\n CheckoutPaymentReturn,\n PaymentReturnParserOptions,\n PaymentReturnSearchParams\n} from './types';\n\nexport const SAZITO_PAYMENT_STATUS_QUERY = {\n resolution: 'sazito_payment_return',\n paymentId: 'sazito_payment_id',\n paymentIdentifier: 'sazito_payment_identifier'\n} as const;\n\n/** Remove server-return credentials from the visible URL after they are read. */\nexport function stripPaymentStatusReturn(url: string | URL): string | undefined {\n let parsedUrl: URL;\n try {\n parsedUrl = typeof url === 'string'\n ? new URL(url, 'https://checkout.sazito.invalid')\n : new URL(url.toString());\n } catch {\n return undefined;\n }\n\n if (parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {\n return undefined;\n }\n\n parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.resolution);\n parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentId);\n parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier);\n return `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;\n}\n\nexport const SAZITO_PAYMENT_RESULT_MARKERS = [\n 'mellatpaymentresult', 'pecpaymentresult', 'uppaymentresult',\n 'seppaymentresult', 'vandarpaymentresult', 'yourgatepaymentresult',\n 'bazarpaymentresult', 'zifypaymentresult', 'zibalpaymentresult',\n 'snapppaypaymentresult', 'torobpaypaymentresult', 'ghestapaypaymentresult',\n 'azkipaymentresult', 'digipaypaymentresult', 'greenpaypaymentresult',\n 'novapaypaymentresult', 'zarinpluspaymentresult', 'tomanpaymentresult',\n 'tarapaymentresult', 'ozonpaymentresult', 'millipaypaymentresult',\n 'ayriapaymentresult', 'sadadpaymentresult', 'freepaymentresult',\n 'paymentinplaceresult', 'cardtocardpaymentresult', 'zarinpalpaymentresult',\n 'directpayresult', 'paypingpaymentresult', 'podpaymentresult',\n 'sabinpaymentresult', 'firoozepaymentresult', 'technopaypaymentresult',\n 'buywithdigikalaresult'\n] as const;\n\n/**\n * Parse Sazito's nested payment callback path into checkout-ready data.\n * Returns undefined for ordinary checkout URLs and malformed callbacks.\n */\nexport function parsePaymentReturn(\n segments: readonly string[] | undefined,\n searchParams: PaymentReturnSearchParams = {},\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n const [resultRoute, paymentSegment, rawPaymentId, identifierSegment, rawIdentifier] =\n segments ?? [];\n const paymentId = Number(rawPaymentId);\n const identifier = rawIdentifier?.trim();\n const allowedMarkers = new Set(\n (options.gatewayResultMarkers ?? SAZITO_PAYMENT_RESULT_MARKERS)\n .map((marker) => marker.toLowerCase())\n );\n\n if (\n segments?.length !== 5 ||\n !resultRoute ||\n !allowedMarkers.has(resultRoute.toLowerCase()) ||\n paymentSegment?.toLowerCase() !== 'payment' ||\n identifierSegment?.toLowerCase() !== 'identifier' ||\n !Number.isSafeInteger(paymentId) ||\n paymentId <= 0 ||\n !identifier\n ) {\n return undefined;\n }\n\n const params = normalizeSearchParams(searchParams);\n params.id = String(paymentId);\n params.paymentIdentifier = identifier;\n\n return {\n payment: { id: paymentId, identifier },\n params\n };\n}\n\n/**\n * Parse a complete checkout URL containing Sazito's nested payment callback.\n * The callback may be mounted below any checkout base path; only its final\n * five path segments are significant.\n */\nexport function parsePaymentReturnUrl(\n url: string | URL,\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n let parsedUrl: URL;\n\n try {\n parsedUrl = typeof url === 'string'\n ? new URL(url, 'https://checkout.sazito.invalid')\n : url;\n } catch {\n return undefined;\n }\n\n const statusReturn = parsePaymentStatusReturn(parsedUrl);\n if (statusReturn) return statusReturn;\n\n const segments = parsedUrl.pathname\n .split('/')\n .filter(Boolean)\n .map(decodePathSegment);\n\n if (segments.length < 5) {\n return undefined;\n }\n\n const searchParams: Record<string, string> = {};\n for (const [key, value] of parsedUrl.searchParams) {\n // Match Next.js search-param normalization: preserve the first value.\n if (searchParams[key] === undefined) {\n searchParams[key] = value;\n }\n }\n\n return parsePaymentReturn(segments.slice(-5), searchParams, options);\n}\n\nfunction parsePaymentStatusReturn(url: URL): CheckoutPaymentReturn | undefined {\n if (url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {\n return undefined;\n }\n\n const rawPaymentId = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.paymentId);\n const identifier = url.searchParams\n .get(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier)\n ?.trim();\n const paymentId = Number(rawPaymentId);\n\n if (!Number.isSafeInteger(paymentId) || paymentId <= 0 || !identifier) {\n return undefined;\n }\n\n return {\n payment: { id: paymentId, identifier },\n params: {\n id: String(paymentId),\n paymentIdentifier: identifier\n },\n resolution: 'status'\n };\n}\n\nfunction decodePathSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\nfunction normalizeSearchParams(\n searchParams: PaymentReturnSearchParams\n): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(searchParams)) {\n const firstValue = Array.isArray(value) ? value[0] : value;\n if (firstValue !== undefined) {\n normalized[key] = firstValue;\n }\n }\n\n return normalized;\n}\n"],"names":[],"mappings":";;AAMO,MAAM,2BAA2B,GAAG;AACzC,IAAA,UAAU,EAAE,uBAAuB;AACnC,IAAA,SAAS,EAAE,mBAAmB;AAC9B,IAAA,iBAAiB,EAAE;;AAGrB;AACM,SAAU,wBAAwB,CAAC,GAAiB,EAAA;AACxD,IAAA,IAAI,SAAc;AAClB,IAAA,IAAI;AACF,QAAA,SAAS,GAAG,OAAO,GAAG,KAAK;AACzB,cAAE,IAAI,GAAG,CAAC,GAAG,EAAE,iCAAiC;cAC9C,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE;AACnF,QAAA,OAAO,SAAS;IAClB;IAEA,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,2BAA2B,CAAC,UAAU,CAAC;IACrE,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,2BAA2B,CAAC,SAAS,CAAC;IACpE,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,2BAA2B,CAAC,iBAAiB,CAAC;AAC5E,IAAA,OAAO,CAAA,EAAG,SAAS,CAAC,QAAQ,CAAA,EAAG,SAAS,CAAC,MAAM,CAAA,EAAG,SAAS,CAAC,IAAI,EAAE;AACpE;AAEO,MAAM,6BAA6B,GAAG;IAC3C,qBAAqB,EAAE,kBAAkB,EAAE,iBAAiB;IAC5D,kBAAkB,EAAE,qBAAqB,EAAE,uBAAuB;IAClE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB;IAC/D,uBAAuB,EAAE,uBAAuB,EAAE,wBAAwB;IAC1E,mBAAmB,EAAE,sBAAsB,EAAE,uBAAuB;IACpE,sBAAsB,EAAE,wBAAwB,EAAE,oBAAoB;IACtE,mBAAmB,EAAE,mBAAmB,EAAE,uBAAuB;IACjE,oBAAoB,EAAE,oBAAoB,EAAE,mBAAmB;IAC/D,sBAAsB,EAAE,yBAAyB,EAAE,uBAAuB;IAC1E,iBAAiB,EAAE,sBAAsB,EAAE,kBAAkB;IAC7D,oBAAoB,EAAE,sBAAsB,EAAE,wBAAwB;IACtE;;AAGF;;;AAGG;AACG,SAAU,kBAAkB,CAChC,QAAuC,EACvC,YAAA,GAA0C,EAAE,EAC5C,OAAA,GAAsC,EAAE,EAAA;AAExC,IAAA,MAAM,CAAC,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,CAAC,GACjF,QAAQ,IAAI,EAAE;AAChB,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;AACtC,IAAA,MAAM,UAAU,GAAG,aAAa,EAAE,IAAI,EAAE;IACxC,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,CAAC,OAAO,CAAC,oBAAoB,IAAI,6BAA6B;AAC3D,SAAA,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CACzC;AAED,IAAA,IACE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACtB,QAAA,CAAC,WAAW;QACZ,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;AAC9C,QAAA,cAAc,EAAE,WAAW,EAAE,KAAK,SAAS;AAC3C,QAAA,iBAAiB,EAAE,WAAW,EAAE,KAAK,YAAY;AACjD,QAAA,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC;AAChC,QAAA,SAAS,IAAI,CAAC;QACd,CAAC,UAAU,EACX;AACA,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,MAAM,GAAG,qBAAqB,CAAC,YAAY,CAAC;AAClD,IAAA,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;AAC7B,IAAA,MAAM,CAAC,iBAAiB,GAAG,UAAU;IAErC,OAAO;AACL,QAAA,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;QACtC;KACD;AACH;AAEA;;;;AAIG;SACa,qBAAqB,CACnC,GAAiB,EACjB,UAAsC,EAAE,EAAA;AAExC,IAAA,IAAI,SAAc;AAElB,IAAA,IAAI;AACF,QAAA,SAAS,GAAG,OAAO,GAAG,KAAK;AACzB,cAAE,IAAI,GAAG,CAAC,GAAG,EAAE,iCAAiC;cAC9C,GAAG;IACT;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,YAAY,GAAG,wBAAwB,CAAC,SAAS,CAAC;AACxD,IAAA,IAAI,YAAY;AAAE,QAAA,OAAO,YAAY;AAErC,IAAA,MAAM,QAAQ,GAAG,SAAS,CAAC;SACxB,KAAK,CAAC,GAAG;SACT,MAAM,CAAC,OAAO;SACd,GAAG,CAAC,iBAAiB,CAAC;AAEzB,IAAA,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AACvB,QAAA,OAAO,SAAS;IAClB;IAEA,MAAM,YAAY,GAA2B,EAAE;IAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,YAAY,EAAE;;AAEjD,QAAA,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;AACnC,YAAA,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK;QAC3B;IACF;AAEA,IAAA,OAAO,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC;AACtE;AAEA,SAAS,wBAAwB,CAAC,GAAQ,EAAA;AACxC,IAAA,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE;AAC7E,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,SAAS,CAAC;AAChF,IAAA,MAAM,UAAU,GAAG,GAAG,CAAC;AACpB,SAAA,GAAG,CAAC,2BAA2B,CAAC,iBAAiB;UAChD,IAAI,EAAE;AACV,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;AAEtC,IAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;AACrE,QAAA,OAAO,SAAS;IAClB;IAEA,OAAO;AACL,QAAA,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;AACtC,QAAA,MAAM,EAAE;AACN,YAAA,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;AACrB,YAAA,iBAAiB,EAAE;AACpB,SAAA;AACD,QAAA,UAAU,EAAE;KACb;AACH;AAEA,SAAS,iBAAiB,CAAC,OAAe,EAAA;AACxC,IAAA,IAAI;AACF,QAAA,OAAO,kBAAkB,CAAC,OAAO,CAAC;IACpC;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,OAAO;IAChB;AACF;AAEA,SAAS,qBAAqB,CAC5B,YAAuC,EAAA;IAEvC,MAAM,UAAU,GAA2B,EAAE;AAE7C,IAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;AACvD,QAAA,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AAC1D,QAAA,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5B,YAAA,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU;QAC9B;IACF;AAEA,IAAA,OAAO,UAAU;AACnB;;;;;;;;"}
@@ -12,7 +12,14 @@ interface CheckoutPaymentReturn {
12
12
  identifier: string;
13
13
  };
14
14
  params: Record<string, string>;
15
+ /**
16
+ * `callback` forwards gateway fields for verification. `status` is emitted
17
+ * by the SDK server handler after it has already verified the gateway POST,
18
+ * so the browser performs only an authoritative status read.
19
+ */
20
+ resolution?: PaymentReturnResolution;
15
21
  }
22
+ type PaymentReturnResolution = 'callback' | 'status';
16
23
  /** Search-param shape exposed by current Next.js App Router pages. */
17
24
  type PaymentReturnSearchParams = Record<string, string | string[] | undefined>;
18
25
  interface PaymentReturnParserOptions {
@@ -20,6 +27,13 @@ interface PaymentReturnParserOptions {
20
27
  gatewayResultMarkers?: readonly string[];
21
28
  }
22
29
 
30
+ declare const SAZITO_PAYMENT_STATUS_QUERY: {
31
+ readonly resolution: "sazito_payment_return";
32
+ readonly paymentId: "sazito_payment_id";
33
+ readonly paymentIdentifier: "sazito_payment_identifier";
34
+ };
35
+ /** Remove server-return credentials from the visible URL after they are read. */
36
+ declare function stripPaymentStatusReturn(url: string | URL): string | undefined;
23
37
  declare const SAZITO_PAYMENT_RESULT_MARKERS: readonly ["mellatpaymentresult", "pecpaymentresult", "uppaymentresult", "seppaymentresult", "vandarpaymentresult", "yourgatepaymentresult", "bazarpaymentresult", "zifypaymentresult", "zibalpaymentresult", "snapppaypaymentresult", "torobpaypaymentresult", "ghestapaypaymentresult", "azkipaymentresult", "digipaypaymentresult", "greenpaypaymentresult", "novapaypaymentresult", "zarinpluspaymentresult", "tomanpaymentresult", "tarapaymentresult", "ozonpaymentresult", "millipaypaymentresult", "ayriapaymentresult", "sadadpaymentresult", "freepaymentresult", "paymentinplaceresult", "cardtocardpaymentresult", "zarinpalpaymentresult", "directpayresult", "paypingpaymentresult", "podpaymentresult", "sabinpaymentresult", "firoozepaymentresult", "technopaypaymentresult", "buywithdigikalaresult"];
24
38
  /**
25
39
  * Parse Sazito's nested payment callback path into checkout-ready data.
@@ -33,5 +47,5 @@ declare function parsePaymentReturn(segments: readonly string[] | undefined, sea
33
47
  */
34
48
  declare function parsePaymentReturnUrl(url: string | URL, options?: PaymentReturnParserOptions): CheckoutPaymentReturn | undefined;
35
49
 
36
- export { SAZITO_PAYMENT_RESULT_MARKERS, parsePaymentReturn, parsePaymentReturnUrl };
37
- export type { CheckoutPaymentReturn, PaymentReturnParserOptions, PaymentReturnSearchParams };
50
+ export { SAZITO_PAYMENT_RESULT_MARKERS, SAZITO_PAYMENT_STATUS_QUERY, parsePaymentReturn, parsePaymentReturnUrl, stripPaymentStatusReturn };
51
+ export type { CheckoutPaymentReturn, PaymentReturnParserOptions, PaymentReturnResolution, PaymentReturnSearchParams };
@@ -12,7 +12,14 @@ interface CheckoutPaymentReturn {
12
12
  identifier: string;
13
13
  };
14
14
  params: Record<string, string>;
15
+ /**
16
+ * `callback` forwards gateway fields for verification. `status` is emitted
17
+ * by the SDK server handler after it has already verified the gateway POST,
18
+ * so the browser performs only an authoritative status read.
19
+ */
20
+ resolution?: PaymentReturnResolution;
15
21
  }
22
+ type PaymentReturnResolution = 'callback' | 'status';
16
23
  /** Search-param shape exposed by current Next.js App Router pages. */
17
24
  type PaymentReturnSearchParams = Record<string, string | string[] | undefined>;
18
25
  interface PaymentReturnParserOptions {
@@ -20,6 +27,13 @@ interface PaymentReturnParserOptions {
20
27
  gatewayResultMarkers?: readonly string[];
21
28
  }
22
29
 
30
+ declare const SAZITO_PAYMENT_STATUS_QUERY: {
31
+ readonly resolution: "sazito_payment_return";
32
+ readonly paymentId: "sazito_payment_id";
33
+ readonly paymentIdentifier: "sazito_payment_identifier";
34
+ };
35
+ /** Remove server-return credentials from the visible URL after they are read. */
36
+ declare function stripPaymentStatusReturn(url: string | URL): string | undefined;
23
37
  declare const SAZITO_PAYMENT_RESULT_MARKERS: readonly ["mellatpaymentresult", "pecpaymentresult", "uppaymentresult", "seppaymentresult", "vandarpaymentresult", "yourgatepaymentresult", "bazarpaymentresult", "zifypaymentresult", "zibalpaymentresult", "snapppaypaymentresult", "torobpaypaymentresult", "ghestapaypaymentresult", "azkipaymentresult", "digipaypaymentresult", "greenpaypaymentresult", "novapaypaymentresult", "zarinpluspaymentresult", "tomanpaymentresult", "tarapaymentresult", "ozonpaymentresult", "millipaypaymentresult", "ayriapaymentresult", "sadadpaymentresult", "freepaymentresult", "paymentinplaceresult", "cardtocardpaymentresult", "zarinpalpaymentresult", "directpayresult", "paypingpaymentresult", "podpaymentresult", "sabinpaymentresult", "firoozepaymentresult", "technopaypaymentresult", "buywithdigikalaresult"];
24
38
  /**
25
39
  * Parse Sazito's nested payment callback path into checkout-ready data.
@@ -33,5 +47,5 @@ declare function parsePaymentReturn(segments: readonly string[] | undefined, sea
33
47
  */
34
48
  declare function parsePaymentReturnUrl(url: string | URL, options?: PaymentReturnParserOptions): CheckoutPaymentReturn | undefined;
35
49
 
36
- export { SAZITO_PAYMENT_RESULT_MARKERS, parsePaymentReturn, parsePaymentReturnUrl };
37
- export type { CheckoutPaymentReturn, PaymentReturnParserOptions, PaymentReturnSearchParams };
50
+ export { SAZITO_PAYMENT_RESULT_MARKERS, SAZITO_PAYMENT_STATUS_QUERY, parsePaymentReturn, parsePaymentReturnUrl, stripPaymentStatusReturn };
51
+ export type { CheckoutPaymentReturn, PaymentReturnParserOptions, PaymentReturnResolution, PaymentReturnSearchParams };
@@ -1,3 +1,27 @@
1
+ const SAZITO_PAYMENT_STATUS_QUERY = {
2
+ resolution: 'sazito_payment_return',
3
+ paymentId: 'sazito_payment_id',
4
+ paymentIdentifier: 'sazito_payment_identifier'
5
+ };
6
+ /** Remove server-return credentials from the visible URL after they are read. */
7
+ function stripPaymentStatusReturn(url) {
8
+ let parsedUrl;
9
+ try {
10
+ parsedUrl = typeof url === 'string'
11
+ ? new URL(url, 'https://checkout.sazito.invalid')
12
+ : new URL(url.toString());
13
+ }
14
+ catch {
15
+ return undefined;
16
+ }
17
+ if (parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {
18
+ return undefined;
19
+ }
20
+ parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.resolution);
21
+ parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentId);
22
+ parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier);
23
+ return `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;
24
+ }
1
25
  const SAZITO_PAYMENT_RESULT_MARKERS = [
2
26
  'mellatpaymentresult', 'pecpaymentresult', 'uppaymentresult',
3
27
  'seppaymentresult', 'vandarpaymentresult', 'yourgatepaymentresult',
@@ -55,6 +79,9 @@ function parsePaymentReturnUrl(url, options = {}) {
55
79
  catch {
56
80
  return undefined;
57
81
  }
82
+ const statusReturn = parsePaymentStatusReturn(parsedUrl);
83
+ if (statusReturn)
84
+ return statusReturn;
58
85
  const segments = parsedUrl.pathname
59
86
  .split('/')
60
87
  .filter(Boolean)
@@ -71,6 +98,27 @@ function parsePaymentReturnUrl(url, options = {}) {
71
98
  }
72
99
  return parsePaymentReturn(segments.slice(-5), searchParams, options);
73
100
  }
101
+ function parsePaymentStatusReturn(url) {
102
+ if (url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {
103
+ return undefined;
104
+ }
105
+ const rawPaymentId = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.paymentId);
106
+ const identifier = url.searchParams
107
+ .get(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier)
108
+ ?.trim();
109
+ const paymentId = Number(rawPaymentId);
110
+ if (!Number.isSafeInteger(paymentId) || paymentId <= 0 || !identifier) {
111
+ return undefined;
112
+ }
113
+ return {
114
+ payment: { id: paymentId, identifier },
115
+ params: {
116
+ id: String(paymentId),
117
+ paymentIdentifier: identifier
118
+ },
119
+ resolution: 'status'
120
+ };
121
+ }
74
122
  function decodePathSegment(segment) {
75
123
  try {
76
124
  return decodeURIComponent(segment);
@@ -90,5 +138,5 @@ function normalizeSearchParams(searchParams) {
90
138
  return normalized;
91
139
  }
92
140
 
93
- export { SAZITO_PAYMENT_RESULT_MARKERS, parsePaymentReturn, parsePaymentReturnUrl };
141
+ export { SAZITO_PAYMENT_RESULT_MARKERS, SAZITO_PAYMENT_STATUS_QUERY, parsePaymentReturn, parsePaymentReturnUrl, stripPaymentStatusReturn };
94
142
  //# sourceMappingURL=payment-return.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"payment-return.js","sources":["../../src/core/payment-return.ts"],"sourcesContent":["import type {\n CheckoutPaymentReturn,\n PaymentReturnParserOptions,\n PaymentReturnSearchParams\n} from './types';\n\nexport const SAZITO_PAYMENT_RESULT_MARKERS = [\n 'mellatpaymentresult', 'pecpaymentresult', 'uppaymentresult',\n 'seppaymentresult', 'vandarpaymentresult', 'yourgatepaymentresult',\n 'bazarpaymentresult', 'zifypaymentresult', 'zibalpaymentresult',\n 'snapppaypaymentresult', 'torobpaypaymentresult', 'ghestapaypaymentresult',\n 'azkipaymentresult', 'digipaypaymentresult', 'greenpaypaymentresult',\n 'novapaypaymentresult', 'zarinpluspaymentresult', 'tomanpaymentresult',\n 'tarapaymentresult', 'ozonpaymentresult', 'millipaypaymentresult',\n 'ayriapaymentresult', 'sadadpaymentresult', 'freepaymentresult',\n 'paymentinplaceresult', 'cardtocardpaymentresult', 'zarinpalpaymentresult',\n 'directpayresult', 'paypingpaymentresult', 'podpaymentresult',\n 'sabinpaymentresult', 'firoozepaymentresult', 'technopaypaymentresult',\n 'buywithdigikalaresult'\n] as const;\n\n/**\n * Parse Sazito's nested payment callback path into checkout-ready data.\n * Returns undefined for ordinary checkout URLs and malformed callbacks.\n */\nexport function parsePaymentReturn(\n segments: readonly string[] | undefined,\n searchParams: PaymentReturnSearchParams = {},\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n const [resultRoute, paymentSegment, rawPaymentId, identifierSegment, rawIdentifier] =\n segments ?? [];\n const paymentId = Number(rawPaymentId);\n const identifier = rawIdentifier?.trim();\n const allowedMarkers = new Set(\n (options.gatewayResultMarkers ?? SAZITO_PAYMENT_RESULT_MARKERS)\n .map((marker) => marker.toLowerCase())\n );\n\n if (\n segments?.length !== 5 ||\n !resultRoute ||\n !allowedMarkers.has(resultRoute.toLowerCase()) ||\n paymentSegment?.toLowerCase() !== 'payment' ||\n identifierSegment?.toLowerCase() !== 'identifier' ||\n !Number.isSafeInteger(paymentId) ||\n paymentId <= 0 ||\n !identifier\n ) {\n return undefined;\n }\n\n const params = normalizeSearchParams(searchParams);\n params.id = String(paymentId);\n params.paymentIdentifier = identifier;\n\n return {\n payment: { id: paymentId, identifier },\n params\n };\n}\n\n/**\n * Parse a complete checkout URL containing Sazito's nested payment callback.\n * The callback may be mounted below any checkout base path; only its final\n * five path segments are significant.\n */\nexport function parsePaymentReturnUrl(\n url: string | URL,\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n let parsedUrl: URL;\n\n try {\n parsedUrl = typeof url === 'string'\n ? new URL(url, 'https://checkout.sazito.invalid')\n : url;\n } catch {\n return undefined;\n }\n\n const segments = parsedUrl.pathname\n .split('/')\n .filter(Boolean)\n .map(decodePathSegment);\n\n if (segments.length < 5) {\n return undefined;\n }\n\n const searchParams: Record<string, string> = {};\n for (const [key, value] of parsedUrl.searchParams) {\n // Match Next.js search-param normalization: preserve the first value.\n if (searchParams[key] === undefined) {\n searchParams[key] = value;\n }\n }\n\n return parsePaymentReturn(segments.slice(-5), searchParams, options);\n}\n\nfunction decodePathSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\nfunction normalizeSearchParams(\n searchParams: PaymentReturnSearchParams\n): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(searchParams)) {\n const firstValue = Array.isArray(value) ? value[0] : value;\n if (firstValue !== undefined) {\n normalized[key] = firstValue;\n }\n }\n\n return normalized;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"payment-return.js","sources":["../../src/core/payment-return.ts"],"sourcesContent":["import type {\n CheckoutPaymentReturn,\n PaymentReturnParserOptions,\n PaymentReturnSearchParams\n} from './types';\n\nexport const SAZITO_PAYMENT_STATUS_QUERY = {\n resolution: 'sazito_payment_return',\n paymentId: 'sazito_payment_id',\n paymentIdentifier: 'sazito_payment_identifier'\n} as const;\n\n/** Remove server-return credentials from the visible URL after they are read. */\nexport function stripPaymentStatusReturn(url: string | URL): string | undefined {\n let parsedUrl: URL;\n try {\n parsedUrl = typeof url === 'string'\n ? new URL(url, 'https://checkout.sazito.invalid')\n : new URL(url.toString());\n } catch {\n return undefined;\n }\n\n if (parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {\n return undefined;\n }\n\n parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.resolution);\n parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentId);\n parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier);\n return `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;\n}\n\nexport const SAZITO_PAYMENT_RESULT_MARKERS = [\n 'mellatpaymentresult', 'pecpaymentresult', 'uppaymentresult',\n 'seppaymentresult', 'vandarpaymentresult', 'yourgatepaymentresult',\n 'bazarpaymentresult', 'zifypaymentresult', 'zibalpaymentresult',\n 'snapppaypaymentresult', 'torobpaypaymentresult', 'ghestapaypaymentresult',\n 'azkipaymentresult', 'digipaypaymentresult', 'greenpaypaymentresult',\n 'novapaypaymentresult', 'zarinpluspaymentresult', 'tomanpaymentresult',\n 'tarapaymentresult', 'ozonpaymentresult', 'millipaypaymentresult',\n 'ayriapaymentresult', 'sadadpaymentresult', 'freepaymentresult',\n 'paymentinplaceresult', 'cardtocardpaymentresult', 'zarinpalpaymentresult',\n 'directpayresult', 'paypingpaymentresult', 'podpaymentresult',\n 'sabinpaymentresult', 'firoozepaymentresult', 'technopaypaymentresult',\n 'buywithdigikalaresult'\n] as const;\n\n/**\n * Parse Sazito's nested payment callback path into checkout-ready data.\n * Returns undefined for ordinary checkout URLs and malformed callbacks.\n */\nexport function parsePaymentReturn(\n segments: readonly string[] | undefined,\n searchParams: PaymentReturnSearchParams = {},\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n const [resultRoute, paymentSegment, rawPaymentId, identifierSegment, rawIdentifier] =\n segments ?? [];\n const paymentId = Number(rawPaymentId);\n const identifier = rawIdentifier?.trim();\n const allowedMarkers = new Set(\n (options.gatewayResultMarkers ?? SAZITO_PAYMENT_RESULT_MARKERS)\n .map((marker) => marker.toLowerCase())\n );\n\n if (\n segments?.length !== 5 ||\n !resultRoute ||\n !allowedMarkers.has(resultRoute.toLowerCase()) ||\n paymentSegment?.toLowerCase() !== 'payment' ||\n identifierSegment?.toLowerCase() !== 'identifier' ||\n !Number.isSafeInteger(paymentId) ||\n paymentId <= 0 ||\n !identifier\n ) {\n return undefined;\n }\n\n const params = normalizeSearchParams(searchParams);\n params.id = String(paymentId);\n params.paymentIdentifier = identifier;\n\n return {\n payment: { id: paymentId, identifier },\n params\n };\n}\n\n/**\n * Parse a complete checkout URL containing Sazito's nested payment callback.\n * The callback may be mounted below any checkout base path; only its final\n * five path segments are significant.\n */\nexport function parsePaymentReturnUrl(\n url: string | URL,\n options: PaymentReturnParserOptions = {}\n): CheckoutPaymentReturn | undefined {\n let parsedUrl: URL;\n\n try {\n parsedUrl = typeof url === 'string'\n ? new URL(url, 'https://checkout.sazito.invalid')\n : url;\n } catch {\n return undefined;\n }\n\n const statusReturn = parsePaymentStatusReturn(parsedUrl);\n if (statusReturn) return statusReturn;\n\n const segments = parsedUrl.pathname\n .split('/')\n .filter(Boolean)\n .map(decodePathSegment);\n\n if (segments.length < 5) {\n return undefined;\n }\n\n const searchParams: Record<string, string> = {};\n for (const [key, value] of parsedUrl.searchParams) {\n // Match Next.js search-param normalization: preserve the first value.\n if (searchParams[key] === undefined) {\n searchParams[key] = value;\n }\n }\n\n return parsePaymentReturn(segments.slice(-5), searchParams, options);\n}\n\nfunction parsePaymentStatusReturn(url: URL): CheckoutPaymentReturn | undefined {\n if (url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution) !== 'status') {\n return undefined;\n }\n\n const rawPaymentId = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.paymentId);\n const identifier = url.searchParams\n .get(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier)\n ?.trim();\n const paymentId = Number(rawPaymentId);\n\n if (!Number.isSafeInteger(paymentId) || paymentId <= 0 || !identifier) {\n return undefined;\n }\n\n return {\n payment: { id: paymentId, identifier },\n params: {\n id: String(paymentId),\n paymentIdentifier: identifier\n },\n resolution: 'status'\n };\n}\n\nfunction decodePathSegment(segment: string): string {\n try {\n return decodeURIComponent(segment);\n } catch {\n return segment;\n }\n}\n\nfunction normalizeSearchParams(\n searchParams: PaymentReturnSearchParams\n): Record<string, string> {\n const normalized: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(searchParams)) {\n const firstValue = Array.isArray(value) ? value[0] : value;\n if (firstValue !== undefined) {\n normalized[key] = firstValue;\n }\n }\n\n return normalized;\n}\n"],"names":[],"mappings":"AAMO,MAAM,2BAA2B,GAAG;AACzC,IAAA,UAAU,EAAE,uBAAuB;AACnC,IAAA,SAAS,EAAE,mBAAmB;AAC9B,IAAA,iBAAiB,EAAE;;AAGrB;AACM,SAAU,wBAAwB,CAAC,GAAiB,EAAA;AACxD,IAAA,IAAI,SAAc;AAClB,IAAA,IAAI;AACF,QAAA,SAAS,GAAG,OAAO,GAAG,KAAK;AACzB,cAAE,IAAI,GAAG,CAAC,GAAG,EAAE,iCAAiC;cAC9C,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC7B;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,IAAI,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE;AACnF,QAAA,OAAO,SAAS;IAClB;IAEA,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,2BAA2B,CAAC,UAAU,CAAC;IACrE,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,2BAA2B,CAAC,SAAS,CAAC;IACpE,SAAS,CAAC,YAAY,CAAC,MAAM,CAAC,2BAA2B,CAAC,iBAAiB,CAAC;AAC5E,IAAA,OAAO,CAAA,EAAG,SAAS,CAAC,QAAQ,CAAA,EAAG,SAAS,CAAC,MAAM,CAAA,EAAG,SAAS,CAAC,IAAI,EAAE;AACpE;AAEO,MAAM,6BAA6B,GAAG;IAC3C,qBAAqB,EAAE,kBAAkB,EAAE,iBAAiB;IAC5D,kBAAkB,EAAE,qBAAqB,EAAE,uBAAuB;IAClE,oBAAoB,EAAE,mBAAmB,EAAE,oBAAoB;IAC/D,uBAAuB,EAAE,uBAAuB,EAAE,wBAAwB;IAC1E,mBAAmB,EAAE,sBAAsB,EAAE,uBAAuB;IACpE,sBAAsB,EAAE,wBAAwB,EAAE,oBAAoB;IACtE,mBAAmB,EAAE,mBAAmB,EAAE,uBAAuB;IACjE,oBAAoB,EAAE,oBAAoB,EAAE,mBAAmB;IAC/D,sBAAsB,EAAE,yBAAyB,EAAE,uBAAuB;IAC1E,iBAAiB,EAAE,sBAAsB,EAAE,kBAAkB;IAC7D,oBAAoB,EAAE,sBAAsB,EAAE,wBAAwB;IACtE;;AAGF;;;AAGG;AACG,SAAU,kBAAkB,CAChC,QAAuC,EACvC,YAAA,GAA0C,EAAE,EAC5C,OAAA,GAAsC,EAAE,EAAA;AAExC,IAAA,MAAM,CAAC,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,CAAC,GACjF,QAAQ,IAAI,EAAE;AAChB,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;AACtC,IAAA,MAAM,UAAU,GAAG,aAAa,EAAE,IAAI,EAAE;IACxC,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,CAAC,OAAO,CAAC,oBAAoB,IAAI,6BAA6B;AAC3D,SAAA,GAAG,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,WAAW,EAAE,CAAC,CACzC;AAED,IAAA,IACE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACtB,QAAA,CAAC,WAAW;QACZ,CAAC,cAAc,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;AAC9C,QAAA,cAAc,EAAE,WAAW,EAAE,KAAK,SAAS;AAC3C,QAAA,iBAAiB,EAAE,WAAW,EAAE,KAAK,YAAY;AACjD,QAAA,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC;AAChC,QAAA,SAAS,IAAI,CAAC;QACd,CAAC,UAAU,EACX;AACA,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,MAAM,GAAG,qBAAqB,CAAC,YAAY,CAAC;AAClD,IAAA,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;AAC7B,IAAA,MAAM,CAAC,iBAAiB,GAAG,UAAU;IAErC,OAAO;AACL,QAAA,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;QACtC;KACD;AACH;AAEA;;;;AAIG;SACa,qBAAqB,CACnC,GAAiB,EACjB,UAAsC,EAAE,EAAA;AAExC,IAAA,IAAI,SAAc;AAElB,IAAA,IAAI;AACF,QAAA,SAAS,GAAG,OAAO,GAAG,KAAK;AACzB,cAAE,IAAI,GAAG,CAAC,GAAG,EAAE,iCAAiC;cAC9C,GAAG;IACT;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,YAAY,GAAG,wBAAwB,CAAC,SAAS,CAAC;AACxD,IAAA,IAAI,YAAY;AAAE,QAAA,OAAO,YAAY;AAErC,IAAA,MAAM,QAAQ,GAAG,SAAS,CAAC;SACxB,KAAK,CAAC,GAAG;SACT,MAAM,CAAC,OAAO;SACd,GAAG,CAAC,iBAAiB,CAAC;AAEzB,IAAA,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE;AACvB,QAAA,OAAO,SAAS;IAClB;IAEA,MAAM,YAAY,GAA2B,EAAE;IAC/C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,SAAS,CAAC,YAAY,EAAE;;AAEjD,QAAA,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;AACnC,YAAA,YAAY,CAAC,GAAG,CAAC,GAAG,KAAK;QAC3B;IACF;AAEA,IAAA,OAAO,kBAAkB,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC;AACtE;AAEA,SAAS,wBAAwB,CAAC,GAAQ,EAAA;AACxC,IAAA,IAAI,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE;AAC7E,QAAA,OAAO,SAAS;IAClB;AAEA,IAAA,MAAM,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,SAAS,CAAC;AAChF,IAAA,MAAM,UAAU,GAAG,GAAG,CAAC;AACpB,SAAA,GAAG,CAAC,2BAA2B,CAAC,iBAAiB;UAChD,IAAI,EAAE;AACV,IAAA,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;AAEtC,IAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,SAAS,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;AACrE,QAAA,OAAO,SAAS;IAClB;IAEA,OAAO;AACL,QAAA,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE;AACtC,QAAA,MAAM,EAAE;AACN,YAAA,EAAE,EAAE,MAAM,CAAC,SAAS,CAAC;AACrB,YAAA,iBAAiB,EAAE;AACpB,SAAA;AACD,QAAA,UAAU,EAAE;KACb;AACH;AAEA,SAAS,iBAAiB,CAAC,OAAe,EAAA;AACxC,IAAA,IAAI;AACF,QAAA,OAAO,kBAAkB,CAAC,OAAO,CAAC;IACpC;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,OAAO;IAChB;AACF;AAEA,SAAS,qBAAqB,CAC5B,YAAuC,EAAA;IAEvC,MAAM,UAAU,GAA2B,EAAE;AAE7C,IAAA,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE;AACvD,QAAA,MAAM,UAAU,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK;AAC1D,QAAA,IAAI,UAAU,KAAK,SAAS,EAAE;AAC5B,YAAA,UAAU,CAAC,GAAG,CAAC,GAAG,UAAU;QAC9B;IACF;AAEA,IAAA,OAAO,UAAU;AACnB;;;;"}
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ var server_index = require('../server/index.cjs');
4
+ require('@sazito/client-sdk');
5
+ require('./payment-return.cjs');
6
+
7
+
8
+
9
+ exports.SazitoCheckout = server_index.SazitoCheckout;
10
+ //# sourceMappingURL=server.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
@@ -0,0 +1,33 @@
1
+ import { SazitoConfig } from '@sazito/client-sdk';
2
+
3
+ /**
4
+ * @sazito/checkout/server — server-only payment callback handlers.
5
+ *
6
+ * The implementation uses only the standard Web Request/Response APIs so the
7
+ * same handlers work in Next.js Route Handlers and other compatible runtimes.
8
+ */
9
+
10
+ type SazitoPaymentRouteHandler = (request: Request) => Promise<Response>;
11
+ interface SazitoCheckoutServerConfig extends SazitoConfig {
12
+ /** Page that renders `SazitoCheckoutPage` after server verification. */
13
+ checkoutPath?: string;
14
+ /** Maximum accepted gateway callback body size. Defaults to 64 KiB. */
15
+ maxCallbackBodyBytes?: number;
16
+ /** Replace the built-in gateway-result marker allowlist. */
17
+ gatewayResultMarkers?: readonly string[];
18
+ }
19
+ interface SazitoCheckoutServer {
20
+ handlers: {
21
+ GET: SazitoPaymentRouteHandler;
22
+ POST: SazitoPaymentRouteHandler;
23
+ };
24
+ }
25
+ /**
26
+ * Create GET and POST route handlers for payment callbacks.
27
+ * A fresh SDK client is created for each request so server-side guest
28
+ * credentials can never leak between concurrent callbacks.
29
+ */
30
+ declare function SazitoCheckout(config: SazitoCheckoutServerConfig): SazitoCheckoutServer;
31
+
32
+ export { SazitoCheckout };
33
+ export type { SazitoCheckoutServer, SazitoCheckoutServerConfig, SazitoPaymentRouteHandler };
@@ -0,0 +1,33 @@
1
+ import { SazitoConfig } from '@sazito/client-sdk';
2
+
3
+ /**
4
+ * @sazito/checkout/server — server-only payment callback handlers.
5
+ *
6
+ * The implementation uses only the standard Web Request/Response APIs so the
7
+ * same handlers work in Next.js Route Handlers and other compatible runtimes.
8
+ */
9
+
10
+ type SazitoPaymentRouteHandler = (request: Request) => Promise<Response>;
11
+ interface SazitoCheckoutServerConfig extends SazitoConfig {
12
+ /** Page that renders `SazitoCheckoutPage` after server verification. */
13
+ checkoutPath?: string;
14
+ /** Maximum accepted gateway callback body size. Defaults to 64 KiB. */
15
+ maxCallbackBodyBytes?: number;
16
+ /** Replace the built-in gateway-result marker allowlist. */
17
+ gatewayResultMarkers?: readonly string[];
18
+ }
19
+ interface SazitoCheckoutServer {
20
+ handlers: {
21
+ GET: SazitoPaymentRouteHandler;
22
+ POST: SazitoPaymentRouteHandler;
23
+ };
24
+ }
25
+ /**
26
+ * Create GET and POST route handlers for payment callbacks.
27
+ * A fresh SDK client is created for each request so server-side guest
28
+ * credentials can never leak between concurrent callbacks.
29
+ */
30
+ declare function SazitoCheckout(config: SazitoCheckoutServerConfig): SazitoCheckoutServer;
31
+
32
+ export { SazitoCheckout };
33
+ export type { SazitoCheckoutServer, SazitoCheckoutServerConfig, SazitoPaymentRouteHandler };
@@ -0,0 +1,4 @@
1
+ export { SazitoCheckout } from '../server/index.js';
2
+ import '@sazito/client-sdk';
3
+ import './payment-return.js';
4
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
  'use strict';
3
3
 
4
- var useCheckout = require('../chunks/use-checkout-wHkKNkbK.cjs');
4
+ var useCheckout = require('../chunks/use-checkout-DsTtOAMs.cjs');
5
5
  require('react/jsx-runtime');
6
6
  require('react');
7
7
  require('../next/payment-return.cjs');
8
- require('../chunks/labels-Cy05dLJx.cjs');
8
+ require('../chunks/labels-FNi3eq4p.cjs');
9
9
  require('@sazito/client-sdk');
10
10
 
11
11
 
@@ -99,6 +99,7 @@ interface CheckoutCredentials {
99
99
  identifier: string;
100
100
  };
101
101
  }
102
+ type PaymentReturnResolution = 'callback' | 'status';
102
103
  interface CheckoutConfig {
103
104
  locale?: CheckoutLocale;
104
105
  direction?: CheckoutDirection;
@@ -240,8 +241,8 @@ interface CheckoutActions {
240
241
  placeOrder(): Promise<void>;
241
242
  /** Rehydrate a failed gateway return and reopen a usable payment step. */
242
243
  retryPayment(): Promise<void>;
243
- /** Resolve a return from the payment gateway (query params from the URL). */
244
- resolvePaymentReturn(params: Record<string, string>): Promise<void>;
244
+ /** Resolve a gateway callback or a server-verified payment status return. */
245
+ resolvePaymentReturn(params: Record<string, string>, resolution?: PaymentReturnResolution): Promise<void>;
245
246
  reset(): void;
246
247
  }
247
248
 
@@ -99,6 +99,7 @@ interface CheckoutCredentials {
99
99
  identifier: string;
100
100
  };
101
101
  }
102
+ type PaymentReturnResolution = 'callback' | 'status';
102
103
  interface CheckoutConfig {
103
104
  locale?: CheckoutLocale;
104
105
  direction?: CheckoutDirection;
@@ -240,8 +241,8 @@ interface CheckoutActions {
240
241
  placeOrder(): Promise<void>;
241
242
  /** Rehydrate a failed gateway return and reopen a usable payment step. */
242
243
  retryPayment(): Promise<void>;
243
- /** Resolve a return from the payment gateway (query params from the URL). */
244
- resolvePaymentReturn(params: Record<string, string>): Promise<void>;
244
+ /** Resolve a gateway callback or a server-verified payment status return. */
245
+ resolvePaymentReturn(params: Record<string, string>, resolution?: PaymentReturnResolution): Promise<void>;
245
246
  reset(): void;
246
247
  }
247
248
 
@@ -1,8 +1,8 @@
1
1
  'use client';
2
- export { C as CheckoutProvider, S as SazitoProvider, u as useCheckout, a as useCheckoutEngine, b as useSazitoClient } from '../chunks/use-checkout-uWEi8iqK.js';
2
+ export { C as CheckoutProvider, S as SazitoProvider, u as useCheckout, a as useCheckoutEngine, b as useSazitoClient } from '../chunks/use-checkout-OyHfWeAh.js';
3
3
  import 'react/jsx-runtime';
4
4
  import 'react';
5
5
  import '../next/payment-return.js';
6
- import '../chunks/labels-Cysz2BgA.js';
6
+ import '../chunks/labels-CwHBYso8.js';
7
7
  import '@sazito/client-sdk';
8
8
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,182 @@
1
+ 'use strict';
2
+
3
+ var clientSdk = require('@sazito/client-sdk');
4
+ var next_paymentReturn = require('../next/payment-return.cjs');
5
+
6
+ /**
7
+ * @sazito/checkout/server — server-only payment callback handlers.
8
+ *
9
+ * The implementation uses only the standard Web Request/Response APIs so the
10
+ * same handlers work in Next.js Route Handlers and other compatible runtimes.
11
+ */
12
+ const DEFAULT_CHECKOUT_PATH = '/checkout';
13
+ const DEFAULT_MAX_BODY_BYTES = 64 * 1024;
14
+ /**
15
+ * Create GET and POST route handlers for payment callbacks.
16
+ * A fresh SDK client is created for each request so server-side guest
17
+ * credentials can never leak between concurrent callbacks.
18
+ */
19
+ function SazitoCheckout(config) {
20
+ const { checkoutPath = DEFAULT_CHECKOUT_PATH, maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES, gatewayResultMarkers, ...sdkConfig } = config;
21
+ validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);
22
+ const parserOptions = { gatewayResultMarkers };
23
+ const createHandler = (method) => async (request) => {
24
+ if (request.method.toUpperCase() !== method) {
25
+ return errorResponse(405, 'method_not_allowed', { Allow: method });
26
+ }
27
+ try {
28
+ const callback = next_paymentReturn.parsePaymentReturnUrl(request.url, parserOptions);
29
+ if (!callback || callback.resolution === 'status') {
30
+ return errorResponse(400, 'invalid_payment_callback');
31
+ }
32
+ const requestUrl = new URL(request.url);
33
+ const body = method === 'POST'
34
+ ? await readCallbackBody(request, maxCallbackBodyBytes)
35
+ : undefined;
36
+ const query = fieldsFromSearchParams(requestUrl.searchParams);
37
+ const client = clientSdk.createSazitoClient(sdkConfig);
38
+ const verification = await client.payments.verifyPaymentCallback({
39
+ paymentId: callback.payment.id,
40
+ paymentIdentifier: callback.payment.identifier,
41
+ body,
42
+ query
43
+ });
44
+ if (verification.error || !verification.data) {
45
+ if (sdkConfig.debug) {
46
+ console.error('[Sazito Checkout] Payment callback verification failed:', {
47
+ paymentId: callback.payment.id,
48
+ error: verification.error
49
+ });
50
+ }
51
+ return errorResponse(502, 'payment_verification_failed');
52
+ }
53
+ const redirectUrl = createStatusRedirectUrl(requestUrl, checkoutPath, callback.payment);
54
+ return new Response(null, {
55
+ status: 303,
56
+ headers: {
57
+ Location: redirectUrl.toString(),
58
+ 'Cache-Control': 'no-store',
59
+ 'Referrer-Policy': 'no-referrer'
60
+ }
61
+ });
62
+ }
63
+ catch (error) {
64
+ if (config.debug) {
65
+ console.error('[Sazito Checkout] Invalid payment callback request:', error);
66
+ }
67
+ const status = error instanceof CallbackRequestError ? error.status : 500;
68
+ const code = error instanceof CallbackRequestError
69
+ ? error.code
70
+ : 'payment_callback_failed';
71
+ return errorResponse(status, code);
72
+ }
73
+ };
74
+ return {
75
+ handlers: {
76
+ GET: createHandler('GET'),
77
+ POST: createHandler('POST')
78
+ }
79
+ };
80
+ }
81
+ function validateConfig(config, checkoutPath, maxCallbackBodyBytes) {
82
+ if (!config.domain?.trim()) {
83
+ throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');
84
+ }
85
+ if (!checkoutPath.trim()) {
86
+ throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');
87
+ }
88
+ if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {
89
+ throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');
90
+ }
91
+ }
92
+ async function readCallbackBody(request, maxBodyBytes) {
93
+ const declaredLength = Number(request.headers.get('content-length') ?? 0);
94
+ if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {
95
+ throw new CallbackRequestError(413, 'payment_callback_too_large');
96
+ }
97
+ const bytes = await request.arrayBuffer();
98
+ if (bytes.byteLength > maxBodyBytes) {
99
+ throw new CallbackRequestError(413, 'payment_callback_too_large');
100
+ }
101
+ if (bytes.byteLength === 0)
102
+ return {};
103
+ const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';
104
+ if (contentType.includes('application/json')) {
105
+ return fieldsFromJson(new TextDecoder().decode(bytes));
106
+ }
107
+ if (contentType.includes('multipart/form-data')) {
108
+ const form = await new Response(bytes, {
109
+ headers: { 'Content-Type': request.headers.get('content-type') ?? '' }
110
+ }).formData();
111
+ return fieldsFromFormData(form);
112
+ }
113
+ // Gateways commonly omit Content-Type or label URL-encoded data as text.
114
+ return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));
115
+ }
116
+ function fieldsFromJson(source) {
117
+ let value;
118
+ try {
119
+ value = JSON.parse(source);
120
+ }
121
+ catch {
122
+ throw new CallbackRequestError(400, 'invalid_payment_callback_body');
123
+ }
124
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
125
+ throw new CallbackRequestError(400, 'invalid_payment_callback_body');
126
+ }
127
+ return value;
128
+ }
129
+ function fieldsFromSearchParams(params) {
130
+ const fields = {};
131
+ for (const [name, value] of params)
132
+ appendField(fields, name, value);
133
+ return fields;
134
+ }
135
+ function fieldsFromFormData(form) {
136
+ const fields = {};
137
+ for (const [name, value] of form) {
138
+ if (typeof value !== 'string') {
139
+ throw new CallbackRequestError(400, 'unsupported_payment_callback_file');
140
+ }
141
+ appendField(fields, name, value);
142
+ }
143
+ return fields;
144
+ }
145
+ function appendField(fields, name, value) {
146
+ const current = fields[name];
147
+ if (current === undefined) {
148
+ fields[name] = value;
149
+ }
150
+ else if (Array.isArray(current)) {
151
+ fields[name] = [...current, value ?? null];
152
+ }
153
+ else {
154
+ fields[name] = [current, value ?? null];
155
+ }
156
+ }
157
+ function createStatusRedirectUrl(requestUrl, checkoutPath, payment) {
158
+ const redirectUrl = new URL(checkoutPath, requestUrl.origin);
159
+ redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.resolution, 'status');
160
+ redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));
161
+ redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier, payment.identifier);
162
+ return redirectUrl;
163
+ }
164
+ function errorResponse(status, code, extraHeaders = {}) {
165
+ return Response.json({ error: code }, {
166
+ status,
167
+ headers: {
168
+ 'Cache-Control': 'no-store',
169
+ ...extraHeaders
170
+ }
171
+ });
172
+ }
173
+ class CallbackRequestError extends Error {
174
+ constructor(status, code) {
175
+ super(code);
176
+ this.status = status;
177
+ this.code = code;
178
+ }
179
+ }
180
+
181
+ exports.SazitoCheckout = SazitoCheckout;
182
+ //# sourceMappingURL=index.cjs.map