@doswiftly/cli 0.1.17 → 0.1.19

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.
Files changed (213) hide show
  1. package/README.md +23 -323
  2. package/dist/commands/check.js +1 -1
  3. package/dist/commands/check.js.map +1 -1
  4. package/dist/commands/deploy.d.ts.map +1 -1
  5. package/dist/commands/deploy.js +43 -20
  6. package/dist/commands/deploy.js.map +1 -1
  7. package/dist/commands/doctor.js +3 -3
  8. package/dist/commands/doctor.js.map +1 -1
  9. package/dist/commands/init.js +4 -4
  10. package/dist/commands/sdk.js +5 -5
  11. package/dist/commands/sdk.js.map +1 -1
  12. package/dist/commands/template.js +4 -4
  13. package/dist/commands/template.js.map +1 -1
  14. package/dist/commands/types.js +5 -5
  15. package/dist/commands/types.js.map +1 -1
  16. package/dist/commands/verify.js +2 -2
  17. package/dist/commands/verify.js.map +1 -1
  18. package/dist/lib/package-manager.d.ts +1 -1
  19. package/dist/lib/package-manager.js +1 -1
  20. package/package.json +1 -1
  21. package/templates/storefront-minimal/wrangler.toml +4 -0
  22. package/templates/storefront-nextjs/README.md +16 -12
  23. package/templates/storefront-nextjs/app/account/orders/page.tsx +2 -2
  24. package/templates/storefront-nextjs/app/account/page.tsx +2 -2
  25. package/templates/storefront-nextjs/app/auth/login/page.tsx +1 -1
  26. package/templates/storefront-nextjs/app/auth/register/page.tsx +1 -1
  27. package/templates/storefront-nextjs/app/cart/page.tsx +1 -1
  28. package/templates/storefront-nextjs/app/categories/[slug]/page.tsx +2 -2
  29. package/templates/storefront-nextjs/app/categories/page.tsx +1 -1
  30. package/templates/storefront-nextjs/app/collections/[slug]/page.tsx +1 -1
  31. package/templates/storefront-nextjs/app/collections/page.tsx +1 -1
  32. package/templates/storefront-nextjs/app/page.tsx +1 -1
  33. package/templates/storefront-nextjs/app/products/[slug]/page.tsx +1 -1
  34. package/templates/storefront-nextjs/app/products/page.tsx +2 -2
  35. package/templates/storefront-nextjs/app/search/page.tsx +1 -1
  36. package/templates/storefront-nextjs/components/auth/auth-guard.tsx +1 -1
  37. package/templates/storefront-nextjs/components/commerce/add-to-cart-button.tsx +1 -1
  38. package/templates/storefront-nextjs/components/commerce/cart-icon.tsx +1 -1
  39. package/templates/storefront-nextjs/components/commerce/currency-selector.tsx +2 -2
  40. package/templates/storefront-nextjs/components/commerce/product-filters.tsx +1 -1
  41. package/templates/storefront-nextjs/components/commerce/product-price.tsx +1 -1
  42. package/templates/storefront-nextjs/components/commerce/search-input.tsx +1 -1
  43. package/templates/storefront-nextjs/components/commerce/sort-select.tsx +1 -1
  44. package/templates/storefront-nextjs/components/providers.tsx +1 -1
  45. package/templates/storefront-nextjs/lib/currency.tsx +3 -3
  46. package/templates/storefront-nextjs/lib/format.ts +1 -1
  47. package/templates/storefront-nextjs/lib/graphql-queries.ts +3 -3
  48. package/templates/storefront-nextjs/package.dev.json +1 -1
  49. package/templates/storefront-nextjs/package.json +1 -1
  50. package/templates/storefront-nextjs/package.json.template +1 -1
  51. package/templates/storefront-nextjs/wrangler.toml +4 -0
  52. package/templates/storefront-nextjs-shadcn/.github/workflows/deploy.yml +47 -0
  53. package/templates/storefront-nextjs-shadcn/.github/workflows/preview.yml +47 -0
  54. package/templates/storefront-nextjs-shadcn/CLAUDE.md +148 -35
  55. package/templates/storefront-nextjs-shadcn/README.md +29 -162
  56. package/templates/storefront-nextjs-shadcn/app/account/addresses/page.tsx +98 -91
  57. package/templates/storefront-nextjs-shadcn/app/account/error.tsx +43 -0
  58. package/templates/storefront-nextjs-shadcn/app/account/loading.tsx +19 -0
  59. package/templates/storefront-nextjs-shadcn/app/account/loyalty/page.tsx +53 -162
  60. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/loading.tsx +60 -0
  61. package/templates/storefront-nextjs-shadcn/app/account/orders/[id]/page.tsx +36 -47
  62. package/templates/storefront-nextjs-shadcn/app/account/orders/page.tsx +46 -29
  63. package/templates/storefront-nextjs-shadcn/app/account/page.tsx +8 -5
  64. package/templates/storefront-nextjs-shadcn/app/account/settings/page.tsx +108 -71
  65. package/templates/storefront-nextjs-shadcn/app/api/auth/clear-token/route.ts +2 -86
  66. package/templates/storefront-nextjs-shadcn/app/api/auth/set-token/route.ts +2 -124
  67. package/templates/storefront-nextjs-shadcn/app/auth/forgot-password/page.tsx +10 -5
  68. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/loading.tsx +17 -0
  69. package/templates/storefront-nextjs-shadcn/app/blog/[slug]/page.tsx +43 -2
  70. package/templates/storefront-nextjs-shadcn/app/blog/loading.tsx +19 -0
  71. package/templates/storefront-nextjs-shadcn/app/brands/page.tsx +2 -1
  72. package/templates/storefront-nextjs-shadcn/app/cart/loading.tsx +26 -0
  73. package/templates/storefront-nextjs-shadcn/app/cart/page.tsx +6 -3
  74. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/category-products-client.tsx +56 -0
  75. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/loading.tsx +32 -0
  76. package/templates/storefront-nextjs-shadcn/app/categories/[slug]/page.tsx +76 -59
  77. package/templates/storefront-nextjs-shadcn/app/categories/page.tsx +8 -4
  78. package/templates/storefront-nextjs-shadcn/app/checkout/error.tsx +43 -0
  79. package/templates/storefront-nextjs-shadcn/app/checkout/loading.tsx +31 -0
  80. package/templates/storefront-nextjs-shadcn/app/checkout/page.tsx +116 -79
  81. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/loading.tsx +19 -0
  82. package/templates/storefront-nextjs-shadcn/app/collections/[handle]/page.tsx +1 -1
  83. package/templates/storefront-nextjs-shadcn/app/collections/loading.tsx +18 -0
  84. package/templates/storefront-nextjs-shadcn/app/collections/page.tsx +7 -4
  85. package/templates/storefront-nextjs-shadcn/app/global-error.tsx +117 -0
  86. package/templates/storefront-nextjs-shadcn/app/globals.css +8 -0
  87. package/templates/storefront-nextjs-shadcn/app/layout.tsx +46 -11
  88. package/templates/storefront-nextjs-shadcn/app/products/[slug]/error.tsx +43 -0
  89. package/templates/storefront-nextjs-shadcn/app/products/[slug]/loading.tsx +29 -0
  90. package/templates/storefront-nextjs-shadcn/app/products/[slug]/page.tsx +6 -6
  91. package/templates/storefront-nextjs-shadcn/app/products/[slug]/product-client.tsx +15 -61
  92. package/templates/storefront-nextjs-shadcn/app/products/loading.tsx +32 -0
  93. package/templates/storefront-nextjs-shadcn/app/products/products-client.tsx +405 -151
  94. package/templates/storefront-nextjs-shadcn/app/search/loading.tsx +18 -0
  95. package/templates/storefront-nextjs-shadcn/app/wishlist/page.tsx +8 -5
  96. package/templates/storefront-nextjs-shadcn/codegen.ts +48 -31
  97. package/templates/storefront-nextjs-shadcn/components/account/customer-info.fragment.graphql +36 -0
  98. package/templates/storefront-nextjs-shadcn/components/account/order-details.tsx +3 -1
  99. package/templates/storefront-nextjs-shadcn/components/account/order-history.tsx +26 -24
  100. package/templates/storefront-nextjs-shadcn/components/account/order-summary.fragment.graphql +36 -0
  101. package/templates/storefront-nextjs-shadcn/components/auth/account-menu.tsx +9 -9
  102. package/templates/storefront-nextjs-shadcn/components/auth/login-form.tsx +11 -37
  103. package/templates/storefront-nextjs-shadcn/components/auth/register-form.tsx +37 -23
  104. package/templates/storefront-nextjs-shadcn/components/cart/cart-drawer.tsx +4 -3
  105. package/templates/storefront-nextjs-shadcn/components/cart/cart-icon.tsx +8 -5
  106. package/templates/storefront-nextjs-shadcn/components/cart/cart-item.tsx +1 -1
  107. package/templates/storefront-nextjs-shadcn/components/cart/cart-line.fragment.graphql +53 -0
  108. package/templates/storefront-nextjs-shadcn/components/cart/cart-summary.tsx +1 -1
  109. package/templates/storefront-nextjs-shadcn/components/cart/shipping-estimator.tsx +22 -7
  110. package/templates/storefront-nextjs-shadcn/components/commerce/currency-selector.tsx +2 -2
  111. package/templates/storefront-nextjs-shadcn/components/commerce/product-actions.tsx +1 -1
  112. package/templates/storefront-nextjs-shadcn/components/commerce/search-input.tsx +2 -2
  113. package/templates/storefront-nextjs-shadcn/components/common/price-display.tsx +35 -11
  114. package/templates/storefront-nextjs-shadcn/components/discount/discount-breakdown.tsx +1 -1
  115. package/templates/storefront-nextjs-shadcn/components/discount/discount-code-input.tsx +3 -3
  116. package/templates/storefront-nextjs-shadcn/components/filters/range-slider-filter.tsx +5 -5
  117. package/templates/storefront-nextjs-shadcn/components/gift-card/gift-card-input.tsx +2 -2
  118. package/templates/storefront-nextjs-shadcn/components/home/category-grid.tsx +2 -1
  119. package/templates/storefront-nextjs-shadcn/components/home/collection-card.fragment.graphql +21 -0
  120. package/templates/storefront-nextjs-shadcn/components/home/featured-collections.tsx +2 -12
  121. package/templates/storefront-nextjs-shadcn/components/home/index.ts +0 -1
  122. package/templates/storefront-nextjs-shadcn/components/hydrated.tsx +24 -0
  123. package/templates/storefront-nextjs-shadcn/components/layout/breadcrumbs.tsx +4 -4
  124. package/templates/storefront-nextjs-shadcn/components/layout/category-node.fragment.graphql +22 -0
  125. package/templates/storefront-nextjs-shadcn/components/layout/currency-selector.tsx +2 -2
  126. package/templates/storefront-nextjs-shadcn/components/layout/header.tsx +33 -23
  127. package/templates/storefront-nextjs-shadcn/components/loyalty/points-balance.tsx +2 -11
  128. package/templates/storefront-nextjs-shadcn/components/loyalty/points-history.tsx +8 -25
  129. package/templates/storefront-nextjs-shadcn/components/loyalty/referral-section.tsx +10 -19
  130. package/templates/storefront-nextjs-shadcn/components/loyalty/rewards-catalog.tsx +17 -41
  131. package/templates/storefront-nextjs-shadcn/components/loyalty/tier-progress.tsx +2 -29
  132. package/templates/storefront-nextjs-shadcn/components/order/index.ts +6 -1
  133. package/templates/storefront-nextjs-shadcn/components/product/b2b-price-display.tsx +3 -1
  134. package/templates/storefront-nextjs-shadcn/components/product/filter-active-pills.tsx +69 -0
  135. package/templates/storefront-nextjs-shadcn/components/product/filter-mobile-sheet.tsx +84 -0
  136. package/templates/storefront-nextjs-shadcn/components/product/filter-price-range.tsx +138 -0
  137. package/templates/storefront-nextjs-shadcn/components/product/index.ts +9 -2
  138. package/templates/storefront-nextjs-shadcn/components/product/product-card.fragment.graphql +49 -0
  139. package/templates/storefront-nextjs-shadcn/components/product/product-card.tsx +3 -31
  140. package/templates/storefront-nextjs-shadcn/components/product/product-detail.fragment.graphql +52 -0
  141. package/templates/storefront-nextjs-shadcn/components/product/product-filters.tsx +176 -123
  142. package/templates/storefront-nextjs-shadcn/components/product/product-grid.tsx +3 -5
  143. package/templates/storefront-nextjs-shadcn/components/product/product-image.tsx +2 -2
  144. package/templates/storefront-nextjs-shadcn/components/product/product-price.tsx +2 -2
  145. package/templates/storefront-nextjs-shadcn/components/product/product-reviews.tsx +5 -4
  146. package/templates/storefront-nextjs-shadcn/components/product/product-sort.tsx +19 -7
  147. package/templates/storefront-nextjs-shadcn/components/product/product-variant-selector.tsx +8 -23
  148. package/templates/storefront-nextjs-shadcn/components/product/product-variant.fragment.graphql +51 -0
  149. package/templates/storefront-nextjs-shadcn/components/product/review-card.tsx +1 -1
  150. package/templates/storefront-nextjs-shadcn/components/product/review-form.tsx +1 -7
  151. package/templates/storefront-nextjs-shadcn/components/product/savings-display.tsx +17 -2
  152. package/templates/storefront-nextjs-shadcn/components/product/similar-products.tsx +3 -2
  153. package/templates/storefront-nextjs-shadcn/components/providers/index.ts +1 -1
  154. package/templates/storefront-nextjs-shadcn/components/providers/stores-provider.tsx +30 -0
  155. package/templates/storefront-nextjs-shadcn/components/providers/theme-provider.tsx +1 -1
  156. package/templates/storefront-nextjs-shadcn/components/returns/index.ts +2 -2
  157. package/templates/storefront-nextjs-shadcn/components/returns/return-request-form.tsx +3 -2
  158. package/templates/storefront-nextjs-shadcn/components/search/search-results.tsx +3 -2
  159. package/templates/storefront-nextjs-shadcn/components/ui/form.tsx +174 -0
  160. package/templates/storefront-nextjs-shadcn/components/ui/index.ts +30 -2
  161. package/templates/storefront-nextjs-shadcn/components/ui/progress.tsx +40 -0
  162. package/templates/storefront-nextjs-shadcn/components/ui/sheet.tsx +107 -0
  163. package/templates/storefront-nextjs-shadcn/components/ui/slider.tsx +33 -0
  164. package/templates/storefront-nextjs-shadcn/components/ui/textarea.tsx +24 -0
  165. package/templates/storefront-nextjs-shadcn/components/wishlist/wishlist-icon.tsx +3 -1
  166. package/templates/storefront-nextjs-shadcn/generated/graphql.ts +12779 -0
  167. package/templates/storefront-nextjs-shadcn/graphql/custom.example.graphql +159 -0
  168. package/templates/storefront-nextjs-shadcn/hooks/index.ts +2 -0
  169. package/templates/storefront-nextjs-shadcn/hooks/use-auth-sync.ts +42 -0
  170. package/templates/storefront-nextjs-shadcn/hooks/use-auth.ts +17 -295
  171. package/templates/storefront-nextjs-shadcn/hooks/use-cart-actions.ts +51 -19
  172. package/templates/storefront-nextjs-shadcn/hooks/use-cart-sync.ts +13 -9
  173. package/templates/storefront-nextjs-shadcn/lib/auth/routes.ts +4 -17
  174. package/templates/storefront-nextjs-shadcn/lib/graphql/client.ts +22 -99
  175. package/templates/storefront-nextjs-shadcn/lib/graphql/config.ts +32 -0
  176. package/templates/storefront-nextjs-shadcn/lib/graphql/fragments.ts +34 -0
  177. package/templates/storefront-nextjs-shadcn/lib/graphql/hooks.ts +687 -632
  178. package/templates/storefront-nextjs-shadcn/lib/graphql/query-keys.ts +86 -0
  179. package/templates/storefront-nextjs-shadcn/lib/graphql/server.ts +131 -182
  180. package/templates/storefront-nextjs-shadcn/lib/graphql/types.ts +62 -0
  181. package/templates/storefront-nextjs-shadcn/lib/theme/theme-config.ts +0 -17
  182. package/templates/storefront-nextjs-shadcn/next-env.d.ts +6 -0
  183. package/templates/storefront-nextjs-shadcn/package.dev.json +1 -3
  184. package/templates/storefront-nextjs-shadcn/package.json +12 -13
  185. package/templates/storefront-nextjs-shadcn/package.json.template +6 -7
  186. package/templates/storefront-nextjs-shadcn/proxy.ts +3 -4
  187. package/templates/storefront-nextjs-shadcn/stores/cart-store.ts +41 -39
  188. package/templates/storefront-nextjs-shadcn/stores/checkout-store.ts +64 -75
  189. package/templates/storefront-nextjs-shadcn/stores/wishlist-store.ts +178 -177
  190. package/templates/storefront-nextjs-shadcn/tsconfig.json +23 -5
  191. package/templates/storefront-nextjs-shadcn/wrangler.toml +4 -0
  192. package/templates/storefront-nextjs-shadcn/CART_INTEGRATION.md +0 -282
  193. package/templates/storefront-nextjs-shadcn/GRAPHQL_DOCUMENT_NAMES.md +0 -190
  194. package/templates/storefront-nextjs-shadcn/GRAPHQL_ERROR_HANDLING.md +0 -263
  195. package/templates/storefront-nextjs-shadcn/GRAPHQL_FIXES_SUMMARY.md +0 -135
  196. package/templates/storefront-nextjs-shadcn/GRAPHQL_INTEGRATION_COMPLETE.md +0 -142
  197. package/templates/storefront-nextjs-shadcn/INTEGRATION_CHECKLIST.md +0 -448
  198. package/templates/storefront-nextjs-shadcn/PRODUCT_DETAIL_PAGE_IMPLEMENTATION.md +0 -307
  199. package/templates/storefront-nextjs-shadcn/THEME_CUSTOMIZATION.md +0 -245
  200. package/templates/storefront-nextjs-shadcn/components/providers/currency-provider.tsx +0 -103
  201. package/templates/storefront-nextjs-shadcn/graphql/collections.example.ts +0 -168
  202. package/templates/storefront-nextjs-shadcn/graphql/products.example.ts +0 -160
  203. package/templates/storefront-nextjs-shadcn/lib/auth/cookies.ts +0 -220
  204. package/templates/storefront-nextjs-shadcn/lib/config.ts +0 -46
  205. package/templates/storefront-nextjs-shadcn/lib/currency/IMPLEMENTATION_SUMMARY.md +0 -254
  206. package/templates/storefront-nextjs-shadcn/lib/currency/README.md +0 -464
  207. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.test.ts +0 -328
  208. package/templates/storefront-nextjs-shadcn/lib/currency/cookie-manager.ts +0 -295
  209. package/templates/storefront-nextjs-shadcn/lib/currency/index.ts +0 -27
  210. package/templates/storefront-nextjs-shadcn/lib/format.ts +0 -226
  211. package/templates/storefront-nextjs-shadcn/lib/hooks.ts +0 -30
  212. package/templates/storefront-nextjs-shadcn/stores/auth-store.ts +0 -66
  213. package/templates/storefront-nextjs-shadcn/stores/currency-store.ts +0 -103
