@doswiftly/storefront-sdk 11.2.0 → 11.4.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 +108 -0
- package/README.md +214 -2
- package/dist/core/auth/handlers.d.ts.map +1 -1
- package/dist/core/auth/handlers.js +29 -1
- package/dist/core/bot-protection/turnstile-manager.d.ts +0 -1
- package/dist/core/bot-protection/turnstile-manager.d.ts.map +1 -1
- package/dist/core/bot-protection/turnstile-manager.js +0 -1
- package/dist/react/components/AddToCartButton.d.ts +49 -0
- package/dist/react/components/AddToCartButton.d.ts.map +1 -0
- package/dist/react/components/AddToCartButton.js +47 -0
- package/dist/react/components/CartCount.d.ts +35 -0
- package/dist/react/components/CartCount.d.ts.map +1 -0
- package/dist/react/components/CartCount.js +23 -0
- package/dist/react/components/CartTotals.d.ts +54 -0
- package/dist/react/components/CartTotals.d.ts.map +1 -0
- package/dist/react/components/CartTotals.js +38 -0
- package/dist/react/components/Image.d.ts +42 -0
- package/dist/react/components/Image.d.ts.map +1 -0
- package/dist/react/components/Image.js +33 -0
- package/dist/react/components/Money.d.ts +32 -0
- package/dist/react/components/Money.d.ts.map +1 -0
- package/dist/react/components/Money.js +27 -0
- package/dist/react/components/PriceDisplay.d.ts +34 -0
- package/dist/react/components/PriceDisplay.d.ts.map +1 -0
- package/dist/react/components/PriceDisplay.js +21 -0
- package/dist/react/components/index.d.ts +15 -0
- package/dist/react/components/index.d.ts.map +1 -0
- package/dist/react/components/index.js +14 -0
- package/dist/react/hooks/use-auth.d.ts +19 -46
- package/dist/react/hooks/use-auth.d.ts.map +1 -1
- package/dist/react/hooks/use-auth.js +24 -141
- package/dist/react/hooks/use-cart-manager.d.ts +34 -0
- package/dist/react/hooks/use-cart-manager.d.ts.map +1 -1
- package/dist/react/hooks/use-cart-manager.js +22 -19
- package/dist/react/hooks/use-login.d.ts +40 -0
- package/dist/react/hooks/use-login.d.ts.map +1 -0
- package/dist/react/hooks/use-login.js +75 -0
- package/dist/react/hooks/use-logout.d.ts +40 -0
- package/dist/react/hooks/use-logout.d.ts.map +1 -0
- package/dist/react/hooks/use-logout.js +50 -0
- package/dist/react/hooks/use-refresh-token.d.ts +40 -0
- package/dist/react/hooks/use-refresh-token.d.ts.map +1 -0
- package/dist/react/hooks/use-refresh-token.js +66 -0
- package/dist/react/index.d.ts +5 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -0
- package/dist/react/server/get-storefront-client.d.ts +15 -5
- package/dist/react/server/get-storefront-client.d.ts.map +1 -1
- package/dist/react/stores/cart.store.d.ts.map +1 -1
- package/dist/react/stores/cart.store.js +0 -7
- package/dist/react/stores/store-context.d.ts.map +1 -1
- package/dist/react/stores/store-context.js +0 -2
- package/package.json +5 -1
- package/dist/__tests__/unit/test-helpers.d.ts +0 -46
- package/dist/__tests__/unit/test-helpers.d.ts.map +0 -1
- package/dist/__tests__/unit/test-helpers.js +0 -72
- package/dist/__tests__/unit/use-cart-manager.test.d.ts +0 -2
- package/dist/__tests__/unit/use-cart-manager.test.d.ts.map +0 -1
- package/dist/__tests__/unit/use-cart-manager.test.js +0 -400
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<CartTotals>` — render a description list (`<dl>`) of cart financial
|
|
3
|
+
* breakdown rows: subtotal, optional discount / shipping / tax, total.
|
|
4
|
+
*
|
|
5
|
+
* Renders only the rows you pass. `subtotal`, `total`, and `currency` are
|
|
6
|
+
* required; everything else is optional and elided when undefined or zero
|
|
7
|
+
* (discount specifically — pass zero to hide rather than showing "-0,00").
|
|
8
|
+
*
|
|
9
|
+
* Labels are passed by the consumer (i18n is its responsibility). The
|
|
10
|
+
* component defaults to English labels so it works out of the box during
|
|
11
|
+
* prototyping.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <CartTotals
|
|
16
|
+
* subtotal={cart.cost.subtotal.amount * 100}
|
|
17
|
+
* shipping={cart.cost.shipping?.amount * 100}
|
|
18
|
+
* tax={cart.cost.tax?.amount * 100}
|
|
19
|
+
* total={cart.cost.total.amount * 100}
|
|
20
|
+
* currency={cart.cost.total.currencyCode}
|
|
21
|
+
* labels={{ subtotal: 'Suma częściowa', shipping: 'Dostawa', tax: 'Podatek', total: 'Razem' }}
|
|
22
|
+
* />
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
'use client';
|
|
26
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
27
|
+
import { Money } from './Money';
|
|
28
|
+
const DEFAULT_LABELS = {
|
|
29
|
+
subtotal: 'Subtotal',
|
|
30
|
+
discount: 'Discount',
|
|
31
|
+
shipping: 'Shipping',
|
|
32
|
+
tax: 'Tax',
|
|
33
|
+
total: 'Total',
|
|
34
|
+
};
|
|
35
|
+
export function CartTotals({ subtotal, discount, shipping, tax, total, currency, className, rowClassName, labels, }) {
|
|
36
|
+
const L = { ...DEFAULT_LABELS, ...labels };
|
|
37
|
+
return (_jsxs("dl", { className: className, children: [_jsxs("div", { className: rowClassName, children: [_jsx("dt", { children: L.subtotal }), _jsx("dd", { children: _jsx(Money, { amount: subtotal, currency: currency }) })] }), discount !== undefined && discount > 0 && (_jsxs("div", { className: rowClassName, children: [_jsx("dt", { children: L.discount }), _jsxs("dd", { children: [_jsx("span", { "aria-hidden": "true", children: "\u2212" }), _jsx(Money, { amount: discount, currency: currency })] })] })), shipping !== undefined && (_jsxs("div", { className: rowClassName, children: [_jsx("dt", { children: L.shipping }), _jsx("dd", { children: _jsx(Money, { amount: shipping, currency: currency }) })] })), tax !== undefined && (_jsxs("div", { className: rowClassName, children: [_jsx("dt", { children: L.tax }), _jsx("dd", { children: _jsx(Money, { amount: tax, currency: currency }) })] })), _jsxs("div", { className: rowClassName, children: [_jsx("dt", { children: L.total }), _jsx("dd", { children: _jsx(Money, { amount: total, currency: currency }) })] })] }));
|
|
38
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Image>` — render a GraphQL `Image` payload as an `<img>` with thumbhash
|
|
3
|
+
* blur placeholder (via `thumbHashToDataURL` from core).
|
|
4
|
+
*
|
|
5
|
+
* Headless and framework-agnostic — does NOT depend on `next/image`. If you
|
|
6
|
+
* want Next.js `<Image>` optimisations, pass `data.url` to it directly; this
|
|
7
|
+
* component is for runtimes outside Next or when you don't need `next/image`'s
|
|
8
|
+
* trade-offs (CLS guard, prefetch).
|
|
9
|
+
*
|
|
10
|
+
* Lazy by default. Pass `priority` for above-the-fold images to switch to
|
|
11
|
+
* `loading="eager"` + `fetchPriority="high"`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <Image data={product.featuredImage} sizes="(max-width: 768px) 100vw, 800px" />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import type { CSSProperties } from 'react';
|
|
19
|
+
import { type ImageData } from '../../core/image';
|
|
20
|
+
export interface ImageComponentProps {
|
|
21
|
+
/** Image payload from a GraphQL query (`url`, `altText`, `width`, `height`, `thumbhash`). */
|
|
22
|
+
data: ImageData;
|
|
23
|
+
/** Responsive `sizes` attribute. Defaults to `100vw`. */
|
|
24
|
+
sizes?: string;
|
|
25
|
+
/** Class name for styling — keeps the component headless. */
|
|
26
|
+
className?: string;
|
|
27
|
+
/** Inline style override. Merged with the blur placeholder background. */
|
|
28
|
+
style?: CSSProperties;
|
|
29
|
+
/**
|
|
30
|
+
* Above-the-fold flag. When true: `loading="eager"` + `fetchPriority="high"`.
|
|
31
|
+
* When false (default): `loading="lazy"` + `fetchPriority="auto"`.
|
|
32
|
+
*/
|
|
33
|
+
priority?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Alt text override. Defaults to `data.altText`. Pass an empty string
|
|
36
|
+
* (`alt=""`) when the image is purely decorative — explicit empty alt is the
|
|
37
|
+
* correct accessibility signal.
|
|
38
|
+
*/
|
|
39
|
+
alt?: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function Image({ data, sizes, className, style, priority, alt }: ImageComponentProps): import("react/jsx-runtime").JSX.Element;
|
|
42
|
+
//# sourceMappingURL=Image.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Image.d.ts","sourceRoot":"","sources":["../../../src/react/components/Image.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAEtE,MAAM,WAAW,mBAAmB;IAClC,6FAA6F;IAC7F,IAAI,EAAE,SAAS,CAAC;IAChB,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,KAAK,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,mBAAmB,2CA6B1F"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Image>` — render a GraphQL `Image` payload as an `<img>` with thumbhash
|
|
3
|
+
* blur placeholder (via `thumbHashToDataURL` from core).
|
|
4
|
+
*
|
|
5
|
+
* Headless and framework-agnostic — does NOT depend on `next/image`. If you
|
|
6
|
+
* want Next.js `<Image>` optimisations, pass `data.url` to it directly; this
|
|
7
|
+
* component is for runtimes outside Next or when you don't need `next/image`'s
|
|
8
|
+
* trade-offs (CLS guard, prefetch).
|
|
9
|
+
*
|
|
10
|
+
* Lazy by default. Pass `priority` for above-the-fold images to switch to
|
|
11
|
+
* `loading="eager"` + `fetchPriority="high"`.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <Image data={product.featuredImage} sizes="(max-width: 768px) 100vw, 800px" />
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
'use client';
|
|
19
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
20
|
+
import { thumbHashToDataURL } from '../../core/image';
|
|
21
|
+
export function Image({ data, sizes, className, style, priority, alt }) {
|
|
22
|
+
const blurUrl = data.thumbhash ? thumbHashToDataURL(data.thumbhash) : undefined;
|
|
23
|
+
const effectiveAlt = alt ?? data.altText ?? '';
|
|
24
|
+
const composedStyle = blurUrl
|
|
25
|
+
? {
|
|
26
|
+
backgroundImage: `url(${blurUrl})`,
|
|
27
|
+
backgroundSize: 'cover',
|
|
28
|
+
backgroundPosition: 'center',
|
|
29
|
+
...style,
|
|
30
|
+
}
|
|
31
|
+
: style;
|
|
32
|
+
return (_jsx("img", { src: data.url, alt: effectiveAlt, width: data.width ?? undefined, height: data.height ?? undefined, sizes: sizes ?? '100vw', loading: priority ? 'eager' : 'lazy', decoding: "async", ...{ fetchpriority: priority ? 'high' : 'auto' }, style: composedStyle, className: className }));
|
|
33
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Money>` — render a price in minor units (grosze / cents) as a locale-aware
|
|
3
|
+
* formatted string. Wraps `formatPrice` from core so consumers don't need to
|
|
4
|
+
* import the formatter manually.
|
|
5
|
+
*
|
|
6
|
+
* Headless: no styling, no currency context dependency. `currency` is required
|
|
7
|
+
* — render explicitly from your cart/product/shop data. This keeps the
|
|
8
|
+
* component usable both inside `StorefrontProvider` and in isolated rendering
|
|
9
|
+
* (server components, e-mail templates, PDFs).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Money amount={9990} currency="PLN" /> // → "99,90 zł"
|
|
14
|
+
* <Money amount={1295} currency="USD" /> // → "$12.95"
|
|
15
|
+
* <Money amount={0} currency="EUR" /> // → "0,00 €"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export interface MoneyProps {
|
|
19
|
+
/** Amount in minor units (grosze, cents). 9990 = 99.90 PLN. */
|
|
20
|
+
amount: number;
|
|
21
|
+
/** ISO 4217 currency code (PLN, EUR, USD, …). Required — no implicit default. */
|
|
22
|
+
currency: string;
|
|
23
|
+
/** Optional class for styling — keeps the component headless. */
|
|
24
|
+
className?: string;
|
|
25
|
+
/**
|
|
26
|
+
* HTML element to render. Defaults to `<span>` so the price flows inline.
|
|
27
|
+
* Pass `'div'` (or `'p'`) when the price is a block-level item.
|
|
28
|
+
*/
|
|
29
|
+
as?: 'span' | 'div' | 'p' | 'strong' | 'em' | 'output';
|
|
30
|
+
}
|
|
31
|
+
export declare function Money({ amount, currency, className, as: As }: MoneyProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
//# sourceMappingURL=Money.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Money.d.ts","sourceRoot":"","sources":["../../../src/react/components/Money.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI,GAAG,QAAQ,CAAC;CACxD;AAED,wBAAgB,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,EAAE,EAAW,EAAE,EAAE,UAAU,2CAMjF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<Money>` — render a price in minor units (grosze / cents) as a locale-aware
|
|
3
|
+
* formatted string. Wraps `formatPrice` from core so consumers don't need to
|
|
4
|
+
* import the formatter manually.
|
|
5
|
+
*
|
|
6
|
+
* Headless: no styling, no currency context dependency. `currency` is required
|
|
7
|
+
* — render explicitly from your cart/product/shop data. This keeps the
|
|
8
|
+
* component usable both inside `StorefrontProvider` and in isolated rendering
|
|
9
|
+
* (server components, e-mail templates, PDFs).
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <Money amount={9990} currency="PLN" /> // → "99,90 zł"
|
|
14
|
+
* <Money amount={1295} currency="USD" /> // → "$12.95"
|
|
15
|
+
* <Money amount={0} currency="EUR" /> // → "0,00 €"
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
'use client';
|
|
19
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
20
|
+
import { formatPrice } from '../../core/format';
|
|
21
|
+
export function Money({ amount, currency, className, as: As = 'span' }) {
|
|
22
|
+
const formatted = formatPrice({
|
|
23
|
+
amount: (amount / 100).toString(),
|
|
24
|
+
currencyCode: currency,
|
|
25
|
+
});
|
|
26
|
+
return _jsx(As, { className: className, children: formatted });
|
|
27
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<PriceDisplay>` — render a single price or a sale-price layout (current
|
|
3
|
+
* price + strikethrough compare-at). Composes `<Money>` so locale + currency
|
|
4
|
+
* formatting stays consistent with the rest of the SDK.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <PriceDisplay price={9990} currency="PLN" />
|
|
9
|
+
* // → "99,90 zł"
|
|
10
|
+
*
|
|
11
|
+
* <PriceDisplay price={7990} compareAtPrice={9990} currency="PLN" />
|
|
12
|
+
* // → "79,90 zł <s>99,90 zł</s>"
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export interface PriceDisplayProps {
|
|
16
|
+
/** Current price in minor units. */
|
|
17
|
+
price: number;
|
|
18
|
+
/**
|
|
19
|
+
* Original price in minor units before the discount. When provided AND
|
|
20
|
+
* strictly greater than `price`, renders as strikethrough next to the
|
|
21
|
+
* current price. Otherwise ignored.
|
|
22
|
+
*/
|
|
23
|
+
compareAtPrice?: number;
|
|
24
|
+
/** ISO 4217 currency code. */
|
|
25
|
+
currency: string;
|
|
26
|
+
/** Wrapping element class. */
|
|
27
|
+
className?: string;
|
|
28
|
+
/** Class for the *current* price portion. */
|
|
29
|
+
priceClassName?: string;
|
|
30
|
+
/** Class for the strikethrough compare-at portion. */
|
|
31
|
+
compareAtClassName?: string;
|
|
32
|
+
}
|
|
33
|
+
export declare function PriceDisplay({ price, compareAtPrice, currency, className, priceClassName, compareAtClassName, }: PriceDisplayProps): import("react/jsx-runtime").JSX.Element;
|
|
34
|
+
//# sourceMappingURL=PriceDisplay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PriceDisplay.d.ts","sourceRoot":"","sources":["../../../src/react/components/PriceDisplay.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,MAAM,WAAW,iBAAiB;IAChC,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,8BAA8B;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,cAAc,EACd,QAAQ,EACR,SAAS,EACT,cAAc,EACd,kBAAkB,GACnB,EAAE,iBAAiB,2CAgBnB"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `<PriceDisplay>` — render a single price or a sale-price layout (current
|
|
3
|
+
* price + strikethrough compare-at). Composes `<Money>` so locale + currency
|
|
4
|
+
* formatting stays consistent with the rest of the SDK.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <PriceDisplay price={9990} currency="PLN" />
|
|
9
|
+
* // → "99,90 zł"
|
|
10
|
+
*
|
|
11
|
+
* <PriceDisplay price={7990} compareAtPrice={9990} currency="PLN" />
|
|
12
|
+
* // → "79,90 zł <s>99,90 zł</s>"
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
'use client';
|
|
16
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
|
+
import { Money } from './Money';
|
|
18
|
+
export function PriceDisplay({ price, compareAtPrice, currency, className, priceClassName, compareAtClassName, }) {
|
|
19
|
+
const isOnSale = compareAtPrice !== undefined && compareAtPrice > price;
|
|
20
|
+
return (_jsxs("span", { className: className, children: [_jsx(Money, { amount: price, currency: currency, className: priceClassName }), isOnSale && (_jsxs(_Fragment, { children: [' ', _jsx("s", { className: compareAtClassName, children: _jsx(Money, { amount: compareAtPrice, currency: currency }) })] }))] }));
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-built React components — headless, accessibility-aware, framework-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* Every component is intentionally unstyled. Pass `className` (or `style`) to
|
|
5
|
+
* integrate with your CSS approach (Tailwind, CSS Modules, styled-components,
|
|
6
|
+
* vanilla CSS). Components compose `formatPrice` + `thumbHashToDataURL` from
|
|
7
|
+
* core and `useCartManager` from the hook layer.
|
|
8
|
+
*/
|
|
9
|
+
export { Money, type MoneyProps } from './Money';
|
|
10
|
+
export { Image, type ImageComponentProps } from './Image';
|
|
11
|
+
export { CartCount, type CartCountProps } from './CartCount';
|
|
12
|
+
export { AddToCartButton, type AddToCartButtonProps } from './AddToCartButton';
|
|
13
|
+
export { PriceDisplay, type PriceDisplayProps } from './PriceDisplay';
|
|
14
|
+
export { CartTotals, type CartTotalsProps, type CartTotalsLabels } from './CartTotals';
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pre-built React components — headless, accessibility-aware, framework-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* Every component is intentionally unstyled. Pass `className` (or `style`) to
|
|
5
|
+
* integrate with your CSS approach (Tailwind, CSS Modules, styled-components,
|
|
6
|
+
* vanilla CSS). Components compose `formatPrice` + `thumbHashToDataURL` from
|
|
7
|
+
* core and `useCartManager` from the hook layer.
|
|
8
|
+
*/
|
|
9
|
+
export { Money } from './Money';
|
|
10
|
+
export { Image } from './Image';
|
|
11
|
+
export { CartCount } from './CartCount';
|
|
12
|
+
export { AddToCartButton } from './AddToCartButton';
|
|
13
|
+
export { PriceDisplay } from './PriceDisplay';
|
|
14
|
+
export { CartTotals } from './CartTotals';
|
|
@@ -1,56 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* useAuth —
|
|
2
|
+
* useAuth — convenience facade composing `useLogin`, `useLogout`, and
|
|
3
|
+
* `useRefreshToken`. Preserves the pre-11.2 API for backward compatibility.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Zustand store (for client-side state)
|
|
5
|
+
* **Prefer the focused hooks** in new code — they tree-shake better, isolate
|
|
6
|
+
* state, and keep dependency arrays smaller:
|
|
7
7
|
*
|
|
8
|
-
* Does NOT use React Query — plain async + store updates.
|
|
9
|
-
* Template can wrap in useMutation() if React Query features are needed.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
8
|
* ```tsx
|
|
13
|
-
*
|
|
9
|
+
* // Smaller bundle, single-responsibility:
|
|
10
|
+
* const { login, isLoggingIn } = useLogin({ onSetToken });
|
|
11
|
+
* const { logout } = useLogout({ onClearToken });
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* // Convenience aggregator (legacy / mixed flows):
|
|
14
|
+
* const { login, logout, refreshToken, isLoading } = useAuth({ onSetToken, onClearToken });
|
|
17
15
|
* ```
|
|
16
|
+
*
|
|
17
|
+
* Centralizes dual-layer persistence:
|
|
18
|
+
* - httpOnly cookie (for SSR/middleware) — via `onSetToken`/`onClearToken`
|
|
19
|
+
* callbacks that hit your BFF route handlers
|
|
20
|
+
* - Zustand auth store (for client-side state).
|
|
18
21
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
onSetToken?: (token: string) => Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Called after logout to clear httpOnly cookie.
|
|
27
|
-
*/
|
|
28
|
-
onClearToken?: () => Promise<void>;
|
|
29
|
-
}
|
|
30
|
-
export interface LoginResult {
|
|
31
|
-
success: boolean;
|
|
32
|
-
userErrors: Array<{
|
|
33
|
-
message: string;
|
|
34
|
-
field?: string[];
|
|
35
|
-
}>;
|
|
36
|
-
accessToken?: string;
|
|
37
|
-
expiresAt?: string;
|
|
38
|
-
}
|
|
39
|
-
export interface LogoutResult {
|
|
40
|
-
success: boolean;
|
|
41
|
-
userErrors: Array<{
|
|
42
|
-
message: string;
|
|
43
|
-
field?: string[];
|
|
44
|
-
}>;
|
|
45
|
-
}
|
|
46
|
-
export interface TokenRefreshResult {
|
|
47
|
-
success: boolean;
|
|
48
|
-
userErrors: Array<{
|
|
49
|
-
message: string;
|
|
50
|
-
field?: string[];
|
|
51
|
-
}>;
|
|
52
|
-
accessToken?: string;
|
|
53
|
-
expiresAt?: string;
|
|
22
|
+
import { type UseLoginOptions, type LoginResult } from './use-login';
|
|
23
|
+
import { type UseLogoutOptions, type LogoutResult } from './use-logout';
|
|
24
|
+
import { type UseRefreshTokenOptions, type TokenRefreshResult } from './use-refresh-token';
|
|
25
|
+
export type { LoginResult, LogoutResult, TokenRefreshResult };
|
|
26
|
+
export interface UseAuthOptions extends UseLoginOptions, UseLogoutOptions, UseRefreshTokenOptions {
|
|
54
27
|
}
|
|
55
28
|
export declare function useAuth(options?: UseAuthOptions): {
|
|
56
29
|
login: (email: string, password: string) => Promise<LoginResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-auth.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-auth.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"use-auth.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,OAAO,EAAY,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAa,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AACnF,OAAO,EAAmB,KAAK,sBAAsB,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAE5G,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAE9D,MAAM,WAAW,cAAe,SAAQ,eAAe,EAAE,gBAAgB,EAAE,sBAAsB;CAAG;AAEpG,wBAAgB,OAAO,CAAC,OAAO,GAAE,cAAmB;;;;;;;;;EAoBnD"}
|
|
@@ -1,153 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* useAuth —
|
|
2
|
+
* useAuth — convenience facade composing `useLogin`, `useLogout`, and
|
|
3
|
+
* `useRefreshToken`. Preserves the pre-11.2 API for backward compatibility.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* - Zustand store (for client-side state)
|
|
5
|
+
* **Prefer the focused hooks** in new code — they tree-shake better, isolate
|
|
6
|
+
* state, and keep dependency arrays smaller:
|
|
7
7
|
*
|
|
8
|
-
* Does NOT use React Query — plain async + store updates.
|
|
9
|
-
* Template can wrap in useMutation() if React Query features are needed.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
8
|
* ```tsx
|
|
13
|
-
*
|
|
9
|
+
* // Smaller bundle, single-responsibility:
|
|
10
|
+
* const { login, isLoggingIn } = useLogin({ onSetToken });
|
|
11
|
+
* const { logout } = useLogout({ onClearToken });
|
|
14
12
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* // Convenience aggregator (legacy / mixed flows):
|
|
14
|
+
* const { login, logout, refreshToken, isLoading } = useAuth({ onSetToken, onClearToken });
|
|
17
15
|
* ```
|
|
16
|
+
*
|
|
17
|
+
* Centralizes dual-layer persistence:
|
|
18
|
+
* - httpOnly cookie (for SSR/middleware) — via `onSetToken`/`onClearToken`
|
|
19
|
+
* callbacks that hit your BFF route handlers
|
|
20
|
+
* - Zustand auth store (for client-side state).
|
|
18
21
|
*/
|
|
19
22
|
'use client';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { StorefrontError } from '../../core/errors';
|
|
23
|
+
import { useLogin } from './use-login';
|
|
24
|
+
import { useLogout } from './use-logout';
|
|
25
|
+
import { useRefreshToken } from './use-refresh-token';
|
|
24
26
|
export function useAuth(options = {}) {
|
|
25
|
-
const {
|
|
26
|
-
const {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
const login = useCallback(async (email, password) => {
|
|
33
|
-
setError(null);
|
|
34
|
-
setIsLoggingIn(true);
|
|
35
|
-
try {
|
|
36
|
-
const result = await authClient.login(email, password);
|
|
37
|
-
// Set httpOnly cookie
|
|
38
|
-
if (options.onSetToken) {
|
|
39
|
-
await options.onSetToken(result.accessToken);
|
|
40
|
-
}
|
|
41
|
-
// Fetch customer data and set store
|
|
42
|
-
try {
|
|
43
|
-
const customer = await authClient.getCustomer();
|
|
44
|
-
if (customer) {
|
|
45
|
-
setAuth({
|
|
46
|
-
id: customer.id,
|
|
47
|
-
email: customer.email,
|
|
48
|
-
firstName: customer.firstName ?? undefined,
|
|
49
|
-
lastName: customer.lastName ?? undefined,
|
|
50
|
-
phone: customer.phone ?? undefined,
|
|
51
|
-
}, result.accessToken);
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
setAuth({ id: '', email }, result.accessToken);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
// Customer fetch failed — store minimal data
|
|
59
|
-
setAuth({ id: '', email }, result.accessToken);
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
success: true,
|
|
63
|
-
userErrors: [],
|
|
64
|
-
accessToken: result.accessToken,
|
|
65
|
-
expiresAt: result.expiresAt,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
if (err instanceof StorefrontError && err.hasUserErrors) {
|
|
70
|
-
return {
|
|
71
|
-
success: false,
|
|
72
|
-
userErrors: err.userErrors.map((e) => ({
|
|
73
|
-
message: e.message,
|
|
74
|
-
field: e.field,
|
|
75
|
-
})),
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
const message = err instanceof Error ? err.message : 'Login failed';
|
|
79
|
-
setError(message);
|
|
80
|
-
return { success: false, userErrors: [{ message }] };
|
|
81
|
-
}
|
|
82
|
-
finally {
|
|
83
|
-
setIsLoggingIn(false);
|
|
84
|
-
}
|
|
85
|
-
}, [authClient, setAuth, options]);
|
|
86
|
-
const logout = useCallback(async () => {
|
|
87
|
-
setError(null);
|
|
88
|
-
setIsLoggingOut(true);
|
|
89
|
-
try {
|
|
90
|
-
// Auth context resolved server-side from cookie/Bearer — no token arg needed
|
|
91
|
-
await authClient.logout();
|
|
92
|
-
// Clear httpOnly cookie
|
|
93
|
-
if (options.onClearToken) {
|
|
94
|
-
await options.onClearToken();
|
|
95
|
-
}
|
|
96
|
-
clearAuth();
|
|
97
|
-
return { success: true, userErrors: [] };
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
// Even on error, clear local state
|
|
101
|
-
clearAuth();
|
|
102
|
-
const message = err instanceof Error ? err.message : 'Logout failed';
|
|
103
|
-
setError(message);
|
|
104
|
-
return { success: false, userErrors: [{ message }] };
|
|
105
|
-
}
|
|
106
|
-
finally {
|
|
107
|
-
setIsLoggingOut(false);
|
|
108
|
-
}
|
|
109
|
-
}, [authClient, clearAuth, options, authStore]);
|
|
110
|
-
const refreshToken = useCallback(async () => {
|
|
111
|
-
setError(null);
|
|
112
|
-
setIsRenewingToken(true);
|
|
113
|
-
try {
|
|
114
|
-
// Auth context resolved server-side from cookie/Bearer — no token arg needed.
|
|
115
|
-
// If no active session, backend will return 401 and refreshToken throws.
|
|
116
|
-
const result = await authClient.refreshToken();
|
|
117
|
-
// Update httpOnly cookie
|
|
118
|
-
if (options.onSetToken) {
|
|
119
|
-
await options.onSetToken(result.accessToken);
|
|
120
|
-
}
|
|
121
|
-
// Update store (keep customer data, update token)
|
|
122
|
-
const currentCustomer = authStore.getState().customer;
|
|
123
|
-
if (currentCustomer) {
|
|
124
|
-
setAuth(currentCustomer, result.accessToken);
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
success: true,
|
|
128
|
-
userErrors: [],
|
|
129
|
-
accessToken: result.accessToken,
|
|
130
|
-
expiresAt: result.expiresAt,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
catch (err) {
|
|
134
|
-
if (err instanceof StorefrontError && err.hasUserErrors) {
|
|
135
|
-
return {
|
|
136
|
-
success: false,
|
|
137
|
-
userErrors: err.userErrors.map((e) => ({
|
|
138
|
-
message: e.message,
|
|
139
|
-
field: e.field,
|
|
140
|
-
})),
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
const message = err instanceof Error ? err.message : 'Token renewal failed';
|
|
144
|
-
setError(message);
|
|
145
|
-
return { success: false, userErrors: [{ message }] };
|
|
146
|
-
}
|
|
147
|
-
finally {
|
|
148
|
-
setIsRenewingToken(false);
|
|
149
|
-
}
|
|
150
|
-
}, [authClient, setAuth, options, authStore]);
|
|
27
|
+
const { login, isLoggingIn, error: loginError } = useLogin(options);
|
|
28
|
+
const { logout, isLoggingOut, error: logoutError } = useLogout(options);
|
|
29
|
+
const { refreshToken, isRefreshingToken, error: refreshError } = useRefreshToken(options);
|
|
30
|
+
// Aggregate the most-recent error across the three flows. Each focused hook
|
|
31
|
+
// tracks its own error independently, but legacy consumers expect a single
|
|
32
|
+
// `error` field — surface whichever is non-null (priority: login > logout > refresh).
|
|
33
|
+
const error = loginError ?? logoutError ?? refreshError;
|
|
151
34
|
return {
|
|
152
35
|
login,
|
|
153
36
|
logout,
|
|
@@ -38,6 +38,37 @@
|
|
|
38
38
|
import type { Cart, CartLineInput, CartLineUpdateInput, CartBuyerIdentityInput, CartAddressInput } from '../../core/cart/types';
|
|
39
39
|
import type { CartMutationOutcome } from '../../core/cart/cart-client';
|
|
40
40
|
import { type CartExpiredEvent } from '../../core/cart/cart-recovery';
|
|
41
|
+
/**
|
|
42
|
+
* Names of mutations exposed by the hook — narrows `status.operation` for
|
|
43
|
+
* exhaustive consumer-side switching (e.g. operation-specific spinners).
|
|
44
|
+
*/
|
|
45
|
+
export type CartManagerOperation = 'addItem' | 'updateItem' | 'removeItem' | 'updateBuyerIdentity' | 'setShippingAddress' | 'updateDiscountCodes' | 'updateNote';
|
|
46
|
+
/**
|
|
47
|
+
* Tagged union of cart mutation lifecycle states. Lets callers do exhaustive
|
|
48
|
+
* switching without remembering which boolean flag pairs with which:
|
|
49
|
+
*
|
|
50
|
+
* ```tsx
|
|
51
|
+
* const { status } = useCartManager();
|
|
52
|
+
* if (status.type === 'loading') return <Spinner label={status.operation} />;
|
|
53
|
+
* if (status.type === 'error') return <ErrorBanner error={status.error} />;
|
|
54
|
+
* // narrowed here: status.type ∈ { 'idle', 'success' }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* `idle` is the initial state and the state after `clearCart()`.
|
|
58
|
+
*/
|
|
59
|
+
export type CartManagerStatus = {
|
|
60
|
+
type: 'idle';
|
|
61
|
+
} | {
|
|
62
|
+
type: 'loading';
|
|
63
|
+
operation: CartManagerOperation;
|
|
64
|
+
} | {
|
|
65
|
+
type: 'error';
|
|
66
|
+
operation: CartManagerOperation;
|
|
67
|
+
error: Error;
|
|
68
|
+
} | {
|
|
69
|
+
type: 'success';
|
|
70
|
+
operation: CartManagerOperation;
|
|
71
|
+
};
|
|
41
72
|
export interface UseCartManagerResult {
|
|
42
73
|
getCart: () => Promise<Cart | null>;
|
|
43
74
|
getCartId: () => string | null;
|
|
@@ -50,7 +81,10 @@ export interface UseCartManagerResult {
|
|
|
50
81
|
removeItem: (lineIds: string[]) => Promise<CartMutationOutcome>;
|
|
51
82
|
clearCart: () => void;
|
|
52
83
|
onExpired: (listener: (event: CartExpiredEvent) => void) => () => void;
|
|
84
|
+
status: CartManagerStatus;
|
|
85
|
+
/** `true` when status.type === 'loading'. */
|
|
53
86
|
isLoading: boolean;
|
|
87
|
+
/** Error message when status.type === 'error', otherwise null. */
|
|
54
88
|
error: string | null;
|
|
55
89
|
}
|
|
56
90
|
export declare function useCartManager(): UseCartManagerResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-cart-manager.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-cart-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAMH,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,+BAA+B,CAAC;AAGvC,MAAM,WAAW,oBAAoB;IAEnC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACpC,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAG/B,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClE,mBAAmB,EAAE,CAAC,aAAa,EAAE,sBAAsB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC7F,kBAAkB,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChF,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvE,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAG3D,UAAU,EAAE,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAGhE,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAGvE,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,cAAc,IAAI,oBAAoB,
|
|
1
|
+
{"version":3,"file":"use-cart-manager.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-cart-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAMH,OAAO,KAAK,EACV,IAAI,EACJ,aAAa,EACb,mBAAmB,EACnB,sBAAsB,EACtB,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AACvE,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,+BAA+B,CAAC;AAGvC;;;GAGG;AACH,MAAM,MAAM,oBAAoB,GAC5B,SAAS,GACT,YAAY,GACZ,YAAY,GACZ,qBAAqB,GACrB,oBAAoB,GACpB,qBAAqB,GACrB,YAAY,CAAC;AAEjB;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,oBAAoB,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,oBAAoB,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,oBAAoB,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IAEnC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACpC,SAAS,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAG/B,OAAO,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAClE,mBAAmB,EAAE,CAAC,aAAa,EAAE,sBAAsB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC7F,kBAAkB,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAChF,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvE,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAG3D,UAAU,EAAE,CAAC,KAAK,EAAE,mBAAmB,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC3E,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAGhE,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAGvE,MAAM,EAAE,iBAAiB,CAAC;IAG1B,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,kEAAkE;IAClE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,cAAc,IAAI,oBAAoB,CA0LrD"}
|