@sazito/checkout 0.4.19 → 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.
Files changed (47) hide show
  1. package/README.md +22 -37
  2. package/dist/chunks/{labels-Cy05dLJx.cjs → labels-BYJQjaT_.cjs} +9 -5
  3. package/dist/chunks/labels-BYJQjaT_.cjs.map +1 -0
  4. package/dist/chunks/{labels-Cysz2BgA.js → labels-Cqrb2MwA.js} +9 -5
  5. package/dist/chunks/labels-Cqrb2MwA.js.map +1 -0
  6. package/dist/chunks/{use-checkout-uWEi8iqK.js → use-checkout-BRDfZp4Z.js} +8 -5
  7. package/dist/chunks/use-checkout-BRDfZp4Z.js.map +1 -0
  8. package/dist/chunks/{use-checkout-wHkKNkbK.cjs → use-checkout-MM-Ld0Ew.cjs} +7 -4
  9. package/dist/chunks/use-checkout-MM-Ld0Ew.cjs.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 +52 -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 +51 -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 +205 -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 +203 -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
@@ -0,0 +1,205 @@
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
+ const BROWSER_FINALIZED_RESULT_MARKERS = new Set(['paymentinplaceresult']);
15
+ /**
16
+ * Create GET and POST route handlers for payment callbacks.
17
+ * A fresh SDK client is created for each request so server-side guest
18
+ * credentials can never leak between concurrent callbacks.
19
+ */
20
+ function SazitoCheckout(config) {
21
+ const { checkoutPath = DEFAULT_CHECKOUT_PATH, maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES, gatewayResultMarkers, ...sdkConfig } = config;
22
+ validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);
23
+ const parserOptions = { gatewayResultMarkers };
24
+ const createHandler = (method) => async (request) => {
25
+ if (request.method.toUpperCase() !== method) {
26
+ return errorResponse(405, 'method_not_allowed', { Allow: method });
27
+ }
28
+ try {
29
+ const callback = next_paymentReturn.parsePaymentReturnUrl(request.url, parserOptions);
30
+ if (!callback || callback.resolution === 'status') {
31
+ return errorResponse(400, 'invalid_payment_callback');
32
+ }
33
+ const requestUrl = new URL(request.url);
34
+ const body = method === 'POST'
35
+ ? await readCallbackBody(request, maxCallbackBodyBytes)
36
+ : undefined;
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
+ }
47
+ const client = clientSdk.createSazitoClient(sdkConfig);
48
+ const verification = await client.payments.verifyPaymentCallback({
49
+ paymentId: callback.payment.id,
50
+ paymentIdentifier: callback.payment.identifier,
51
+ body,
52
+ query
53
+ });
54
+ if (verification.error || !verification.data) {
55
+ if (sdkConfig.debug) {
56
+ console.error('[Sazito Checkout] Payment callback verification failed:', {
57
+ paymentId: callback.payment.id,
58
+ error: verification.error
59
+ });
60
+ }
61
+ return errorResponse(502, 'payment_verification_failed');
62
+ }
63
+ const redirectUrl = createPaymentReturnRedirectUrl(requestUrl, checkoutPath, callback.payment, 'status');
64
+ return redirectResponse(redirectUrl);
65
+ }
66
+ catch (error) {
67
+ if (config.debug) {
68
+ console.error('[Sazito Checkout] Invalid payment callback request:', error);
69
+ }
70
+ const status = error instanceof CallbackRequestError ? error.status : 500;
71
+ const code = error instanceof CallbackRequestError
72
+ ? error.code
73
+ : 'payment_callback_failed';
74
+ return errorResponse(status, code);
75
+ }
76
+ };
77
+ return {
78
+ handlers: {
79
+ GET: createHandler('GET'),
80
+ POST: createHandler('POST')
81
+ }
82
+ };
83
+ }
84
+ function validateConfig(config, checkoutPath, maxCallbackBodyBytes) {
85
+ if (!config.domain?.trim()) {
86
+ throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');
87
+ }
88
+ if (!checkoutPath.trim()) {
89
+ throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');
90
+ }
91
+ if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {
92
+ throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');
93
+ }
94
+ }
95
+ async function readCallbackBody(request, maxBodyBytes) {
96
+ const declaredLength = Number(request.headers.get('content-length') ?? 0);
97
+ if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {
98
+ throw new CallbackRequestError(413, 'payment_callback_too_large');
99
+ }
100
+ const bytes = await request.arrayBuffer();
101
+ if (bytes.byteLength > maxBodyBytes) {
102
+ throw new CallbackRequestError(413, 'payment_callback_too_large');
103
+ }
104
+ if (bytes.byteLength === 0)
105
+ return {};
106
+ const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';
107
+ if (contentType.includes('application/json')) {
108
+ return fieldsFromJson(new TextDecoder().decode(bytes));
109
+ }
110
+ if (contentType.includes('multipart/form-data')) {
111
+ const form = await new Response(bytes, {
112
+ headers: { 'Content-Type': request.headers.get('content-type') ?? '' }
113
+ }).formData();
114
+ return fieldsFromFormData(form);
115
+ }
116
+ // Gateways commonly omit Content-Type or label URL-encoded data as text.
117
+ return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));
118
+ }
119
+ function fieldsFromJson(source) {
120
+ let value;
121
+ try {
122
+ value = JSON.parse(source);
123
+ }
124
+ catch {
125
+ throw new CallbackRequestError(400, 'invalid_payment_callback_body');
126
+ }
127
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
128
+ throw new CallbackRequestError(400, 'invalid_payment_callback_body');
129
+ }
130
+ return value;
131
+ }
132
+ function fieldsFromSearchParams(params) {
133
+ const fields = {};
134
+ for (const [name, value] of params)
135
+ appendField(fields, name, value);
136
+ return fields;
137
+ }
138
+ function fieldsFromFormData(form) {
139
+ const fields = {};
140
+ for (const [name, value] of form) {
141
+ if (typeof value !== 'string') {
142
+ throw new CallbackRequestError(400, 'unsupported_payment_callback_file');
143
+ }
144
+ appendField(fields, name, value);
145
+ }
146
+ return fields;
147
+ }
148
+ function appendField(fields, name, value) {
149
+ const current = fields[name];
150
+ if (current === undefined) {
151
+ fields[name] = value;
152
+ }
153
+ else if (Array.isArray(current)) {
154
+ fields[name] = [...current, value ?? null];
155
+ }
156
+ else {
157
+ fields[name] = [current, value ?? null];
158
+ }
159
+ }
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) {
171
+ const redirectUrl = new URL(checkoutPath, requestUrl.origin);
172
+ redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.resolution, resolution);
173
+ redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));
174
+ redirectUrl.searchParams.set(next_paymentReturn.SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier, payment.identifier);
175
+ return redirectUrl;
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
+ }
187
+ function errorResponse(status, code, extraHeaders = {}) {
188
+ return Response.json({ error: code }, {
189
+ status,
190
+ headers: {
191
+ 'Cache-Control': 'no-store',
192
+ ...extraHeaders
193
+ }
194
+ });
195
+ }
196
+ class CallbackRequestError extends Error {
197
+ constructor(status, code) {
198
+ super(code);
199
+ this.status = status;
200
+ this.code = code;
201
+ }
202
+ }
203
+
204
+ exports.SazitoCheckout = SazitoCheckout;
205
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +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;\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":"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"}
@@ -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,203 @@
1
+ import { createSazitoClient } from '@sazito/client-sdk';
2
+ import { parsePaymentReturnUrl, SAZITO_PAYMENT_STATUS_QUERY } from '../next/payment-return.js';
3
+
4
+ /**
5
+ * @sazito/checkout/server — server-only payment callback handlers.
6
+ *
7
+ * The implementation uses only the standard Web Request/Response APIs so the
8
+ * same handlers work in Next.js Route Handlers and other compatible runtimes.
9
+ */
10
+ const DEFAULT_CHECKOUT_PATH = '/checkout';
11
+ const DEFAULT_MAX_BODY_BYTES = 64 * 1024;
12
+ const BROWSER_FINALIZED_RESULT_MARKERS = new Set(['paymentinplaceresult']);
13
+ /**
14
+ * Create GET and POST route handlers for payment callbacks.
15
+ * A fresh SDK client is created for each request so server-side guest
16
+ * credentials can never leak between concurrent callbacks.
17
+ */
18
+ function SazitoCheckout(config) {
19
+ const { checkoutPath = DEFAULT_CHECKOUT_PATH, maxCallbackBodyBytes = DEFAULT_MAX_BODY_BYTES, gatewayResultMarkers, ...sdkConfig } = config;
20
+ validateConfig(sdkConfig, checkoutPath, maxCallbackBodyBytes);
21
+ const parserOptions = { gatewayResultMarkers };
22
+ const createHandler = (method) => async (request) => {
23
+ if (request.method.toUpperCase() !== method) {
24
+ return errorResponse(405, 'method_not_allowed', { Allow: method });
25
+ }
26
+ try {
27
+ const callback = parsePaymentReturnUrl(request.url, parserOptions);
28
+ if (!callback || callback.resolution === 'status') {
29
+ return errorResponse(400, 'invalid_payment_callback');
30
+ }
31
+ const requestUrl = new URL(request.url);
32
+ const body = method === 'POST'
33
+ ? await readCallbackBody(request, maxCallbackBodyBytes)
34
+ : undefined;
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
+ }
45
+ const client = createSazitoClient(sdkConfig);
46
+ const verification = await client.payments.verifyPaymentCallback({
47
+ paymentId: callback.payment.id,
48
+ paymentIdentifier: callback.payment.identifier,
49
+ body,
50
+ query
51
+ });
52
+ if (verification.error || !verification.data) {
53
+ if (sdkConfig.debug) {
54
+ console.error('[Sazito Checkout] Payment callback verification failed:', {
55
+ paymentId: callback.payment.id,
56
+ error: verification.error
57
+ });
58
+ }
59
+ return errorResponse(502, 'payment_verification_failed');
60
+ }
61
+ const redirectUrl = createPaymentReturnRedirectUrl(requestUrl, checkoutPath, callback.payment, 'status');
62
+ return redirectResponse(redirectUrl);
63
+ }
64
+ catch (error) {
65
+ if (config.debug) {
66
+ console.error('[Sazito Checkout] Invalid payment callback request:', error);
67
+ }
68
+ const status = error instanceof CallbackRequestError ? error.status : 500;
69
+ const code = error instanceof CallbackRequestError
70
+ ? error.code
71
+ : 'payment_callback_failed';
72
+ return errorResponse(status, code);
73
+ }
74
+ };
75
+ return {
76
+ handlers: {
77
+ GET: createHandler('GET'),
78
+ POST: createHandler('POST')
79
+ }
80
+ };
81
+ }
82
+ function validateConfig(config, checkoutPath, maxCallbackBodyBytes) {
83
+ if (!config.domain?.trim()) {
84
+ throw new Error('[@sazito/checkout] `domain` is required by the payment callback handler.');
85
+ }
86
+ if (!checkoutPath.trim()) {
87
+ throw new Error('[@sazito/checkout] `checkoutPath` cannot be empty.');
88
+ }
89
+ if (!Number.isSafeInteger(maxCallbackBodyBytes) || maxCallbackBodyBytes <= 0) {
90
+ throw new Error('[@sazito/checkout] `maxCallbackBodyBytes` must be a positive integer.');
91
+ }
92
+ }
93
+ async function readCallbackBody(request, maxBodyBytes) {
94
+ const declaredLength = Number(request.headers.get('content-length') ?? 0);
95
+ if (Number.isFinite(declaredLength) && declaredLength > maxBodyBytes) {
96
+ throw new CallbackRequestError(413, 'payment_callback_too_large');
97
+ }
98
+ const bytes = await request.arrayBuffer();
99
+ if (bytes.byteLength > maxBodyBytes) {
100
+ throw new CallbackRequestError(413, 'payment_callback_too_large');
101
+ }
102
+ if (bytes.byteLength === 0)
103
+ return {};
104
+ const contentType = request.headers.get('content-type')?.toLowerCase() ?? '';
105
+ if (contentType.includes('application/json')) {
106
+ return fieldsFromJson(new TextDecoder().decode(bytes));
107
+ }
108
+ if (contentType.includes('multipart/form-data')) {
109
+ const form = await new Response(bytes, {
110
+ headers: { 'Content-Type': request.headers.get('content-type') ?? '' }
111
+ }).formData();
112
+ return fieldsFromFormData(form);
113
+ }
114
+ // Gateways commonly omit Content-Type or label URL-encoded data as text.
115
+ return fieldsFromSearchParams(new URLSearchParams(new TextDecoder().decode(bytes)));
116
+ }
117
+ function fieldsFromJson(source) {
118
+ let value;
119
+ try {
120
+ value = JSON.parse(source);
121
+ }
122
+ catch {
123
+ throw new CallbackRequestError(400, 'invalid_payment_callback_body');
124
+ }
125
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
126
+ throw new CallbackRequestError(400, 'invalid_payment_callback_body');
127
+ }
128
+ return value;
129
+ }
130
+ function fieldsFromSearchParams(params) {
131
+ const fields = {};
132
+ for (const [name, value] of params)
133
+ appendField(fields, name, value);
134
+ return fields;
135
+ }
136
+ function fieldsFromFormData(form) {
137
+ const fields = {};
138
+ for (const [name, value] of form) {
139
+ if (typeof value !== 'string') {
140
+ throw new CallbackRequestError(400, 'unsupported_payment_callback_file');
141
+ }
142
+ appendField(fields, name, value);
143
+ }
144
+ return fields;
145
+ }
146
+ function appendField(fields, name, value) {
147
+ const current = fields[name];
148
+ if (current === undefined) {
149
+ fields[name] = value;
150
+ }
151
+ else if (Array.isArray(current)) {
152
+ fields[name] = [...current, value ?? null];
153
+ }
154
+ else {
155
+ fields[name] = [current, value ?? null];
156
+ }
157
+ }
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) {
169
+ const redirectUrl = new URL(checkoutPath, requestUrl.origin);
170
+ redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.resolution, resolution);
171
+ redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentId, String(payment.id));
172
+ redirectUrl.searchParams.set(SAZITO_PAYMENT_STATUS_QUERY.paymentIdentifier, payment.identifier);
173
+ return redirectUrl;
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
+ }
185
+ function errorResponse(status, code, extraHeaders = {}) {
186
+ return Response.json({ error: code }, {
187
+ status,
188
+ headers: {
189
+ 'Cache-Control': 'no-store',
190
+ ...extraHeaders
191
+ }
192
+ });
193
+ }
194
+ class CallbackRequestError extends Error {
195
+ constructor(status, code) {
196
+ super(code);
197
+ this.status = status;
198
+ this.code = code;
199
+ }
200
+ }
201
+
202
+ export { SazitoCheckout };
203
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;\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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sazito/checkout",
3
- "version": "0.4.19",
3
+ "version": "0.4.21",
4
4
  "description": "Headless checkout engine + React UI for the Sazito platform, powered by @sazito/client-sdk",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -67,6 +67,28 @@