@@ -0,0 +1,159 @@
1
+ # ============================================================================
2
+ # Custom GraphQL Operations — Example File
3
+ # ============================================================================
4
+ #
5
+ # How to add custom queries/mutations to your storefront:
6
+ #
7
+ # 1. Create a .graphql file in this directory (e.g. graphql/my-queries.graphql)
8
+ # 2. Run `pnpm run codegen` to generate TypeScript types
9
+ # 3. Import the generated Document constant from @/generated/graphql
10
+ #
11
+ # Example usage in components:
12
+ #
13
+ # // Server Component
14
+ # import { request } from '@/lib/graphql/server';
15
+ # import { GetFeaturedProductsDocument } from '@/generated/graphql';
16
+ # const data = await request(GetFeaturedProductsDocument, { first: 6 });
17
+ #
18
+ # // Client Component
19
+ # import { useGraphQLQuery } from '@/lib/graphql/hooks';
20
+ # import { GetFeaturedProductsDocument } from '@/generated/graphql';
21
+ # const { data } = useGraphQLQuery(GetFeaturedProductsDocument, { first: 6 });
22
+ #
23
+ # To activate these examples, rename this file to custom.graphql and run codegen.
24
+ # ============================================================================
25
+
26
+ # Get featured products with specific fields
27
+ query GetFeaturedProducts($first: Int = 6) {
28
+ products(first: $first, query: "tag:featured") {
29
+ edges {
30
+ node {
31
+ id
32
+ handle
33
+ title
34
+ description
35
+ featuredImage {
36
+ url
37
+ altText
38
+ width
39
+ height
40
+ }
41
+ priceRange {
42
+ minVariantPrice {
43
+ amount
44
+ currencyCode
45
+ }
46
+ }
47
+ }
48
+ cursor
49
+ }
50
+ pageInfo {
51
+ hasNextPage
52
+ endCursor
53
+ }
54
+ }
55
+ }
56
+
57
+ # Search products with filters (category, price, attributes)
58
+ query SearchProductsWithFilters(
59
+ $query: String!
60
+ $first: Int = 20
61
+ $after: String
62
+ $filters: ProductFilterInput
63
+ ) {
64
+ products(
65
+ query: $query
66
+ first: $first
67
+ after: $after
68
+ filters: $filters
69
+ ) {
70
+ edges {
71
+ node {
72
+ id
73
+ handle
74
+ title
75
+ vendor
76
+ productType
77
+ featuredImage {
78
+ url
79
+ altText
80
+ }
81
+ priceRange {
82
+ minVariantPrice {
83
+ amount
84
+ currencyCode
85
+ }
86
+ maxVariantPrice {
87
+ amount
88
+ currencyCode
89
+ }
90
+ }
91
+ }
92
+ cursor
93
+ }
94
+ pageInfo {
95
+ hasNextPage
96
+ hasPreviousPage
97
+ startCursor
98
+ endCursor
99
+ }
100
+ totalCount
101
+ }
102
+ }
103
+
104
+ # Get collection with products (inline — useful when collection page needs custom fields)
105
+ query GetCollectionWithProducts(
106
+ $handle: String!
107
+ $first: Int = 20
108
+ $after: String
109
+ ) {
110
+ collection(handle: $handle) {
111
+ id
112
+ title
113
+ description
114
+ descriptionHtml
115
+ image {
116
+ url
117
+ altText
118
+ }
119
+ seo {
120
+ title
121
+ description
122
+ }
123
+ products(first: $first, after: $after) {
124
+ edges {
125
+ node {
126
+ id
127
+ handle
128
+ title
129
+ description
130
+ featuredImage {
131
+ url
132
+ altText
133
+ }
134
+ priceRange {
135
+ minVariantPrice {
136
+ amount
137
+ currencyCode
138
+ baseAmount
139
+ baseCurrencyCode
140
+ isConverted
141
+ }
142
+ }
143
+ vendor
144
+ productType
145
+ tags
146
+ totalInventory
147
+ }
148
+ cursor
149
+ }
150
+ pageInfo {
151
+ hasNextPage
152
+ hasPreviousPage
153
+ startCursor
154
+ endCursor
155
+ }
156
+ totalCount
157
+ }
158
+ }
159
+ }
@@ -3,6 +3,8 @@
3
3
  */
