@doswiftly/storefront-sdk 4.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/README.md +430 -0
- package/dist/__tests__/unit/test-helpers.d.ts +46 -0
- package/dist/__tests__/unit/test-helpers.d.ts.map +1 -0
- package/dist/__tests__/unit/test-helpers.js +72 -0
- package/dist/core/auth/auth-client.d.ts +46 -0
- package/dist/core/auth/auth-client.d.ts.map +1 -0
- package/dist/core/auth/auth-client.js +82 -0
- package/dist/core/auth/cookie-config.d.ts +18 -0
- package/dist/core/auth/cookie-config.d.ts.map +1 -0
- package/dist/core/auth/cookie-config.js +18 -0
- package/dist/core/auth/handlers.d.ts +32 -0
- package/dist/core/auth/handlers.d.ts.map +1 -0
- package/dist/core/auth/handlers.js +127 -0
- package/dist/core/auth/routes.d.ts +21 -0
- package/dist/core/auth/routes.d.ts.map +1 -0
- package/dist/core/auth/routes.js +14 -0
- package/dist/core/auth/token-client.d.ts +26 -0
- package/dist/core/auth/token-client.d.ts.map +1 -0
- package/dist/core/auth/token-client.js +42 -0
- package/dist/core/auth/types.d.ts +53 -0
- package/dist/core/auth/types.d.ts.map +1 -0
- package/dist/core/auth/types.js +4 -0
- package/dist/core/cache.d.ts +54 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +82 -0
- package/dist/core/cart/cart-client.d.ts +57 -0
- package/dist/core/cart/cart-client.d.ts.map +1 -0
- package/dist/core/cart/cart-client.js +89 -0
- package/dist/core/cart/types.d.ts +110 -0
- package/dist/core/cart/types.d.ts.map +1 -0
- package/dist/core/cart/types.js +6 -0
- package/dist/core/client/compose.d.ts +9 -0
- package/dist/core/client/compose.d.ts.map +1 -0
- package/dist/core/client/compose.js +9 -0
- package/dist/core/client/create-client.d.ts +15 -0
- package/dist/core/client/create-client.d.ts.map +1 -0
- package/dist/core/client/create-client.js +85 -0
- package/dist/core/client/dedupe.d.ts +7 -0
- package/dist/core/client/dedupe.d.ts.map +1 -0
- package/dist/core/client/dedupe.js +16 -0
- package/dist/core/client/execute.d.ts +20 -0
- package/dist/core/client/execute.d.ts.map +1 -0
- package/dist/core/client/execute.js +48 -0
- package/dist/core/client/hash.d.ts +7 -0
- package/dist/core/client/hash.d.ts.map +1 -0
- package/dist/core/client/hash.js +21 -0
- package/dist/core/client/operation-name.d.ts +7 -0
- package/dist/core/client/operation-name.d.ts.map +1 -0
- package/dist/core/client/operation-name.js +10 -0
- package/dist/core/client/types.d.ts +126 -0
- package/dist/core/client/types.d.ts.map +1 -0
- package/dist/core/client/types.js +26 -0
- package/dist/core/errors.d.ts +43 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +43 -0
- package/dist/core/format.d.ts +92 -0
- package/dist/core/format.d.ts.map +1 -0
- package/dist/core/format.js +216 -0
- package/dist/core/helpers/assert-no-user-errors.d.ts +10 -0
- package/dist/core/helpers/assert-no-user-errors.d.ts.map +1 -0
- package/dist/core/helpers/assert-no-user-errors.js +16 -0
- package/dist/core/helpers/normalize-connection.d.ts +36 -0
- package/dist/core/helpers/normalize-connection.d.ts.map +1 -0
- package/dist/core/helpers/normalize-connection.js +21 -0
- package/dist/core/helpers/sanitize-html.d.ts +8 -0
- package/dist/core/helpers/sanitize-html.d.ts.map +1 -0
- package/dist/core/helpers/sanitize-html.js +35 -0
- package/dist/core/index.d.ts +59 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +68 -0
- package/dist/core/middleware/auth.d.ts +16 -0
- package/dist/core/middleware/auth.d.ts.map +1 -0
- package/dist/core/middleware/auth.js +22 -0
- package/dist/core/middleware/currency.d.ts +15 -0
- package/dist/core/middleware/currency.d.ts.map +1 -0
- package/dist/core/middleware/currency.js +21 -0
- package/dist/core/middleware/errors.d.ts +24 -0
- package/dist/core/middleware/errors.d.ts.map +1 -0
- package/dist/core/middleware/errors.js +77 -0
- package/dist/core/middleware/retry.d.ts +22 -0
- package/dist/core/middleware/retry.d.ts.map +1 -0
- package/dist/core/middleware/retry.js +58 -0
- package/dist/core/middleware/timeout.d.ts +19 -0
- package/dist/core/middleware/timeout.d.ts.map +1 -0
- package/dist/core/middleware/timeout.js +51 -0
- package/dist/core/operations/auth.d.ts +11 -0
- package/dist/core/operations/auth.d.ts.map +1 -0
- package/dist/core/operations/auth.js +112 -0
- package/dist/core/operations/cart.d.ts +15 -0
- package/dist/core/operations/cart.d.ts.map +1 -0
- package/dist/core/operations/cart.js +169 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/react/cookies.d.ts +28 -0
- package/dist/react/cookies.d.ts.map +1 -0
- package/dist/react/cookies.js +49 -0
- package/dist/react/helpers/create-store-context.d.ts +37 -0
- package/dist/react/helpers/create-store-context.d.ts.map +1 -0
- package/dist/react/helpers/create-store-context.js +47 -0
- package/dist/react/hooks/use-auth.d.ts +65 -0
- package/dist/react/hooks/use-auth.d.ts.map +1 -0
- package/dist/react/hooks/use-auth.js +168 -0
- package/dist/react/hooks/use-cart-manager.d.ts +30 -0
- package/dist/react/hooks/use-cart-manager.d.ts.map +1 -0
- package/dist/react/hooks/use-cart-manager.js +223 -0
- package/dist/react/hooks/use-currency.d.ts +11 -0
- package/dist/react/hooks/use-currency.d.ts.map +1 -0
- package/dist/react/hooks/use-currency.js +19 -0
- package/dist/react/hooks/use-debounced-value.d.ts +15 -0
- package/dist/react/hooks/use-debounced-value.d.ts.map +1 -0
- package/dist/react/hooks/use-debounced-value.js +25 -0
- package/dist/react/hooks/use-hydrated.d.ts +9 -0
- package/dist/react/hooks/use-hydrated.d.ts.map +1 -0
- package/dist/react/hooks/use-hydrated.js +14 -0
- package/dist/react/hooks/use-storefront-client.d.ts +6 -0
- package/dist/react/hooks/use-storefront-client.d.ts.map +1 -0
- package/dist/react/hooks/use-storefront-client.js +8 -0
- package/dist/react/index.d.ts +30 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +34 -0
- package/dist/react/providers/currency-provider.d.ts +14 -0
- package/dist/react/providers/currency-provider.d.ts.map +1 -0
- package/dist/react/providers/currency-provider.js +20 -0
- package/dist/react/providers/storefront-client-provider.d.ts +33 -0
- package/dist/react/providers/storefront-client-provider.d.ts.map +1 -0
- package/dist/react/providers/storefront-client-provider.js +57 -0
- package/dist/react/providers/storefront-provider.d.ts +42 -0
- package/dist/react/providers/storefront-provider.d.ts.map +1 -0
- package/dist/react/providers/storefront-provider.js +40 -0
- package/dist/react/server/get-storefront-client.d.ts +42 -0
- package/dist/react/server/get-storefront-client.d.ts.map +1 -0
- package/dist/react/server/get-storefront-client.js +44 -0
- package/dist/react/server/index.d.ts +2 -0
- package/dist/react/server/index.d.ts.map +1 -0
- package/dist/react/server/index.js +1 -0
- package/dist/react/stores/auth.store.d.ts +48 -0
- package/dist/react/stores/auth.store.d.ts.map +1 -0
- package/dist/react/stores/auth.store.js +67 -0
- package/dist/react/stores/currency.store.d.ts +29 -0
- package/dist/react/stores/currency.store.d.ts.map +1 -0
- package/dist/react/stores/currency.store.js +76 -0
- package/dist/react/stores/index.d.ts +8 -0
- package/dist/react/stores/index.d.ts.map +1 -0
- package/dist/react/stores/index.js +10 -0
- package/dist/react/stores/store-context.d.ts +27 -0
- package/dist/react/stores/store-context.d.ts.map +1 -0
- package/dist/react/stores/store-context.js +62 -0
- package/package.json +71 -0
- package/src/__tests__/contract/storefront-api.contract.test.ts +450 -0
- package/src/__tests__/unit/auth-client.test.ts +210 -0
- package/src/__tests__/unit/cart-client.test.ts +233 -0
- package/src/__tests__/unit/create-client.test.ts +356 -0
- package/src/__tests__/unit/helpers.test.ts +377 -0
- package/src/__tests__/unit/middleware.test.ts +374 -0
- package/src/__tests__/unit/test-helpers.ts +103 -0
- package/src/core/auth/auth-client.ts +123 -0
- package/src/core/auth/cookie-config.ts +23 -0
- package/src/core/auth/handlers.ts +168 -0
- package/src/core/auth/routes.ts +26 -0
- package/src/core/auth/token-client.ts +51 -0
- package/src/core/auth/types.ts +54 -0
- package/src/core/cache.ts +102 -0
- package/src/core/cart/cart-client.ts +150 -0
- package/src/core/cart/types.ts +104 -0
- package/src/core/client/compose.ts +15 -0
- package/src/core/client/create-client.ts +129 -0
- package/src/core/client/dedupe.ts +19 -0
- package/src/core/client/execute.ts +70 -0
- package/src/core/client/hash.ts +21 -0
- package/src/core/client/operation-name.ts +12 -0
- package/src/core/client/types.ts +171 -0
- package/src/core/errors.ts +67 -0
- package/src/core/format.ts +254 -0
- package/src/core/helpers/assert-no-user-errors.ts +21 -0
- package/src/core/helpers/normalize-connection.ts +48 -0
- package/src/core/helpers/sanitize-html.ts +42 -0
- package/src/core/index.ts +148 -0
- package/src/core/middleware/auth.ts +27 -0
- package/src/core/middleware/currency.ts +26 -0
- package/src/core/middleware/errors.ts +86 -0
- package/src/core/middleware/retry.ts +75 -0
- package/src/core/middleware/timeout.ts +61 -0
- package/src/core/operations/auth.ts +123 -0
- package/src/core/operations/cart.ts +185 -0
- package/src/index.ts +25 -0
- package/src/react/cookies.ts +54 -0
- package/src/react/helpers/create-store-context.ts +56 -0
- package/src/react/hooks/use-auth.ts +218 -0
- package/src/react/hooks/use-cart-manager.ts +236 -0
- package/src/react/hooks/use-currency.ts +23 -0
- package/src/react/hooks/use-debounced-value.ts +30 -0
- package/src/react/hooks/use-hydrated.ts +20 -0
- package/src/react/hooks/use-storefront-client.ts +12 -0
- package/src/react/index.ts +45 -0
- package/src/react/providers/currency-provider.tsx +30 -0
- package/src/react/providers/storefront-client-provider.tsx +90 -0
- package/src/react/providers/storefront-provider.tsx +71 -0
- package/src/react/server/get-storefront-client.ts +60 -0
- package/src/react/server/index.ts +1 -0
- package/src/react/stores/auth.store.ts +112 -0
- package/src/react/stores/currency.store.ts +113 -0
- package/src/react/stores/index.ts +17 -0
- package/src/react/stores/store-context.tsx +82 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +14 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side StorefrontClient factory — for Server Components, API routes, etc.
|
|
3
|
+
*
|
|
4
|
+
* Creates a StorefrontClient with default middleware pipeline,
|
|
5
|
+
* without requiring React context (no providers needed server-side).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // lib/graphql/server.ts
|
|
10
|
+
* import { getStorefrontClient } from '@doswiftly/storefront-sdk/react/server';
|
|
11
|
+
*
|
|
12
|
+
* const client = getStorefrontClient({
|
|
13
|
+
* apiUrl: process.env.NEXT_PUBLIC_API_URL!,
|
|
14
|
+
* shopSlug: process.env.NEXT_PUBLIC_SHOP_SLUG!,
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* export const fetchProduct = cache(async (handle: string) => {
|
|
18
|
+
* return client.query(ProductDocument, { handle });
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import type { StorefrontClient, StorefrontClientConfig, Middleware } from '../../core/client/types';
|
|
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
|
+
/**
|
|
30
|
+
* Additional middleware (prepended to default pipeline).
|
|
31
|
+
*/
|
|
32
|
+
middleware?: Middleware[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a StorefrontClient for server-side use.
|
|
36
|
+
*
|
|
37
|
+
* Includes default middleware: retry → timeout → errors.
|
|
38
|
+
* Does NOT include auth/currency middleware (server has no Zustand stores).
|
|
39
|
+
* Pass headers via config.defaultHeaders or getHeaders option.
|
|
40
|
+
*/
|
|
41
|
+
export declare function getStorefrontClient(options: ServerClientOptions): StorefrontClient;
|
|
42
|
+
//# sourceMappingURL=get-storefront-client.d.ts.map
|
|
@@ -0,0 +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;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E;;OAEG;IACH,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,GAAG,gBAAgB,CAYlF"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server-side StorefrontClient factory — for Server Components, API routes, etc.
|
|
3
|
+
*
|
|
4
|
+
* Creates a StorefrontClient with default middleware pipeline,
|
|
5
|
+
* without requiring React context (no providers needed server-side).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* // lib/graphql/server.ts
|
|
10
|
+
* import { getStorefrontClient } from '@doswiftly/storefront-sdk/react/server';
|
|
11
|
+
*
|
|
12
|
+
* const client = getStorefrontClient({
|
|
13
|
+
* apiUrl: process.env.NEXT_PUBLIC_API_URL!,
|
|
14
|
+
* shopSlug: process.env.NEXT_PUBLIC_SHOP_SLUG!,
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* export const fetchProduct = cache(async (handle: string) => {
|
|
18
|
+
* return client.query(ProductDocument, { handle });
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import { createStorefrontClient } from '../../core/client/create-client';
|
|
23
|
+
import { retryMiddleware } from '../../core/middleware/retry';
|
|
24
|
+
import { timeoutMiddleware } from '../../core/middleware/timeout';
|
|
25
|
+
import { errorMiddleware } from '../../core/middleware/errors';
|
|
26
|
+
/**
|
|
27
|
+
* Create a StorefrontClient for server-side use.
|
|
28
|
+
*
|
|
29
|
+
* Includes default middleware: retry → timeout → errors.
|
|
30
|
+
* Does NOT include auth/currency middleware (server has no Zustand stores).
|
|
31
|
+
* Pass headers via config.defaultHeaders or getHeaders option.
|
|
32
|
+
*/
|
|
33
|
+
export function getStorefrontClient(options) {
|
|
34
|
+
const { middleware: customMiddleware = [], ...config } = options;
|
|
35
|
+
return createStorefrontClient({
|
|
36
|
+
...config,
|
|
37
|
+
middleware: [
|
|
38
|
+
...customMiddleware,
|
|
39
|
+
retryMiddleware({ maxRetries: 2 }),
|
|
40
|
+
timeoutMiddleware({ timeout: 10000 }), // Server-side: 10s timeout
|
|
41
|
+
errorMiddleware(),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,KAAK,mBAAmB,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getStorefrontClient } from './get-storefront-client';
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth store factory — localStorage persistence via Zustand persist.
|
|
3
|
+
*
|
|
4
|
+
* Creates a vanilla Zustand store (not a React hook singleton).
|
|
5
|
+
* Instance is created in StorefrontProvider via useRef and provided
|
|
6
|
+
* through React Context — eliminates module duplication in Turbopack.
|
|
7
|
+
*
|
|
8
|
+
* httpOnly cookie is managed separately (for SSR/middleware).
|
|
9
|
+
*/
|
|
10
|
+
export interface CustomerInfo {
|
|
11
|
+
id: string;
|
|
12
|
+
email: string;
|
|
13
|
+
firstName?: string;
|
|
14
|
+
lastName?: string;
|
|
15
|
+
phone?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface AuthStore {
|
|
18
|
+
customer: CustomerInfo | null;
|
|
19
|
+
accessToken: string | null;
|
|
20
|
+
isAuthenticated: boolean;
|
|
21
|
+
isLoading: boolean;
|
|
22
|
+
setAuth: (customer: CustomerInfo, accessToken: string) => void;
|
|
23
|
+
clearAuth: () => void;
|
|
24
|
+
updateCustomer: (updates: Partial<CustomerInfo>) => void;
|
|
25
|
+
setLoading: (isLoading: boolean) => void;
|
|
26
|
+
}
|
|
27
|
+
export declare const createAuthStore: (initialIsAuthenticated?: boolean) => Omit<import("zustand").StoreApi<AuthStore>, "setState" | "persist"> & {
|
|
28
|
+
setState(partial: AuthStore | Partial<AuthStore> | ((state: AuthStore) => AuthStore | Partial<AuthStore>), replace?: false | undefined): unknown;
|
|
29
|
+
setState(state: AuthStore | ((state: AuthStore) => AuthStore), replace: true): unknown;
|
|
30
|
+
persist: {
|
|
31
|
+
setOptions: (options: Partial<import("zustand/middleware").PersistOptions<AuthStore, {
|
|
32
|
+
customer: CustomerInfo | null;
|
|
33
|
+
accessToken: string | null;
|
|
34
|
+
isAuthenticated: boolean;
|
|
35
|
+
}, unknown>>) => void;
|
|
36
|
+
clearStorage: () => void;
|
|
37
|
+
rehydrate: () => Promise<void> | void;
|
|
38
|
+
hasHydrated: () => boolean;
|
|
39
|
+
onHydrate: (fn: (state: AuthStore) => void) => () => void;
|
|
40
|
+
onFinishHydration: (fn: (state: AuthStore) => void) => () => void;
|
|
41
|
+
getOptions: () => Partial<import("zustand/middleware").PersistOptions<AuthStore, {
|
|
42
|
+
customer: CustomerInfo | null;
|
|
43
|
+
accessToken: string | null;
|
|
44
|
+
isAuthenticated: boolean;
|
|
45
|
+
}, unknown>>;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=auth.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.store.d.ts","sourceRoot":"","sources":["../../../src/react/stores/auth.store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IAExB,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,eAAe,EAAE,OAAO,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IAGnB,OAAO,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/D,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACzD,UAAU,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;CAC1C;AAED,eAAO,MAAM,eAAe,GAAI,gCAA8B;;;;;sBA+DtC,YAAY,GAAG,IAAI;yBAChB,MAAM,GAAG,IAAI;6BACT,OAAO;;;;;;;;sBAFd,YAAY,GAAG,IAAI;yBAChB,MAAM,GAAG,IAAI;6BACT,OAAO;;;CAWnC,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth store factory — localStorage persistence via Zustand persist.
|
|
3
|
+
*
|
|
4
|
+
* Creates a vanilla Zustand store (not a React hook singleton).
|
|
5
|
+
* Instance is created in StorefrontProvider via useRef and provided
|
|
6
|
+
* through React Context — eliminates module duplication in Turbopack.
|
|
7
|
+
*
|
|
8
|
+
* httpOnly cookie is managed separately (for SSR/middleware).
|
|
9
|
+
*/
|
|
10
|
+
import { createStore } from 'zustand/vanilla';
|
|
11
|
+
import { persist } from 'zustand/middleware';
|
|
12
|
+
export const createAuthStore = (initialIsAuthenticated = false) => createStore()(persist((set) => ({
|
|
13
|
+
customer: null,
|
|
14
|
+
accessToken: null,
|
|
15
|
+
isAuthenticated: initialIsAuthenticated,
|
|
16
|
+
isLoading: false,
|
|
17
|
+
setAuth: (customer, accessToken) => set({
|
|
18
|
+
customer,
|
|
19
|
+
accessToken,
|
|
20
|
+
isAuthenticated: true,
|
|
21
|
+
}),
|
|
22
|
+
clearAuth: () => set({
|
|
23
|
+
customer: null,
|
|
24
|
+
accessToken: null,
|
|
25
|
+
isAuthenticated: false,
|
|
26
|
+
}),
|
|
27
|
+
updateCustomer: (updates) => set((state) => ({
|
|
28
|
+
customer: state.customer
|
|
29
|
+
? { ...state.customer, ...updates }
|
|
30
|
+
: null,
|
|
31
|
+
})),
|
|
32
|
+
setLoading: (isLoading) => set({ isLoading }),
|
|
33
|
+
}), {
|
|
34
|
+
name: 'auth-storage',
|
|
35
|
+
version: 2, // Invalidate stale data from old module-level store era
|
|
36
|
+
partialize: (state) => ({
|
|
37
|
+
customer: state.customer,
|
|
38
|
+
accessToken: state.accessToken,
|
|
39
|
+
isAuthenticated: state.isAuthenticated,
|
|
40
|
+
}),
|
|
41
|
+
/**
|
|
42
|
+
* Custom merge — server cookie check (initialIsAuthenticated) is authoritative
|
|
43
|
+
* for isAuthenticated. localStorage provides supplementary data (customer, token).
|
|
44
|
+
*
|
|
45
|
+
* This prevents stale localStorage from overwriting the server-provided auth state.
|
|
46
|
+
*/
|
|
47
|
+
merge: (persistedState, currentState) => {
|
|
48
|
+
const persisted = persistedState;
|
|
49
|
+
if (!persisted)
|
|
50
|
+
return currentState;
|
|
51
|
+
return {
|
|
52
|
+
...currentState,
|
|
53
|
+
customer: persisted.customer ?? currentState.customer,
|
|
54
|
+
accessToken: persisted.accessToken ?? currentState.accessToken,
|
|
55
|
+
// Server cookie is the authority — never let stale localStorage override it
|
|
56
|
+
isAuthenticated: currentState.isAuthenticated,
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
migrate: (persistedState, version) => {
|
|
60
|
+
if (version < 2) {
|
|
61
|
+
// Data from old module-level store may be unreliable (Turbopack duplication)
|
|
62
|
+
// Clear it — user will re-authenticate via cookie or login
|
|
63
|
+
return { customer: null, accessToken: null, isAuthenticated: false };
|
|
64
|
+
}
|
|
65
|
+
return persistedState;
|
|
66
|
+
},
|
|
67
|
+
}));
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Currency store factory — cookie persistence (SSR-safe).
|
|
3
|
+
*
|
|
4
|
+
* Creates a vanilla Zustand store (not a React hook singleton).
|
|
5
|
+
* Instance is created in StorefrontProvider via useRef and provided
|
|
6
|
+
* through React Context — eliminates module duplication in Turbopack.
|
|
7
|
+
*/
|
|
8
|
+
export interface ShopCurrencyData {
|
|
9
|
+
currencyCode: string;
|
|
10
|
+
supportedCurrencies: string[];
|
|
11
|
+
localeToCurrencyMap?: Array<{
|
|
12
|
+
locale: string;
|
|
13
|
+
currency: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
export interface CurrencyStore {
|
|
17
|
+
baseCurrency: string | null;
|
|
18
|
+
supportedCurrencies: string[];
|
|
19
|
+
currency: string | null;
|
|
20
|
+
isLoaded: boolean;
|
|
21
|
+
initialize: (shopData: ShopCurrencyData) => void;
|
|
22
|
+
setCurrency: (currency: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export declare const createCurrencyStore: () => import("zustand").StoreApi<CurrencyStore>;
|
|
25
|
+
export declare const selectCurrency: (state: CurrencyStore) => string | null;
|
|
26
|
+
export declare const selectBaseCurrency: (state: CurrencyStore) => string | null;
|
|
27
|
+
export declare const selectSupportedCurrencies: (state: CurrencyStore) => string[];
|
|
28
|
+
export declare const selectIsLoaded: (state: CurrencyStore) => boolean;
|
|
29
|
+
//# sourceMappingURL=currency.store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency.store.d.ts","sourceRoot":"","sources":["../../../src/react/stores/currency.store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,mBAAmB,CAAC,EAAE,KAAK,CAAC;QAC1B,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,aAAa;IAE5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAGlB,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACjD,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAqBD,eAAO,MAAM,mBAAmB,iDAqD3B,CAAC;AAMN,eAAO,MAAM,cAAc,GAAI,OAAO,aAAa,kBAAmB,CAAC;AACvE,eAAO,MAAM,kBAAkB,GAAI,OAAO,aAAa,kBAAuB,CAAC;AAC/E,eAAO,MAAM,yBAAyB,GAAI,OAAO,aAAa,aAA8B,CAAC;AAC7F,eAAO,MAAM,cAAc,GAAI,OAAO,aAAa,YAAmB,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Currency store factory — cookie persistence (SSR-safe).
|
|
3
|
+
*
|
|
4
|
+
* Creates a vanilla Zustand store (not a React hook singleton).
|
|
5
|
+
* Instance is created in StorefrontProvider via useRef and provided
|
|
6
|
+
* through React Context — eliminates module duplication in Turbopack.
|
|
7
|
+
*/
|
|
8
|
+
import { createStore } from 'zustand/vanilla';
|
|
9
|
+
/**
|
|
10
|
+
* Get currency from cookie (client-side).
|
|
11
|
+
*/
|
|
12
|
+
function getCurrencyFromCookie() {
|
|
13
|
+
if (typeof document === 'undefined')
|
|
14
|
+
return null;
|
|
15
|
+
const match = document.cookie.match(/(?:^|;\s*)preferred-currency=([^;]*)/);
|
|
16
|
+
return match ? decodeURIComponent(match[1]) : null;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Set currency in cookie (client-side).
|
|
20
|
+
*/
|
|
21
|
+
function setCurrencyCookie(currency) {
|
|
22
|
+
if (typeof document === 'undefined')
|
|
23
|
+
return;
|
|
24
|
+
const maxAge = 365 * 24 * 60 * 60; // 1 year
|
|
25
|
+
const secure = typeof location !== 'undefined' && location.protocol === 'https:' ? ';secure' : '';
|
|
26
|
+
document.cookie = `preferred-currency=${encodeURIComponent(currency)};max-age=${maxAge};path=/;samesite=lax${secure}`;
|
|
27
|
+
}
|
|
28
|
+
export const createCurrencyStore = () => createStore()((set, get) => ({
|
|
29
|
+
baseCurrency: null,
|
|
30
|
+
supportedCurrencies: [],
|
|
31
|
+
currency: null,
|
|
32
|
+
isLoaded: false,
|
|
33
|
+
initialize: (shopData) => {
|
|
34
|
+
// 1. Try saved currency from cookie (SSR-safe)
|
|
35
|
+
const saved = getCurrencyFromCookie();
|
|
36
|
+
// 2. Try to detect from browser locale
|
|
37
|
+
let detected;
|
|
38
|
+
if (shopData.localeToCurrencyMap && typeof navigator !== 'undefined') {
|
|
39
|
+
const browserLocale = navigator.language;
|
|
40
|
+
const match = shopData.localeToCurrencyMap.find((m) => m.locale === browserLocale);
|
|
41
|
+
detected = match?.currency;
|
|
42
|
+
}
|
|
43
|
+
// 3. Determine final currency (priority: saved > detected > base)
|
|
44
|
+
const finalCurrency = saved && shopData.supportedCurrencies.includes(saved)
|
|
45
|
+
? saved
|
|
46
|
+
: detected && shopData.supportedCurrencies.includes(detected)
|
|
47
|
+
? detected
|
|
48
|
+
: shopData.currencyCode;
|
|
49
|
+
set({
|
|
50
|
+
baseCurrency: shopData.currencyCode,
|
|
51
|
+
supportedCurrencies: shopData.supportedCurrencies,
|
|
52
|
+
currency: finalCurrency,
|
|
53
|
+
isLoaded: true,
|
|
54
|
+
});
|
|
55
|
+
// Ensure cookie is set if we determined a currency
|
|
56
|
+
if (finalCurrency && !saved) {
|
|
57
|
+
setCurrencyCookie(finalCurrency);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
setCurrency: (currency) => {
|
|
61
|
+
const { supportedCurrencies } = get();
|
|
62
|
+
if (!supportedCurrencies.includes(currency)) {
|
|
63
|
+
console.warn(`[CurrencyStore] Currency ${currency} not supported`);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
set({ currency });
|
|
67
|
+
setCurrencyCookie(currency);
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Selectors (for use with useCurrencyStore(selector))
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
export const selectCurrency = (state) => state.currency;
|
|
74
|
+
export const selectBaseCurrency = (state) => state.baseCurrency;
|
|
75
|
+
export const selectSupportedCurrencies = (state) => state.supportedCurrencies;
|
|
76
|
+
export const selectIsLoaded = (state) => state.isLoaded;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zustand stores — factory functions + context hooks.
|
|
3
|
+
*/
|
|
4
|
+
export { createAuthStore, type AuthStore, type CustomerInfo } from './auth.store';
|
|
5
|
+
export { createCurrencyStore, type CurrencyStore, type ShopCurrencyData } from './currency.store';
|
|
6
|
+
export { selectCurrency, selectBaseCurrency, selectSupportedCurrencies, selectIsLoaded } from './currency.store';
|
|
7
|
+
export { useAuthStore, useAuthStoreApi, useAuthHydrated, useCurrencyStore, useCurrencyStoreApi, AuthStoreContext, CurrencyStoreContext, } from './store-context';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/react/stores/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGlG,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGjH,OAAO,EACL,YAAY,EAAE,eAAe,EAAE,eAAe,EAC9C,gBAAgB,EAAE,mBAAmB,EACrC,gBAAgB,EAAE,oBAAoB,GACvC,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zustand stores — factory functions + context hooks.
|
|
3
|
+
*/
|
|
4
|
+
// Factory functions
|
|
5
|
+
export { createAuthStore } from './auth.store';
|
|
6
|
+
export { createCurrencyStore } from './currency.store';
|
|
7
|
+
// Selectors
|
|
8
|
+
export { selectCurrency, selectBaseCurrency, selectSupportedCurrencies, selectIsLoaded } from './currency.store';
|
|
9
|
+
// Context hooks
|
|
10
|
+
export { useAuthStore, useAuthStoreApi, useAuthHydrated, useCurrencyStore, useCurrencyStoreApi, AuthStoreContext, CurrencyStoreContext, } from './store-context';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store Context — React Context + hooks for Zustand vanilla stores.
|
|
3
|
+
*
|
|
4
|
+
* This is the SINGLE source for useAuthStore and useCurrencyStore hooks.
|
|
5
|
+
* Stores are created in StorefrontProvider (useRef) and provided via Context.
|
|
6
|
+
* This eliminates module-level singletons and Turbopack duplication bugs.
|
|
7
|
+
*
|
|
8
|
+
* useAuthHydrated() replaces the old isHydrated store field — tracks
|
|
9
|
+
* Zustand persist rehydration via React lifecycle (not module-level code).
|
|
10
|
+
*/
|
|
11
|
+
import { type StoreApi } from 'zustand';
|
|
12
|
+
import type { AuthStore } from './auth.store';
|
|
13
|
+
import type { CurrencyStore } from './currency.store';
|
|
14
|
+
export declare const AuthStoreContext: import("react").Context<StoreApi<AuthStore> | null>;
|
|
15
|
+
export declare const CurrencyStoreContext: import("react").Context<StoreApi<CurrencyStore> | null>;
|
|
16
|
+
export declare function useAuthStore(): AuthStore;
|
|
17
|
+
export declare function useAuthStore<T>(selector: (s: AuthStore) => T): T;
|
|
18
|
+
export declare function useAuthStoreApi(): StoreApi<AuthStore>;
|
|
19
|
+
/**
|
|
20
|
+
* Tracks persist hydration state via React lifecycle (not module-level).
|
|
21
|
+
* Returns `true` once Zustand persist has finished rehydrating from localStorage.
|
|
22
|
+
*/
|
|
23
|
+
export declare function useAuthHydrated(): boolean;
|
|
24
|
+
export declare function useCurrencyStore(): CurrencyStore;
|
|
25
|
+
export declare function useCurrencyStore<T>(selector: (s: CurrencyStore) => T): T;
|
|
26
|
+
export declare function useCurrencyStoreApi(): StoreApi<CurrencyStore>;
|
|
27
|
+
//# sourceMappingURL=store-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-context.d.ts","sourceRoot":"","sources":["../../../src/react/stores/store-context.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMtD,eAAO,MAAM,gBAAgB,qDAAkD,CAAC;AAChF,eAAO,MAAM,oBAAoB,yDAAsD,CAAC;AAMxF,wBAAgB,YAAY,IAAI,SAAS,CAAC;AAC1C,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,SAAS,KAAK,CAAC,GAAG,CAAC,CAAC;AAQlE,wBAAgB,eAAe,IAAI,QAAQ,CAAC,SAAS,CAAC,CAIrD;AAED;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAczC;AAMD,wBAAgB,gBAAgB,IAAI,aAAa,CAAC;AAClD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,EAAE,aAAa,KAAK,CAAC,GAAG,CAAC,CAAC;AAQ1E,wBAAgB,mBAAmB,IAAI,QAAQ,CAAC,aAAa,CAAC,CAI7D"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Store Context — React Context + hooks for Zustand vanilla stores.
|
|
3
|
+
*
|
|
4
|
+
* This is the SINGLE source for useAuthStore and useCurrencyStore hooks.
|
|
5
|
+
* Stores are created in StorefrontProvider (useRef) and provided via Context.
|
|
6
|
+
* This eliminates module-level singletons and Turbopack duplication bugs.
|
|
7
|
+
*
|
|
8
|
+
* useAuthHydrated() replaces the old isHydrated store field — tracks
|
|
9
|
+
* Zustand persist rehydration via React lifecycle (not module-level code).
|
|
10
|
+
*/
|
|
11
|
+
'use client';
|
|
12
|
+
import { createContext, useContext, useState, useEffect } from 'react';
|
|
13
|
+
import { useStore } from 'zustand';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Contexts
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
export const AuthStoreContext = createContext(null);
|
|
18
|
+
export const CurrencyStoreContext = createContext(null);
|
|
19
|
+
export function useAuthStore(selector) {
|
|
20
|
+
const store = useContext(AuthStoreContext);
|
|
21
|
+
if (!store)
|
|
22
|
+
throw new Error('useAuthStore must be used within StorefrontProvider');
|
|
23
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
24
|
+
return selector ? useStore(store, selector) : useStore(store);
|
|
25
|
+
}
|
|
26
|
+
export function useAuthStoreApi() {
|
|
27
|
+
const store = useContext(AuthStoreContext);
|
|
28
|
+
if (!store)
|
|
29
|
+
throw new Error('useAuthStoreApi must be used within StorefrontProvider');
|
|
30
|
+
return store;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Tracks persist hydration state via React lifecycle (not module-level).
|
|
34
|
+
* Returns `true` once Zustand persist has finished rehydrating from localStorage.
|
|
35
|
+
*/
|
|
36
|
+
export function useAuthHydrated() {
|
|
37
|
+
const store = useAuthStoreApi();
|
|
38
|
+
const [hydrated, setHydrated] = useState(false);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const persistApi = store.persist;
|
|
41
|
+
// Subscribe to future hydration completions
|
|
42
|
+
const unsubFinish = persistApi.onFinishHydration(() => setHydrated(true));
|
|
43
|
+
// Check if hydration already completed before effect ran
|
|
44
|
+
if (persistApi.hasHydrated())
|
|
45
|
+
setHydrated(true);
|
|
46
|
+
return unsubFinish;
|
|
47
|
+
}, [store]);
|
|
48
|
+
return hydrated;
|
|
49
|
+
}
|
|
50
|
+
export function useCurrencyStore(selector) {
|
|
51
|
+
const store = useContext(CurrencyStoreContext);
|
|
52
|
+
if (!store)
|
|
53
|
+
throw new Error('useCurrencyStore must be used within StorefrontProvider');
|
|
54
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
55
|
+
return selector ? useStore(store, selector) : useStore(store);
|
|
56
|
+
}
|
|
57
|
+
export function useCurrencyStoreApi() {
|
|
58
|
+
const store = useContext(CurrencyStoreContext);
|
|
59
|
+
if (!store)
|
|
60
|
+
throw new Error('useCurrencyStoreApi must be used within StorefrontProvider');
|
|
61
|
+
return store;
|
|
62
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@doswiftly/storefront-sdk",
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Storefront runtime SDK for DoSwiftly Commerce — layered transport, middleware pipeline, React providers, Zustand stores, cache strategies. 0 runtime dependencies in core.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"types": "dist/core/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/core/index.d.ts",
|
|
10
|
+
"default": "./dist/core/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./react": {
|
|
13
|
+
"types": "./dist/react/index.d.ts",
|
|
14
|
+
"default": "./dist/react/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./react/server": {
|
|
17
|
+
"types": "./dist/react/server/index.d.ts",
|
|
18
|
+
"default": "./dist/react/server/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./cache": {
|
|
21
|
+
"types": "./dist/core/cache.d.ts",
|
|
22
|
+
"default": "./dist/core/cache.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"build:only": "tsc",
|
|
28
|
+
"dev": "tsc --watch",
|
|
29
|
+
"clean": "rm -rf dist",
|
|
30
|
+
"test": "vitest run",
|
|
31
|
+
"test:watch": "vitest",
|
|
32
|
+
"test:unit": "vitest run src/__tests__/unit/",
|
|
33
|
+
"test:contract": "vitest run src/__tests__/contract/"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"sdk",
|
|
37
|
+
"typescript",
|
|
38
|
+
"storefront",
|
|
39
|
+
"ecommerce",
|
|
40
|
+
"graphql",
|
|
41
|
+
"react",
|
|
42
|
+
"zustand",
|
|
43
|
+
"middleware",
|
|
44
|
+
"hydrogen"
|
|
45
|
+
],
|
|
46
|
+
"author": "DoSwiftly Team",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"dependencies": {},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.10.2",
|
|
51
|
+
"@types/react": "^18.3.0 || ^19.0.0",
|
|
52
|
+
"fast-check": "^3.23.2",
|
|
53
|
+
"next": "^15.0.0",
|
|
54
|
+
"typescript": "^5.7.2",
|
|
55
|
+
"vitest": "^2.1.8",
|
|
56
|
+
"zustand": "^5.0.2",
|
|
57
|
+
"react": "^19.0.0"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
61
|
+
"zustand": "^5.0.0"
|
|
62
|
+
},
|
|
63
|
+
"peerDependenciesMeta": {
|
|
64
|
+
"react": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"zustand": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|