67
67
  },
68
68
  "default": "./dist/next/payment-return.js"
69
69
  },
70
+ "./next/server": {
71
+ "import": {
72
+ "types": "./dist/next/server.d.ts",
73
+ "default": "./dist/next/server.js"
74
+ },
75
+ "require": {
76
+ "types": "./dist/next/server.d.cts",
77
+ "default": "./dist/next/server.cjs"
78
+ },
79
+ "default": "./dist/next/server.js"
80
+ },
81
+ "./server": {
82
+ "import": {
83
+ "types": "./dist/server/index.d.ts",
84
+ "default": "./dist/server/index.js"
85
+ },
86
+ "require": {
87
+ "types": "./dist/server/index.d.cts",
88
+ "default": "./dist/server/index.cjs"
89
+ },
90
+ "default": "./dist/server/index.js"
91
+ },
70
92
  "./styles.css": "./dist/styles.css"
71
93
  },
72
94
  "typesVersions": {
@@ -82,6 +104,12 @@
82
104
  ],
83
105
  "next/payment-return": [
84
106
  "dist/next/payment-return.d.ts"
107
+ ],
108
+ "next/server": [
109
+ "dist/next/server.d.ts"
110
+ ],
111
+ "server": [
112
+ "dist/server/index.d.ts"
85
113
  ]
86
114
  }
87
115
  },
@@ -99,7 +127,7 @@
99
127
  "prepublishOnly": "pnpm run release:check"
100
128
  },
101
129
  "peerDependencies": {
102
- "@sazito/client-sdk": "^1.2.3",
130
+ "@sazito/client-sdk": "^1.2.28",
103
131
  "react": "^18.0.0 || ^19.0.0",
104
132
  "react-dom": "^18.0.0 || ^19.0.0"
105
133
  },