4
4
 
5
5
  export { useAuth } from "./use-auth";
6
+ export type { LoginResult, LogoutResult, TokenRenewResult } from "./use-auth";
7
+ export { useAuthSync } from "./use-auth-sync";
6
8
  export { useCartSync } from "./use-cart-sync";
7
9
  export { useCartActions } from "./use-cart-actions";
8
10
  export { useFilterParams } from "./use-filter-params";
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ import { useEffect } from 'react';
4
+ import { useRouter } from 'next/navigation';
5
+ import { useAuthStore, useAuthHydrated } from '@doswiftly/storefront-sdk/react';
6
+ import { createAuthTokenClient } from '@doswiftly/storefront-sdk';
7
+
8
+ const { clearToken } = createAuthTokenClient();
9
+
10
+ /**
11
+ * Detects and fixes auth state desync between httpOnly cookie and Zustand store.
12
+ *
13
+ * When server says authenticated (cookie exists → initialIsAuthenticated: true)
14
+ * but store has no accessToken after persist hydration (localStorage empty/cleared),
15
+ * the client can't make authenticated GraphQL requests.
16
+ *
17
+ * Fix: clear the stale cookie, reset auth state, redirect to login.
18
+ * The user re-authenticates once, which correctly populates both cookie AND localStorage.
19
+ */
20
+ export function useAuthSync() {
21
+ const router = useRouter();
22
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
23
+ const accessToken = useAuthStore((s) => s.accessToken);
24
+ const clearAuth = useAuthStore((s) => s.clearAuth);
25
+ const authHydrated = useAuthHydrated();
26
+
27
+ useEffect(() => {
28
+ if (!authHydrated) return;
29
+
30
+ // Desync: cookie exists (isAuthenticated: true from server) but no token in store
31
+ if (isAuthenticated && !accessToken) {
32
+ // Reset store state immediately
33
+ clearAuth();
34
+ // Clear stale cookie THEN redirect — must await so proxy sees cleared cookie
35
+ clearToken()
36
+ .catch(() => {})
37
+ .finally(() => {
38
+ router.push('/auth/login');
39
+ });
40
+ }
41
+ }, [authHydrated, isAuthenticated, accessToken, clearAuth, router]);
42
+ }
@@ -1,310 +1,32 @@
1
1
  /**
2
- * Authentication Hook
2
+ * useAuth — thin wrapper around SDK's useAuth with template-specific integrations.
3
3
  *
4
- * Provides login, logout, and authentication state management.
5
- *
6
- * Security Model:
7
- * 1. Login: Calls GraphQL mutation → Stores token in httpOnly cookie via API route
8
- * 2. Logout: Calls GraphQL mutation → Clears httpOnly cookie via API route
9
- * 3. Token validation: Happens on GraphQL backend (not client-side)
10
- *
11
- * Usage:
12
- * - Login/Register pages: Call login() after successful mutation
13
- * - Protected pages: Use AuthGuard component (checks cookie existence)
14
- * - Logout button: Call logout() to clear session
15
- *
16
- * @see lib/auth/cookies.ts - Cookie helper functions
17
- * @see lib/auth/routes.ts - Route configuration
18
- * @see proxy.ts - Server-side route protection
19
- *
20
- * @example
21
- * ```tsx
22
- * function LoginForm() {
23
- * const { login, isLoading, error } = useAuth();
24
- *
25
- * const handleSubmit = async (e) => {
26
- * e.preventDefault();
27
- * const result = await login(email, password);
28
- * if (result.userErrors.length === 0) {
29
- * // Success - redirected to /account
30
- * }
31
- * };
32
- *
33
- * return <form onSubmit={handleSubmit}>...</form>;
34
- * }
35
- * ```
4
+ * Adds:
5
+ * - httpOnly cookie management via API routes (onSetToken/onClearToken)
6
+ * - React Query cache invalidation on login/logout
36
7
  */
