@doswiftly/storefront-sdk 16.1.0 → 18.0.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.
Files changed (94) hide show
  1. package/CHANGELOG.md +1255 -0
  2. package/README.md +16 -4
  3. package/dist/core/auth/auth-client.d.ts +39 -3
  4. package/dist/core/auth/auth-client.d.ts.map +1 -1
  5. package/dist/core/auth/auth-client.js +51 -3
  6. package/dist/core/auth/cookie-config.d.ts +52 -3
  7. package/dist/core/auth/cookie-config.d.ts.map +1 -1
  8. package/dist/core/auth/cookie-config.js +60 -6
  9. package/dist/core/auth/handlers.d.ts +46 -0
  10. package/dist/core/auth/handlers.d.ts.map +1 -1
  11. package/dist/core/auth/handlers.js +9 -2
  12. package/dist/core/auth/session-events.d.ts +38 -0
  13. package/dist/core/auth/session-events.d.ts.map +1 -0
  14. package/dist/core/auth/session-events.js +35 -0
  15. package/dist/core/cart/cart-client.d.ts +10 -1
  16. package/dist/core/cart/cart-client.d.ts.map +1 -1
  17. package/dist/core/cart/cart-client.js +17 -1
  18. package/dist/core/cart/cart-recovery.d.ts +23 -0
  19. package/dist/core/cart/cart-recovery.d.ts.map +1 -1
  20. package/dist/core/cart/cart-recovery.js +20 -3
  21. package/dist/core/cart/types.d.ts +2 -1
  22. package/dist/core/cart/types.d.ts.map +1 -1
  23. package/dist/core/cart/types.js +7 -1
  24. package/dist/core/client/create-client.d.ts.map +1 -1
  25. package/dist/core/client/create-client.js +7 -3
  26. package/dist/core/client/execute.d.ts +29 -3
  27. package/dist/core/client/execute.d.ts.map +1 -1
  28. package/dist/core/client/execute.js +174 -3
  29. package/dist/core/client/types.d.ts +50 -2
  30. package/dist/core/client/types.d.ts.map +1 -1
  31. package/dist/core/errors.d.ts +6 -0
  32. package/dist/core/errors.d.ts.map +1 -1
  33. package/dist/core/errors.js +6 -0
  34. package/dist/core/generated/operation-types.d.ts +937 -182
  35. package/dist/core/generated/operation-types.d.ts.map +1 -1
  36. package/dist/core/generated/operation-types.js +560 -1
  37. package/dist/core/index.d.ts +6 -3
  38. package/dist/core/index.d.ts.map +1 -1
  39. package/dist/core/index.js +12 -2
  40. package/dist/core/middleware/session-retry.d.ts +47 -0
  41. package/dist/core/middleware/session-retry.d.ts.map +1 -0
  42. package/dist/core/middleware/session-retry.js +71 -0
  43. package/dist/core/operations/auth.d.ts.map +1 -1
  44. package/dist/core/operations/auth.js +1 -0
  45. package/dist/core/operations/cart.d.ts +7 -0
  46. package/dist/core/operations/cart.d.ts.map +1 -1
  47. package/dist/core/operations/cart.js +54 -3
  48. package/dist/react/components/PaymentInstrumentSection.d.ts +56 -0
  49. package/dist/react/components/PaymentInstrumentSection.d.ts.map +1 -0
  50. package/dist/react/components/PaymentInstrumentSection.js +89 -0
  51. package/dist/react/components/PaymentInstrumentTile.d.ts +56 -0
  52. package/dist/react/components/PaymentInstrumentTile.d.ts.map +1 -0
  53. package/dist/react/components/PaymentInstrumentTile.js +41 -0
  54. package/dist/react/components/index.d.ts +2 -0
  55. package/dist/react/components/index.d.ts.map +1 -1
  56. package/dist/react/components/index.js +2 -0
  57. package/dist/react/helpers/browser-data.d.ts +89 -0
  58. package/dist/react/helpers/browser-data.d.ts.map +1 -0
  59. package/dist/react/helpers/browser-data.js +84 -0
  60. package/dist/react/hooks/use-cart-manager.d.ts +104 -13
  61. package/dist/react/hooks/use-cart-manager.d.ts.map +1 -1
  62. package/dist/react/hooks/use-cart-manager.js +144 -12
  63. package/dist/react/hooks/use-login.d.ts.map +1 -1
  64. package/dist/react/hooks/use-login.js +3 -3
  65. package/dist/react/hooks/use-refresh-token.d.ts.map +1 -1
  66. package/dist/react/hooks/use-refresh-token.js +6 -4
  67. package/dist/react/hooks/use-session-expired.d.ts +16 -0
  68. package/dist/react/hooks/use-session-expired.d.ts.map +1 -0
  69. package/dist/react/hooks/use-session-expired.js +26 -0
  70. package/dist/react/hooks/use-session-refresh.d.ts +32 -0
  71. package/dist/react/hooks/use-session-refresh.d.ts.map +1 -0
  72. package/dist/react/hooks/use-session-refresh.js +147 -0
  73. package/dist/react/index.d.ts +5 -1
  74. package/dist/react/index.d.ts.map +1 -1
  75. package/dist/react/index.js +5 -1
  76. package/dist/react/providers/storefront-client-provider.d.ts +10 -1
  77. package/dist/react/providers/storefront-client-provider.d.ts.map +1 -1
  78. package/dist/react/providers/storefront-client-provider.js +38 -3
  79. package/dist/react/providers/storefront-provider.d.ts +51 -3
  80. package/dist/react/providers/storefront-provider.d.ts.map +1 -1
  81. package/dist/react/providers/storefront-provider.js +22 -5
  82. package/dist/react/server/create-storefront-auth-route.d.ts +63 -0
  83. package/dist/react/server/create-storefront-auth-route.d.ts.map +1 -0
  84. package/dist/react/server/create-storefront-auth-route.js +239 -0
  85. package/dist/react/server/get-initial-auth.d.ts +57 -0
  86. package/dist/react/server/get-initial-auth.d.ts.map +1 -0
  87. package/dist/react/server/get-initial-auth.js +55 -0
  88. package/dist/react/server/index.d.ts +3 -0
  89. package/dist/react/server/index.d.ts.map +1 -1
  90. package/dist/react/server/index.js +6 -0
  91. package/dist/react/stores/auth.store.d.ts +46 -2
  92. package/dist/react/stores/auth.store.d.ts.map +1 -1
  93. package/dist/react/stores/auth.store.js +19 -7
  94. package/package.json +4 -2
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Session-retry middleware — reactive 401 handling (must be OUTERMOST).
3
+ *
4
+ * When a request fails with HTTP 401 (the access token lapsed between the
5
+ * proactive refresh and this call):
6
+ *
7
+ * - **Read query** — refresh the session once and replay the request (R2.1).
8
+ * Because this middleware is the outermost one, the retry re-runs the auth
9
+ * middleware, which re-reads the freshly-stored token. Concurrent 401s share
10
+ * a single renewal because the injected `refresh` dedupes in-flight calls
11
+ * (R2.2). If the refresh also fails, the session is gone — signal and bail
12
+ * (R2.4).
13
+ *
14
+ * - **Mutation** — never auto-retry (mutations are sacred; client-side
15
+ * idempotency is not guaranteed). Bail and signal the session loss (R2.3).
16
+ *
17
+ * Auth operations (login / signup / refresh / logout) are exempt: they own
18
+ * their own error handling, and retrying the refresh op itself would recurse.
19
+ *
20
+ * 0-deps core: takes the renewal + notification as injected callbacks, so it
21
+ * stays framework-agnostic (the provider wires the React store + emitter).
22
+ *
23
+ * NOTE — this fires only on a genuine HTTP 401. The storefront GraphQL data
24
+ * transport returns HTTP 200 with GraphQL errors / `userErrors` for an expired
25
+ * customer token (not a 401), so on that path the proactive scheduler
26
+ * (`useSessionRefresh`) is the protection and this middleware stays inert. It
27
+ * activates wherever a request really does return 401 — e.g. the same-origin
28
+ * BFF refresh route — keeping reactive recovery forward-compatible with no
29
+ * backend change. Cart-level session loss is handled separately by cart-recovery
30
+ * (`CART_UNAUTHENTICATED`).
31
+ */
32
+ import type { Middleware } from '../client/types';
33
+ import type { SessionExpiredEvent } from '../auth/session-events';
34
+ export interface SessionRetryOptions {
35
+ /**
36
+ * Renew the session (refresh token → cookie sync → store update). Resolves
37
+ * `true` on success. MUST dedupe concurrent calls so simultaneous 401s share
38
+ * a single renewal (R2.2).
39
+ */
40
+ refresh: () => Promise<boolean>;
41
+ /** Notify that the session is gone (a mutation 401, or a query whose refresh-retry failed). */
42
+ onSessionExpired: (event: SessionExpiredEvent) => void;
43
+ /** Operation names exempt from 401 handling (default: the auth operations). */
44
+ skipOperations?: string[];
45
+ }
46
+ export declare function sessionRetryMiddleware(options: SessionRetryOptions): Middleware;
47
+ //# sourceMappingURL=session-retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-retry.d.ts","sourceRoot":"","sources":["../../../src/core/middleware/session-retry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAQlE,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,+FAA+F;IAC/F,gBAAgB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACvD,+EAA+E;IAC/E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAMD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,GAAG,UAAU,CAgC/E"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Session-retry middleware — reactive 401 handling (must be OUTERMOST).
3
+ *
4
+ * When a request fails with HTTP 401 (the access token lapsed between the
5
+ * proactive refresh and this call):
6
+ *
7
+ * - **Read query** — refresh the session once and replay the request (R2.1).
8
+ * Because this middleware is the outermost one, the retry re-runs the auth
9
+ * middleware, which re-reads the freshly-stored token. Concurrent 401s share
10
+ * a single renewal because the injected `refresh` dedupes in-flight calls
11
+ * (R2.2). If the refresh also fails, the session is gone — signal and bail
12
+ * (R2.4).
13
+ *
14
+ * - **Mutation** — never auto-retry (mutations are sacred; client-side
15
+ * idempotency is not guaranteed). Bail and signal the session loss (R2.3).
16
+ *
17
+ * Auth operations (login / signup / refresh / logout) are exempt: they own
18
+ * their own error handling, and retrying the refresh op itself would recurse.
19
+ *
20
+ * 0-deps core: takes the renewal + notification as injected callbacks, so it
21
+ * stays framework-agnostic (the provider wires the React store + emitter).
22
+ *
23
+ * NOTE — this fires only on a genuine HTTP 401. The storefront GraphQL data
24
+ * transport returns HTTP 200 with GraphQL errors / `userErrors` for an expired
25
+ * customer token (not a 401), so on that path the proactive scheduler
26
+ * (`useSessionRefresh`) is the protection and this middleware stays inert. It
27
+ * activates wherever a request really does return 401 — e.g. the same-origin
28
+ * BFF refresh route — keeping reactive recovery forward-compatible with no
29
+ * backend change. Cart-level session loss is handled separately by cart-recovery
30
+ * (`CART_UNAUTHENTICATED`).
31
+ */
32
+ import { StorefrontError } from '../errors';
33
+ /**
34
+ * Auth operations that must NOT trigger the 401 retry/signal dance — they
35
+ * surface their own errors, and the refresh op would otherwise recurse.
36
+ */
37
+ const DEFAULT_SKIP_OPERATIONS = ['CustomerLogin', 'CustomerSignup', 'CustomerRefreshToken', 'CustomerLogout'];
38
+ function isUnauthorized(err) {
39
+ return err instanceof StorefrontError && err.status === 401;
40
+ }
41
+ export function sessionRetryMiddleware(options) {
42
+ const { refresh, onSessionExpired } = options;
43
+ const skip = new Set(options.skipOperations ?? DEFAULT_SKIP_OPERATIONS);
44
+ return async (request, next) => {
45
+ if (request.operationName && skip.has(request.operationName)) {
46
+ return next(request);
47
+ }
48
+ try {
49
+ return await next(request);
50
+ }
51
+ catch (err) {
52
+ if (!isUnauthorized(err))
53
+ throw err;
54
+ if (request.isMutation) {
55
+ // R2.3 — mutations are sacred: bail, never auto-retry.
56
+ onSessionExpired({ reason: 'mutation-unauthorized', cause: err });
57
+ throw err;
58
+ }
59
+ // R2.1 / R2.2 — read query: refresh once (deduped) and replay.
60
+ const renewed = await refresh();
61
+ if (!renewed) {
62
+ // R2.4 — the refresh also failed; the session is gone.
63
+ onSessionExpired({ reason: 'reactive-refresh-failed', cause: err });
64
+ throw err;
65
+ }
66
+ // Retry once — this middleware is outermost, so the replay re-runs the
67
+ // auth middleware, which attaches the freshly-stored token.
68
+ return next(request);
69
+ }
70
+ };
71
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/core/operations/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAoHH,eAAO,MAAM,cAAc,QASzB,CAAC;AAEH,eAAO,MAAM,eAAe,QAS1B,CAAC;AAEH,eAAO,MAAM,sBAAsB,QASjC,CAAC;AAEH,eAAO,MAAM,eAAe,QAW1B,CAAC;AAMH,eAAO,MAAM,cAAc,QAOzB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QAYnC,CAAC"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/core/operations/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAqHH,eAAO,MAAM,cAAc,QASzB,CAAC;AAEH,eAAO,MAAM,eAAe,QAS1B,CAAC;AAEH,eAAO,MAAM,sBAAsB,QASjC,CAAC;AAEH,eAAO,MAAM,eAAe,QAW1B,CAAC;AAMH,eAAO,MAAM,cAAc,QAOzB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QAYnC,CAAC"}
@@ -109,6 +109,7 @@ const CUSTOMER_FRAGMENT = `
109
109
  }
110
110
  createdAt
111
111
  updatedAt
112
+ sessionExpiresAt
112
113
  }
113
114
  `;
