@sazito/checkout 0.4.20 → 0.4.21
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/README.md +3 -0
- package/dist/chunks/{labels-FNi3eq4p.cjs → labels-BYJQjaT_.cjs} +2 -2
- package/dist/chunks/labels-BYJQjaT_.cjs.map +1 -0
- package/dist/chunks/{labels-CwHBYso8.js → labels-Cqrb2MwA.js} +2 -2
- package/dist/chunks/labels-Cqrb2MwA.js.map +1 -0
- package/dist/chunks/{use-checkout-OyHfWeAh.js → use-checkout-BRDfZp4Z.js} +5 -7
- package/dist/chunks/use-checkout-BRDfZp4Z.js.map +1 -0
- package/dist/chunks/{use-checkout-DsTtOAMs.cjs → use-checkout-MM-Ld0Ew.cjs} +5 -7
- package/dist/chunks/use-checkout-MM-Ld0Ew.cjs.map +1 -0
- package/dist/core/index.cjs +1 -1
- package/dist/core/index.d.cts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +1 -1
- package/dist/next/index.cjs +3 -3
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.js +4 -4
- package/dist/next/index.js.map +1 -1
- package/dist/next/payment-return.cjs +6 -4
- package/dist/next/payment-return.cjs.map +1 -1
- package/dist/next/payment-return.d.cts +1 -1
- package/dist/next/payment-return.d.ts +1 -1
- package/dist/next/payment-return.js +6 -4
- package/dist/next/payment-return.js.map +1 -1
- package/dist/react/index.cjs +2 -2
- package/dist/react/index.js +2 -2
- package/dist/server/index.cjs +34 -11
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +34 -11
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/labels-CwHBYso8.js.map +0 -1
- package/dist/chunks/labels-FNi3eq4p.cjs.map +0 -1
- package/dist/chunks/use-checkout-DsTtOAMs.cjs.map +0 -1
- package/dist/chunks/use-checkout-OyHfWeAh.js.map +0 -1
|
@@ -5,7 +5,7 @@ const SAZITO_PAYMENT_STATUS_QUERY = {
|
|
|
5
5
|
paymentId: 'sazito_payment_id',
|
|
6
6
|
paymentIdentifier: 'sazito_payment_identifier'
|
|
7
7
|
};
|
|
8
|
-
/** Remove
|
|
8
|
+
/** Remove internal payment-return credentials from the visible URL after they are read. */
|
|
9
9
|
function stripPaymentStatusReturn(url) {
|
|
10
10
|
let parsedUrl;
|
|
11
11
|
try {
|
|
@@ -16,7 +16,8 @@ function stripPaymentStatusReturn(url) {
|
|
|
16
16
|
catch {
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
const resolution = parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);
|
|
20
|
+
if (resolution !== 'status' && resolution !== 'callback') {
|
|
20
21
|
return undefined;
|
|
21
22
|
}
|
|
22
23
|
parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.resolution);
|
|
@@ -101,7 +102,8 @@ function parsePaymentReturnUrl(url, options = {}) {
|
|
|
101
102
|
return parsePaymentReturn(segments.slice(-5), searchParams, options);
|
|
102
103
|
}
|
|
103
104
|
function parsePaymentStatusReturn(url) {
|
|
104
|
-
|
|
105
|
+
const resolution = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);
|
|
106
|
+
if (resolution !== 'status' && resolution !== 'callback') {
|
|
105
107
|
return undefined;
|
|
106
108
|
}
|
|
107
109
|
const rawPaymentId = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.paymentId);
|
|
@@ -118,7 +120,7 @@ function parsePaymentStatusReturn(url) {
|
|
|
118
120
|
id: String(paymentId),
|
|
119
121
|
paymentIdentifier: identifier
|
|
120
122
|
},
|
|
121
|
-
resolution
|
|
123
|
+
resolution
|
|
122
124
|
};
|
|
123
125
|
}
|
|
124
126
|
function decodePathSegment(segment) {
|
|
@@ -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_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;;;;;;;;"}
|
|
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 internal payment-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 const resolution = parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);\n if (resolution !== 'status' && resolution !== 'callback') {\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 const resolution = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);\n if (resolution !== 'status' && resolution !== 'callback') {\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\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":"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"}
|
|
@@ -32,7 +32,7 @@ declare const SAZITO_PAYMENT_STATUS_QUERY: {
|
|
|
32
32
|
readonly paymentId: "sazito_payment_id";
|
|
33
33
|
readonly paymentIdentifier: "sazito_payment_identifier";
|
|
34
34
|
};
|
|
35
|
-
/** Remove
|
|
35
|
+
/** Remove internal payment-return credentials from the visible URL after they are read. */
|
|
36
36
|
declare function stripPaymentStatusReturn(url: string | URL): string | undefined;
|
|
37
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"];
|
|
38
38
|
/**
|
|
@@ -32,7 +32,7 @@ declare const SAZITO_PAYMENT_STATUS_QUERY: {
|
|
|
32
32
|
readonly paymentId: "sazito_payment_id";
|
|
33
33
|
readonly paymentIdentifier: "sazito_payment_identifier";
|
|
34
34
|
};
|
|
35
|
-
/** Remove
|
|
35
|
+
/** Remove internal payment-return credentials from the visible URL after they are read. */
|
|
36
36
|
declare function stripPaymentStatusReturn(url: string | URL): string | undefined;
|
|
37
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"];
|
|
38
38
|
/**
|
|
@@ -3,7 +3,7 @@ const SAZITO_PAYMENT_STATUS_QUERY = {
|
|
|
3
3
|
paymentId: 'sazito_payment_id',
|
|
4
4
|
paymentIdentifier: 'sazito_payment_identifier'
|
|
5
5
|
};
|
|
6
|
-
/** Remove
|
|
6
|
+
/** Remove internal payment-return credentials from the visible URL after they are read. */
|
|
7
7
|
function stripPaymentStatusReturn(url) {
|
|
8
8
|
let parsedUrl;
|
|
9
9
|
try {
|
|
@@ -14,7 +14,8 @@ function stripPaymentStatusReturn(url) {
|
|
|
14
14
|
catch {
|
|
15
15
|
return undefined;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
const resolution = parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);
|
|
18
|
+
if (resolution !== 'status' && resolution !== 'callback') {
|
|
18
19
|
return undefined;
|
|
19
20
|
}
|
|
20
21
|
parsedUrl.searchParams.delete(SAZITO_PAYMENT_STATUS_QUERY.resolution);
|
|
@@ -99,7 +100,8 @@ function parsePaymentReturnUrl(url, options = {}) {
|
|
|
99
100
|
return parsePaymentReturn(segments.slice(-5), searchParams, options);
|
|
100
101
|
}
|
|
101
102
|
function parsePaymentStatusReturn(url) {
|
|
102
|
-
|
|
103
|
+
const resolution = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);
|
|
104
|
+
if (resolution !== 'status' && resolution !== 'callback') {
|
|
103
105
|
return undefined;
|
|
104
106
|
}
|
|
105
107
|
const rawPaymentId = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.paymentId);
|
|
@@ -116,7 +118,7 @@ function parsePaymentStatusReturn(url) {
|
|
|
116
118
|
id: String(paymentId),
|
|
117
119
|
paymentIdentifier: identifier
|
|
118
120
|
},
|
|
119
|
-
resolution
|
|
121
|
+
resolution
|
|
120
122
|
};
|
|
121
123
|
}
|
|
122
124
|
function decodePathSegment(segment) {
|
|
@@ -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_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;;;;"}
|
|
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 internal payment-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 const resolution = parsedUrl.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);\n if (resolution !== 'status' && resolution !== 'callback') {\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 const resolution = url.searchParams.get(SAZITO_PAYMENT_STATUS_QUERY.resolution);\n if (resolution !== 'status' && resolution !== 'callback') {\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\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":"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"}
|
package/dist/react/index.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var useCheckout = require('../chunks/use-checkout-
|
|
4
|
+
var useCheckout = require('../chunks/use-checkout-MM-Ld0Ew.cjs');
|
|
5
5
|
require('react/jsx-runtime');
|
|
6
6
|
require('react');
|
|
7
7
|
require('../next/payment-return.cjs');
|
|
8
|
-
require('../chunks/labels-
|
|
8
|
+
require('../chunks/labels-BYJQjaT_.cjs');
|
|
9
9
|
require('@sazito/client-sdk');
|
|
10
10
|
|
|
11
11
|
|
package/dist/react/index.js
CHANGED
|
@@ -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-
|
|
2
|
+
export { C as CheckoutProvider, S as SazitoProvider, u as useCheckout, a as useCheckoutEngine, b as useSazitoClient } from '../chunks/use-checkout-BRDfZp4Z.js';
|
|
3
3
|
import 'react/jsx-runtime';
|
|
4
4
|
import 'react';
|
|
5
5
|
import '../next/payment-return.js';
|
|
6
|
-
import '../chunks/labels-
|
|
6
|
+
import '../chunks/labels-Cqrb2MwA.js';
|
|
7
7
|
import '@sazito/client-sdk';
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
package/dist/server/index.cjs
CHANGED
|
@@ -11,6 +11,7 @@ var next_paymentReturn = require('../next/payment-return.cjs');
|
|
|
11
11
|
*/
|
|
12
12
|
const DEFAULT_CHECKOUT_PATH = '/checkout';
|
|
13
13
|
const DEFAULT_MAX_BODY_BYTES = 64 * 1024;
|
|
14
|
+
const BROWSER_FINALIZED_RESULT_MARKERS = new Set(['paymentinplaceresult']);
|
|
14
15
|
/**
|
|
15
16
|
* Create GET and POST route handlers for payment callbacks.
|
|
16
17
|
* A fresh SDK client is created for each request so server-side guest
|
|
@@ -34,6 +35,15 @@ function SazitoCheckout(config) {
|
|
|
34
35
|
? await readCallbackBody(request, maxCallbackBodyBytes)
|
|
35
36
|
: undefined;
|
|
36
37
|
const query = fieldsFromSearchParams(requestUrl.searchParams);
|
|
38
|
+
// Payment-in-place uses an empty POST only to return control to the
|
|
39
|
+
// storefront. Processing it on the server and then performing a status
|
|
40
|
+
// read in the browser calls process_payment_step twice; some deployments
|
|
41
|
+
// report the second call as failed even though the first one created the
|
|
42
|
+
// order. Redirect the empty first-party callback to the browser so the
|
|
43
|
+
// order is finalized exactly once and the returned order can be rendered.
|
|
44
|
+
if (shouldFinalizeInBrowser(requestUrl, body, query)) {
|
|
45
|
+
return redirectResponse(createPaymentReturnRedirectUrl(requestUrl, checkoutPath, callback.payment, 'callback'));
|
|
46
|
+
}
|
|
37
47
|
const client = clientSdk.createSazitoClient(sdkConfig);
|
|
38
48
|
const verification = await client.payments.verifyPaymentCallback({
|
|
39
49
|
paymentId: callback.payment.id,
|
|
@@ -50,15 +60,8 @@ function SazitoCheckout(config) {
|
|
|
50
60
|
}
|
|
51
61
|
return errorResponse(502, 'payment_verification_failed');
|
|
52
62
|
}
|
|
53
|
-
const redirectUrl =
|
|
54
|
-
return
|
|
55
|
-
status: 303,
|
|
56
|
-
headers: {
|
|
57
|
-
Location: redirectUrl.toString(),
|
|
58
|
-
'Cache-Control': 'no-store',
|
|
59
|
-
'Referrer-Policy': 'no-referrer'
|
|
60
|
-
}
|
|
61
|
-
});
|
|
63
|
+
const redirectUrl = createPaymentReturnRedirectUrl(requestUrl, checkoutPath, callback.payment, 'status');
|
|
64
|
+
return redirectResponse(redirectUrl);
|
|
62
65
|
}
|
|
63
66
|
catch (error) {
|
|
64
67
|
if (config.debug) {
|
|
@@ -154,13 +157,33 @@ function appendField(fields, name, value) {
|
|
|
154
157
|
fields[name] = [current, value ?? null];
|
|
155
158
|
}
|
|
156
159
|
}
|
|
157
|
-
function
|
|
160
|
+
function shouldFinalizeInBrowser(requestUrl, body, query) {
|
|
161
|
+
const pathSegments = requestUrl.pathname
|
|
162
|
+
.split('/')
|
|
163
|
+
.filter(Boolean);
|
|
164
|
+
const resultMarker = pathSegments[pathSegments.length - 5]?.toLowerCase();
|
|
165
|
+
return Boolean(resultMarker &&
|
|
166
|
+
BROWSER_FINALIZED_RESULT_MARKERS.has(resultMarker) &&
|
|
167
|
+
Object.keys(body ?? {}).length === 0 &&
|
|
168
|
+
Object.keys(query).length === 0);
|
|
169
|
+
}
|
|
170
|
+
function createPaymentReturnRedirectUrl(requestUrl, checkoutPath, payment, resolution) {
|
|
158
171
|
const redirectUrl = new URL(checkoutPath, requestUrl.origin);
|
|
159
|
-
redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.resolution,
|
|
172
|
+
redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.resolution, resolution);
|
|
160
173
|
redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));
|
|
161
174
|
redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier, payment.identifier);
|
|
162
175
|
return redirectUrl;
|
|
163
176
|
}
|
|
177
|
+
function redirectResponse(url) {
|
|
178
|
+
return new Response(null, {
|
|
179
|
+
status: 303,
|
|
180
|
+
headers: {
|
|
181
|
+
Location: url.toString(),
|
|
182
|
+
'Cache-Control': 'no-store',
|
|
183
|
+
'Referrer-Policy': 'no-referrer'
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
}
|
|
164
187
|
function errorResponse(status, code, extraHeaders = {}) {
|
|
165
188
|
return Response.json({ error: code }, {
|
|
166
189
|
status,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/server/index.ts"],"sourcesContent":["/**\n * @sazito/checkout/server — server-only payment callback handlers.\n *\n * The implementation uses only the standard Web Request/Response APIs so the\n * same handlers work in Next.js Route Handlers and other compatible runtimes.\n */\nimport {\n createSazitoClient,\n type PaymentCallbackFieldValue,\n type PaymentCallbackFields,\n type SazitoConfig\n} from '@sazito/client-sdk';\nimport {\n parsePaymentReturnUrl,\n SAZITO_PAYMENT_STATUS_QUERY\n} from '../core/payment-return';\nimport type { PaymentReturnParserOptions } from '../core/types';\n\nconst DEFAULT_CHECKOUT_PATH = '/checkout';\nconst DEFAULT_MAX_BODY_BYTES = 64 * 1024;\n\nexport type SazitoPaymentRouteHandler = (request: Request) => Promise<Response>;\n\nexport interface SazitoCheckoutServerConfig extends SazitoConfig {\n /** Page that renders `SazitoCheckoutPage` after server verification. */\n checkoutPath?: string;\n /** Maximum accepted gateway callback body size. Defaults to 64 KiB. */\n maxCallbackBodyBytes?: number;\n /** Replace the built-in gateway-result marker allowlist. */\n gatewayResultMarkers?: readonly string[];\n}\n\nexport interface SazitoCheckoutServer {\n handlers: {\n GET: SazitoPaymentRouteHandler;\n POST: SazitoPaymentRouteHandler;\n };\n}\n\n/**\n * Create GET and POST route handlers for payment callbacks.\n * A fresh SDK client is created for each request so server-side guest\n * credentials can never leak between concurrent callbacks.\n */\nexport function SazitoCheckout(config: SazitoCheckoutServerConfig): SazitoCheckoutServer {\n const {\n checkoutPath = DEFAULT_CHECKOUT_PATH,\n maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES,\n gatewayResultMarkers,\n ...sdkConfig\n } = config;\n\n validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);\n const parserOptions: PaymentReturnParserOptions = { gatewayResultMarkers };\n\n const createHandler = (method: 'GET' | 'POST'): SazitoPaymentRouteHandler =>\n async (request) => {\n if (request.method.toUpperCase() !== method) {\n return errorResponse(405, 'method_not_allowed', { Allow: method });\n }\n\n try {\n const callback = parsePaymentReturnUrl(request.url, parserOptions);\n if (!callback || callback.resolution === 'status') {\n return errorResponse(400, 'invalid_payment_callback');\n }\n\n const requestUrl = new URL(request.url);\n const body = method === 'POST'\n ? await readCallbackBody(request, maxCallbackBodyBytes)\n : undefined;\n const query = fieldsFromSearchParams(requestUrl.searchParams);\n const client = createSazitoClient(sdkConfig);\n const verification = await client.payments.verifyPaymentCallback({\n paymentId: callback.payment.id,\n paymentIdentifier: callback.payment.identifier,\n body,\n query\n });\n\n if (verification.error || !verification.data) {\n if (sdkConfig.debug) {\n console.error('[Sazito Checkout] Payment callback verification failed:', {\n paymentId: callback.payment.id,\n error: verification.error\n });\n }\n return errorResponse(502, 'payment_verification_failed');\n }\n\n const redirectUrl = createStatusRedirectUrl(\n requestUrl,\n checkoutPath,\n callback.payment\n );\n return new Response(null, {\n status: 303,\n headers: {\n Location: redirectUrl.toString(),\n 'Cache-Control': 'no-store',\n 'Referrer-Policy': 'no-referrer'\n }\n });\n } catch (error) {\n if (config.debug) {\n console.error('[Sazito Checkout] Invalid payment callback request:', error);\n }\n const status = error instanceof CallbackRequestError ? error.status : 500;\n const code = error instanceof CallbackRequestError\n ? error.code\n : 'payment_callback_failed';\n return errorResponse(status, code);\n }\n };\n\n return {\n handlers: {\n GET: createHandler('GET'),\n POST: createHandler('POST')\n }\n };\n}\n\nfunction validateConfig(\n config: SazitoConfig,\n checkoutPath: string,\n maxCallbackBodyBytes: number\n): void {\n if (!config.domain?.trim()) {\n throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');\n }\n if (!checkoutPath.trim()) {\n throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');\n }\n if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {\n throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');\n }\n}\n\nasync function readCallbackBody(\n request: Request,\n maxBodyBytes: number\n): Promise<PaymentCallbackFields> {\n const declaredLength = Number(request.headers.get('content-length') ?? 0);\n if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n\n const bytes = await request.arrayBuffer();\n if (bytes.byteLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n if (bytes.byteLength === 0) return {};\n\n const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';\n if (contentType.includes('application/json')) {\n return fieldsFromJson(new TextDecoder().decode(bytes));\n }\n if (contentType.includes('multipart/form-data')) {\n const form = await new Response(bytes, {\n headers: { 'Content-Type': request.headers.get('content-type') ?? '' }\n }).formData();\n return fieldsFromFormData(form);\n }\n\n // Gateways commonly omit Content-Type or label URL-encoded data as text.\n return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));\n}\n\nfunction fieldsFromJson(source: string): PaymentCallbackFields {\n let value: unknown;\n try {\n value = JSON.parse(source);\n } catch {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n return value as PaymentCallbackFields;\n}\n\nfunction fieldsFromSearchParams(params: URLSearchParams): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of params) appendField(fields, name, value);\n return fields;\n}\n\nfunction fieldsFromFormData(form: FormData): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of form) {\n if (typeof value !== 'string') {\n throw new CallbackRequestError(400, 'unsupported_payment_callback_file');\n }\n appendField(fields, name, value);\n }\n return fields;\n}\n\nfunction appendField(\n fields: PaymentCallbackFields,\n name: string,\n value: PaymentCallbackFieldValue\n): void {\n const current = fields[name];\n if (current === undefined) {\n fields[name] = value;\n } else if (Array.isArray(current)) {\n fields[name] = [...current, value ?? null];\n } else {\n fields[name] = [current, value ?? null];\n }\n}\n\nfunction createStatusRedirectUrl(\n requestUrl: URL,\n checkoutPath: string,\n payment: { id: number; identifier: string }\n): URL {\n const redirectUrl = new URL(checkoutPath, requestUrl.origin);\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution, 'status');\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));\n redirectUrl.searchParams.set(\n SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier,\n payment.identifier\n );\n return redirectUrl;\n}\n\nfunction errorResponse(\n status: number,\n code: string,\n extraHeaders: Record<string, string> = {}\n): Response {\n return Response.json(\n { error: code },\n {\n status,\n headers: {\n 'Cache-Control': 'no-store',\n ...extraHeaders\n }\n }\n );\n}\n\nclass CallbackRequestError extends Error {\n constructor(\n readonly status: number,\n readonly code: string\n ) {\n super(code);\n }\n}\n"],"names":["parsePaymentReturnUrl","createSazitoClient","SAZITO_PAYMENT_STATUS_QUERY"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/server/index.ts"],"sourcesContent":["/**\n * @sazito/checkout/server — server-only payment callback handlers.\n *\n * The implementation uses only the standard Web Request/Response APIs so the\n * same handlers work in Next.js Route Handlers and other compatible runtimes.\n */\nimport {\n createSazitoClient,\n type PaymentCallbackFieldValue,\n type PaymentCallbackFields,\n type SazitoConfig\n} from '@sazito/client-sdk';\nimport {\n parsePaymentReturnUrl,\n SAZITO_PAYMENT_STATUS_QUERY\n} from '../core/payment-return';\nimport type { PaymentReturnParserOptions } from '../core/types';\n\nconst DEFAULT_CHECKOUT_PATH = '/checkout';\nconst DEFAULT_MAX_BODY_BYTES = 64 * 1024;\nconst BROWSER_FINALIZED_RESULT_MARKERS = new Set(['paymentinplaceresult']);\n\nexport type SazitoPaymentRouteHandler = (request: Request) => Promise<Response>;\n\nexport interface SazitoCheckoutServerConfig extends SazitoConfig {\n /** Page that renders `SazitoCheckoutPage` after server verification. */\n checkoutPath?: string;\n /** Maximum accepted gateway callback body size. Defaults to 64 KiB. */\n maxCallbackBodyBytes?: number;\n /** Replace the built-in gateway-result marker allowlist. */\n gatewayResultMarkers?: readonly string[];\n}\n\nexport interface SazitoCheckoutServer {\n handlers: {\n GET: SazitoPaymentRouteHandler;\n POST: SazitoPaymentRouteHandler;\n };\n}\n\n/**\n * Create GET and POST route handlers for payment callbacks.\n * A fresh SDK client is created for each request so server-side guest\n * credentials can never leak between concurrent callbacks.\n */\nexport function SazitoCheckout(config: SazitoCheckoutServerConfig): SazitoCheckoutServer {\n const {\n checkoutPath = DEFAULT_CHECKOUT_PATH,\n maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES,\n gatewayResultMarkers,\n ...sdkConfig\n } = config;\n\n validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);\n const parserOptions: PaymentReturnParserOptions = { gatewayResultMarkers };\n\n const createHandler = (method: 'GET' | 'POST'): SazitoPaymentRouteHandler =>\n async (request) => {\n if (request.method.toUpperCase() !== method) {\n return errorResponse(405, 'method_not_allowed', { Allow: method });\n }\n\n try {\n const callback = parsePaymentReturnUrl(request.url, parserOptions);\n if (!callback || callback.resolution === 'status') {\n return errorResponse(400, 'invalid_payment_callback');\n }\n\n const requestUrl = new URL(request.url);\n const body = method === 'POST'\n ? await readCallbackBody(request, maxCallbackBodyBytes)\n : undefined;\n const query = fieldsFromSearchParams(requestUrl.searchParams);\n\n // Payment-in-place uses an empty POST only to return control to the\n // storefront. Processing it on the server and then performing a status\n // read in the browser calls process_payment_step twice; some deployments\n // report the second call as failed even though the first one created the\n // order. Redirect the empty first-party callback to the browser so the\n // order is finalized exactly once and the returned order can be rendered.\n if (shouldFinalizeInBrowser(requestUrl, body, query)) {\n return redirectResponse(createPaymentReturnRedirectUrl(\n requestUrl,\n checkoutPath,\n callback.payment,\n 'callback'\n ));\n }\n\n const client = createSazitoClient(sdkConfig);\n const verification = await client.payments.verifyPaymentCallback({\n paymentId: callback.payment.id,\n paymentIdentifier: callback.payment.identifier,\n body,\n query\n });\n\n if (verification.error || !verification.data) {\n if (sdkConfig.debug) {\n console.error('[Sazito Checkout] Payment callback verification failed:', {\n paymentId: callback.payment.id,\n error: verification.error\n });\n }\n return errorResponse(502, 'payment_verification_failed');\n }\n\n const redirectUrl = createPaymentReturnRedirectUrl(\n requestUrl,\n checkoutPath,\n callback.payment,\n 'status'\n );\n return redirectResponse(redirectUrl);\n } catch (error) {\n if (config.debug) {\n console.error('[Sazito Checkout] Invalid payment callback request:', error);\n }\n const status = error instanceof CallbackRequestError ? error.status : 500;\n const code = error instanceof CallbackRequestError\n ? error.code\n : 'payment_callback_failed';\n return errorResponse(status, code);\n }\n };\n\n return {\n handlers: {\n GET: createHandler('GET'),\n POST: createHandler('POST')\n }\n };\n}\n\nfunction validateConfig(\n config: SazitoConfig,\n checkoutPath: string,\n maxCallbackBodyBytes: number\n): void {\n if (!config.domain?.trim()) {\n throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');\n }\n if (!checkoutPath.trim()) {\n throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');\n }\n if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {\n throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');\n }\n}\n\nasync function readCallbackBody(\n request: Request,\n maxBodyBytes: number\n): Promise<PaymentCallbackFields> {\n const declaredLength = Number(request.headers.get('content-length') ?? 0);\n if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n\n const bytes = await request.arrayBuffer();\n if (bytes.byteLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n if (bytes.byteLength === 0) return {};\n\n const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';\n if (contentType.includes('application/json')) {\n return fieldsFromJson(new TextDecoder().decode(bytes));\n }\n if (contentType.includes('multipart/form-data')) {\n const form = await new Response(bytes, {\n headers: { 'Content-Type': request.headers.get('content-type') ?? '' }\n }).formData();\n return fieldsFromFormData(form);\n }\n\n // Gateways commonly omit Content-Type or label URL-encoded data as text.\n return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));\n}\n\nfunction fieldsFromJson(source: string): PaymentCallbackFields {\n let value: unknown;\n try {\n value = JSON.parse(source);\n } catch {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n return value as PaymentCallbackFields;\n}\n\nfunction fieldsFromSearchParams(params: URLSearchParams): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of params) appendField(fields, name, value);\n return fields;\n}\n\nfunction fieldsFromFormData(form: FormData): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of form) {\n if (typeof value !== 'string') {\n throw new CallbackRequestError(400, 'unsupported_payment_callback_file');\n }\n appendField(fields, name, value);\n }\n return fields;\n}\n\nfunction appendField(\n fields: PaymentCallbackFields,\n name: string,\n value: PaymentCallbackFieldValue\n): void {\n const current = fields[name];\n if (current === undefined) {\n fields[name] = value;\n } else if (Array.isArray(current)) {\n fields[name] = [...current, value ?? null];\n } else {\n fields[name] = [current, value ?? null];\n }\n}\n\nfunction shouldFinalizeInBrowser(\n requestUrl: URL,\n body: PaymentCallbackFields | undefined,\n query: PaymentCallbackFields\n): boolean {\n const pathSegments = requestUrl.pathname\n .split('/')\n .filter(Boolean);\n const resultMarker = pathSegments[pathSegments.length - 5]?.toLowerCase();\n\n return Boolean(\n resultMarker &&\n BROWSER_FINALIZED_RESULT_MARKERS.has(resultMarker) &&\n Object.keys(body ?? {}).length === 0 &&\n Object.keys(query).length === 0\n );\n}\n\nfunction createPaymentReturnRedirectUrl(\n requestUrl: URL,\n checkoutPath: string,\n payment: { id: number; identifier: string },\n resolution: 'callback' | 'status'\n): URL {\n const redirectUrl = new URL(checkoutPath, requestUrl.origin);\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution, resolution);\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));\n redirectUrl.searchParams.set(\n SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier,\n payment.identifier\n );\n return redirectUrl;\n}\n\nfunction redirectResponse(url: URL): Response {\n return new Response(null, {\n status: 303,\n headers: {\n Location: url.toString(),\n 'Cache-Control': 'no-store',\n 'Referrer-Policy': 'no-referrer'\n }\n });\n}\n\nfunction errorResponse(\n status: number,\n code: string,\n extraHeaders: Record<string, string> = {}\n): Response {\n return Response.json(\n { error: code },\n {\n status,\n headers: {\n 'Cache-Control': 'no-store',\n ...extraHeaders\n }\n }\n );\n}\n\nclass CallbackRequestError extends Error {\n constructor(\n readonly status: number,\n readonly code: string\n ) {\n super(code);\n }\n}\n"],"names":["parsePaymentReturnUrl","createSazitoClient","SAZITO_PAYMENT_STATUS_QUERY"],"mappings":";;;;;AAAA;;;;;AAKG;AAaH,MAAM,qBAAqB,GAAG,WAAW;AACzC,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI;AACxC,MAAM,gCAAgC,GAAG,IAAI,GAAG,CAAC,CAAC,sBAAsB,CAAC,CAAC;AAoB1E;;;;AAIG;AACG,SAAU,cAAc,CAAC,MAAkC,EAAA;AAC/D,IAAA,MAAM,EACJ,YAAY,GAAG,qBAAqB,EACpC,oBAAoB,GAAG,sBAAsB,EAC7C,oBAAoB,EACpB,GAAG,SAAS,EACb,GAAG,MAAM;AAEV,IAAA,cAAc,CAAC,SAAS,EAAE,YAAY,EAAE,oBAAoB,CAAC;AAC7D,IAAA,MAAM,aAAa,GAA+B,EAAE,oBAAoB,EAAE;IAE1E,MAAM,aAAa,GAAG,CAAC,MAAsB,KAC3C,OAAO,OAAO,KAAI;QAChB,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE;AAC3C,YAAA,OAAO,aAAa,CAAC,GAAG,EAAE,oBAAoB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QACpE;AAEA,QAAA,IAAI;YACF,MAAM,QAAQ,GAAGA,wCAAqB,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC;YAClE,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,UAAU,KAAK,QAAQ,EAAE;AACjD,gBAAA,OAAO,aAAa,CAAC,GAAG,EAAE,0BAA0B,CAAC;YACvD;YAEA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC;AACvC,YAAA,MAAM,IAAI,GAAG,MAAM,KAAK;AACtB,kBAAE,MAAM,gBAAgB,CAAC,OAAO,EAAE,oBAAoB;kBACpD,SAAS;YACb,MAAM,KAAK,GAAG,sBAAsB,CAAC,UAAU,CAAC,YAAY,CAAC;;;;;;;YAQ7D,IAAI,uBAAuB,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE;AACpD,gBAAA,OAAO,gBAAgB,CAAC,8BAA8B,CACpD,UAAU,EACV,YAAY,EACZ,QAAQ,CAAC,OAAO,EAChB,UAAU,CACX,CAAC;YACJ;AAEA,YAAA,MAAM,MAAM,GAAGC,4BAAkB,CAAC,SAAS,CAAC;YAC5C,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAC;AAC/D,gBAAA,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE;AAC9B,gBAAA,iBAAiB,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU;gBAC9C,IAAI;gBACJ;AACD,aAAA,CAAC;YAEF,IAAI,YAAY,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;AAC5C,gBAAA,IAAI,SAAS,CAAC,KAAK,EAAE;AACnB,oBAAA,OAAO,CAAC,KAAK,CAAC,yDAAyD,EAAE;AACvE,wBAAA,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,EAAE;wBAC9B,KAAK,EAAE,YAAY,CAAC;AACrB,qBAAA,CAAC;gBACJ;AACA,gBAAA,OAAO,aAAa,CAAC,GAAG,EAAE,6BAA6B,CAAC;YAC1D;AAEA,YAAA,MAAM,WAAW,GAAG,8BAA8B,CAChD,UAAU,EACV,YAAY,EACZ,QAAQ,CAAC,OAAO,EAChB,QAAQ,CACT;AACD,YAAA,OAAO,gBAAgB,CAAC,WAAW,CAAC;QACtC;QAAE,OAAO,KAAK,EAAE;AACd,YAAA,IAAI,MAAM,CAAC,KAAK,EAAE;AAChB,gBAAA,OAAO,CAAC,KAAK,CAAC,qDAAqD,EAAE,KAAK,CAAC;YAC7E;AACA,YAAA,MAAM,MAAM,GAAG,KAAK,YAAY,oBAAoB,GAAG,KAAK,CAAC,MAAM,GAAG,GAAG;AACzE,YAAA,MAAM,IAAI,GAAG,KAAK,YAAY;kBAC1B,KAAK,CAAC;kBACN,yBAAyB;AAC7B,YAAA,OAAO,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC;QACpC;AACF,IAAA,CAAC;IAEH,OAAO;AACL,QAAA,QAAQ,EAAE;AACR,YAAA,GAAG,EAAE,aAAa,CAAC,KAAK,CAAC;AACzB,YAAA,IAAI,EAAE,aAAa,CAAC,MAAM;AAC3B;KACF;AACH;AAEA,SAAS,cAAc,CACrB,MAAoB,EACpB,YAAoB,EACpB,oBAA4B,EAAA;IAE5B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE;AAC1B,QAAA,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC;IAC7F;AACA,IAAA,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,EAAE;AACxB,QAAA,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC;IACvE;AACA,IAAA,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,IAAI,oBAAoB,IAAI,CAAC,EAAE;AAC5E,QAAA,MAAM,IAAI,KAAK,CAAC,uEAAuE,CAAC;IAC1F;AACF;AAEA,eAAe,gBAAgB,CAC7B,OAAgB,EAChB,YAAoB,EAAA;AAEpB,IAAA,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzE,IAAI,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,cAAc,GAAG,YAAY,EAAE;AACpE,QAAA,MAAM,IAAI,oBAAoB,CAAC,GAAG,EAAE,4BAA4B,CAAC;IACnE;AAEA,IAAA,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE;AACzC,IAAA,IAAI,KAAK,CAAC,UAAU,GAAG,YAAY,EAAE;AACnC,QAAA,MAAM,IAAI,oBAAoB,CAAC,GAAG,EAAE,4BAA4B,CAAC;IACnE;AACA,IAAA,IAAI,KAAK,CAAC,UAAU,KAAK,CAAC;AAAE,QAAA,OAAO,EAAE;AAErC,IAAA,MAAM,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE;AAC5E,IAAA,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE;QAC5C,OAAO,cAAc,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxD;AACA,IAAA,IAAI,WAAW,CAAC,QAAQ,CAAC,qBAAqB,CAAC,EAAE;AAC/C,QAAA,MAAM,IAAI,GAAG,MAAM,IAAI,QAAQ,CAAC,KAAK,EAAE;AACrC,YAAA,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE;SACrE,CAAC,CAAC,QAAQ,EAAE;AACb,QAAA,OAAO,kBAAkB,CAAC,IAAI,CAAC;IACjC;;AAGA,IAAA,OAAO,sBAAsB,CAAC,IAAI,eAAe,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;AACrF;AAEA,SAAS,cAAc,CAAC,MAAc,EAAA;AACpC,IAAA,IAAI,KAAc;AAClB,IAAA,IAAI;AACF,QAAA,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC5B;AAAE,IAAA,MAAM;AACN,QAAA,MAAM,IAAI,oBAAoB,CAAC,GAAG,EAAE,+BAA+B,CAAC;IACtE;AACA,IAAA,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;AAC/D,QAAA,MAAM,IAAI,oBAAoB,CAAC,GAAG,EAAE,+BAA+B,CAAC;IACtE;AACA,IAAA,OAAO,KAA8B;AACvC;AAEA,SAAS,sBAAsB,CAAC,MAAuB,EAAA;IACrD,MAAM,MAAM,GAA0B,EAAE;AACxC,IAAA,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM;AAAE,QAAA,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC;AACpE,IAAA,OAAO,MAAM;AACf;AAEA,SAAS,kBAAkB,CAAC,IAAc,EAAA;IACxC,MAAM,MAAM,GAA0B,EAAE;IACxC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE;AAChC,QAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,YAAA,MAAM,IAAI,oBAAoB,CAAC,GAAG,EAAE,mCAAmC,CAAC;QAC1E;AACA,QAAA,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC;IAClC;AACA,IAAA,OAAO,MAAM;AACf;AAEA,SAAS,WAAW,CAClB,MAA6B,EAC7B,IAAY,EACZ,KAAgC,EAAA;AAEhC,IAAA,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC;AAC5B,IAAA,IAAI,OAAO,KAAK,SAAS,EAAE;AACzB,QAAA,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK;IACtB;AAAO,SAAA,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;AACjC,QAAA,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC;IAC5C;SAAO;QACL,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC;IACzC;AACF;AAEA,SAAS,uBAAuB,CAC9B,UAAe,EACf,IAAuC,EACvC,KAA4B,EAAA;AAE5B,IAAA,MAAM,YAAY,GAAG,UAAU,CAAC;SAC7B,KAAK,CAAC,GAAG;SACT,MAAM,CAAC,OAAO,CAAC;AAClB,IAAA,MAAM,YAAY,GAAG,YAAY,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,WAAW,EAAE;IAEzE,OAAO,OAAO,CACZ,YAAY;AACZ,QAAA,gCAAgC,CAAC,GAAG,CAAC,YAAY,CAAC;QAClD,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAChC;AACH;AAEA,SAAS,8BAA8B,CACrC,UAAe,EACf,YAAoB,EACpB,OAA2C,EAC3C,UAAiC,EAAA;IAEjC,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,MAAM,CAAC;IAC5D,WAAW,CAAC,YAAY,CAAC,GAAG,CAACC,8CAA2B,CAAC,UAAU,EAAE,UAAU,CAAC;AAChF,IAAA,WAAW,CAAC,YAAY,CAAC,GAAG,CAACA,8CAA2B,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;AACvF,IAAA,WAAW,CAAC,YAAY,CAAC,GAAG,CAC1BA,8CAA2B,CAAC,iBAAiB,EAC7C,OAAO,CAAC,UAAU,CACnB;AACD,IAAA,OAAO,WAAW;AACpB;AAEA,SAAS,gBAAgB,CAAC,GAAQ,EAAA;AAChC,IAAA,OAAO,IAAI,QAAQ,CAAC,IAAI,EAAE;AACxB,QAAA,MAAM,EAAE,GAAG;AACX,QAAA,OAAO,EAAE;AACP,YAAA,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE;AACxB,YAAA,eAAe,EAAE,UAAU;AAC3B,YAAA,iBAAiB,EAAE;AACpB;AACF,KAAA,CAAC;AACJ;AAEA,SAAS,aAAa,CACpB,MAAc,EACd,IAAY,EACZ,eAAuC,EAAE,EAAA;IAEzC,OAAO,QAAQ,CAAC,IAAI,CAClB,EAAE,KAAK,EAAE,IAAI,EAAE,EACf;QACE,MAAM;AACN,QAAA,OAAO,EAAE;AACP,YAAA,eAAe,EAAE,UAAU;AAC3B,YAAA,GAAG;AACJ;AACF,KAAA,CACF;AACH;AAEA,MAAM,oBAAqB,SAAQ,KAAK,CAAA;IACtC,WAAA,CACW,MAAc,EACd,IAAY,EAAA;QAErB,KAAK,CAAC,IAAI,CAAC;QAHF,IAAA,CAAA,MAAM,GAAN,MAAM;QACN,IAAA,CAAA,IAAI,GAAJ,IAAI;IAGf;AACD;;;;"}
|
package/dist/server/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { parsePaymentReturnUrl, SAZITO_PAYMENT_STATUS_QUERY } from '../next/paym
|
|
|
9
9
|
*/
|
|
10
10
|
const DEFAULT_CHECKOUT_PATH = '/checkout';
|
|
11
11
|
const DEFAULT_MAX_BODY_BYTES = 64 * 1024;
|
|
12
|
+
const BROWSER_FINALIZED_RESULT_MARKERS = new Set(['paymentinplaceresult']);
|
|
12
13
|
/**
|
|
13
14
|
* Create GET and POST route handlers for payment callbacks.
|
|
14
15
|
* A fresh SDK client is created for each request so server-side guest
|
|
@@ -32,6 +33,15 @@ function SazitoCheckout(config) {
|
|
|
32
33
|
? await readCallbackBody(request, maxCallbackBodyBytes)
|
|
33
34
|
: undefined;
|
|
34
35
|
const query = fieldsFromSearchParams(requestUrl.searchParams);
|
|
36
|
+
// Payment-in-place uses an empty POST only to return control to the
|
|
37
|
+
// storefront. Processing it on the server and then performing a status
|
|
38
|
+
// read in the browser calls process_payment_step twice; some deployments
|
|
39
|
+
// report the second call as failed even though the first one created the
|
|
40
|
+
// order. Redirect the empty first-party callback to the browser so the
|
|
41
|
+
// order is finalized exactly once and the returned order can be rendered.
|
|
42
|
+
if (shouldFinalizeInBrowser(requestUrl, body, query)) {
|
|
43
|
+
return redirectResponse(createPaymentReturnRedirectUrl(requestUrl, checkoutPath, callback.payment, 'callback'));
|
|
44
|
+
}
|
|
35
45
|
const client = createSazitoClient(sdkConfig);
|
|
36
46
|
const verification = await client.payments.verifyPaymentCallback({
|
|
37
47
|
paymentId: callback.payment.id,
|
|
@@ -48,15 +58,8 @@ function SazitoCheckout(config) {
|
|
|
48
58
|
}
|
|
49
59
|
return errorResponse(502, 'payment_verification_failed');
|
|
50
60
|
}
|
|
51
|
-
const redirectUrl =
|
|
52
|
-
return
|
|
53
|
-
status: 303,
|
|
54
|
-
headers: {
|
|
55
|
-
Location: redirectUrl.toString(),
|
|
56
|
-
'Cache-Control': 'no-store',
|
|
57
|
-
'Referrer-Policy': 'no-referrer'
|
|
58
|
-
}
|
|
59
|
-
});
|
|
61
|
+
const redirectUrl = createPaymentReturnRedirectUrl(requestUrl, checkoutPath, callback.payment, 'status');
|
|
62
|
+
return redirectResponse(redirectUrl);
|
|
60
63
|
}
|
|
61
64
|
catch (error) {
|
|
62
65
|
if (config.debug) {
|
|
@@ -152,13 +155,33 @@ function appendField(fields, name, value) {
|
|
|
152
155
|
fields[name] = [current, value ?? null];
|
|
153
156
|
}
|
|
154
157
|
}
|
|
155
|
-
function
|
|
158
|
+
function shouldFinalizeInBrowser(requestUrl, body, query) {
|
|
159
|
+
const pathSegments = requestUrl.pathname
|
|
160
|
+
.split('/')
|
|
161
|
+
.filter(Boolean);
|
|
162
|
+
const resultMarker = pathSegments[pathSegments.length - 5]?.toLowerCase();
|
|
163
|
+
return Boolean(resultMarker &&
|
|
164
|
+
BROWSER_FINALIZED_RESULT_MARKERS.has(resultMarker) &&
|
|
165
|
+
Object.keys(body ?? {}).length === 0 &&
|
|
166
|
+
Object.keys(query).length === 0);
|
|
167
|
+
}
|
|
168
|
+
function createPaymentReturnRedirectUrl(requestUrl, checkoutPath, payment, resolution) {
|
|
156
169
|
const redirectUrl = new URL(checkoutPath, requestUrl.origin);
|
|
157
|
-
redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution,
|
|
170
|
+
redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution, resolution);
|
|
158
171
|
redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));
|
|
159
172
|
redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier, payment.identifier);
|
|
160
173
|
return redirectUrl;
|
|
161
174
|
}
|
|
175
|
+
function redirectResponse(url) {
|
|
176
|
+
return new Response(null, {
|
|
177
|
+
status: 303,
|
|
178
|
+
headers: {
|
|
179
|
+
Location: url.toString(),
|
|
180
|
+
'Cache-Control': 'no-store',
|
|
181
|
+
'Referrer-Policy': 'no-referrer'
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
162
185
|
function errorResponse(status, code, extraHeaders = {}) {
|
|
163
186
|
return Response.json({ error: code }, {
|
|
164
187
|
status,
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["/**\n * @sazito/checkout/server — server-only payment callback handlers.\n *\n * The implementation uses only the standard Web Request/Response APIs so the\n * same handlers work in Next.js Route Handlers and other compatible runtimes.\n */\nimport {\n createSazitoClient,\n type PaymentCallbackFieldValue,\n type PaymentCallbackFields,\n type SazitoConfig\n} from '@sazito/client-sdk';\nimport {\n parsePaymentReturnUrl,\n SAZITO_PAYMENT_STATUS_QUERY\n} from '../core/payment-return';\nimport type { PaymentReturnParserOptions } from '../core/types';\n\nconst DEFAULT_CHECKOUT_PATH = '/checkout';\nconst DEFAULT_MAX_BODY_BYTES = 64 * 1024;\n\nexport type SazitoPaymentRouteHandler = (request: Request) => Promise<Response>;\n\nexport interface SazitoCheckoutServerConfig extends SazitoConfig {\n /** Page that renders `SazitoCheckoutPage` after server verification. */\n checkoutPath?: string;\n /** Maximum accepted gateway callback body size. Defaults to 64 KiB. */\n maxCallbackBodyBytes?: number;\n /** Replace the built-in gateway-result marker allowlist. */\n gatewayResultMarkers?: readonly string[];\n}\n\nexport interface SazitoCheckoutServer {\n handlers: {\n GET: SazitoPaymentRouteHandler;\n POST: SazitoPaymentRouteHandler;\n };\n}\n\n/**\n * Create GET and POST route handlers for payment callbacks.\n * A fresh SDK client is created for each request so server-side guest\n * credentials can never leak between concurrent callbacks.\n */\nexport function SazitoCheckout(config: SazitoCheckoutServerConfig): SazitoCheckoutServer {\n const {\n checkoutPath = DEFAULT_CHECKOUT_PATH,\n maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES,\n gatewayResultMarkers,\n ...sdkConfig\n } = config;\n\n validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);\n const parserOptions: PaymentReturnParserOptions = { gatewayResultMarkers };\n\n const createHandler = (method: 'GET' | 'POST'): SazitoPaymentRouteHandler =>\n async (request) => {\n if (request.method.toUpperCase() !== method) {\n return errorResponse(405, 'method_not_allowed', { Allow: method });\n }\n\n try {\n const callback = parsePaymentReturnUrl(request.url, parserOptions);\n if (!callback || callback.resolution === 'status') {\n return errorResponse(400, 'invalid_payment_callback');\n }\n\n const requestUrl = new URL(request.url);\n const body = method === 'POST'\n ? await readCallbackBody(request, maxCallbackBodyBytes)\n : undefined;\n const query = fieldsFromSearchParams(requestUrl.searchParams);\n const client = createSazitoClient(sdkConfig);\n const verification = await client.payments.verifyPaymentCallback({\n paymentId: callback.payment.id,\n paymentIdentifier: callback.payment.identifier,\n body,\n query\n });\n\n if (verification.error || !verification.data) {\n if (sdkConfig.debug) {\n console.error('[Sazito Checkout] Payment callback verification failed:', {\n paymentId: callback.payment.id,\n error: verification.error\n });\n }\n return errorResponse(502, 'payment_verification_failed');\n }\n\n const redirectUrl = createStatusRedirectUrl(\n requestUrl,\n checkoutPath,\n callback.payment\n );\n return new Response(null, {\n status: 303,\n headers: {\n Location: redirectUrl.toString(),\n 'Cache-Control': 'no-store',\n 'Referrer-Policy': 'no-referrer'\n }\n });\n } catch (error) {\n if (config.debug) {\n console.error('[Sazito Checkout] Invalid payment callback request:', error);\n }\n const status = error instanceof CallbackRequestError ? error.status : 500;\n const code = error instanceof CallbackRequestError\n ? error.code\n : 'payment_callback_failed';\n return errorResponse(status, code);\n }\n };\n\n return {\n handlers: {\n GET: createHandler('GET'),\n POST: createHandler('POST')\n }\n };\n}\n\nfunction validateConfig(\n config: SazitoConfig,\n checkoutPath: string,\n maxCallbackBodyBytes: number\n): void {\n if (!config.domain?.trim()) {\n throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');\n }\n if (!checkoutPath.trim()) {\n throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');\n }\n if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {\n throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');\n }\n}\n\nasync function readCallbackBody(\n request: Request,\n maxBodyBytes: number\n): Promise<PaymentCallbackFields> {\n const declaredLength = Number(request.headers.get('content-length') ?? 0);\n if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n\n const bytes = await request.arrayBuffer();\n if (bytes.byteLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n if (bytes.byteLength === 0) return {};\n\n const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';\n if (contentType.includes('application/json')) {\n return fieldsFromJson(new TextDecoder().decode(bytes));\n }\n if (contentType.includes('multipart/form-data')) {\n const form = await new Response(bytes, {\n headers: { 'Content-Type': request.headers.get('content-type') ?? '' }\n }).formData();\n return fieldsFromFormData(form);\n }\n\n // Gateways commonly omit Content-Type or label URL-encoded data as text.\n return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));\n}\n\nfunction fieldsFromJson(source: string): PaymentCallbackFields {\n let value: unknown;\n try {\n value = JSON.parse(source);\n } catch {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n return value as PaymentCallbackFields;\n}\n\nfunction fieldsFromSearchParams(params: URLSearchParams): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of params) appendField(fields, name, value);\n return fields;\n}\n\nfunction fieldsFromFormData(form: FormData): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of form) {\n if (typeof value !== 'string') {\n throw new CallbackRequestError(400, 'unsupported_payment_callback_file');\n }\n appendField(fields, name, value);\n }\n return fields;\n}\n\nfunction appendField(\n fields: PaymentCallbackFields,\n name: string,\n value: PaymentCallbackFieldValue\n): void {\n const current = fields[name];\n if (current === undefined) {\n fields[name] = value;\n } else if (Array.isArray(current)) {\n fields[name] = [...current, value ?? null];\n } else {\n fields[name] = [current, value ?? null];\n }\n}\n\nfunction createStatusRedirectUrl(\n requestUrl: URL,\n checkoutPath: string,\n payment: { id: number; identifier: string }\n): URL {\n const redirectUrl = new URL(checkoutPath, requestUrl.origin);\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution, 'status');\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));\n redirectUrl.searchParams.set(\n SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier,\n payment.identifier\n );\n return redirectUrl;\n}\n\nfunction errorResponse(\n status: number,\n code: string,\n extraHeaders: Record<string, string> = {}\n): Response {\n return Response.json(\n { error: code },\n {\n status,\n headers: {\n 'Cache-Control': 'no-store',\n ...extraHeaders\n }\n }\n );\n}\n\nclass CallbackRequestError extends Error {\n constructor(\n readonly status: number,\n readonly code: string\n ) {\n super(code);\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/server/index.ts"],"sourcesContent":["/**\n * @sazito/checkout/server — server-only payment callback handlers.\n *\n * The implementation uses only the standard Web Request/Response APIs so the\n * same handlers work in Next.js Route Handlers and other compatible runtimes.\n */\nimport {\n createSazitoClient,\n type PaymentCallbackFieldValue,\n type PaymentCallbackFields,\n type SazitoConfig\n} from '@sazito/client-sdk';\nimport {\n parsePaymentReturnUrl,\n SAZITO_PAYMENT_STATUS_QUERY\n} from '../core/payment-return';\nimport type { PaymentReturnParserOptions } from '../core/types';\n\nconst DEFAULT_CHECKOUT_PATH = '/checkout';\nconst DEFAULT_MAX_BODY_BYTES = 64 * 1024;\nconst BROWSER_FINALIZED_RESULT_MARKERS = new Set(['paymentinplaceresult']);\n\nexport type SazitoPaymentRouteHandler = (request: Request) => Promise<Response>;\n\nexport interface SazitoCheckoutServerConfig extends SazitoConfig {\n /** Page that renders `SazitoCheckoutPage` after server verification. */\n checkoutPath?: string;\n /** Maximum accepted gateway callback body size. Defaults to 64 KiB. */\n maxCallbackBodyBytes?: number;\n /** Replace the built-in gateway-result marker allowlist. */\n gatewayResultMarkers?: readonly string[];\n}\n\nexport interface SazitoCheckoutServer {\n handlers: {\n GET: SazitoPaymentRouteHandler;\n POST: SazitoPaymentRouteHandler;\n };\n}\n\n/**\n * Create GET and POST route handlers for payment callbacks.\n * A fresh SDK client is created for each request so server-side guest\n * credentials can never leak between concurrent callbacks.\n */\nexport function SazitoCheckout(config: SazitoCheckoutServerConfig): SazitoCheckoutServer {\n const {\n checkoutPath = DEFAULT_CHECKOUT_PATH,\n maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES,\n gatewayResultMarkers,\n ...sdkConfig\n } = config;\n\n validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);\n const parserOptions: PaymentReturnParserOptions = { gatewayResultMarkers };\n\n const createHandler = (method: 'GET' | 'POST'): SazitoPaymentRouteHandler =>\n async (request) => {\n if (request.method.toUpperCase() !== method) {\n return errorResponse(405, 'method_not_allowed', { Allow: method });\n }\n\n try {\n const callback = parsePaymentReturnUrl(request.url, parserOptions);\n if (!callback || callback.resolution === 'status') {\n return errorResponse(400, 'invalid_payment_callback');\n }\n\n const requestUrl = new URL(request.url);\n const body = method === 'POST'\n ? await readCallbackBody(request, maxCallbackBodyBytes)\n : undefined;\n const query = fieldsFromSearchParams(requestUrl.searchParams);\n\n // Payment-in-place uses an empty POST only to return control to the\n // storefront. Processing it on the server and then performing a status\n // read in the browser calls process_payment_step twice; some deployments\n // report the second call as failed even though the first one created the\n // order. Redirect the empty first-party callback to the browser so the\n // order is finalized exactly once and the returned order can be rendered.\n if (shouldFinalizeInBrowser(requestUrl, body, query)) {\n return redirectResponse(createPaymentReturnRedirectUrl(\n requestUrl,\n checkoutPath,\n callback.payment,\n 'callback'\n ));\n }\n\n const client = createSazitoClient(sdkConfig);\n const verification = await client.payments.verifyPaymentCallback({\n paymentId: callback.payment.id,\n paymentIdentifier: callback.payment.identifier,\n body,\n query\n });\n\n if (verification.error || !verification.data) {\n if (sdkConfig.debug) {\n console.error('[Sazito Checkout] Payment callback verification failed:', {\n paymentId: callback.payment.id,\n error: verification.error\n });\n }\n return errorResponse(502, 'payment_verification_failed');\n }\n\n const redirectUrl = createPaymentReturnRedirectUrl(\n requestUrl,\n checkoutPath,\n callback.payment,\n 'status'\n );\n return redirectResponse(redirectUrl);\n } catch (error) {\n if (config.debug) {\n console.error('[Sazito Checkout] Invalid payment callback request:', error);\n }\n const status = error instanceof CallbackRequestError ? error.status : 500;\n const code = error instanceof CallbackRequestError\n ? error.code\n : 'payment_callback_failed';\n return errorResponse(status, code);\n }\n };\n\n return {\n handlers: {\n GET: createHandler('GET'),\n POST: createHandler('POST')\n }\n };\n}\n\nfunction validateConfig(\n config: SazitoConfig,\n checkoutPath: string,\n maxCallbackBodyBytes: number\n): void {\n if (!config.domain?.trim()) {\n throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');\n }\n if (!checkoutPath.trim()) {\n throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');\n }\n if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {\n throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');\n }\n}\n\nasync function readCallbackBody(\n request: Request,\n maxBodyBytes: number\n): Promise<PaymentCallbackFields> {\n const declaredLength = Number(request.headers.get('content-length') ?? 0);\n if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n\n const bytes = await request.arrayBuffer();\n if (bytes.byteLength > maxBodyBytes) {\n throw new CallbackRequestError(413, 'payment_callback_too_large');\n }\n if (bytes.byteLength === 0) return {};\n\n const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';\n if (contentType.includes('application/json')) {\n return fieldsFromJson(new TextDecoder().decode(bytes));\n }\n if (contentType.includes('multipart/form-data')) {\n const form = await new Response(bytes, {\n headers: { 'Content-Type': request.headers.get('content-type') ?? '' }\n }).formData();\n return fieldsFromFormData(form);\n }\n\n // Gateways commonly omit Content-Type or label URL-encoded data as text.\n return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));\n}\n\nfunction fieldsFromJson(source: string): PaymentCallbackFields {\n let value: unknown;\n try {\n value = JSON.parse(source);\n } catch {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n throw new CallbackRequestError(400, 'invalid_payment_callback_body');\n }\n return value as PaymentCallbackFields;\n}\n\nfunction fieldsFromSearchParams(params: URLSearchParams): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of params) appendField(fields, name, value);\n return fields;\n}\n\nfunction fieldsFromFormData(form: FormData): PaymentCallbackFields {\n const fields: PaymentCallbackFields = {};\n for (const [name, value] of form) {\n if (typeof value !== 'string') {\n throw new CallbackRequestError(400, 'unsupported_payment_callback_file');\n }\n appendField(fields, name, value);\n }\n return fields;\n}\n\nfunction appendField(\n fields: PaymentCallbackFields,\n name: string,\n value: PaymentCallbackFieldValue\n): void {\n const current = fields[name];\n if (current === undefined) {\n fields[name] = value;\n } else if (Array.isArray(current)) {\n fields[name] = [...current, value ?? null];\n } else {\n fields[name] = [current, value ?? null];\n }\n}\n\nfunction shouldFinalizeInBrowser(\n requestUrl: URL,\n body: PaymentCallbackFields | undefined,\n query: PaymentCallbackFields\n): boolean {\n const pathSegments = requestUrl.pathname\n .split('/')\n .filter(Boolean);\n const resultMarker = pathSegments[pathSegments.length - 5]?.toLowerCase();\n\n return Boolean(\n resultMarker &&\n BROWSER_FINALIZED_RESULT_MARKERS.has(resultMarker) &&\n Object.keys(body ?? {}).length === 0 &&\n Object.keys(query).length === 0\n );\n}\n\nfunction createPaymentReturnRedirectUrl(\n requestUrl: URL,\n checkoutPath: string,\n payment: { id: number; identifier: string },\n resolution: 'callback' | 'status'\n): URL {\n const redirectUrl = new URL(checkoutPath, requestUrl.origin);\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution, resolution);\n redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));\n redirectUrl.searchParams.set(\n SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier,\n payment.identifier\n );\n return redirectUrl;\n}\n\nfunction redirectResponse(url: URL): Response {\n return new Response(null, {\n status: 303,\n headers: {\n Location: url.toString(),\n 'Cache-Control': 'no-store',\n 'Referrer-Policy': 'no-referrer'\n }\n });\n}\n\nfunction errorResponse(\n status: number,\n code: string,\n extraHeaders: Record<string, string> = {}\n): Response {\n return Response.json(\n { error: code },\n {\n status,\n headers: {\n 'Cache-Control': 'no-store',\n ...extraHeaders\n }\n }\n );\n}\n\nclass CallbackRequestError extends Error {\n constructor(\n readonly status: number,\n readonly code: string\n ) {\n super(code);\n }\n}\n"],"names":[],"mappings":"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"}
|