37
8
 
38
- "use client";
9
+ 'use client';
39
10
 
40
- import { useState } from "react";
41
- import { useRouter, useSearchParams } from "next/navigation";
42
- import { useMutation, useQueryClient } from "@tanstack/react-query";
43
- import { getGraphQLClient } from "@/lib/graphql/client";
44
- import {
45
- CustomerLoginDocument,
46
- CustomerLogoutDocument,
47
- CustomerTokenRenewDocument,
48
- type CustomerLoginMutation,
49
- type CustomerLogoutMutation,
50
- type CustomerTokenRenewMutation,
51
- } from "@/generated/graphql";
52
- import { setAuthToken, clearAuthToken, getAuthToken } from "@/lib/auth/cookies";
53
- import { redirects } from "@/lib/auth/routes";
11
+ import { useAuth as useSDKAuth, type LoginResult, type LogoutResult, type TokenRenewResult } from '@doswiftly/storefront-sdk/react';
12
+ import { createAuthTokenClient } from '@doswiftly/storefront-sdk';
13
+ import { useQueryClient } from '@tanstack/react-query';
54
14
 
55
- /**
56
- * Login input
57
- */
58
- export interface LoginInput {
59
- email: string;
60
- password: string;
61
- }
62
-
63
- /**
64
- * Login result
65
- */
66
- export interface LoginResult {
67
- success: boolean;
68
- userErrors: Array<{ message: string; field?: string[] }>;
69
- accessToken?: string;
70
- expiresAt?: string;
71
- }
72
-
73
- /**
74
- * Logout result
75
- */
76
- export interface LogoutResult {
77
- success: boolean;
78
- userErrors: Array<{ message: string; field?: string[] }>;
79
- }
15
+ export type { LoginResult, LogoutResult, TokenRenewResult };
80
16
 
