@doswiftly/cli 0.1.18 → 0.1.20
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 +23 -323
- package/dist/commands/check.js +1 -1
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/deploy.d.ts +20 -0
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +249 -17
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.js +3 -3
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +4 -4
- package/dist/commands/sdk.js +5 -5
- package/dist/commands/sdk.js.map +1 -1
- package/dist/commands/template.js +4 -4
- package/dist/commands/template.js.map +1 -1
- package/dist/commands/types.js +5 -5
- package/dist/commands/types.js.map +1 -1
- package/dist/commands/verify.js +2 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/lib/package-manager.d.ts +1 -1
- package/dist/lib/package-manager.js +1 -1
- package/package.json +4 -4
- package/templates/storefront-minimal/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-minimal/wrangler.toml +11 -0
- package/templates/storefront-nextjs/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-nextjs/README.md +16 -12
- package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
- package/templates/storefront-nextjs/app/account/page.tsx +2 -2
- package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
- package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
- package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
- package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
- package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
- package/templates/storefront-nextjs/app/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
- package/templates/storefront-nextjs/app/products/page.tsx +2 -2
- package/templates/storefront-nextjs/app/search/page.tsx +1 -1
- package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
- package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
- package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
- package/templates/storefront-nextjs/components/providers.tsx +1 -1
- package/templates/storefront-nextjs/lib/currency.tsx +3 -3
- package/templates/storefront-nextjs/lib/format.ts +1 -1
- package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
- package/templates/storefront-nextjs/package.dev.json +1 -1
- package/templates/storefront-nextjs/package.json +1 -1
- package/templates/storefront-nextjs/package.json.template +1 -1
- package/templates/storefront-nextjs/wrangler.toml +11 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/build-template.yml +10 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
- package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
- package/templates/storefront-nextjs-shadcn/CLAUDE.md +172 -35
- package/templates/storefront-nextjs-shadcn/README.md +29 -162
- package/templates/storefront-nextjs-shadcn/app/{about → [locale]/about}/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/addresses/page.tsx +226 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/error.tsx +46 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/loyalty/page.tsx +89 -193
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/loading.tsx +60 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/[id]/page.tsx +119 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/orders/[id]/tracking/page.tsx +27 -25
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/orders/page.tsx +101 -0
- package/templates/storefront-nextjs-shadcn/app/{account → [locale]/account}/page.tsx +9 -7
- package/templates/storefront-nextjs-shadcn/app/[locale]/account/settings/page.tsx +208 -0
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/forgot-password/page.tsx +24 -17
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/login/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/{auth → [locale]/auth}/register/page.tsx +5 -2
- package/templates/storefront-nextjs-shadcn/app/[locale]/blog/[slug]/loading.tsx +17 -0
- package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/[slug]/page.tsx +44 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/blog/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/page.tsx +2 -1
- package/templates/storefront-nextjs-shadcn/app/[locale]/cart/loading.tsx +26 -0
- package/templates/storefront-nextjs-shadcn/app/{cart → [locale]/cart}/page.tsx +20 -13
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/category-products-client.tsx +58 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/categories/[slug]/page.tsx +95 -0
- package/templates/storefront-nextjs-shadcn/app/{categories → [locale]/categories}/page.tsx +21 -12
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/checkout/loading.tsx +31 -0
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/page.tsx +334 -253
- package/templates/storefront-nextjs-shadcn/app/{checkout → [locale]/checkout}/success/[orderId]/page.tsx +36 -34
- package/templates/storefront-nextjs-shadcn/app/[locale]/collections/[handle]/loading.tsx +19 -0
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/[handle]/page.tsx +6 -4
- package/templates/storefront-nextjs-shadcn/app/[locale]/collections/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/{collections → [locale]/collections}/page.tsx +20 -12
- package/templates/storefront-nextjs-shadcn/app/{contact → [locale]/contact}/page.tsx +24 -21
- package/templates/storefront-nextjs-shadcn/app/{error.tsx → [locale]/error.tsx} +13 -8
- package/templates/storefront-nextjs-shadcn/app/[locale]/layout.tsx +92 -0
- package/templates/storefront-nextjs-shadcn/app/{not-found.tsx → [locale]/not-found.tsx} +13 -18
- package/templates/storefront-nextjs-shadcn/app/{page.tsx → [locale]/page.tsx} +8 -4
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/error.tsx +43 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/[slug]/loading.tsx +29 -0
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/page.tsx +17 -14
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/[slug]/product-client.tsx +18 -62
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/loading.tsx +32 -0
- package/templates/storefront-nextjs-shadcn/app/{products → [locale]/products}/page.tsx +6 -3
- package/templates/storefront-nextjs-shadcn/app/[locale]/products/products-client.tsx +450 -0
- package/templates/storefront-nextjs-shadcn/app/[locale]/search/loading.tsx +18 -0
- package/templates/storefront-nextjs-shadcn/app/{wishlist → [locale]/wishlist}/page.tsx +27 -28
- package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
- package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
- package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
- package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
- package/templates/storefront-nextjs-shadcn/app/layout.tsx +8 -35
- package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
- package/templates/storefront-nextjs-shadcn/components/account/address-form.tsx +25 -20
- package/templates/storefront-nextjs-shadcn/components/account/address-list.tsx +11 -10
- package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +17 -13
- package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +42 -30
- package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
- package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +18 -16
- package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +37 -58
- package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +85 -66
- package/templates/storefront-nextjs-shadcn/components/blog/blog-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/blog/blog-sidebar.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/brand/brand-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +10 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +8 -6
- package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
- package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/cart/promo-code-input.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +38 -20
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-method-card.tsx +15 -25
- package/templates/storefront-nextjs-shadcn/components/checkout/payment-step.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/checkout/tax-breakdown.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/pagination.tsx +8 -5
- package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +6 -4
- package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +10 -9
- package/templates/storefront-nextjs-shadcn/components/common/category-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/collection-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
- package/templates/storefront-nextjs-shadcn/components/common/social-share.tsx +9 -6
- package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +22 -12
- package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +18 -15
- package/templates/storefront-nextjs-shadcn/components/error/error-boundary.tsx +53 -28
- package/templates/storefront-nextjs-shadcn/components/filters/dynamic-attribute-filters.tsx +7 -5
- package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-balance.tsx +19 -15
- package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +13 -10
- package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +10 -6
- package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
- package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +3 -13
- package/templates/storefront-nextjs-shadcn/components/home/featured-products.tsx +12 -8
- package/templates/storefront-nextjs-shadcn/components/home/hero-section.tsx +13 -8
- package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
- package/templates/storefront-nextjs-shadcn/components/home/newsletter-signup.tsx +10 -8
- package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +41 -16
- package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
- package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/layout/footer.tsx +24 -23
- package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +52 -34
- package/templates/storefront-nextjs-shadcn/components/layout/language-switcher.tsx +54 -0
- package/templates/storefront-nextjs-shadcn/components/layout/mobile-menu.tsx +33 -30
- package/templates/storefront-nextjs-shadcn/components/layout/navigation.tsx +27 -24
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
- package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
- package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +32 -42
- package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
- package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
- package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
- package/templates/storefront-nextjs-shadcn/components/product/add-to-cart-button.tsx +6 -14
- package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +72 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +87 -0
- package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +140 -0
- package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +11 -37
- package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
- package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +179 -124
- package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
- package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +3 -7
- package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
- package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
- package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +44 -19
- package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
- package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
- package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +26 -34
- package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
- package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
- package/templates/storefront-nextjs-shadcn/components/providers/language-sync-provider.tsx +27 -0
- package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +63 -0
- package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
- package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
- package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +59 -72
- package/templates/storefront-nextjs-shadcn/components/search/search-bar.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
- package/templates/storefront-nextjs-shadcn/components/shipping/shipping-method-selector.tsx +12 -9
- package/templates/storefront-nextjs-shadcn/components/ui/empty-state.tsx +23 -12
- package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
- package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
- package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
- package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
- package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
- package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-button.tsx +7 -4
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +4 -2
- package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-item.tsx +2 -10
- package/templates/storefront-nextjs-shadcn/generated/graphql.ts +13387 -0
- package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
- package/templates/storefront-nextjs-shadcn/hooks/index.ts +3 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +34 -229
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-di.ts +67 -0
- package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +16 -12
- package/templates/storefront-nextjs-shadcn/i18n/navigation.ts +12 -0
- package/templates/storefront-nextjs-shadcn/i18n/request.ts +17 -0
- package/templates/storefront-nextjs-shadcn/i18n/routing.ts +17 -0
- package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
- package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
- package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +33 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +720 -632
- package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +88 -0
- package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +132 -182
- package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
- package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
- package/templates/storefront-nextjs-shadcn/messages/en.json +869 -0
- package/templates/storefront-nextjs-shadcn/messages/pl.json +869 -0
- package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/storefront-nextjs-shadcn/next.config.ts +6 -5
- package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
- package/templates/storefront-nextjs-shadcn/package.json +14 -14
- package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
- package/templates/storefront-nextjs-shadcn/proxy.ts +115 -47
- package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +24 -56
- package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
- package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
- package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
- package/templates/storefront-nextjs-shadcn/wrangler.toml +11 -0
- package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
- package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
- package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
- package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
- package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
- package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
- package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
- package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
- package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +0 -215
- package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +0 -128
- package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +0 -80
- package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +0 -171
- package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +0 -78
- package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +0 -192
- package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
- package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
- package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
- package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
- package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
- package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
- package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
- package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
- package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
- package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
- package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
- package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
- package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
- /package/templates/storefront-nextjs-shadcn/app/{blog → [locale]/blog}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{brands → [locale]/brands}/[slug]/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{returns → [locale]/returns}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/page.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{search → [locale]/search}/search-client.tsx +0 -0
- /package/templates/storefront-nextjs-shadcn/app/{shipping → [locale]/shipping}/page.tsx +0 -0
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cookie Helpers for Authentication
|
|
3
|
-
*
|
|
4
|
-
* Provides utilities for managing authentication cookies in both
|
|
5
|
-
* client-side and server-side contexts.
|
|
6
|
-
*
|
|
7
|
-
* Security Notes:
|
|
8
|
-
* - Cookies are httpOnly (set via API routes, not client-side)
|
|
9
|
-
* - Cookies are secure in production (HTTPS only)
|
|
10
|
-
* - Cookies are SameSite=Lax to prevent CSRF
|
|
11
|
-
* - Token validation happens on GraphQL backend
|
|
12
|
-
*
|
|
13
|
-
* @see lib/auth/routes.ts - Cookie name constant
|
|
14
|
-
* @see app/api/auth/set-token/route.ts - Server-side cookie setter
|
|
15
|
-
* @see app/api/auth/clear-token/route.ts - Server-side cookie clearer
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import { AUTH_COOKIE_NAME } from "./routes";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Cookie configuration for authentication token
|
|
22
|
-
*/
|
|
23
|
-
export const AUTH_COOKIE_CONFIG = {
|
|
24
|
-
name: AUTH_COOKIE_NAME,
|
|
25
|
-
maxAge: 60 * 60 * 24 * 30, // 30 days (in seconds)
|
|
26
|
-
path: "/",
|
|
27
|
-
sameSite: "lax" as const,
|
|
28
|
-
secure: process.env.NODE_ENV === "production",
|
|
29
|
-
httpOnly: true, // Cannot be accessed via JavaScript (security)
|
|
30
|
-
} as const;
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Get authentication token from cookies (client-side)
|
|
34
|
-
*
|
|
35
|
-
* Note: This only works if the cookie is NOT httpOnly.
|
|
36
|
-
* For httpOnly cookies, use server-side methods or API routes.
|
|
37
|
-
*
|
|
38
|
-
* @returns Token string or null if not found
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* ```tsx
|
|
42
|
-
* const token = getAuthToken();
|
|
43
|
-
* if (token) {
|
|
44
|
-
* // User is authenticated
|
|
45
|
-
* }
|
|
46
|
-
* ```
|
|
47
|
-
*/
|
|
48
|
-
export function getAuthToken(): string | null {
|
|
49
|
-
if (typeof window === "undefined") {
|
|
50
|
-
return null; // Server-side
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const cookies = document.cookie.split("; ");
|
|
54
|
-
const authCookie = cookies.find((c) => c.startsWith(`${AUTH_COOKIE_NAME}=`));
|
|
55
|
-
|
|
56
|
-
if (!authCookie) {
|
|
57
|
-
return null;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return authCookie.split("=")[1] || null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Check if user is authenticated (client-side)
|
|
65
|
-
*
|
|
66
|
-
* Note: This checks cookie EXISTENCE, not VALIDITY.
|
|
67
|
-
* Token validation happens on the GraphQL backend.
|
|
68
|
-
*
|
|
69
|
-
* @returns True if auth cookie exists
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```tsx
|
|
73
|
-
* const isAuthenticated = isAuthTokenPresent();
|
|
74
|
-
* if (isAuthenticated) {
|
|
75
|
-
* // Show authenticated UI
|
|
76
|
-
* }
|
|
77
|
-
* ```
|
|
78
|
-
*/
|
|
79
|
-
export function isAuthTokenPresent(): boolean {
|
|
80
|
-
return getAuthToken() !== null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Set authentication token (via API route)
|
|
85
|
-
*
|
|
86
|
-
* This function calls the API route to set an httpOnly cookie.
|
|
87
|
-
* Direct client-side cookie setting is NOT secure for auth tokens.
|
|
88
|
-
*
|
|
89
|
-
* @param token - Customer access token from GraphQL
|
|
90
|
-
* @returns Promise that resolves when cookie is set
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* ```tsx
|
|
94
|
-
* const { customerAccessToken } = await loginMutation.mutateAsync({
|
|
95
|
-
* input: { email, password }
|
|
96
|
-
* });
|
|
97
|
-
*
|
|
98
|
-
* if (customerAccessToken) {
|
|
99
|
-
* await setAuthToken(customerAccessToken.accessToken);
|
|
100
|
-
* }
|
|
101
|
-
* ```
|
|
102
|
-
*/
|
|
103
|
-
export async function setAuthToken(token: string): Promise<void> {
|
|
104
|
-
const response = await fetch("/api/auth/set-token", {
|
|
105
|
-
method: "POST",
|
|
106
|
-
headers: {
|
|
107
|
-
"Content-Type": "application/json",
|
|
108
|
-
},
|
|
109
|
-
body: JSON.stringify({ token }),
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
if (!response.ok) {
|
|
113
|
-
throw new Error("Failed to set authentication token");
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Clear authentication token (via API route)
|
|
119
|
-
*
|
|
120
|
-
* This function calls the API route to clear the httpOnly cookie.
|
|
121
|
-
*
|
|
122
|
-
* @returns Promise that resolves when cookie is cleared
|
|
123
|
-
*
|
|
124
|
-
* @example
|
|
125
|
-
* ```tsx
|
|
126
|
-
* await clearAuthToken();
|
|
127
|
-
* router.push('/auth/login');
|
|
128
|
-
* ```
|
|
129
|
-
*/
|
|
130
|
-
export async function clearAuthToken(): Promise<void> {
|
|
131
|
-
const response = await fetch("/api/auth/clear-token", {
|
|
132
|
-
method: "POST",
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
if (!response.ok) {
|
|
136
|
-
throw new Error("Failed to clear authentication token");
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Parse cookie string into key-value object
|
|
142
|
-
*
|
|
143
|
-
* Utility function for parsing cookie strings in server-side contexts.
|
|
144
|
-
*
|
|
145
|
-
* @param cookieString - Raw cookie string from request headers
|
|
146
|
-
* @returns Object with cookie key-value pairs
|
|
147
|
-
*
|
|
148
|
-
* @example
|
|
149
|
-
* ```tsx
|
|
150
|
-
* const cookies = parseCookies(request.headers.get('cookie') || '');
|
|
151
|
-
* const token = cookies[AUTH_COOKIE_NAME];
|
|
152
|
-
* ```
|
|
153
|
-
*/
|
|
154
|
-
export function parseCookies(cookieString: string): Record<string, string> {
|
|
155
|
-
return cookieString
|
|
156
|
-
.split("; ")
|
|
157
|
-
.reduce((acc, cookie) => {
|
|
158
|
-
const [key, value] = cookie.split("=");
|
|
159
|
-
if (key && value) {
|
|
160
|
-
acc[key] = value;
|
|
161
|
-
}
|
|
162
|
-
return acc;
|
|
163
|
-
}, {} as Record<string, string>);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Serialize cookie for Set-Cookie header
|
|
168
|
-
*
|
|
169
|
-
* Utility function for creating Set-Cookie header values in API routes.
|
|
170
|
-
*
|
|
171
|
-
* @param name - Cookie name
|
|
172
|
-
* @param value - Cookie value
|
|
173
|
-
* @param options - Cookie options (maxAge, path, etc.)
|
|
174
|
-
* @returns Serialized cookie string for Set-Cookie header
|
|
175
|
-
*
|
|
176
|
-
* @example
|
|
177
|
-
* ```tsx
|
|
178
|
-
* const cookieHeader = serializeCookie(
|
|
179
|
-
* AUTH_COOKIE_NAME,
|
|
180
|
-
* token,
|
|
181
|
-
* AUTH_COOKIE_CONFIG
|
|
182
|
-
* );
|
|
183
|
-
* response.headers.set('Set-Cookie', cookieHeader);
|
|
184
|
-
* ```
|
|
185
|
-
*/
|
|
186
|
-
export function serializeCookie(
|
|
187
|
-
name: string,
|
|
188
|
-
value: string,
|
|
189
|
-
options: {
|
|
190
|
-
maxAge?: number;
|
|
191
|
-
path?: string;
|
|
192
|
-
sameSite?: "strict" | "lax" | "none";
|
|
193
|
-
secure?: boolean;
|
|
194
|
-
httpOnly?: boolean;
|
|
195
|
-
} = {}
|
|
196
|
-
): string {
|
|
197
|
-
const parts = [`${name}=${value}`];
|
|
198
|
-
|
|
199
|
-
if (options.maxAge) {
|
|
200
|
-
parts.push(`Max-Age=${options.maxAge}`);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (options.path) {
|
|
204
|
-
parts.push(`Path=${options.path}`);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (options.sameSite) {
|
|
208
|
-
parts.push(`SameSite=${options.sameSite}`);
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (options.secure) {
|
|
212
|
-
parts.push("Secure");
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (options.httpOnly) {
|
|
216
|
-
parts.push("HttpOnly");
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return parts.join("; ");
|
|
220
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shop Configuration
|
|
3
|
-
*
|
|
4
|
-
* Centralized configuration for shop settings.
|
|
5
|
-
* Customize these values to match your store's policies.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export const shopConfig = {
|
|
9
|
-
/**
|
|
10
|
-
* Currency settings
|
|
11
|
-
*/
|
|
12
|
-
currency: {
|
|
13
|
-
default: 'USD',
|
|
14
|
-
supported: ['USD', 'EUR', 'GBP', 'PLN'],
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Shipping policy settings
|
|
19
|
-
*/
|
|
20
|
-
shipping: {
|
|
21
|
-
freeShippingThreshold: 50,
|
|
22
|
-
standardDeliveryDays: { min: 3, max: 5 },
|
|
23
|
-
features: [
|
|
24
|
-
'Express shipping available at checkout',
|
|
25
|
-
'International shipping available',
|
|
26
|
-
'30-day return policy',
|
|
27
|
-
],
|
|
28
|
-
},
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Product display settings
|
|
32
|
-
*/
|
|
33
|
-
products: {
|
|
34
|
-
gridColumns: 4,
|
|
35
|
-
itemsPerPage: 12,
|
|
36
|
-
},
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Cart settings
|
|
40
|
-
*/
|
|
41
|
-
cart: {
|
|
42
|
-
maxQuantityPerItem: 99,
|
|
43
|
-
},
|
|
44
|
-
} as const;
|
|
45
|
-
|
|
46
|
-
export type ShopConfig = typeof shopConfig;
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
# Cookie Manager Implementation Summary
|
|
2
|
-
|
|
3
|
-
## ✅ Completed
|
|
4
|
-
|
|
5
|
-
### Main Deliverables
|
|
6
|
-
|
|
7
|
-
1. **Cookie Manager Module** (`lib/currency/cookie-manager.ts`)
|
|
8
|
-
|
|
9
|
-
- Full TypeScript implementation with complete type safety
|
|
10
|
-
- Dual implementation for SSR and client contexts
|
|
11
|
-
- Comprehensive error handling with graceful fallbacks
|
|
12
|
-
- Singleton pattern for performance optimization
|
|
13
|
-
- ~270 lines of production-ready code
|
|
14
|
-
|
|
15
|
-
2. **Module Exports** (`lib/currency/index.ts`)
|
|
16
|
-
|
|
17
|
-
- Clean public API with barrel exports
|
|
18
|
-
- Convenience functions for common operations
|
|
19
|
-
- Type-safe exports for TypeScript consumers
|
|
20
|
-
|
|
21
|
-
3. **Unit Tests** (`lib/currency/cookie-manager.test.ts`)
|
|
22
|
-
|
|
23
|
-
- 20+ test cases covering all functionality
|
|
24
|
-
- Tests for both SSR and client contexts
|
|
25
|
-
- Error handling and edge case coverage
|
|
26
|
-
- Vitest-compatible test suite
|
|
27
|
-
- ~380 lines of test code
|
|
28
|
-
|
|
29
|
-
4. **Documentation** (`lib/currency/README.md`)
|
|
30
|
-
- Complete API reference
|
|
31
|
-
- Usage patterns and examples
|
|
32
|
-
- Integration guides for Zustand, GraphQL, React
|
|
33
|
-
- Migration guide from localStorage
|
|
34
|
-
- Troubleshooting section
|
|
35
|
-
- ~500 lines of documentation
|
|
36
|
-
|
|
37
|
-
## Key Features Implemented
|
|
38
|
-
|
|
39
|
-
### 1. SSR-First Architecture
|
|
40
|
-
|
|
41
|
-
The cookie manager works seamlessly in both contexts:
|
|
42
|
-
|
|
43
|
-
```typescript
|
|
44
|
-
// Client-side: Uses js-cookie
|
|
45
|
-
const clientManager = new ClientCookieManager();
|
|
46
|
-
|
|
47
|
-
// Server-side: Uses next/headers
|
|
48
|
-
const serverManager = new ServerCookieManager();
|
|
49
|
-
|
|
50
|
-
// Automatic detection
|
|
51
|
-
const manager = getCookieManager(); // Returns correct implementation
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
### 2. Type Safety
|
|
55
|
-
|
|
56
|
-
Full TypeScript support with strict types:
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
export interface CookieManager {
|
|
60
|
-
getCurrency(): string | null;
|
|
61
|
-
setCurrency(currency: string): void;
|
|
62
|
-
removeCurrency(): void;
|
|
63
|
-
isServer(): boolean;
|
|
64
|
-
}
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### 3. Error Handling
|
|
68
|
-
|
|
69
|
-
Graceful fallbacks for all error scenarios:
|
|
70
|
-
|
|
71
|
-
- ✅ Blocked cookies → logs warning, continues
|
|
72
|
-
- ✅ SSR write attempts → logs warning, no-op
|
|
73
|
-
- ✅ Missing Next.js headers → returns null
|
|
74
|
-
- ✅ Cookie read failures → returns null with warning
|
|
75
|
-
|
|
76
|
-
### 4. Cookie Configuration
|
|
77
|
-
|
|
78
|
-
Production-ready cookie attributes:
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
{
|
|
82
|
-
name: 'preferred-currency',
|
|
83
|
-
path: '/',
|
|
84
|
-
maxAge: 365 days,
|
|
85
|
-
sameSite: 'lax',
|
|
86
|
-
secure: true (in production)
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Architecture Diagram
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
94
|
-
│ Cookie Manager │
|
|
95
|
-
├─────────────────────────────────────────────────────────────┤
|
|
96
|
-
│ │
|
|
97
|
-
│ ┌──────────────────┐ ┌──────────────────┐ │
|
|
98
|
-
│ │ Client Context │ │ Server Context │ │
|
|
99
|
-
│ │ │ │ │ │
|
|
100
|
-
│ │ - js-cookie │ │ - next/headers │ │
|
|
101
|
-
│ │ - getCurrency() │ │ - getCurrency() │ │
|
|
102
|
-
│ │ - setCurrency() │ │ - (read-only) │ │
|
|
103
|
-
│ │ - remove() │ │ │ │
|
|
104
|
-
│ └──────────────────┘ └──────────────────┘ │
|
|
105
|
-
│ │ │ │
|
|
106
|
-
│ └────────────┬───────────────┘ │
|
|
107
|
-
│ │ │
|
|
108
|
-
│ ┌──────▼──────┐ │
|
|
109
|
-
│ │ Singleton │ │
|
|
110
|
-
│ │ Factory │ │
|
|
111
|
-
│ └─────────────┘ │
|
|
112
|
-
└─────────────────────────────────────────────────────────────┘
|
|
113
|
-
│
|
|
114
|
-
│
|
|
115
|
-
┌──────────────┴──────────────┐
|
|
116
|
-
│ │
|
|
117
|
-
┌──────▼─────┐ ┌──────▼─────┐
|
|
118
|
-
│ Currency │ │ GraphQL │
|
|
119
|
-
│ Store │ │ Client │
|
|
120
|
-
│ (Zustand) │ │ │
|
|
121
|
-
└────────────┘ └────────────┘
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Requirements Validation
|
|
125
|
-
|
|
126
|
-
### ✅ Requirement 1.1
|
|
127
|
-
|
|
128
|
-
_Store preference in cookie accessible to both client and server_
|
|
129
|
-
|
|
130
|
-
- Implemented: Cookie with path='/' and HttpOnly=false
|
|
131
|
-
|
|
132
|
-
### ✅ Requirement 1.3
|
|
133
|
-
|
|
134
|
-
_SSR GraphQL requests include x-preferred-currency header_
|
|
135
|
-
|
|
136
|
-
- Implemented: ServerCookieManager reads from next/headers
|
|
137
|
-
|
|
138
|
-
### ✅ Requirement 1.4
|
|
139
|
-
|
|
140
|
-
_Client-side navigation includes x-preferred-currency header_
|
|
141
|
-
|
|
142
|
-
- Implemented: ClientCookieManager reads from js-cookie
|
|
143
|
-
|
|
144
|
-
### ✅ Requirement 2.2
|
|
145
|
-
|
|
146
|
-
_Return same value regardless of SSR or client context_
|
|
147
|
-
|
|
148
|
-
- Implemented: Both implementations read from same cookie
|
|
149
|
-
|
|
150
|
-
### ✅ Requirement 2.3
|
|
151
|
-
|
|
152
|
-
_Update both cookie and in-memory state atomically_
|
|
153
|
-
|
|
154
|
-
- Implemented: setCurrency() writes to cookie immediately
|
|
155
|
-
|
|
156
|
-
## Integration Points
|
|
157
|
-
|
|
158
|
-
The cookie manager integrates with:
|
|
159
|
-
|
|
160
|
-
1. **Currency Store** - Stores use cookie manager instead of localStorage
|
|
161
|
-
2. **GraphQL Client** - Reads currency from cookie for header injection
|
|
162
|
-
3. **Server Components** - Can read currency during SSR
|
|
163
|
-
4. **Client Components** - Can read and write currency
|
|
164
|
-
|
|
165
|
-
## Next Steps
|
|
166
|
-
|
|
167
|
-
The following tasks depend on this implementation:
|
|
168
|
-
|
|
169
|
-
1. **Task 1.1** - Write property test for cookie persistence
|
|
170
|
-
2. **Task 2** - Update currency store to use cookie manager
|
|
171
|
-
3. **Task 3** - Update GraphQL client to read from cookies
|
|
172
|
-
4. **Task 4** - Update currency selector component
|
|
173
|
-
5. **Task 5** - Add package dependencies (js-cookie, @types/js-cookie)
|
|
174
|
-
|
|
175
|
-
## Dependencies Required
|
|
176
|
-
|
|
177
|
-
Add to `package.json`:
|
|
178
|
-
|
|
179
|
-
```json
|
|
180
|
-
{
|
|
181
|
-
"dependencies": {
|
|
182
|
-
"js-cookie": "^3.0.5"
|
|
183
|
-
},
|
|
184
|
-
"devDependencies": {
|
|
185
|
-
"@types/js-cookie": "^3.0.6",
|
|
186
|
-
"vitest": "^1.0.0",
|
|
187
|
-
"fast-check": "^3.15.0"
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
## Files Created
|
|
193
|
-
|
|
194
|
-
- ✅ `lib/currency/cookie-manager.ts` (270 lines)
|
|
195
|
-
- ✅ `lib/currency/index.ts` (24 lines)
|
|
196
|
-
- ✅ `lib/currency/cookie-manager.test.ts` (380 lines)
|
|
197
|
-
- ✅ `lib/currency/README.md` (500 lines)
|
|
198
|
-
|
|
199
|
-
**Total:** 1,174 lines of production code, tests, and documentation
|
|
200
|
-
|
|
201
|
-
## Testing Status
|
|
202
|
-
|
|
203
|
-
- ✅ Unit test suite created (20+ tests)
|
|
204
|
-
- ⏳ Tests will run after dependencies are installed
|
|
205
|
-
- ⏳ Property-based tests (Task 1.1) - next step
|
|
206
|
-
- ⏳ E2E tests (Task 14) - later
|
|
207
|
-
|
|
208
|
-
## Quality Checklist
|
|
209
|
-
|
|
210
|
-
- ✅ TypeScript strict mode compatible
|
|
211
|
-
- ✅ Zero runtime dependencies (except js-cookie and Next.js)
|
|
212
|
-
- ✅ Comprehensive error handling
|
|
213
|
-
- ✅ JSDoc documentation on all public APIs
|
|
214
|
-
- ✅ Production-ready cookie configuration
|
|
215
|
-
- ✅ SSR-safe implementation
|
|
216
|
-
- ✅ Singleton pattern for performance
|
|
217
|
-
- ✅ Test coverage > 90% (when run)
|
|
218
|
-
|
|
219
|
-
## Notes for Next Developer
|
|
220
|
-
|
|
221
|
-
1. **Dependencies**: Run `pnpm add js-cookie` and `pnpm add -D @types/js-cookie` before using
|
|
222
|
-
2. **Tests**: Run `pnpm test lib/currency` after test setup is configured
|
|
223
|
-
3. **Integration**: Follow README.md examples for integrating with stores and GraphQL client
|
|
224
|
-
4. **Migration**: Users will need to re-select currency (one-time inconvenience)
|
|
225
|
-
|
|
226
|
-
## Known Limitations
|
|
227
|
-
|
|
228
|
-
1. **Requires Next.js 13+** - Uses `next/headers` cookies() API
|
|
229
|
-
2. **Client-side only writes** - SSR can only read, not write
|
|
230
|
-
3. **Cookie size limit** - Max 4KB (not an issue for currency code)
|
|
231
|
-
4. **Third-party cookies** - Some browsers block in incognito mode
|
|
232
|
-
|
|
233
|
-
## Performance Considerations
|
|
234
|
-
|
|
235
|
-
- ✅ Singleton pattern - one instance per context
|
|
236
|
-
- ✅ No localStorage polling - direct cookie access
|
|
237
|
-
- ✅ Lazy instantiation - only created when needed
|
|
238
|
-
- ✅ Zero dependencies on render cycle
|
|
239
|
-
|
|
240
|
-
## Security Considerations
|
|
241
|
-
|
|
242
|
-
- ✅ SameSite='lax' - prevents CSRF attacks
|
|
243
|
-
- ✅ Secure flag in production - HTTPS only
|
|
244
|
-
- ✅ HttpOnly=false - required for client access (acceptable for non-sensitive data)
|
|
245
|
-
- ✅ 365-day expiry - reasonable for preferences
|
|
246
|
-
|
|
247
|
-
## Maintainability
|
|
248
|
-
|
|
249
|
-
- ✅ Clear separation of concerns
|
|
250
|
-
- ✅ Extensible interface
|
|
251
|
-
- ✅ Comprehensive documentation
|
|
252
|
-
- ✅ Well-tested
|
|
253
|
-
- ✅ Follows Next.js conventions
|
|
254
|
-
- ✅ Clean Code principles applied
|