@doswiftly/storefront-sdk 21.0.0 → 22.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.
- package/CHANGELOG.md +35 -0
- package/README.md +818 -527
- package/dist/core/auth/handlers.d.ts +10 -9
- package/dist/core/auth/handlers.d.ts.map +1 -1
- package/dist/core/auth/handlers.js +10 -9
- package/dist/core/auth/session-events.d.ts +2 -2
- package/dist/core/auth/session-events.js +2 -2
- package/dist/core/cart/cart-client.d.ts +23 -24
- package/dist/core/cart/cart-client.d.ts.map +1 -1
- package/dist/core/cart/cart-client.js +24 -25
- package/dist/core/generated/operation-types.d.ts +52 -52
- package/dist/core/generated/operation-types.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/dist/core/middleware/session-retry.d.ts +5 -6
- package/dist/core/middleware/session-retry.d.ts.map +1 -1
- package/dist/core/middleware/session-retry.js +7 -8
- package/dist/core/operations/auth.d.ts.map +1 -1
- package/dist/core/operations/auth.js +4 -0
- package/dist/core/operations/cart.d.ts +11 -10
- package/dist/core/operations/cart.d.ts.map +1 -1
- package/dist/core/operations/cart.js +14 -11
- package/dist/core/referral/cookie-config.d.ts +56 -0
- package/dist/core/referral/cookie-config.d.ts.map +1 -0
- package/dist/core/referral/cookie-config.js +83 -0
- package/dist/react/components/PaymentInstrumentSection.d.ts +24 -24
- package/dist/react/components/PaymentInstrumentSection.d.ts.map +1 -1
- package/dist/react/components/PaymentInstrumentSection.js +15 -15
- package/dist/react/components/PaymentInstrumentTile.d.ts +19 -20
- package/dist/react/components/PaymentInstrumentTile.d.ts.map +1 -1
- package/dist/react/components/PaymentInstrumentTile.js +15 -16
- package/dist/react/helpers/browser-data.d.ts +30 -33
- package/dist/react/helpers/browser-data.d.ts.map +1 -1
- package/dist/react/helpers/browser-data.js +26 -29
- package/dist/react/hooks/use-cart-manager.d.ts +1 -1
- package/dist/react/hooks/use-cart-manager.js +1 -1
- package/dist/react/hooks/use-cart.d.ts +2 -2
- package/dist/react/hooks/use-cart.js +3 -3
- package/dist/react/hooks/use-referral-capture.d.ts +9 -0
- package/dist/react/hooks/use-referral-capture.d.ts.map +1 -0
- package/dist/react/hooks/use-referral-capture.js +40 -0
- package/dist/react/hooks/use-session-expired.d.ts +6 -5
- package/dist/react/hooks/use-session-expired.d.ts.map +1 -1
- package/dist/react/hooks/use-session-expired.js +6 -5
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -1
- package/dist/react/referral.d.ts +53 -0
- package/dist/react/referral.d.ts.map +1 -0
- package/dist/react/referral.js +51 -0
- package/dist/react/server/cookie-readers.d.ts +7 -0
- package/dist/react/server/cookie-readers.d.ts.map +1 -1
- package/dist/react/server/cookie-readers.js +10 -0
- package/dist/react/server/index.d.ts +1 -1
- package/dist/react/server/index.d.ts.map +1 -1
- package/dist/react/server/index.js +2 -2
- package/dist/react/stores/auth.store.d.ts.map +1 -1
- package/dist/react/stores/auth.store.js +13 -10
- package/dist/react/stores/cart.store.d.ts +1 -1
- package/dist/react/stores/cart.store.js +1 -1
- package/package.json +1 -1
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `<PaymentInstrumentTile>` — single payment instrument tile (BLIK code,
|
|
3
|
-
* bank logo, wallet button, card brand). Headless — buyer-facing button
|
|
4
|
-
*
|
|
5
|
-
* `data-instrument-code`, `data-display-hint`). Pass className per part
|
|
6
|
-
* (button, icon, label)
|
|
7
|
-
* styled-components —
|
|
3
|
+
* bank logo, wallet button, card brand). Headless — a buyer-facing button
|
|
4
|
+
* with accessibility built in (`role="radio"`, `aria-checked`, `aria-label`,
|
|
5
|
+
* `data-instrument-code`, `data-display-hint`). Pass a className per part
|
|
6
|
+
* (button, icon, label) to integrate with Tailwind / CSS Modules /
|
|
7
|
+
* styled-components — the component has no styling of its own.
|
|
8
8
|
*
|
|
9
|
-
* `displayHint` dispatch — backend hint
|
|
10
|
-
* instrument.
|
|
11
|
-
* `<button>`
|
|
9
|
+
* `displayHint` dispatch — a backend hint describing how the storefront should
|
|
10
|
+
* render the instrument. The component emits the hint as a `data-display-hint`
|
|
11
|
+
* attribute on the `<button>` so the caller can style it through CSS attribute
|
|
12
|
+
* selectors:
|
|
12
13
|
*
|
|
13
|
-
* - `BRANDED_TILE` — bank logo / wallet icon
|
|
14
|
-
* - `PROMINENT_BUTTON` —
|
|
15
|
-
* - `RADIO_OPTION` — radio-list look, image (
|
|
16
|
-
* - `DROPDOWN_OPTION` — text-only
|
|
14
|
+
* - `BRANDED_TILE` — bank logo / wallet icon dominates, label as a caption.
|
|
15
|
+
* - `PROMINENT_BUTTON` — large CTA (BLIK code entry), brand image omitted.
|
|
16
|
+
* - `RADIO_OPTION` — radio-list look, image (when present) + label inline.
|
|
17
|
+
* - `DROPDOWN_OPTION` — text-only for dropdown integration (caller wraps it).
|
|
17
18
|
*
|
|
18
|
-
* Headless = no opinion. CSS styling
|
|
19
|
+
* Headless = no opinion. CSS styling decides, the component only hints.
|
|
19
20
|
*
|
|
20
21
|
* @example
|
|
21
22
|
* ```tsx
|
|
@@ -27,15 +28,13 @@
|
|
|
27
28
|
* labelClassName="font-semibold"
|
|
28
29
|
* />
|
|
29
30
|
* ```
|
|
30
|
-
*
|
|
31
|
-
* Added by payment-instrument-preselection-advanced sub-sprint Adv-2 Req 9.
|
|
32
31
|
*/
|
|
33
32
|
'use client';
|
|
34
33
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
35
34
|
export function PaymentInstrumentTile({ instrument, selected, onSelect, className, iconClassName, labelClassName, }) {
|
|
36
35
|
const { code, displayName, displayHint, brandImage, enabled } = instrument;
|
|
37
36
|
const brandImageUrl = brandImage?.url;
|
|
38
|
-
// PROMINENT_BUTTON hides brand image — instrument
|
|
37
|
+
// PROMINENT_BUTTON hides the brand image — the instrument is a text-only CTA (BLIK code entry).
|
|
39
38
|
const showImage = displayHint !== 'PROMINENT_BUTTON' && brandImageUrl;
|
|
40
39
|
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
40
|
}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `getBrowserDataForPayment()` — collects browser context required by PSD2/3DS2
|
|
3
|
-
* authentication flows (card-on-file
|
|
4
|
-
* Apple/Google Pay
|
|
3
|
+
* authentication flows (card-on-file with a 3DS challenge, BLIK confirmation,
|
|
4
|
+
* Apple/Google Pay with risk scoring).
|
|
5
5
|
*
|
|
6
|
-
* **Browser-only** — throws
|
|
7
|
-
* rendering).
|
|
8
|
-
* code path. NEVER call this
|
|
6
|
+
* **Browser-only** — throws when `typeof window === 'undefined'` (server-side
|
|
7
|
+
* rendering). Callers MUST gate the call inside a useEffect / event handler /
|
|
8
|
+
* browser-only code path. NEVER call this in a Server Component or Route Handler.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* Values come from standard Web APIs:
|
|
11
11
|
* - `userAgent` — `navigator.userAgent`.
|
|
12
12
|
* - `language` — `navigator.language` (BCP 47, fallback `en-US`).
|
|
13
13
|
* - `screen{Width,Height}` — `window.screen.{width,height}`.
|
|
14
14
|
* - `colorDepth` — `window.screen.colorDepth`.
|
|
15
15
|
* - `timezoneOffset` — `new Date().getTimezoneOffset()` (signed integer, minutes,
|
|
16
|
-
* reverse signed per ECMA:
|
|
17
|
-
* - `javaEnabled` — `navigator.javaEnabled?.()` (deprecated
|
|
18
|
-
* specification;
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* reverse signed per ECMA: positive = behind UTC, negative = ahead of UTC).
|
|
17
|
+
* - `javaEnabled` — `navigator.javaEnabled?.()` (deprecated but required by the
|
|
18
|
+
* PSD2/EMV specification; falls back to `false` when the browser does not
|
|
19
|
+
* expose it).
|
|
20
|
+
* - `acceptHeader` — NOT available client-side (`navigator` does not expose
|
|
21
|
+
* request headers). Callers pass it from server context or omit it
|
|
22
|
+
* (gateway-dependent requirement). The helper returns undefined.
|
|
22
23
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* Mollie `cardToken` z 3DS lookup).
|
|
24
|
+
* The shape matches the PSD2/3DS2 BrowserData specification (EMVCo), so it can
|
|
25
|
+
* be merged into gateway-specific request bodies (gateway-specific field names
|
|
26
|
+
* vary).
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* ```tsx
|
|
30
|
-
* //
|
|
30
|
+
* // In an event handler (browser-only):
|
|
31
31
|
* function handleCheckoutSubmit() {
|
|
32
32
|
* const browserData = getBrowserDataForPayment();
|
|
33
|
-
*
|
|
33
|
+
* // pass to your payment integration where required
|
|
34
34
|
* }
|
|
35
35
|
*
|
|
36
36
|
* // SSR-safe wrap:
|
|
@@ -39,21 +39,18 @@
|
|
|
39
39
|
* ...
|
|
40
40
|
* }
|
|
41
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
42
|
*/
|
|
47
43
|
/**
|
|
48
|
-
* PSD2/3DS2 browser context shape. All fields optional
|
|
49
|
-
* standard API — gateway-specific requirements
|
|
44
|
+
* PSD2/3DS2 browser context shape. All fields are optional except the ones
|
|
45
|
+
* backed by a standard API — gateway-specific requirements decide which fields
|
|
46
|
+
* are mandatory.
|
|
50
47
|
*/
|
|
51
48
|
export interface PaymentBrowserData {
|
|
52
49
|
/** Accept HTTP header value — NOT available client-side (caller passes from server context or omits). */
|
|
53
50
|
acceptHeader?: string;
|
|
54
51
|
/** Full user-agent string (`navigator.userAgent`). */
|
|
55
52
|
userAgent: string;
|
|
56
|
-
/** BCP 47 language tag (`navigator.language`).
|
|
53
|
+
/** BCP 47 language tag (`navigator.language`). Falls back to `'en-US'` when missing. */
|
|
57
54
|
language: string;
|
|
58
55
|
/** Screen width in pixels (`window.screen.width`). */
|
|
59
56
|
screenWidth: number;
|
|
@@ -62,25 +59,25 @@ export interface PaymentBrowserData {
|
|
|
62
59
|
/** Color depth bits-per-pixel (`window.screen.colorDepth`). Typically `24` or `32`. */
|
|
63
60
|
colorDepth: number;
|
|
64
61
|
/**
|
|
65
|
-
* Local timezone offset
|
|
66
|
-
*
|
|
62
|
+
* Local timezone offset in minutes (ECMA signed convention — positive = behind UTC,
|
|
63
|
+
* negative = ahead of UTC). For example, CET in winter = `-60`, PST in winter = `480`.
|
|
67
64
|
*/
|
|
68
65
|
timezoneOffset: number;
|
|
69
66
|
/**
|
|
70
|
-
* Java support (`navigator.javaEnabled?.()`). Deprecated API
|
|
71
|
-
* specification;
|
|
67
|
+
* Java support (`navigator.javaEnabled?.()`). Deprecated API but required by the
|
|
68
|
+
* PSD2/EMV specification; falls back to `false` when the browser does not expose it.
|
|
72
69
|
*/
|
|
73
70
|
javaEnabled: boolean;
|
|
74
71
|
/**
|
|
75
72
|
* IANA timezone name (`Intl.DateTimeFormat().resolvedOptions().timeZone`).
|
|
76
|
-
* Optional —
|
|
73
|
+
* Optional — some gateways use it instead of the numeric offset for risk scoring.
|
|
77
74
|
*/
|
|
78
75
|
timezone?: string;
|
|
79
76
|
}
|
|
80
77
|
/**
|
|
81
|
-
*
|
|
82
|
-
* Node
|
|
83
|
-
*
|
|
78
|
+
* Thrown when the helper is called in an SSR context (Server Component, Route
|
|
79
|
+
* Handler, Node without JSDOM). Callers MUST guard with a `typeof window` check
|
|
80
|
+
* or call it only inside an event handler / `useEffect`.
|
|
84
81
|
*/
|
|
85
82
|
export declare class BrowserDataNotAvailableError extends Error {
|
|
86
83
|
constructor();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-data.d.ts","sourceRoot":"","sources":["../../../src/react/helpers/browser-data.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"browser-data.d.ts","sourceRoot":"","sources":["../../../src/react/helpers/browser-data.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,yGAAyG;IACzG,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,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,CA8B7D"}
|
|
@@ -1,36 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `getBrowserDataForPayment()` — collects browser context required by PSD2/3DS2
|
|
3
|
-
* authentication flows (card-on-file
|
|
4
|
-
* Apple/Google Pay
|
|
3
|
+
* authentication flows (card-on-file with a 3DS challenge, BLIK confirmation,
|
|
4
|
+
* Apple/Google Pay with risk scoring).
|
|
5
5
|
*
|
|
6
|
-
* **Browser-only** — throws
|
|
7
|
-
* rendering).
|
|
8
|
-
* code path. NEVER call this
|
|
6
|
+
* **Browser-only** — throws when `typeof window === 'undefined'` (server-side
|
|
7
|
+
* rendering). Callers MUST gate the call inside a useEffect / event handler /
|
|
8
|
+
* browser-only code path. NEVER call this in a Server Component or Route Handler.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* Values come from standard Web APIs:
|
|
11
11
|
* - `userAgent` — `navigator.userAgent`.
|
|
12
12
|
* - `language` — `navigator.language` (BCP 47, fallback `en-US`).
|
|
13
13
|
* - `screen{Width,Height}` — `window.screen.{width,height}`.
|
|
14
14
|
* - `colorDepth` — `window.screen.colorDepth`.
|
|
15
15
|
* - `timezoneOffset` — `new Date().getTimezoneOffset()` (signed integer, minutes,
|
|
16
|
-
* reverse signed per ECMA:
|
|
17
|
-
* - `javaEnabled` — `navigator.javaEnabled?.()` (deprecated
|
|
18
|
-
* specification;
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* reverse signed per ECMA: positive = behind UTC, negative = ahead of UTC).
|
|
17
|
+
* - `javaEnabled` — `navigator.javaEnabled?.()` (deprecated but required by the
|
|
18
|
+
* PSD2/EMV specification; falls back to `false` when the browser does not
|
|
19
|
+
* expose it).
|
|
20
|
+
* - `acceptHeader` — NOT available client-side (`navigator` does not expose
|
|
21
|
+
* request headers). Callers pass it from server context or omit it
|
|
22
|
+
* (gateway-dependent requirement). The helper returns undefined.
|
|
22
23
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* Mollie `cardToken` z 3DS lookup).
|
|
24
|
+
* The shape matches the PSD2/3DS2 BrowserData specification (EMVCo), so it can
|
|
25
|
+
* be merged into gateway-specific request bodies (gateway-specific field names
|
|
26
|
+
* vary).
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* ```tsx
|
|
30
|
-
* //
|
|
30
|
+
* // In an event handler (browser-only):
|
|
31
31
|
* function handleCheckoutSubmit() {
|
|
32
32
|
* const browserData = getBrowserDataForPayment();
|
|
33
|
-
*
|
|
33
|
+
* // pass to your payment integration where required
|
|
34
34
|
* }
|
|
35
35
|
*
|
|
36
36
|
* // SSR-safe wrap:
|
|
@@ -39,15 +39,11 @@
|
|
|
39
39
|
* ...
|
|
40
40
|
* }
|
|
41
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
42
|
*/
|
|
47
43
|
/**
|
|
48
|
-
*
|
|
49
|
-
* Node
|
|
50
|
-
*
|
|
44
|
+
* Thrown when the helper is called in an SSR context (Server Component, Route
|
|
45
|
+
* Handler, Node without JSDOM). Callers MUST guard with a `typeof window` check
|
|
46
|
+
* or call it only inside an event handler / `useEffect`.
|
|
51
47
|
*/
|
|
52
48
|
export class BrowserDataNotAvailableError extends Error {
|
|
53
49
|
constructor() {
|
|
@@ -59,11 +55,12 @@ export function getBrowserDataForPayment() {
|
|
|
59
55
|
if (typeof window === 'undefined' || typeof navigator === 'undefined' || typeof window.screen === 'undefined') {
|
|
60
56
|
throw new BrowserDataNotAvailableError();
|
|
61
57
|
}
|
|
62
|
-
// `navigator.javaEnabled`
|
|
63
|
-
//
|
|
58
|
+
// `navigator.javaEnabled` is deprecated but still present in major browsers — guard
|
|
59
|
+
// against future removal. Falls back to `false` when missing (the PSD2 spec requires
|
|
60
|
+
// a boolean, not undefined).
|
|
64
61
|
const javaEnabled = typeof navigator.javaEnabled === 'function' ? Boolean(navigator.javaEnabled()) : false;
|
|
65
|
-
// `Intl.DateTimeFormat`
|
|
66
|
-
//
|
|
62
|
+
// `Intl.DateTimeFormat` is available in all modern browsers — optional capture for
|
|
63
|
+
// gateways that require the IANA name instead of the numeric offset.
|
|
67
64
|
let timezone;
|
|
68
65
|
try {
|
|
69
66
|
timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
* function CartUI() {
|
|
63
63
|
* const { addItem, onExpired } = useCartManager();
|
|
64
64
|
*
|
|
65
|
-
* useEffect(() => onExpired(() => toast('
|
|
65
|
+
* useEffect(() => onExpired(() => toast('Your cart expired — please add the items again')), [onExpired]);
|
|
66
66
|
*
|
|
67
67
|
* return <button onClick={() => addItem([{ variantId, quantity: 1 }])}>Add</button>;
|
|
68
68
|
* }
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
* function CartUI() {
|
|
63
63
|
* const { addItem, onExpired } = useCartManager();
|
|
64
64
|
*
|
|
65
|
-
* useEffect(() => onExpired(() => toast('
|
|
65
|
+
* useEffect(() => onExpired(() => toast('Your cart expired — please add the items again')), [onExpired]);
|
|
66
66
|
*
|
|
67
67
|
* return <button onClick={() => addItem([{ variantId, quantity: 1 }])}>Add</button>;
|
|
68
68
|
* }
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* UIs need.
|
|
10
10
|
*
|
|
11
11
|
* State management follows the platform's store pattern: a vanilla Zustand
|
|
12
|
-
* store is created per hook mount via `useMemo` (component-scoped,
|
|
13
|
-
* module-level
|
|
12
|
+
* store is created per hook mount via `useMemo` (stores are component-scoped,
|
|
13
|
+
* never module-level singletons), and React subscribes through
|
|
14
14
|
* `useStore`. Changing `cartId` recreates the store; refetches are explicit
|
|
15
15
|
* (`refetch()` or any mutation triggers one).
|
|
16
16
|
*
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* UIs need.
|
|
10
10
|
*
|
|
11
11
|
* State management follows the platform's store pattern: a vanilla Zustand
|
|
12
|
-
* store is created per hook mount via `useMemo` (component-scoped,
|
|
13
|
-
* module-level
|
|
12
|
+
* store is created per hook mount via `useMemo` (stores are component-scoped,
|
|
13
|
+
* never module-level singletons), and React subscribes through
|
|
14
14
|
* `useStore`. Changing `cartId` recreates the store; refetches are explicit
|
|
15
15
|
* (`refetch()` or any mutation triggers one).
|
|
16
16
|
*
|
|
@@ -84,7 +84,7 @@ export function useCart(cartId, options = {}) {
|
|
|
84
84
|
const { autoFetch = true, initialCart } = options;
|
|
85
85
|
// Recreate the store when `cartId` or the underlying client changes. The
|
|
86
86
|
// useMemo dependency list captures store identity (component-scoped, not
|
|
87
|
-
// module-level
|
|
87
|
+
// module-level). Mutations capture the store instance for stable
|
|
88
88
|
// references via the api object.
|
|
89
89
|
const api = useMemo(() => createServerCartStore({ cartClient, cartId, initialCart }),
|
|
90
90
|
// initialCart deliberately excluded — it only seeds the FIRST mount; we do
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CaptureReferralCodeOptions } from '../referral';
|
|
2
|
+
export interface UseReferralCaptureOptions extends Pick<CaptureReferralCodeOptions, 'paramName' | 'maxAge'> {
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Capture the referral code from the current URL into the `referral-code`
|
|
6
|
+
* cookie and return the active code (`null` when none).
|
|
7
|
+
*/
|
|
8
|
+
export declare function useReferralCapture(options?: UseReferralCaptureOptions): string | null;
|
|
9
|
+
//# sourceMappingURL=use-referral-capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-referral-capture.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-referral-capture.ts"],"names":[],"mappings":"AA4BA,OAAO,EAAuB,KAAK,0BAA0B,EAAE,MAAM,aAAa,CAAC;AAEnF,MAAM,WAAW,yBACf,SAAQ,IAAI,CAAC,0BAA0B,EAAE,WAAW,GAAG,QAAQ,CAAC;CAAG;AAErE;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,yBAAyB,GAAG,MAAM,GAAG,IAAI,CAWrF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
/**
|
|
3
|
+
* useReferralCapture — capture a referral code from the landing URL.
|
|
4
|
+
*
|
|
5
|
+
* Mount the hook once near the top of the app (layout or a dedicated client
|
|
6
|
+
* component). On mount it inspects the current URL for the referral parameter
|
|
7
|
+
* (`?ref=CODE` by default), persists it in the `referral-code` cookie and
|
|
8
|
+
* returns the active code (from the URL, or a previously stored one when the
|
|
9
|
+
* visitor navigated away from the landing URL before signing up).
|
|
10
|
+
*
|
|
11
|
+
* At signup time read the code with `readReferralCodeCookie()` (or use the
|
|
12
|
+
* value returned here), pass it as `customerSignup(input: { referralCode })`
|
|
13
|
+
* and call `clearReferralCodeCookie()` after success.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* 'use client';
|
|
18
|
+
* import { useReferralCapture } from '@doswiftly/storefront-sdk/react';
|
|
19
|
+
*
|
|
20
|
+
* export function ReferralCapture() {
|
|
21
|
+
* useReferralCapture();
|
|
22
|
+
* return null;
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import { useEffect, useState } from 'react';
|
|
27
|
+
import { captureReferralCode } from '../referral';
|
|
28
|
+
/**
|
|
29
|
+
* Capture the referral code from the current URL into the `referral-code`
|
|
30
|
+
* cookie and return the active code (`null` when none).
|
|
31
|
+
*/
|
|
32
|
+
export function useReferralCapture(options) {
|
|
33
|
+
const [code, setCode] = useState(null);
|
|
34
|
+
const paramName = options?.paramName;
|
|
35
|
+
const maxAge = options?.maxAge;
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
setCode(captureReferralCode({ paramName, maxAge }));
|
|
38
|
+
}, [paramName, maxAge]);
|
|
39
|
+
return code;
|
|
40
|
+
}
|
|
@@ -2,14 +2,15 @@
|
|
|
2
2
|
* useSessionExpired — subscribe to the global session-expired signal.
|
|
3
3
|
*
|
|
4
4
|
* Fired when the SDK can no longer keep the customer session alive: a proactive
|
|
5
|
-
* refresh failed on tab wake
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* refresh failed on tab wake, or a reactive refresh after a 401 also failed.
|
|
6
|
+
* Use once near the app root to react globally — show a notice and redirect
|
|
7
|
+
* to sign-in. No-op outside `StorefrontProvider`.
|
|
8
8
|
*/
|
|
9
9
|
import type { SessionExpiredEmitter, SessionExpiredEvent } from '../../core/auth/session-events';
|
|
10
10
|
/**
|
|
11
|
-
* Context carrying the provider-scoped session-expired emitter. Created
|
|
12
|
-
* `StorefrontProvider` via `useRef`
|
|
11
|
+
* Context carrying the provider-scoped session-expired emitter. Created per
|
|
12
|
+
* provider mount in `StorefrontProvider` via `useRef` — never a module-level
|
|
13
|
+
* singleton.
|
|
13
14
|
*/
|
|
14
15
|
export declare const SessionExpiredContext: import("react").Context<SessionExpiredEmitter | null>;
|
|
15
16
|
export declare function useSessionExpired(listener: (event: SessionExpiredEvent) => void): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-session-expired.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-session-expired.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAEjG
|
|
1
|
+
{"version":3,"file":"use-session-expired.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-session-expired.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAEjG;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,uDAAoD,CAAC;AAEvF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,GAAG,IAAI,CAUtF"}
|
|
@@ -2,15 +2,16 @@
|
|
|
2
2
|
* useSessionExpired — subscribe to the global session-expired signal.
|
|
3
3
|
*
|
|
4
4
|
* Fired when the SDK can no longer keep the customer session alive: a proactive
|
|
5
|
-
* refresh failed on tab wake
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* refresh failed on tab wake, or a reactive refresh after a 401 also failed.
|
|
6
|
+
* Use once near the app root to react globally — show a notice and redirect
|
|
7
|
+
* to sign-in. No-op outside `StorefrontProvider`.
|
|
8
8
|
*/
|
|
9
9
|
'use client';
|
|
10
10
|
import { createContext, useContext, useEffect, useRef } from 'react';
|
|
11
11
|
/**
|
|
12
|
-
* Context carrying the provider-scoped session-expired emitter. Created
|
|
13
|
-
* `StorefrontProvider` via `useRef`
|
|
12
|
+
* Context carrying the provider-scoped session-expired emitter. Created per
|
|
13
|
+
* provider mount in `StorefrontProvider` via `useRef` — never a module-level
|
|
14
|
+
* singleton.
|
|
14
15
|
*/
|
|
15
16
|
export const SessionExpiredContext = createContext(null);
|
|
16
17
|
export function useSessionExpired(listener) {
|
package/dist/react/index.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export type { ShopConfig } from './types/shop-config';
|
|
|
37
37
|
export { selectCurrency, selectBaseCurrency, selectSupportedCurrencies, selectIsLoaded } from './stores/currency.store';
|
|
38
38
|
export { selectLanguage, selectDefaultLanguage, selectSupportedLanguages, selectLanguageIsLoaded } from './stores/language.store';
|
|
39
39
|
export { getCookie, setCookie, deleteCookie, createBrowserCartCookieStore, } from './cookies';
|
|
40
|
+
export { captureReferralCode, getReferralCodeCookie, clearReferralCodeCookie, type CaptureReferralCodeOptions, } from './referral';
|
|
41
|
+
export { useReferralCapture, type UseReferralCaptureOptions } from './hooks/use-referral-capture';
|
|
40
42
|
export { useBotProtection } from './hooks/use-bot-protection';
|
|
41
43
|
export { useHydrated } from './hooks/use-hydrated';
|
|
42
44
|
export { useDebouncedValue } from './hooks/use-debounced-value';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AACnG,OAAO,EAAE,wBAAwB,EAAE,KAAK,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACtH,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,KAAK,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,KAAK,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAG9H,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC9H,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,KAAK,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACrH,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC/F,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpH,OAAO,EAAE,cAAc,EAAE,KAAK,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,KAAK,oBAAoB,EAAE,KAAK,qBAAqB,EAAE,KAAK,6BAA6B,EAAE,MAAM,0BAA0B,CAAC;AACxM,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC9G,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAG/E,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC/E,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAGtD,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACxH,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}
|
package/dist/react/index.js
CHANGED
|
@@ -36,8 +36,12 @@ export { useLanguageStore, useLanguageStoreApi } from './stores/store-context';
|
|
|
36
36
|
export { selectCurrency, selectBaseCurrency, selectSupportedCurrencies, selectIsLoaded } from './stores/currency.store';
|
|
37
37
|
export { selectLanguage, selectDefaultLanguage, selectSupportedLanguages, selectLanguageIsLoaded } from './stores/language.store';
|
|
38
38
|
// Cookie utilities (client-side). Server-side readers (readCartIdCookie,
|
|
39
|
-
// readCurrencyCookie) live in
|
|
39
|
+
// readCurrencyCookie, readReferralCodeCookie) live in
|
|
40
|
+
// `@doswiftly/storefront-sdk/react/server`.
|
|
40
41
|
export { getCookie, setCookie, deleteCookie, createBrowserCartCookieStore, } from './cookies';
|
|
42
|
+
// Referral capture (loyalty referral program — landing-link `?ref=CODE` → cookie)
|
|
43
|
+
export { captureReferralCode, getReferralCodeCookie, clearReferralCodeCookie, } from './referral';
|
|
44
|
+
export { useReferralCapture } from './hooks/use-referral-capture';
|
|
41
45
|
// Bot protection
|
|
42
46
|
export { useBotProtection } from './hooks/use-bot-protection';
|
|
43
47
|
// Generic hooks
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side referral capture helpers.
|
|
3
|
+
*
|
|
4
|
+
* Flow: a visitor lands through a referral share link (`/register?ref=CODE`),
|
|
5
|
+
* `captureReferralCode()` persists the code in the readable `referral-code`
|
|
6
|
+
* cookie, and the signup form reads it back with `getReferralCodeCookie()`
|
|
7
|
+
* and passes it as `customerSignup(input: { referralCode })`. After a
|
|
8
|
+
* successful signup call `clearReferralCodeCookie()` so the code is not
|
|
9
|
+
* re-submitted by other browser tabs or future registrations.
|
|
10
|
+
*
|
|
11
|
+
* All helpers are SSR-safe (no-op / `null` without a `document`). For Server
|
|
12
|
+
* Components use the async `readReferralCodeCookie` from
|
|
13
|
+
* `@doswiftly/storefront-sdk/react/server` instead — the client helper is
|
|
14
|
+
* deliberately named differently (`get…`, synchronous) so the two cannot be
|
|
15
|
+
* confused in auto-imports.
|
|
16
|
+
*/
|
|
17
|
+
export interface CaptureReferralCodeOptions {
|
|
18
|
+
/**
|
|
19
|
+
* URL (or search string) to inspect. Defaults to the current
|
|
20
|
+
* `window.location.href`.
|
|
21
|
+
*/
|
|
22
|
+
url?: string | URL;
|
|
23
|
+
/** Query parameter carrying the code. Default `'ref'`. */
|
|
24
|
+
paramName?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Cookie lifetime in seconds. Default {@link REFERRAL_COOKIE_MAX_AGE}
|
|
27
|
+
* (30 days) — the "landing → signup" window, independent of the shop's
|
|
28
|
+
* referral validity setting (see the constant's docs).
|
|
29
|
+
*/
|
|
30
|
+
maxAge?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Capture a referral code from the current URL (or an explicit one) into the
|
|
34
|
+
* `referral-code` cookie.
|
|
35
|
+
*
|
|
36
|
+
* Returns the captured code, or the previously stored one when the URL carries
|
|
37
|
+
* no code (so a visitor who navigated away from the landing URL still counts),
|
|
38
|
+
* or `null` when there is nothing to capture. A code present in the URL always
|
|
39
|
+
* wins over a previously stored one — the most recent referral link decides.
|
|
40
|
+
*/
|
|
41
|
+
export declare function captureReferralCode(options?: CaptureReferralCodeOptions): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Read the stored referral code (client-side, synchronous). Returns `null`
|
|
44
|
+
* when absent or outside a browser environment. Server Components use the
|
|
45
|
+
* async `readReferralCodeCookie` from `@doswiftly/storefront-sdk/react/server`.
|
|
46
|
+
*/
|
|
47
|
+
export declare function getReferralCodeCookie(): string | null;
|
|
48
|
+
/**
|
|
49
|
+
* Remove the stored referral code. Call after a successful signup so the code
|
|
50
|
+
* is not re-submitted by future registrations from the same browser.
|
|
51
|
+
*/
|
|
52
|
+
export declare function clearReferralCodeCookie(): void;
|
|
53
|
+
//# sourceMappingURL=referral.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"referral.d.ts","sourceRoot":"","sources":["../../src/react/referral.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACnB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,MAAM,GAAG,IAAI,CAU3F;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,GAAG,IAAI,CAErD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side referral capture helpers.
|
|
3
|
+
*
|
|
4
|
+
* Flow: a visitor lands through a referral share link (`/register?ref=CODE`),
|
|
5
|
+
* `captureReferralCode()` persists the code in the readable `referral-code`
|
|
6
|
+
* cookie, and the signup form reads it back with `getReferralCodeCookie()`
|
|
7
|
+
* and passes it as `customerSignup(input: { referralCode })`. After a
|
|
8
|
+
* successful signup call `clearReferralCodeCookie()` so the code is not
|
|
9
|
+
* re-submitted by other browser tabs or future registrations.
|
|
10
|
+
*
|
|
11
|
+
* All helpers are SSR-safe (no-op / `null` without a `document`). For Server
|
|
12
|
+
* Components use the async `readReferralCodeCookie` from
|
|
13
|
+
* `@doswiftly/storefront-sdk/react/server` instead — the client helper is
|
|
14
|
+
* deliberately named differently (`get…`, synchronous) so the two cannot be
|
|
15
|
+
* confused in auto-imports.
|
|
16
|
+
*/
|
|
17
|
+
import { REFERRAL_COOKIE_NAME, REFERRAL_COOKIE_MAX_AGE, extractReferralCodeFromUrl, } from '../core/referral/cookie-config';
|
|
18
|
+
import { getCookie, setCookie, deleteCookie } from './cookies';
|
|
19
|
+
/**
|
|
20
|
+
* Capture a referral code from the current URL (or an explicit one) into the
|
|
21
|
+
* `referral-code` cookie.
|
|
22
|
+
*
|
|
23
|
+
* Returns the captured code, or the previously stored one when the URL carries
|
|
24
|
+
* no code (so a visitor who navigated away from the landing URL still counts),
|
|
25
|
+
* or `null` when there is nothing to capture. A code present in the URL always
|
|
26
|
+
* wins over a previously stored one — the most recent referral link decides.
|
|
27
|
+
*/
|
|
28
|
+
export function captureReferralCode(options = {}) {
|
|
29
|
+
const url = options.url ?? (typeof window !== 'undefined' ? window.location.href : null);
|
|
30
|
+
const fromUrl = url ? extractReferralCodeFromUrl(url, options.paramName) : null;
|
|
31
|
+
if (fromUrl) {
|
|
32
|
+
setCookie(REFERRAL_COOKIE_NAME, fromUrl, { maxAge: options.maxAge ?? REFERRAL_COOKIE_MAX_AGE });
|
|
33
|
+
return fromUrl;
|
|
34
|
+
}
|
|
35
|
+
return getReferralCodeCookie();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Read the stored referral code (client-side, synchronous). Returns `null`
|
|
39
|
+
* when absent or outside a browser environment. Server Components use the
|
|
40
|
+
* async `readReferralCodeCookie` from `@doswiftly/storefront-sdk/react/server`.
|
|
41
|
+
*/
|
|
42
|
+
export function getReferralCodeCookie() {
|
|
43
|
+
return getCookie(REFERRAL_COOKIE_NAME);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Remove the stored referral code. Call after a successful signup so the code
|
|
47
|
+
* is not re-submitted by future registrations from the same browser.
|
|
48
|
+
*/
|
|
49
|
+
export function clearReferralCodeCookie() {
|
|
50
|
+
deleteCookie(REFERRAL_COOKIE_NAME);
|
|
51
|
+
}
|
|
@@ -46,4 +46,11 @@ export declare function readCartIdCookie(): Promise<string | null>;
|
|
|
46
46
|
export declare function readCartCredentials(): Promise<CartCredentials | null>;
|
|
47
47
|
/** Read the first-party `preferred-currency` cookie (server-first, client fallback). */
|
|
48
48
|
export declare function readCurrencyCookie(): Promise<string | null>;
|
|
49
|
+
/**
|
|
50
|
+
* Read the first-party `referral-code` cookie (server-first, client fallback) —
|
|
51
|
+
* the referral code captured when the visitor landed through a referral share
|
|
52
|
+
* link. Useful for SSR-rendered signup forms that pre-fill the code field;
|
|
53
|
+
* pass it as `customerSignup(input: { referralCode })`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function readReferralCodeCookie(): Promise<string | null>;
|
|
49
56
|
//# sourceMappingURL=cookie-readers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cookie-readers.d.ts","sourceRoot":"","sources":["../../../src/react/server/cookie-readers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"cookie-readers.d.ts","sourceRoot":"","sources":["../../../src/react/server/cookie-readers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;AAsBvC,6EAA6E;AAC7E,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE/D;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAE3E;AAED,wFAAwF;AACxF,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAEjE;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAErE"}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { CART_COOKIE_NAME, parseCartCookieValue, } from '../../core/cart/cookie-config';
|
|
26
26
|
import { CURRENCY_COOKIE_NAME } from '../../core/currency/cookie-config';
|
|
27
|
+
import { REFERRAL_COOKIE_NAME } from '../../core/referral/cookie-config';
|
|
27
28
|
import { getCookie } from '../cookies';
|
|
28
29
|
/**
|
|
29
30
|
* Read a cookie server-first: the request cookies via `next/headers` in a Server
|
|
@@ -71,3 +72,12 @@ export async function readCartCredentials() {
|
|
|
71
72
|
export async function readCurrencyCookie() {
|
|
72
73
|
return readCookieIsomorphic(CURRENCY_COOKIE_NAME);
|
|
73
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Read the first-party `referral-code` cookie (server-first, client fallback) —
|
|
77
|
+
* the referral code captured when the visitor landed through a referral share
|
|
78
|
+
* link. Useful for SSR-rendered signup forms that pre-fill the code field;
|
|
79
|
+
* pass it as `customerSignup(input: { referralCode })`.
|
|
80
|
+
*/
|
|
81
|
+
export async function readReferralCodeCookie() {
|
|
82
|
+
return readCookieIsomorphic(REFERRAL_COOKIE_NAME);
|
|
83
|
+
}
|