@doswiftly/storefront-sdk 22.1.0 → 22.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,43 @@
1
1
  # Changelog
2
2
 
3
+ ## 22.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 21b0c44: Storefront payments: surface buyer acknowledgements (such as the Przelewy24 regulation consent) on payment methods, and accept them when starting a payment.
8
+
9
+ `PaymentMethod` now exposes an `acknowledgements` list — consents the buyer can affirm before paying. Each one carries a localized `statement` (with `<token>…</token>` tags marking the words that link to its `documents`), the linked document URLs, and an `enforcement` flag (optional vs required). Render each as a checkbox (never pre-checked) and link the tagged words to the matching `documents[].url`, then send the accepted ones back through the new optional `PaymentCreateInput.acknowledgements` field (`{ code, accepted }`).
10
+
11
+ For Przelewy24 this lets a storefront collect the regulation consent in-store (showing the required statement and links) so the buyer skips the gateway's consent page and goes straight to the bank / BLIK / card form. When you omit it, the gateway shows the consent itself, so it is fully optional.
12
+
13
+ Additive and backwards-compatible — existing operations are unaffected.
14
+
15
+ ## 22.2.0
16
+
17
+ ### Minor Changes
18
+
19
+ - 27934d1: Server `getStorefrontClient`: forwarded-IP signing is now **opt-in** via `getBuyerIp`.
20
+
21
+ Previously the server client auto-read the buyer IP through `next/headers` on every
22
+ request. That is a dynamic API and is illegal in statically-generated / ISR routes —
23
+ it crashed such pages with "Page changed from static to dynamic at runtime".
24
+
25
+ Forwarded-IP is now wired only when you pass `getBuyerIp`, which you should do **only
26
+ on routes that are already dynamic** (per-request rendered). Without it the client is
27
+ a fully static-safe, inert pass-through.
28
+
29
+ Migration — to keep forwarding the buyer IP, pass `getBuyerIp` on your dynamic routes:
30
+
31
+ ```typescript
32
+ import { headers } from "next/headers";
33
+
34
+ getStorefrontClient({
35
+ apiUrl,
36
+ shopSlug,
37
+ getBuyerIp: async () => (await headers()).get("cf-connecting-ip"),
38
+ });
39
+ ```
40
+
3
41
  ## 22.1.0
4
42
 
5
43
  ### Minor Changes
