@doswiftly/storefront-sdk 11.1.0 → 11.3.1
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 +131 -0
- package/README.md +297 -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/core/cart/cart-recovery.d.ts +210 -0
- package/dist/core/cart/cart-recovery.d.ts.map +1 -0
- package/dist/core/cart/cart-recovery.js +271 -0
- package/dist/core/index.d.ts +2 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- 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/cookies.d.ts +21 -0
- package/dist/react/cookies.d.ts.map +1 -1
- package/dist/react/cookies.js +29 -1
- 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 +75 -15
- package/dist/react/hooks/use-cart-manager.d.ts.map +1 -1
- package/dist/react/hooks/use-cart-manager.js +106 -194
- 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 +6 -2
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +6 -1
- 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 +57 -10
- package/dist/react/stores/cart.store.d.ts.map +1 -1
- package/dist/react/stores/cart.store.js +112 -21
- package/dist/react/stores/store-context.d.ts.map +1 -1
- package/dist/react/stores/store-context.js +0 -2
- package/package.json +11 -4
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-login.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-login.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,gHAAgH;IAChH,KAAK,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IACjE,iDAAiD;IACjD,WAAW,EAAE,OAAO,CAAC;IACrB,0GAA0G;IAC1G,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,cAAc,CA+DtE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useLogin — focused hook for the login flow.
|
|
3
|
+
*
|
|
4
|
+
* Composes the auth client + Zustand store + httpOnly cookie BFF callback.
|
|
5
|
+
* Returns `success`/`userErrors` rather than throwing on credential errors —
|
|
6
|
+
* standard form submission pattern.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const { login, isLoggingIn, error } = useLogin({ onSetToken });
|
|
11
|
+
* const result = await login(email, password);
|
|
12
|
+
* if (!result.success) showErrors(result.userErrors);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
'use client';
|
|
16
|
+
import { useCallback, useState } from 'react';
|
|
17
|
+
import { useStorefrontClientContext } from '../providers/storefront-client-provider';
|
|
18
|
+
import { useAuthStore } from '../stores/store-context';
|
|
19
|
+
import { StorefrontError } from '../../core/errors';
|
|
20
|
+
export function useLogin(options = {}) {
|
|
21
|
+
const { authClient } = useStorefrontClientContext();
|
|
22
|
+
const { setAuth } = useAuthStore();
|
|
23
|
+
const [isLoggingIn, setIsLoggingIn] = useState(false);
|
|
24
|
+
const [error, setError] = useState(null);
|
|
25
|
+
const login = useCallback(async (email, password) => {
|
|
26
|
+
setError(null);
|
|
27
|
+
setIsLoggingIn(true);
|
|
28
|
+
try {
|
|
29
|
+
const result = await authClient.login(email, password);
|
|
30
|
+
if (options.onSetToken) {
|
|
31
|
+
await options.onSetToken(result.accessToken);
|
|
32
|
+
}
|
|
33
|
+
// Fetch customer data and set store (best-effort — fallback to minimal data)
|
|
34
|
+
try {
|
|
35
|
+
const customer = await authClient.getCustomer();
|
|
36
|
+
if (customer) {
|
|
37
|
+
setAuth({
|
|
38
|
+
id: customer.id,
|
|
39
|
+
email: customer.email,
|
|
40
|
+
firstName: customer.firstName ?? undefined,
|
|
41
|
+
lastName: customer.lastName ?? undefined,
|
|
42
|
+
phone: customer.phone ?? undefined,
|
|
43
|
+
}, result.accessToken);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
setAuth({ id: '', email }, result.accessToken);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
setAuth({ id: '', email }, result.accessToken);
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
success: true,
|
|
54
|
+
userErrors: [],
|
|
55
|
+
accessToken: result.accessToken,
|
|
56
|
+
expiresAt: result.expiresAt,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
if (err instanceof StorefrontError && err.hasUserErrors) {
|
|
61
|
+
return {
|
|
62
|
+
success: false,
|
|
63
|
+
userErrors: err.userErrors.map((e) => ({ message: e.message, field: e.field })),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const message = err instanceof Error ? err.message : 'Login failed';
|
|
67
|
+
setError(message);
|
|
68
|
+
return { success: false, userErrors: [{ message }] };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
setIsLoggingIn(false);
|
|
72
|
+
}
|
|
73
|
+
}, [authClient, setAuth, options]);
|
|
74
|
+
return { login, isLoggingIn, error };
|
|
75
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useLogout — focused hook for the logout flow.
|
|
3
|
+
*
|
|
4
|
+
* Calls the auth client logout (which clears the backend's httpOnly cookie),
|
|
5
|
+
* invokes the consumer's `onClearToken` callback (BFF), and resets the local
|
|
6
|
+
* auth store. Even when the backend request fails, the local state is
|
|
7
|
+
* cleared (defensive — better to log a user out than leave them in a half
|
|
8
|
+
* state).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const { logout, isLoggingOut } = useLogout({ onClearToken });
|
|
13
|
+
* await logout();
|
|
14
|
+
* router.push('/');
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
export interface UseLogoutOptions {
|
|
18
|
+
/**
|
|
19
|
+
* Called after logout to clear the httpOnly cookie via an API route handler
|
|
20
|
+
* (`createClearTokenHandler`).
|
|
21
|
+
*/
|
|
22
|
+
onClearToken?: () => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
export interface LogoutResult {
|
|
25
|
+
success: boolean;
|
|
26
|
+
userErrors: Array<{
|
|
27
|
+
message: string;
|
|
28
|
+
field?: string[];
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
export interface UseLogoutReturn {
|
|
32
|
+
/** Run the logout flow. Resolves with `{success}` — local state is always cleared. */
|
|
33
|
+
logout: () => Promise<LogoutResult>;
|
|
34
|
+
/** `true` while the logout request is in flight. */
|
|
35
|
+
isLoggingOut: boolean;
|
|
36
|
+
/** Last error message (network, server) — local state is cleared regardless. */
|
|
37
|
+
error: string | null;
|
|
38
|
+
}
|
|
39
|
+
export declare function useLogout(options?: UseLogoutOptions): UseLogoutReturn;
|
|
40
|
+
//# sourceMappingURL=use-logout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-logout.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-logout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAQH,MAAM,WAAW,gBAAgB;IAC/B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,eAAe;IAC9B,sFAAsF;IACtF,MAAM,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC;IACpC,oDAAoD;IACpD,YAAY,EAAE,OAAO,CAAC;IACtB,gFAAgF;IAChF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,OAAO,GAAE,gBAAqB,GAAG,eAAe,CAgCzE"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useLogout — focused hook for the logout flow.
|
|
3
|
+
*
|
|
4
|
+
* Calls the auth client logout (which clears the backend's httpOnly cookie),
|
|
5
|
+
* invokes the consumer's `onClearToken` callback (BFF), and resets the local
|
|
6
|
+
* auth store. Even when the backend request fails, the local state is
|
|
7
|
+
* cleared (defensive — better to log a user out than leave them in a half
|
|
8
|
+
* state).
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const { logout, isLoggingOut } = useLogout({ onClearToken });
|
|
13
|
+
* await logout();
|
|
14
|
+
* router.push('/');
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
'use client';
|
|
18
|
+
import { useCallback, useState } from 'react';
|
|
19
|
+
import { useStorefrontClientContext } from '../providers/storefront-client-provider';
|
|
20
|
+
import { useAuthStore } from '../stores/store-context';
|
|
21
|
+
export function useLogout(options = {}) {
|
|
22
|
+
const { authClient } = useStorefrontClientContext();
|
|
23
|
+
const { clearAuth } = useAuthStore();
|
|
24
|
+
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
25
|
+
const [error, setError] = useState(null);
|
|
26
|
+
const logout = useCallback(async () => {
|
|
27
|
+
setError(null);
|
|
28
|
+
setIsLoggingOut(true);
|
|
29
|
+
try {
|
|
30
|
+
// Auth context resolved server-side from cookie/Bearer — no token arg needed
|
|
31
|
+
await authClient.logout();
|
|
32
|
+
if (options.onClearToken) {
|
|
33
|
+
await options.onClearToken();
|
|
34
|
+
}
|
|
35
|
+
clearAuth();
|
|
36
|
+
return { success: true, userErrors: [] };
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
// Even on error, clear local state — better than a stuck half-state
|
|
40
|
+
clearAuth();
|
|
41
|
+
const message = err instanceof Error ? err.message : 'Logout failed';
|
|
42
|
+
setError(message);
|
|
43
|
+
return { success: false, userErrors: [{ message }] };
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
setIsLoggingOut(false);
|
|
47
|
+
}
|
|
48
|
+
}, [authClient, clearAuth, options]);
|
|
49
|
+
return { logout, isLoggingOut, error };
|
|
50
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useRefreshToken — focused hook for renewing the access token.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `AuthClient.refreshToken`. On success the new token is propagated to
|
|
5
|
+
* the consumer's BFF (`onSetToken`) and the store keeps the existing customer
|
|
6
|
+
* data with the new token attached.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // Periodic refresh (e.g. every 30 min)
|
|
11
|
+
* const { refreshToken } = useRefreshToken({ onSetToken });
|
|
12
|
+
* useEffect(() => {
|
|
13
|
+
* const timer = setInterval(() => refreshToken(), 30 * 60 * 1000);
|
|
14
|
+
* return () => clearInterval(timer);
|
|
15
|
+
* }, [refreshToken]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export interface UseRefreshTokenOptions {
|
|
19
|
+
/** Called after a successful refresh with the new access token (BFF cookie sync). */
|
|
20
|
+
onSetToken?: (token: string) => Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export interface TokenRefreshResult {
|
|
23
|
+
success: boolean;
|
|
24
|
+
userErrors: Array<{
|
|
25
|
+
message: string;
|
|
26
|
+
field?: string[];
|
|
27
|
+
}>;
|
|
28
|
+
accessToken?: string;
|
|
29
|
+
expiresAt?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface UseRefreshTokenReturn {
|
|
32
|
+
/** Renew the access token. Resolves with `{success}`. */
|
|
33
|
+
refreshToken: () => Promise<TokenRefreshResult>;
|
|
34
|
+
/** `true` while a refresh request is in flight. */
|
|
35
|
+
isRefreshingToken: boolean;
|
|
36
|
+
/** Last unexpected error message — credential / session expiry lands in `userErrors`. */
|
|
37
|
+
error: string | null;
|
|
38
|
+
}
|
|
39
|
+
export declare function useRefreshToken(options?: UseRefreshTokenOptions): UseRefreshTokenReturn;
|
|
40
|
+
//# sourceMappingURL=use-refresh-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-refresh-token.d.ts","sourceRoot":"","sources":["../../../src/react/hooks/use-refresh-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,WAAW,sBAAsB;IACrC,qFAAqF;IACrF,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,qBAAqB;IACpC,yDAAyD;IACzD,YAAY,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAChD,mDAAmD;IACnD,iBAAiB,EAAE,OAAO,CAAC;IAC3B,yFAAyF;IACzF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,qBAAqB,CA+C3F"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useRefreshToken — focused hook for renewing the access token.
|
|
3
|
+
*
|
|
4
|
+
* Wraps `AuthClient.refreshToken`. On success the new token is propagated to
|
|
5
|
+
* the consumer's BFF (`onSetToken`) and the store keeps the existing customer
|
|
6
|
+
* data with the new token attached.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* // Periodic refresh (e.g. every 30 min)
|
|
11
|
+
* const { refreshToken } = useRefreshToken({ onSetToken });
|
|
12
|
+
* useEffect(() => {
|
|
13
|
+
* const timer = setInterval(() => refreshToken(), 30 * 60 * 1000);
|
|
14
|
+
* return () => clearInterval(timer);
|
|
15
|
+
* }, [refreshToken]);
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
'use client';
|
|
19
|
+
import { useCallback, useState } from 'react';
|
|
20
|
+
import { useStorefrontClientContext } from '../providers/storefront-client-provider';
|
|
21
|
+
import { useAuthStore, useAuthStoreApi } from '../stores/store-context';
|
|
22
|
+
import { StorefrontError } from '../../core/errors';
|
|
23
|
+
export function useRefreshToken(options = {}) {
|
|
24
|
+
const { authClient } = useStorefrontClientContext();
|
|
25
|
+
const { setAuth } = useAuthStore();
|
|
26
|
+
const authStore = useAuthStoreApi();
|
|
27
|
+
const [isRefreshingToken, setIsRefreshingToken] = useState(false);
|
|
28
|
+
const [error, setError] = useState(null);
|
|
29
|
+
const refreshToken = useCallback(async () => {
|
|
30
|
+
setError(null);
|
|
31
|
+
setIsRefreshingToken(true);
|
|
32
|
+
try {
|
|
33
|
+
// Auth context resolved server-side from cookie/Bearer. If no active
|
|
34
|
+
// session, backend returns 401 and refreshToken throws.
|
|
35
|
+
const result = await authClient.refreshToken();
|
|
36
|
+
if (options.onSetToken) {
|
|
37
|
+
await options.onSetToken(result.accessToken);
|
|
38
|
+
}
|
|
39
|
+
const currentCustomer = authStore.getState().customer;
|
|
40
|
+
if (currentCustomer) {
|
|
41
|
+
setAuth(currentCustomer, result.accessToken);
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
success: true,
|
|
45
|
+
userErrors: [],
|
|
46
|
+
accessToken: result.accessToken,
|
|
47
|
+
expiresAt: result.expiresAt,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err instanceof StorefrontError && err.hasUserErrors) {
|
|
52
|
+
return {
|
|
53
|
+
success: false,
|
|
54
|
+
userErrors: err.userErrors.map((e) => ({ message: e.message, field: e.field })),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const message = err instanceof Error ? err.message : 'Token renewal failed';
|
|
58
|
+
setError(message);
|
|
59
|
+
return { success: false, userErrors: [{ message }] };
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
setIsRefreshingToken(false);
|
|
63
|
+
}
|
|
64
|
+
}, [authClient, setAuth, authStore, options]);
|
|
65
|
+
return { refreshToken, isRefreshingToken, error };
|
|
66
|
+
}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -16,7 +16,10 @@ export { StorefrontClientProvider, type StorefrontClientProviderProps } from './
|
|
|
16
16
|
export { CurrencyProvider, type CurrencyProviderProps } from './providers/currency-provider';
|
|
17
17
|
export { LanguageProvider, type LanguageProviderProps } from './providers/language-provider';
|
|
18
18
|
export { useAuth, type UseAuthOptions, type LoginResult, type LogoutResult, type TokenRefreshResult } from './hooks/use-auth';
|
|
19
|
-
export {
|
|
19
|
+
export { useLogin, type UseLoginOptions, type UseLoginReturn } from './hooks/use-login';
|
|
20
|
+
export { useLogout, type UseLogoutOptions, type UseLogoutReturn } from './hooks/use-logout';
|
|
21
|
+
export { useRefreshToken, type UseRefreshTokenOptions, type UseRefreshTokenReturn } from './hooks/use-refresh-token';
|
|
22
|
+
export { useCartManager, type CartManagerOperation, type CartManagerStatus, type UseCartManagerResult } from './hooks/use-cart-manager';
|
|
20
23
|
export { useStorefrontClient } from './hooks/use-storefront-client';
|
|
21
24
|
export { useCurrency } from './hooks/use-currency';
|
|
22
25
|
export { useAuthStore, useAuthStoreApi, useAuthHydrated } from './stores/store-context';
|
|
@@ -28,7 +31,7 @@ export type { LanguageStore } from './stores/language.store';
|
|
|
28
31
|
export type { ShopConfig } from './types/shop-config';
|
|
29
32
|
export { selectCurrency, selectBaseCurrency, selectSupportedCurrencies, selectIsLoaded } from './stores/currency.store';
|
|
30
33
|
export { selectLanguage, selectDefaultLanguage, selectSupportedLanguages, selectLanguageIsLoaded } from './stores/language.store';
|
|
31
|
-
export { getCookie, setCookie, deleteCookie, getCurrencyFromCookieAsync, getCartIdFromCookieAsync } from './cookies';
|
|
34
|
+
export { getCookie, setCookie, deleteCookie, getCurrencyFromCookieAsync, getCartIdFromCookieAsync, createBrowserCartCookieStore, } from './cookies';
|
|
32
35
|
export { useBotProtection } from './hooks/use-bot-protection';
|
|
33
36
|
export { useHydrated } from './hooks/use-hydrated';
|
|
34
37
|
export { useDebouncedValue } from './hooks/use-debounced-value';
|
|
@@ -36,4 +39,5 @@ export { createCartStore, selectCartId, selectIsCartOpen, selectCartIsLoading, }
|
|
|
36
39
|
export type { CartState, CartStoreConfig, CartActions, CartData, CartMutationAction, CartLineInput, CartLineUpdateInput, } from './stores/cart.store';
|
|
37
40
|
export { CartProvider, useCartStore, useCartStoreApi } from './stores/cart.context';
|
|
38
41
|
export { createStoreContext } from './helpers/create-store-context';
|
|
42
|
+
export { Money, type MoneyProps, Image, type ImageComponentProps, CartCount, type CartCountProps, AddToCartButton, type AddToCartButtonProps, PriceDisplay, type PriceDisplayProps, CartTotals, type CartTotalsProps, type CartTotalsLabels, } from './components';
|
|
39
43
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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;AAG7F,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAC9H,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,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
|
@@ -18,6 +18,9 @@ export { CurrencyProvider } from './providers/currency-provider';
|
|
|
18
18
|
export { LanguageProvider } from './providers/language-provider';
|
|
19
19
|
// Hooks
|
|
20
20
|
export { useAuth } from './hooks/use-auth';
|
|
21
|
+
export { useLogin } from './hooks/use-login';
|
|
22
|
+
export { useLogout } from './hooks/use-logout';
|
|
23
|
+
export { useRefreshToken } from './hooks/use-refresh-token';
|
|
21
24
|
export { useCartManager } from './hooks/use-cart-manager';
|
|
22
25
|
export { useStorefrontClient } from './hooks/use-storefront-client';
|
|
23
26
|
export { useCurrency } from './hooks/use-currency';
|
|
@@ -29,7 +32,7 @@ export { useLanguageStore, useLanguageStoreApi } from './stores/store-context';
|
|
|
29
32
|
export { selectCurrency, selectBaseCurrency, selectSupportedCurrencies, selectIsLoaded } from './stores/currency.store';
|
|
30
33
|
export { selectLanguage, selectDefaultLanguage, selectSupportedLanguages, selectLanguageIsLoaded } from './stores/language.store';
|
|
31
34
|
// Cookie utilities
|
|
32
|
-
export { getCookie, setCookie, deleteCookie, getCurrencyFromCookieAsync, getCartIdFromCookieAsync } from './cookies';
|
|
35
|
+
export { getCookie, setCookie, deleteCookie, getCurrencyFromCookieAsync, getCartIdFromCookieAsync, createBrowserCartCookieStore, } from './cookies';
|
|
33
36
|
// Bot protection
|
|
34
37
|
export { useBotProtection } from './hooks/use-bot-protection';
|
|
35
38
|
// Generic hooks
|
|
@@ -40,3 +43,5 @@ export { createCartStore, selectCartId, selectIsCartOpen, selectCartIsLoading, }
|
|
|
40
43
|
export { CartProvider, useCartStore, useCartStoreApi } from './stores/cart.context';
|
|
41
44
|
// Store context helper
|
|
42
45
|
export { createStoreContext } from './helpers/create-store-context';
|
|
46
|
+
// Pre-built components (headless — no styling, accessibility-aware)
|
|
47
|
+
export { Money, Image, CartCount, AddToCartButton, PriceDisplay, CartTotals, } from './components';
|
|
@@ -21,13 +21,23 @@
|
|
|
21
21
|
*/
|
|
22
22
|
import type { StorefrontClient, StorefrontClientConfig, Middleware } from '../../core/client/types';
|
|
23
23
|
export interface ServerClientOptions extends Omit<StorefrontClientConfig, 'middleware'> {
|
|
24
|
-
/**
|
|
25
|
-
* Function that returns request-scoped headers (e.g. currency from cookie).
|
|
26
|
-
* Called once per client creation.
|
|
27
|
-
*/
|
|
28
|
-
getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
29
24
|
/**
|
|
30
25
|
* Additional middleware (prepended to default pipeline).
|
|
26
|
+
*
|
|
27
|
+
* Use this for request-scoped headers (e.g. currency from cookie, language
|
|
28
|
+
* from URL, custom tracking):
|
|
29
|
+
*
|
|
30
|
+
* ```ts
|
|
31
|
+
* getStorefrontClient({
|
|
32
|
+
* apiUrl, shopSlug,
|
|
33
|
+
* middleware: [
|
|
34
|
+
* async (req, next) => {
|
|
35
|
+
* req.headers['X-Preferred-Currency'] = await readCookieFromHeaders();
|
|
36
|
+
* return next(req);
|
|
37
|
+
* },
|
|
38
|
+
* ],
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
31
41
|
*/
|
|
32
42
|
middleware?: Middleware[];
|
|
33
43
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-storefront-client.d.ts","sourceRoot":"","sources":["../../../src/react/server/get-storefront-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpG,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC;IACrF
|
|
1
|
+
{"version":3,"file":"get-storefront-client.d.ts","sourceRoot":"","sources":["../../../src/react/server/get-storefront-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,OAAO,KAAK,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAEpG,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,sBAAsB,EAAE,YAAY,CAAC;IACrF;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,CAYlF"}
|
|
@@ -1,27 +1,50 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cart Store — DI-based cart state management with cookie persistence
|
|
2
|
+
* Cart Store — DI-based cart state management with cookie persistence and
|
|
3
|
+
* automatic stale-cart recovery.
|
|
3
4
|
*
|
|
4
|
-
* SDK orchestrates cart lifecycle (init, mutations, error handling).
|
|
5
|
-
* Template provides CartActions
|
|
6
|
-
*
|
|
5
|
+
* SDK orchestrates cart lifecycle (init, mutations, recovery, error handling).
|
|
6
|
+
* Template provides `CartActions` via DI (getActions getter). Cart id persisted
|
|
7
|
+
* in cookie (SSR/edge visible) — follows currency store pattern.
|
|
8
|
+
*
|
|
9
|
+
* Per-operation recovery strategy (DX-first — caller never thinks about it):
|
|
10
|
+
*
|
|
11
|
+
* - **`addToCart`** auto-replays on stale-cart errors. If the template
|
|
12
|
+
* implements the optional `actions.createCartWithLines`, recovery is atomic
|
|
13
|
+
* (single `cartCreate({ lines })` round trip). Otherwise falls back to
|
|
14
|
+
* `createCart()` + `addLines()` (2 round trips, same end result).
|
|
15
|
+
*
|
|
16
|
+
* - **`updateQuantity`** and **`removeFromCart`** bail on stale-cart errors:
|
|
17
|
+
* local cart id is cleared, `onExpired` listeners fire, error surfaces via
|
|
18
|
+
* `onMutationError`. Replaying on a fresh empty cart would silently lose
|
|
19
|
+
* user intent (the lineId no longer exists).
|
|
20
|
+
*
|
|
21
|
+
* Stale-cart detection inspects `err.userErrors[].code` (CART_NOT_FOUND /
|
|
22
|
+
* ALREADY_COMPLETED) — locale-proof, see {@link isCartRecoverableError}.
|
|
7
23
|
*
|
|
8
24
|
* @example
|
|
9
25
|
* ```typescript
|
|
10
26
|
* import { createCartStore, type CartActions } from '@doswiftly/storefront-sdk/react';
|
|
11
27
|
*
|
|
12
28
|
* const actions: CartActions = {
|
|
13
|
-
* fetchCart:
|
|
14
|
-
* createCart:
|
|
15
|
-
* addLines:
|
|
16
|
-
* updateLines:
|
|
17
|
-
* removeLines:
|
|
29
|
+
* fetchCart: (id) => api.getCart(id),
|
|
30
|
+
* createCart: () => api.createCart().then(c => c.id),
|
|
31
|
+
* addLines: (id, lines) => api.addLines(id, lines),
|
|
32
|
+
* updateLines: (id, lines) => api.updateLines(id, lines),
|
|
33
|
+
* removeLines: (id, ids) => api.removeLines(id, ids),
|
|
34
|
+
* // optional — enables atomic add-to-cart recovery
|
|
35
|
+
* createCartWithLines: (lines) => api.cartCreate({ lines }),
|
|
18
36
|
* };
|
|
19
37
|
*
|
|
20
|
-
* const store = createCartStore({
|
|
38
|
+
* const store = createCartStore({
|
|
39
|
+
* getActions: () => actions,
|
|
40
|
+
* onExpired: (e) => toast.error('Koszyk wygasł, dodaj produkty ponownie'),
|
|
41
|
+
* });
|
|
21
42
|
* ```
|
|
22
43
|
*/
|
|
23
44
|
import type { CartLineInput, CartLineUpdateInput } from '../../core/cart/types';
|
|
45
|
+
import { type CartExpiredEvent } from '../../core/cart/cart-recovery';
|
|
24
46
|
export type { CartLineInput, CartLineUpdateInput } from '../../core/cart/types';
|
|
47
|
+
export type { CartExpiredEvent } from '../../core/cart/cart-recovery';
|
|
25
48
|
/** Minimal cart data returned by DI actions. */
|
|
26
49
|
export interface CartData {
|
|
27
50
|
id: string;
|
|
@@ -39,6 +62,16 @@ export interface CartActions {
|
|
|
39
62
|
updateLines: (cartId: string, lines: CartLineUpdateInput[]) => Promise<CartData>;
|
|
40
63
|
/** Remove line items. Return updated cart or throw. */
|
|
41
64
|
removeLines: (cartId: string, lineIds: string[]) => Promise<CartData>;
|
|
65
|
+
/**
|
|
66
|
+
* Optional — atomic create-with-lines for stale-cart recovery. When provided,
|
|
67
|
+
* the store recovers from `CART_NOT_FOUND` / `ALREADY_COMPLETED` in a single
|
|
68
|
+
* `cartCreate({ lines })` round trip. When omitted, store falls back to
|
|
69
|
+
* `createCart()` + `addLines()` (2 round trips, identical outcome).
|
|
70
|
+
*
|
|
71
|
+
* Wire this when your GraphQL `cartCreate` mutation accepts an initial
|
|
72
|
+
* `lines` payload (DoSwiftly Storefront API does).
|
|
73
|
+
*/
|
|
74
|
+
createCartWithLines?: (lines: CartLineInput[]) => Promise<CartData>;
|
|
42
75
|
}
|
|
43
76
|
/** Action names passed to mutation callbacks. */
|
|
44
77
|
export type CartMutationAction = 'initCart' | 'addToCart' | 'updateQuantity' | 'removeFromCart';
|
|
@@ -49,6 +82,20 @@ export interface CartStoreConfig {
|
|
|
49
82
|
onMutationSuccess?: (action: CartMutationAction, cart: CartData) => void;
|
|
50
83
|
/** Called on mutation error. */
|
|
51
84
|
onMutationError?: (action: CartMutationAction, error: unknown) => void;
|
|
85
|
+
/**
|
|
86
|
+
* Called when a stale-cart event terminates an operation:
|
|
87
|
+
*
|
|
88
|
+
* - `state-dependent` — bail-on-stale operation (`updateQuantity`,
|
|
89
|
+
* `removeFromCart`) cannot be safely replayed on a new cart.
|
|
90
|
+
* - `recreate-failed` — recovery attempted but creating the replacement
|
|
91
|
+
* cart failed (network / backend error).
|
|
92
|
+
* - `retry-also-failed` — replacement cart also rejected by backend
|
|
93
|
+
* (rare; usually indicates a backend race / bug).
|
|
94
|
+
*
|
|
95
|
+
* Typical UI usage: subscribe once globally and surface a toast / banner
|
|
96
|
+
* inviting the user to add products again.
|
|
97
|
+
*/
|
|
98
|
+
onExpired?: (event: CartExpiredEvent) => void;
|
|
52
99
|
}
|
|
53
100
|
export interface CartState {
|
|
54
101
|
cartId: string | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cart.store.d.ts","sourceRoot":"","sources":["../../../src/react/stores/cart.store.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"cart.store.d.ts","sourceRoot":"","sources":["../../../src/react/stores/cart.store.ts"],"names":[],"mappings":"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"}
|