81
- /**
82
- * Token renew result
83
- */
84
- export interface TokenRenewResult {
85
- success: boolean;
86
- userErrors: Array<{ message: string; field?: string[] }>;
87
- accessToken?: string;
88
- expiresAt?: string;
89
- }
17
+ const { setToken, clearToken } = createAuthTokenClient();
90
18
 
91
- /**
92
- * Authentication hook
93
- */
94
19
  export function useAuth() {
95
- const router = useRouter();
96
- const searchParams = useSearchParams();
97
20
  const queryClient = useQueryClient();
98
- const client = getGraphQLClient();
99
-
100
- const [error, setError] = useState<string | null>(null);
101
-
102
- /**
103
- * Login mutation
104
- */
105
- const loginMutation = useMutation({
106
- mutationFn: async (input: LoginInput): Promise<LoginResult> => {
107
- const data = await client.request<CustomerLoginMutation>(
108
- CustomerLoginDocument,
109
- { input }
110
- );
111
-
112
- const { customerAccessToken, userErrors } =
113
- data.customerAccessTokenCreate;
114
-
115
- if (userErrors && userErrors.length > 0) {
116
- return {
117
- success: false,
118
- userErrors: userErrors.map((e: any) => ({
119
- message: e.message,
120
- field: e.field || undefined,
121
- })),
122
- };
123
- }
124
-
125
- if (!customerAccessToken) {
126
- return {
127
- success: false,
128
- userErrors: [{ message: "Failed to create access token" }],
129
- };
130
- }
131
-
132
- // Store token in httpOnly cookie via API route
133
- await setAuthToken(customerAccessToken.accessToken);
134
-
135
- return {
136
- success: true,
137
- userErrors: [],
138
- accessToken: customerAccessToken.accessToken,
139
- expiresAt: customerAccessToken.expiresAt,
140
- };
141
- },
142
- onSuccess: (result: LoginResult) => {
143
- if (result.success) {
144
- // Clear any cached queries that might need authentication
145
- queryClient.invalidateQueries();
146
21
 
147
- // Redirect to original destination or account page
148
- const redirect = searchParams.get("redirect");
149
- router.push(redirect || redirects.authenticated);
150
- }
22
+ return useSDKAuth({
23
+ onSetToken: async (token: string) => {
24
+ await setToken(token);
25
+ queryClient.invalidateQueries();
151
26
  },
152
- onError: (err: unknown) => {
153
- setError(err instanceof Error ? err.message : "Login failed");
27
+ onClearToken: async () => {
28
+ await clearToken();
29
+ queryClient.clear();
154
30
  },
155
31
  });
156
-
157
- /**
158
- * Logout mutation
159
- */
160
- const logoutMutation = useMutation({
161
- mutationFn: async (): Promise<LogoutResult> => {
162
- const token = getAuthToken();
163
-
164
- if (!token) {
165
- // No token to logout
166
- return {
167
- success: true,
168
- userErrors: [],
169
- };
170
- }
171
-
172
- const data = await client.request<CustomerLogoutMutation>(
173
- CustomerLogoutDocument,
174
- { customerAccessToken: token }
175
- );
176
-
177
- const { userErrors } = data.customerAccessTokenDelete;
178
-
179
- if (userErrors && userErrors.length > 0) {
180
- return {
181
- success: false,
182
- userErrors: userErrors.map((e: any) => ({
183
- message: e.message,
184
- field: e.field || undefined,
185
- })),
186
- };
187
- }
188
-
189
- // Clear httpOnly cookie via API route
190
- await clearAuthToken();
191
-
192
- return {
193
- success: true,
194
- userErrors: [],
195
- };
196
- },
197
- onSuccess: (result: LogoutResult) => {
198
- if (result.success) {
199
- // Clear all cached queries
200
- queryClient.clear();
201
-
202
- // Redirect to home page
203
- router.push("/");
204
- }
205
- },
206
- onError: (err: unknown) => {
207
- setError(err instanceof Error ? err.message : "Logout failed");
208
- },
209
- });
210
-
211
- /**
212
- * Token renew mutation
213
- */
214
- const renewTokenMutation = useMutation({
215
- mutationFn: async (): Promise<TokenRenewResult> => {
216
- const token = getAuthToken();
217
-
218
- if (!token) {
219
- return {
220
- success: false,
221
- userErrors: [{ message: "No token to renew" }],
222
- };
223
- }
224
-
225
- const data = await client.request<CustomerTokenRenewMutation>(
226
- CustomerTokenRenewDocument,
227
- { customerAccessToken: token }
228
- );
229
-
230
- const { customerAccessToken, userErrors } =
231
- data.customerAccessTokenRenew;
232
-
233
- if (userErrors && userErrors.length > 0) {
234
- return {
235
- success: false,
236
- userErrors: userErrors.map((e: any) => ({
237
- message: e.message,
238
- field: e.field || undefined,
239
- })),
240
- };
241
- }
242
-
243
- if (!customerAccessToken) {
244
- return {
245
- success: false,
246
- userErrors: [{ message: "Failed to renew access token" }],
247
- };
248
- }
249
-
250
- // Update token in httpOnly cookie via API route
251
- await setAuthToken(customerAccessToken.accessToken);
252
-
253
- return {
254
- success: true,
255
- userErrors: [],
256
- accessToken: customerAccessToken.accessToken,
257
- expiresAt: customerAccessToken.expiresAt,
258
- };
259
- },
260
- onError: (err: unknown) => {
261
- setError(err instanceof Error ? err.message : "Token renewal failed");
262
- },
263
- });
264
-
265
- /**
266
- * Login function
267
- */
268
- const login = async (email: string, password: string): Promise<LoginResult> => {
269
- setError(null);
270
- return loginMutation.mutateAsync({ email, password });
271
- };
272
-
273
- /**
274
- * Logout function
275
- */
276
- const logout = async (): Promise<LogoutResult> => {
277
- setError(null);
278
- return logoutMutation.mutateAsync();
279
- };
280
-
281
- /**
282
- * Renew token function
283
- */
284
- const renewToken = async (): Promise<TokenRenewResult> => {
285
- setError(null);
286
- return renewTokenMutation.mutateAsync();
287
- };
288
-
289
- return {
290
- // Functions
291
- login,
292
- logout,
293
- renewToken,
294
-
295
- // State
296
- isLoggingIn: loginMutation.isPending,
297
- isLoggingOut: logoutMutation.isPending,
298
- isRenewingToken: renewTokenMutation.isPending,
299
- isLoading:
300
- loginMutation.isPending ||
301
- logoutMutation.isPending ||
302
- renewTokenMutation.isPending,
303
- error,
304
-
305
- // Results
306
- loginResult: loginMutation.data,
307
- logoutResult: logoutMutation.data,
308
- renewResult: renewTokenMutation.data,
309
- };
310
32
  }