114
115
  // ---------------------------------------------------------------------------
@@ -73,6 +73,13 @@ export declare const CART_COMPLETE: string;
73
73
  * `payment.flow` (redirect / embedded / instant) to launch the payment.
74
74
  */
75
75
  export declare const PAYMENT_CREATE: string;
76
+ /**
77
+ * cartClearPaymentSelection Mutation (Adv-1 Phase A1-2) — explicit deselect
78
+ * dla storefront accordion UI ("wróć do wyboru metody"). Atomic NULL na
79
+ * wszystkich 4 payment selection fields, idempotent. Cart MUSI być ACTIVE
80
+ * (CONVERTED reject z `ALREADY_COMPLETED`).
81
+ */
82
+ export declare const CART_CLEAR_PAYMENT_SELECTION: string;
76
83
  /**
77
84
  * cartValidateDiscountCode Query — read-only preview discount applicability
78
85
  * (Decision D3). No cart side effects; storefront UI używa do inline feedback
@@ -1 +1 @@
1
- {"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../../src/core/operations/cart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA0YH,eAAO,MAAM,UAAU,QAOrB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,QAehD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAO1C,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,QAO/B,CAAC;AAMH,eAAO,MAAM,WAAW,QAWtB,CAAC;AAEH,eAAO,MAAM,cAAc,QAWzB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAW3B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAWjC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAMH,eAAO,MAAM,yBAAyB,QAWpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAWnC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAWtC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAW/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAWhC,CAAC;AAEH,eAAO,MAAM,+BAA+B,QAW1C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,QAWxB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QASzB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAoBtC,CAAC"}
1
+ {"version":3,"file":"cart.d.ts","sourceRoot":"","sources":["../../../src/core/operations/cart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA2aH,eAAO,MAAM,UAAU,QAOrB,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,qCAAqC,QAehD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,QAO1C,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,QAO/B,CAAC;AAMH,eAAO,MAAM,WAAW,QAWtB,CAAC;AAEH,eAAO,MAAM,cAAc,QAWzB,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAW5B,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAW3B,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAWjC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAMH,eAAO,MAAM,yBAAyB,QAWpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAWnC,CAAC;AAEH,eAAO,MAAM,2BAA2B,QAWtC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAWrC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAW/B,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAWhC,CAAC;AAEH,eAAO,MAAM,+BAA+B,QAW1C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,QAWxB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,QAWzB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAWvC,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAoBtC,CAAC"}
@@ -198,12 +198,13 @@ const CART_SELECTED_PAYMENT_METHOD_FRAGMENT = `
198
198
  name
199
199
  provider
200
200
  type
201
- icon
201
+ icon { ...ImageThumbnail }
202
202
  description
203
203
  isDefault
204
204
  supportedCurrencies
205
205
  position
206
206
  }
207
+ ${IMAGE_THUMBNAIL_FRAGMENT}
207
208
  `;
208
209
  const CART_FRAGMENT = `
209
210
  fragment Cart on Cart {
@@ -227,6 +228,7 @@ const CART_FRAGMENT = `
227
228
  billingAddress { ...MailingAddress }
228
229
  selectedShippingMethod { ...CartShippingMethod }
229
230
  selectedPaymentMethod { ...CartSelectedPaymentMethod }
231
+ selectedPaymentInstrument
230
232
  appliedGiftCards { ...CartAppliedGiftCard }
231
233
  requiresShipping
232
234
  createdAt
@@ -296,9 +298,10 @@ const SHIPPING_CARRIER_FRAGMENT = `
296
298
  fragment ShippingCarrier on ShippingCarrier {
297
299
  id
298
300
  name
299
- logoUrl
301
+ logo { ...ImageThumbnail }
300
302
  serviceCode
301
303
  }
304
+ ${IMAGE_THUMBNAIL_FRAGMENT}
302
305
  `;
303
306
  const DELIVERY_ESTIMATE_FRAGMENT = `
304
307
  fragment DeliveryEstimate on DeliveryEstimate {
@@ -336,18 +339,39 @@ const AVAILABLE_SHIPPING_METHOD_FRAGMENT = `
336
339
  ${DELIVERY_ESTIMATE_FRAGMENT}
337
340
  ${FREE_SHIPPING_PROGRESS_FRAGMENT}
338
341
  `;
342
+ const PAYMENT_INSTRUMENT_FRAGMENT = `
343
+ fragment PaymentInstrument on PaymentInstrument {
344
+ provider
345
+ code
346
+ type
347
+ displayName
348
+ displayHint
349
+ brandImage { ...ImageThumbnail }
350
+ enabled
351
+ }
352
+ ${IMAGE_THUMBNAIL_FRAGMENT}
353
+ `;
339
354
  const PAYMENT_METHOD_FRAGMENT = `
340
355
  fragment PaymentMethod on PaymentMethod {
341
356
  id
342
357
  name
343
358
  provider
344
359
  type
345
- icon
360
+ icon { ...ImageThumbnail }
346
361
  description
347
362
  isDefault
348
363
  supportedCurrencies
349
364
  position
365
+ providersAvailable
366
+ preferredProvider
367
+ available
368
+ unavailableReason
369
+ instruments {
370
+ ...PaymentInstrument
371
+ }
350
372
  }
373
+ ${PAYMENT_INSTRUMENT_FRAGMENT}
374
+ ${IMAGE_THUMBNAIL_FRAGMENT}
351
375
  `;
352
376
  const AVAILABLE_PAYMENT_METHODS_FRAGMENT = `
353
377
  fragment AvailablePaymentMethods on AvailablePaymentMethods {
@@ -368,6 +392,13 @@ const PAYMENT_SESSION_FRAGMENT = `
368
392
  expiresAt
369
393
  }
370
394
  `;
395
+ const PAYMENT_WARNING_FRAGMENT = `
396
+ fragment PaymentWarning on PaymentWarning {
397
+ message
398
+ code
399
+ retryHint
400
+ }
401
+ `;
371
402
  // ---------------------------------------------------------------------------
372
403
  // Queries
373
404
  // ---------------------------------------------------------------------------
@@ -655,10 +686,30 @@ export const PAYMENT_CREATE = composeOperation(`
655
686
  paymentCreate(input: $input) {
656
687
  payment { ...PaymentSession }
657
688
  userErrors { ...UserError }
689
+ warnings { ...PaymentWarning }
658
690
  }
659
691
  }
660
692
  ${PAYMENT_SESSION_FRAGMENT}
661
693
  ${USER_ERROR_FRAGMENT}
694
+ ${PAYMENT_WARNING_FRAGMENT}
695
+ `);
696
+ /**
697
+ * cartClearPaymentSelection Mutation (Adv-1 Phase A1-2) — explicit deselect
698
+ * dla storefront accordion UI ("wróć do wyboru metody"). Atomic NULL na
699
+ * wszystkich 4 payment selection fields, idempotent. Cart MUSI być ACTIVE
700
+ * (CONVERTED reject z `ALREADY_COMPLETED`).
701
+ */
702
+ export const CART_CLEAR_PAYMENT_SELECTION = composeOperation(`
703
+ mutation CartClearPaymentSelection($input: CartClearPaymentSelectionInput!) {
704
+ cartClearPaymentSelection(input: $input) {
705
+ cart { ...Cart }
706
+ userErrors { ...UserError }
707
+ warnings { ...CartWarning }
708
+ }
709
+ }
710
+ ${CART_FRAGMENT}
711
+ ${USER_ERROR_FRAGMENT}
712
+ ${CART_WARNING_FRAGMENT}
662
713
  `);