package/README.md CHANGED
@@ -1078,34 +1078,32 @@ middleware: [
1078
1078
  ### Forwarding the buyer IP for rate limiting
1079
1079
 
1080
1080
  When a storefront fetches on the server, the API sees the storefront server's IP for
1081
- every buyer, so per-IP rate limits collapse onto a single address. The server client
1082
- forwards the buyer's real IP so rate limiting applies per buyer again.
1081
+ every buyer, so per-IP rate limits collapse onto a single address. Forwarding the
1082
+ buyer's real IP restores per-buyer limits.
1083
1083
 
1084
- **Automatic on the server nothing to wire.** Call `getStorefrontClient` as usual:
1084
+ **Opt-in supply `getBuyerIp`.** Reading the buyer IP requires a request-scoped
1085
+ dynamic API (e.g. `next/headers` `headers()`), which is **illegal in
1086
+ statically-generated / ISR routes** and would crash them ("static to dynamic at
1087
+ runtime"). So enable it **only on routes that are already dynamic** (per-request
1088
+ rendered):
1085
1089
 
1086
1090
  ```typescript
1091
+ import { headers } from 'next/headers';
1092
+
1093
+ // In a DYNAMIC route/segment only — headers() forces dynamic rendering:
1087
1094
  const client = getStorefrontClient({
1088
1095
  apiUrl: process.env.DOSWIFTLY_API_URL!,
1089
1096
  shopSlug: process.env.DOSWIFTLY_SHOP_SLUG!,
1097
+ getBuyerIp: async () => (await headers()).get('cf-connecting-ip'),
1090
1098
  });
1091
1099
  ```
1092
1100
 
1093
- It applies only inside a server request with forwarding configured by your
1094
- deployment, and is otherwise an inert pass-through existing setups are unaffected.
1101
+ Without `getBuyerIp` the client never reads the IP and never signs — a fully
1102
+ static-safe, inert pass-through (static / ISR routes are unaffected). Signing also
1103
+ requires the secret `process.env.DOSWIFTLY_FORWARDED_IP_SECRET` (set by your
1104
+ deployment; override via `getForwardedIpSecret` for runtimes without `process.env`).
1095
1105
  **Server-only**: nothing IP-related reaches the browser.
1096
1106
 
1097
- **Non-Next server runtimes** — supply the buyer IP yourself (e.g. from
1098
- `cf-connecting-ip`), plus the signing secret if your runtime has no `process.env`:
1099
-
1100
- ```typescript
1101
- const client = getStorefrontClient({
1102
- apiUrl,
1103
- shopSlug,
1104
- getBuyerIp: () => incomingRequest.headers.get('cf-connecting-ip'),
1105
- // getForwardedIpSecret: () => ...
1106
- });
1107
- ```
1108
-
1109
1107
  The lower-level `forwardedIpMiddleware({ getBuyerIp, getSecret })` is also exported
1110
1108
  for fully custom clients.
1111
1109
 
@@ -2569,7 +2569,44 @@ export type PageInfo = {
2569
2569
  /** Cursor of the first item on the current page — opaque, base64-encoded. Echo as the `before` argument to paginate backwards. */
2570
2570
  startCursor?: Maybe<Scalars['String']['output']>;
2571
2571
  };
2572
+ export type PaymentAcknowledgement = {
2573
+ /** Stable machine code identifying the acknowledgement (e.g. "PRZELEWY24_REGULATION"). Echo it back in `PaymentAcknowledgementInput.code` when the buyer accepts. */
2574
+ code: Scalars['String']['output'];
2575
+ /** Documents linked from `statement`, bound by `token`. Empty when the statement carries no links. */
2576
+ documents: Array<PaymentAcknowledgementDocument>;
2577
+ /** Whether collecting this in the storefront is optional (GATEWAY_FALLBACK) or mandatory (STOREFRONT_REQUIRED). */
2578
+ enforcement: PaymentAcknowledgementEnforcement;
2579
+ /** Localized statement to show next to the checkbox. Contains `<token>…</token>` tags marking the words that link to `documents` (e.g. "… <terms>regulaminem</terms> …"). Render the tagged words as anchors; never inject as raw HTML. */
2580
+ statement: Scalars['String']['output'];
2581
+ };
2582
+ export type PaymentAcknowledgementDocument = {
2583
+ /** Semantic category of the document (TERMS, INFORMATION_OBLIGATION, PRIVACY_POLICY). */
2584
+ kind: PaymentAcknowledgementDocumentKind;
2585
+ /** Binding token — equals the tag name wrapping the linked words inside `PaymentAcknowledgement.statement` (e.g. `terms` ↔ `<terms>…</terms>`). */
2586
+ token: Scalars['String']['output'];
2587
+ /** Absolute URL of the document to link to. */
2588
+ url: Scalars['URL']['output'];
2589
+ };
2590
+ export declare const PaymentAcknowledgementDocumentKind: {
2591
+ readonly InformationObligation: "INFORMATION_OBLIGATION";
2592
+ readonly PrivacyPolicy: "PRIVACY_POLICY";
2593
+ readonly Terms: "TERMS";
2594
+ };
2595
+ export type PaymentAcknowledgementDocumentKind = typeof PaymentAcknowledgementDocumentKind[keyof typeof PaymentAcknowledgementDocumentKind];
2596
+ export declare const PaymentAcknowledgementEnforcement: {
2597
+ readonly GatewayFallback: "GATEWAY_FALLBACK";
2598
+ readonly StorefrontRequired: "STOREFRONT_REQUIRED";
2599
+ };
2600
+ export type PaymentAcknowledgementEnforcement = typeof PaymentAcknowledgementEnforcement[keyof typeof PaymentAcknowledgementEnforcement];
2601
+ export type PaymentAcknowledgementInput = {
2602
+ /** True when the buyer checked the acknowledgement. */
2603
+ accepted: Scalars['Boolean']['input'];
2604
+ /** Code of the acknowledgement the buyer affirmed (e.g. "PRZELEWY24_REGULATION"). */
2605
+ code: Scalars['String']['input'];
2606
+ };
2572
2607
  export type PaymentCreateInput = {
2608
+ /** Payment acknowledgements the buyer affirmed (e.g. accepting the Przelewy24 regulation). Send only the ones the buyer checked. Optional — when omitted, gateways that present their own consent step collect it; a method with a STOREFRONT_REQUIRED acknowledgement returns `ACKNOWLEDGEMENT_REQUIRED` if not accepted. */
2609
+ acknowledgements?: InputMaybe<Array<PaymentAcknowledgementInput>>;
2573
2610
  /** URL the gateway returns the buyer to after they cancel the payment. Must point to a verified domain of the shop. */
2574
2611
  cancelUrl?: InputMaybe<Scalars['URL']['input']>;
2575
2612
  /** ID of the order to pay for — `cartComplete.order.id`. */
@@ -2624,6 +2661,8 @@ export declare const PaymentInstrumentType: {
2624
2661
  };
2625
2662
  export type PaymentInstrumentType = typeof PaymentInstrumentType[keyof typeof PaymentInstrumentType];
2626
2663
  export type PaymentMethod = {
2664
+ /** Consents the buyer can affirm before paying with this method (e.g. the Przelewy24 regulation declaration). Render each as a checkbox using `statement` + `documents`, then echo accepted `code`s back in `PaymentCreateInput.acknowledgements`. Empty when the method carries no acknowledgements. */
2665
+ acknowledgements: Array<PaymentAcknowledgement>;
2627
2666
  /** True when the buyer can actually pick this method right now. False when the resolving gateway is temporarily unavailable (incident/maintenance) or reported the method as disabled. Storefront UI should gray-out the tile when false instead of hiding it — gives merchants observability into routing failures. */
2628
2667
  available: Scalars['Boolean']['output'];
2629
2668
  /** Optional buyer-facing description shown under the name (e.g. "Pay with your bank app"). */