663
714
  /**
664
715
  * cartValidateDiscountCode Query — read-only preview discount applicability
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `<PaymentInstrumentSection>` — radio-group container dla payment instruments
3
+ * w obrębie jednej method (np. lista bankow + BLIK code entry w BLIK method,
4
+ * lista wallets + brand cards w CARD method). Renders jeden `<PaymentInstrumentTile>`
5
+ * per item z keyboard nav (Arrow Up/Down, Home/End) + ARIA `role="radiogroup"`.
6
+ *
7
+ * Headless — section + tiles bez własnego stylingu. Pass `sectionClassName`
8
+ * dla layoutu (grid/flex), `tileClassName` dla per-tile styling, optional
9
+ * `iconClassName`/`labelClassName` dla wewnętrznej struktury tile.
10
+ *
11
+ * Auto-group **nie jest** implementowane w tym sub-sprincie — backend już
12
+ * zwraca instruments sorted (BLIK + wallets pierwsze → banks alpha → others)
13
+ * z `availablePaymentMethods.methods[].instruments[]`. Komponent renderuje
14
+ * w order'ze otrzymanym, bez własnej resort logic.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * const [code, setCode] = useState<string | undefined>(undefined);
19
+ * <PaymentInstrumentSection
20
+ * method={method}
21
+ * selectedInstrumentCode={code}
22
+ * onSelectInstrument={setCode}
23
+ * sectionClassName="grid grid-cols-2 gap-2"
24
+ * tileClassName="rounded border p-3 data-[selected=true]:border-blue-500"
25
+ * />
26
+ * ```
27
+ *
28
+ * Added by payment-instrument-preselection-advanced sub-sprint Adv-2 Req 9.
29
+ */
30
+ import type { PaymentMethod } from '../../core/generated/operation-types';
31
+ /**
32
+ * Minimalna projekcja `PaymentMethod` używana przez section — wymaga tylko
33
+ * `instruments[]`. Caller może pass pełną `PaymentMethod` z `availablePaymentMethods`
34
+ * query — extra pola (id, name, providersAvailable, etc.) są ignorowane.
35
+ */
36
+ export type PaymentInstrumentSectionMethod = Pick<PaymentMethod, 'instruments'>;
37
+ export interface PaymentInstrumentSectionProps {
38
+ /** Payment method z `instruments[]` listą (null/empty → komponent zwraca null). */
39
+ method: PaymentInstrumentSectionMethod;
40
+ /** Currently selected instrument code — controlled by parent. Undefined gdy buyer nie wybrał. */
41
+ selectedInstrumentCode?: string;
42
+ /** Callback gdy buyer selektuje instrument. Parent persistuje state + odpala `cartSelectPaymentMethod`. */
43
+ onSelectInstrument: (instrumentCode: string) => void;
44
+ /** Optional class dla outer section element — typically grid/flex layout. */
45
+ sectionClassName?: string;
46
+ /** Optional class dla each `<PaymentInstrumentTile>` — passed jako `className`. */
47
+ tileClassName?: string;
48
+ /** Optional class dla brand image inside tiles — passed jako `iconClassName`. */
49
+ iconClassName?: string;
50
+ /** Optional class dla label span inside tiles — passed jako `labelClassName`. */
51
+ labelClassName?: string;
52
+ /** Optional ARIA label dla radiogroup. Defaults to nothing (caller's responsibility — section typically nested w wider label structure). */
53
+ ariaLabel?: string;
54
+ }
55
+ export declare function PaymentInstrumentSection({ method, selectedInstrumentCode, onSelectInstrument, sectionClassName, tileClassName, iconClassName, labelClassName, ariaLabel, }: PaymentInstrumentSectionProps): import("react/jsx-runtime").JSX.Element | null;
56
+ //# sourceMappingURL=PaymentInstrumentSection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentInstrumentSection.d.ts","sourceRoot":"","sources":["../../../src/react/components/PaymentInstrumentSection.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAqB,MAAM,sCAAsC,CAAC;AAG7F;;;;GAIG;AACH,MAAM,MAAM,8BAA8B,GAAG,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;AAEhF,MAAM,WAAW,6BAA6B;IAC5C,mFAAmF;IACnF,MAAM,EAAE,8BAA8B,CAAC;IACvC,iGAAiG;IACjG,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,2GAA2G;IAC3G,kBAAkB,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4IAA4I;IAC5I,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,wBAAwB,CAAC,EACvC,MAAM,EACN,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,cAAc,EACd,SAAS,GACV,EAAE,6BAA6B,kDAmF/B"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `<PaymentInstrumentSection>` — radio-group container dla payment instruments
3
+ * w obrębie jednej method (np. lista bankow + BLIK code entry w BLIK method,
4
+ * lista wallets + brand cards w CARD method). Renders jeden `<PaymentInstrumentTile>`
5
+ * per item z keyboard nav (Arrow Up/Down, Home/End) + ARIA `role="radiogroup"`.
6
+ *
7
+ * Headless — section + tiles bez własnego stylingu. Pass `sectionClassName`
8
+ * dla layoutu (grid/flex), `tileClassName` dla per-tile styling, optional
9
+ * `iconClassName`/`labelClassName` dla wewnętrznej struktury tile.
10
+ *
11
+ * Auto-group **nie jest** implementowane w tym sub-sprincie — backend już
12
+ * zwraca instruments sorted (BLIK + wallets pierwsze → banks alpha → others)
13
+ * z `availablePaymentMethods.methods[].instruments[]`. Komponent renderuje
14
+ * w order'ze otrzymanym, bez własnej resort logic.
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * const [code, setCode] = useState<string | undefined>(undefined);
19
+ * <PaymentInstrumentSection
20
+ * method={method}
21
+ * selectedInstrumentCode={code}
22
+ * onSelectInstrument={setCode}
23
+ * sectionClassName="grid grid-cols-2 gap-2"
24
+ * tileClassName="rounded border p-3 data-[selected=true]:border-blue-500"
25
+ * />
26
+ * ```
27
+ *
28
+ * Added by payment-instrument-preselection-advanced sub-sprint Adv-2 Req 9.
29
+ */
30
+ 'use client';
31
+ import { jsx as _jsx } from "react/jsx-runtime";
32
+ import { useCallback, useRef } from 'react';
33
+ import { PaymentInstrumentTile } from './PaymentInstrumentTile';
34
+ export function PaymentInstrumentSection({ method, selectedInstrumentCode, onSelectInstrument, sectionClassName, tileClassName, iconClassName, labelClassName, ariaLabel, }) {
35
+ const instruments = method.instruments ?? [];
36
+ const sectionRef = useRef(null);
37
+ /**
38
+ * Keyboard nav per WAI-ARIA radiogroup pattern:
39
+ * ArrowDown/ArrowRight → focus next tile, wrap to first.
40
+ * ArrowUp/ArrowLeft → focus previous tile, wrap to last.
41
+ * Home → focus first tile.
42
+ * End → focus last tile.
43
+ * Enter/Space → native button activation (no custom handler).
44
+ */
45
+ const handleKeyDown = useCallback((event) => {
46
+ if (!sectionRef.current)
47
+ return;
48
+ const tiles = Array.from(sectionRef.current.querySelectorAll('button[role="radio"]:not([disabled])'));
49
+ if (tiles.length === 0)
50
+ return;
51
+ const currentIndex = tiles.findIndex((tile) => tile === document.activeElement);
52
+ let nextIndex = -1;
53
+ switch (event.key) {
54
+ case 'ArrowDown':
55
+ case 'ArrowRight':
56
+ nextIndex = currentIndex === -1 || currentIndex === tiles.length - 1 ? 0 : currentIndex + 1;
57
+ break;
58
+ case 'ArrowUp':
59
+ case 'ArrowLeft':
60
+ nextIndex = currentIndex <= 0 ? tiles.length - 1 : currentIndex - 1;
61
+ break;
62
+ case 'Home':
63
+ nextIndex = 0;
64
+ break;
65
+ case 'End':
66
+ nextIndex = tiles.length - 1;
67
+ break;
68
+ default:
69
+ return;
70
+ }
71
+ event.preventDefault();
72
+ tiles[nextIndex]?.focus();
73
+ }, []);
74
+ if (instruments.length === 0) {
75
+ return null;
76
+ }
77
+ return (_jsx("div", { ref: sectionRef, role: "radiogroup", "aria-label": ariaLabel, onKeyDown: handleKeyDown, className: sectionClassName, children: instruments.map((instrument) => {
78
+ // Cast to tile-projection shape — instruments[] z generated types ma więcej pól
79
+ // niż tile potrzebuje (provider, type), tile picks subset jawnie.
80
+ const tileInstrument = {
81
+ code: instrument.code,
82
+ displayName: instrument.displayName,
83
+ displayHint: instrument.displayHint,
84
+ enabled: instrument.enabled,
85
+ brandImage: instrument.brandImage ?? undefined,
86
+ };
87
+ return (_jsx(PaymentInstrumentTile, { instrument: tileInstrument, selected: instrument.code === selectedInstrumentCode, onSelect: () => onSelectInstrument(instrument.code), className: tileClassName, iconClassName: iconClassName, labelClassName: labelClassName }, instrument.code));
88
+ }) }));
89
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * `<PaymentInstrumentTile>` — single payment instrument tile (BLIK code,
3
+ * bank logo, wallet button, card brand). Headless — buyer-facing button
4
+ * z accessibility wbudowanym (`role="radio"`, `aria-checked`, `aria-label`,
5
+ * `data-instrument-code`, `data-display-hint`). Pass className per part
6
+ * (button, icon, label) żeby zintegrować z Tailwind / CSS Modules /
7
+ * styled-components — komponent nie ma własnego stylingu.
8
+ *
9
+ * `displayHint` dispatch — backend hint jak storefront powinien renderować
10
+ * instrument. Komponent emituje hint jako `data-display-hint` attribute na
11
+ * `<button>` żeby caller mógł stylizować przez CSS attribute selektory:
12
+ *
13
+ * - `BRANDED_TILE` — bank logo / wallet icon dominuje, label jako caption.
14
+ * - `PROMINENT_BUTTON` — duże CTA (BLIK code entry), brand image pominięty.
15
+ * - `RADIO_OPTION` — radio-list look, image (jeśli is) + label inline.
16
+ * - `DROPDOWN_OPTION` — text-only dla dropdown integration (caller wrap).
17
+ *
18
+ * Headless = no opinion. CSS styling decyduje, komponent tylko hint'uje.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <PaymentInstrumentTile
23
+ * instrument={{ code: 'blik', displayName: 'BLIK', displayHint: 'PROMINENT_BUTTON', enabled: true }}
24
+ * selected={selectedCode === 'blik'}
25
+ * onSelect={() => setSelectedCode('blik')}
26
+ * className="rounded-lg border p-3 hover:bg-gray-50 data-[selected=true]:border-blue-500"
27
+ * labelClassName="font-semibold"
28
+ * />
29
+ * ```
30
+ *
31
+ * Added by payment-instrument-preselection-advanced sub-sprint Adv-2 Req 9.
32
+ */
33
+ import type { PaymentInstrument } from '../../core/generated/operation-types';
34
+ /**
35
+ * Minimalna projekcja `PaymentInstrument` używana przez tile. Caller może
36
+ * pass pełny instrument z `availablePaymentMethods` query — extra pola
37
+ * (provider, type) są ignorowane przez komponent (UI nie branchuje na
38
+ * provider — gateway-agnostic, code + displayHint wystarczą).
39
+ */
40
+ export type PaymentInstrumentTileInstrument = Pick<PaymentInstrument, 'code' | 'displayName' | 'displayHint' | 'enabled'> & Partial<Pick<PaymentInstrument, 'brandImage'>>;
41
+ export interface PaymentInstrumentTileProps {
42
+ /** Instrument projection — gateway code, label, display hint, enabled state. */
43
+ instrument: PaymentInstrumentTileInstrument;
44
+ /** True gdy ten tile jest currently selected w parent section. Controls `aria-checked` + `data-selected`. */
45
+ selected: boolean;
46
+ /** Click handler — caller updates selected state external (controlled component). */
47
+ onSelect: () => void;
48
+ /** Optional class for the outer button — header styling, layout, border. */
49
+ className?: string;
50
+ /** Optional class for the brand image (`<img>` element). Only applied when instrument has `brandImage`. */
51
+ iconClassName?: string;
52
+ /** Optional class for the label span. */
53
+ labelClassName?: string;
54
+ }
55
+ export declare function PaymentInstrumentTile({ instrument, selected, onSelect, className, iconClassName, labelClassName, }: PaymentInstrumentTileProps): import("react/jsx-runtime").JSX.Element;
56
+ //# sourceMappingURL=PaymentInstrumentTile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentInstrumentTile.d.ts","sourceRoot":"","sources":["../../../src/react/components/PaymentInstrumentTile.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAE9E;;;;;GAKG;AACH,MAAM,MAAM,+BAA+B,GAAG,IAAI,CAChD,iBAAiB,EACjB,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,SAAS,CACnD,GACC,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,CAAC,CAAC;AAEjD,MAAM,WAAW,0BAA0B;IACzC,gFAAgF;IAChF,UAAU,EAAE,+BAA+B,CAAC;IAC5C,6GAA6G;IAC7G,QAAQ,EAAE,OAAO,CAAC;IAClB,qFAAqF;IACrF,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2GAA2G;IAC3G,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,aAAa,EACb,cAAc,GACf,EAAE,0BAA0B,2CAuB5B"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * `<PaymentInstrumentTile>` — single payment instrument tile (BLIK code,
3
+ * bank logo, wallet button, card brand). Headless — buyer-facing button
4
+ * z accessibility wbudowanym (`role="radio"`, `aria-checked`, `aria-label`,
5
+ * `data-instrument-code`, `data-display-hint`). Pass className per part
6
+ * (button, icon, label) żeby zintegrować z Tailwind / CSS Modules /
7
+ * styled-components — komponent nie ma własnego stylingu.
8
+ *
9
+ * `displayHint` dispatch — backend hint jak storefront powinien renderować
10
+ * instrument. Komponent emituje hint jako `data-display-hint` attribute na
11
+ * `<button>` żeby caller mógł stylizować przez CSS attribute selektory:
12
+ *
13
+ * - `BRANDED_TILE` — bank logo / wallet icon dominuje, label jako caption.
14
+ * - `PROMINENT_BUTTON` — duże CTA (BLIK code entry), brand image pominięty.
15
+ * - `RADIO_OPTION` — radio-list look, image (jeśli is) + label inline.
16
+ * - `DROPDOWN_OPTION` — text-only dla dropdown integration (caller wrap).
17
+ *
18
+ * Headless = no opinion. CSS styling decyduje, komponent tylko hint'uje.
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <PaymentInstrumentTile
23
+ * instrument={{ code: 'blik', displayName: 'BLIK', displayHint: 'PROMINENT_BUTTON', enabled: true }}
24
+ * selected={selectedCode === 'blik'}
25
+ * onSelect={() => setSelectedCode('blik')}
26
+ * className="rounded-lg border p-3 hover:bg-gray-50 data-[selected=true]:border-blue-500"
27
+ * labelClassName="font-semibold"
28
+ * />
29
+ * ```
30
+ *
31
+ * Added by payment-instrument-preselection-advanced sub-sprint Adv-2 Req 9.
32
+ */
33
+ 'use client';
34
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
35
+ export function PaymentInstrumentTile({ instrument, selected, onSelect, className, iconClassName, labelClassName, }) {
36
+ const { code, displayName, displayHint, brandImage, enabled } = instrument;
37
+ const brandImageUrl = brandImage?.url;
38
+ // PROMINENT_BUTTON hides brand image — instrument jest text-only CTA (BLIK code entry).
39
+ const showImage = displayHint !== 'PROMINENT_BUTTON' && brandImageUrl;
40
+ return (_jsxs("button", { type: "button", role: "radio", "aria-checked": selected, "aria-label": displayName, "data-instrument-code": code, "data-display-hint": displayHint, "data-selected": selected, disabled: !enabled, onClick: onSelect, className: className, children: [showImage && _jsx("img", { src: brandImageUrl, alt: brandImage?.altText ?? '', className: iconClassName }), _jsx("span", { className: labelClassName, children: displayName })] }));
41
+ }
@@ -12,4 +12,6 @@ export { CartCount, type CartCountProps } from './CartCount';
12
12
  export { AddToCartButton, type AddToCartButtonProps } from './AddToCartButton';
13
13
  export { PriceDisplay, type PriceDisplayProps } from './PriceDisplay';
14
14
  export { CartTotals, type CartTotalsProps, type CartTotalsLabels } from './CartTotals';
15
+ export { PaymentInstrumentTile, type PaymentInstrumentTileProps, type PaymentInstrumentTileInstrument, } from './PaymentInstrumentTile';
16
+ export { PaymentInstrumentSection, type PaymentInstrumentSectionProps, type PaymentInstrumentSectionMethod, } from './PaymentInstrumentSection';
15
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/components/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/components/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAE,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,KAAK,mBAAmB,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACvF,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,GACrC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,wBAAwB,EACxB,KAAK,6BAA6B,EAClC,KAAK,8BAA8B,GACpC,MAAM,4BAA4B,CAAC"}
@@ -12,3 +12,5 @@ export { CartCount } from './CartCount';
12
12
  export { AddToCartButton } from './AddToCartButton';
13
13
  export { PriceDisplay } from './PriceDisplay';
14
14
  export { CartTotals } from './CartTotals';
15
+ export { PaymentInstrumentTile, } from './PaymentInstrumentTile';
16
+ export { PaymentInstrumentSection, } from './PaymentInstrumentSection';
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `getBrowserDataForPayment()` — collects browser context required by PSD2/3DS2
3
+ * authentication flows (card-on-file z 3DS challenge, BLIK confirmation,
4
+ * Apple/Google Pay z risk scoring).
5
+ *
6
+ * **Browser-only** — throws gdy `typeof window === 'undefined'` (server-side
7
+ * rendering). Caller MUSI gate'ować call w useEffect / event handler / browser
8
+ * code path. NEVER call this w Server Component lub Route Handler.
9
+ *
10
+ * Wartości pochodzą z standard Web APIs:
11
+ * - `userAgent` — `navigator.userAgent`.
12
+ * - `language` — `navigator.language` (BCP 47, fallback `en-US`).
13
+ * - `screen{Width,Height}` — `window.screen.{width,height}`.
14
+ * - `colorDepth` — `window.screen.colorDepth`.
15
+ * - `timezoneOffset` — `new Date().getTimezoneOffset()` (signed integer, minutes,
16
+ * reverse signed per ECMA: dodatnie = behind UTC, ujemne = ahead).
17
+ * - `javaEnabled` — `navigator.javaEnabled?.()` (deprecated ale wymagane PSD2/EMV
18
+ * specification; fallback `false` gdy browser nie expose'uje).
19
+ * - `acceptHeader` — NIE dostępne client-side (`navigator` nie expose'uje request
20
+ * headers). Caller passes z server context lub omits (gateway-dependent
21
+ * requirement). Helper zwraca undefined.
22
+ *
23
+ * Shape matches PSD2/3DS2 BrowserData specification (EMVCo) — adapter na backend
24
+ * `IPaymentProvider.createPayment` może merge wprost do gateway-specific body
25
+ * (Adyen `browserInfo`, Stripe `payment_method_data.billing_details.browser_info`,
26
+ * Mollie `cardToken` z 3DS lookup).
27
+ *
28
+ * @example
29
+ * ```tsx
30
+ * // W event handler (browser-only):
31
+ * function handleCheckoutSubmit() {
32
+ * const browserData = getBrowserDataForPayment();
33
+ * await cart.createPayment({ ..., browserData });
34
+ * }
35
+ *
36
+ * // SSR-safe wrap:
37
+ * if (typeof window !== 'undefined') {
38
+ * const browserData = getBrowserDataForPayment();
39
+ * ...
40
+ * }
41
+ * ```
42
+ *
43
+ * Added by payment-instrument-preselection-advanced sub-sprint Adv-2 Req 9.5
44
+ * (carry-over z Adv-1 plan — moved here as standalone utility, no backend
45
+ * mutation impact yet — Adv-3 będzie consumer'em w `paymentCreate` input).
46
+ */
47
+ /**
48
+ * PSD2/3DS2 browser context shape. All fields optional poza ones backed by
49
+ * standard API — gateway-specific requirements decyzują które pola są mandatory.
50
+ */
51
+ export interface PaymentBrowserData {
52
+ /** Accept HTTP header value — NOT available client-side (caller passes from server context or omits). */
53
+ acceptHeader?: string;
54
+ /** Full user-agent string (`navigator.userAgent`). */
55
+ userAgent: string;
56
+ /** BCP 47 language tag (`navigator.language`). Fallback `'en-US'` gdy missing. */
57
+ language: string;
58
+ /** Screen width in pixels (`window.screen.width`). */
59
+ screenWidth: number;
60
+ /** Screen height in pixels (`window.screen.height`). */
61
+ screenHeight: number;
62
+ /** Color depth bits-per-pixel (`window.screen.colorDepth`). Typically `24` or `32`. */
63
+ colorDepth: number;
64
+ /**
65
+ * Local timezone offset w minutach (ECMA signed convention — dodatnie = behind UTC,
66
+ * ujemne = ahead UTC). Np. CET zima = `-60`, PST zima = `480`.
67
+ */
68
+ timezoneOffset: number;
69
+ /**
70
+ * Java support (`navigator.javaEnabled?.()`). Deprecated API ale wymagane PSD2/EMV
71
+ * specification; fallback `false` gdy browser nie expose'uje.
72
+ */
73
+ javaEnabled: boolean;
74
+ /**
75
+ * IANA timezone name (`Intl.DateTimeFormat().resolvedOptions().timeZone`).
76
+ * Optional — niektóre gateways używają zamiast offsetu (Adyen risk scoring).
77
+ */
78
+ timezone?: string;
79
+ }
80
+ /**
81
+ * Throw'd gdy helper wywołany w SSR context (Server Component, Route Handler,
82
+ * Node bez JSDOM). Caller MUSI guard'ować przez `typeof window` check albo
83
+ * wywołać tylko w event handler / `useEffect`.
84
+ */
85
+ export declare class BrowserDataNotAvailableError extends Error {
86
+ constructor();
87
+ }
88
+ export declare function getBrowserDataForPayment(): PaymentBrowserData;
89
+ //# sourceMappingURL=browser-data.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-data.d.ts","sourceRoot":"","sources":["../../../src/react/helpers/browser-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,yGAAyG;IACzG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,kFAAkF;IAClF,QAAQ,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,wDAAwD;IACxD,YAAY,EAAE,MAAM,CAAC;IACrB,uFAAuF;IACvF,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,qBAAa,4BAA6B,SAAQ,KAAK;;CAKtD;AAED,wBAAgB,wBAAwB,IAAI,kBAAkB,CA6B7D"}